Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "fontforgeui.h"
28 : #include "fffreetype.h"
29 : #include "edgelist2.h"
30 : #include <gwidget.h>
31 : #include <ustring.h>
32 : #include <math.h>
33 :
34 : /******************************************************************************/
35 : /* ***************************** Debugger Stuff ***************************** */
36 : /******************************************************************************/
37 :
38 : #if FREETYPE_HAS_DEBUGGER
39 : #include <pthread.h>
40 : #include <tterrors.h>
41 :
42 : typedef struct bpdata {
43 : int range; /* tt_coderange_glyph, tt_coderange_font, tt_coderange_cvt */
44 : int ip;
45 : } BpData;
46 :
47 : struct debugger_context {
48 : FT_Library context;
49 : FTC *ftc;
50 : /* I use a thread because freetype doesn't return, it just has a callback */
51 : /* on each instruction. In actuallity only one thread should be executable*/
52 : /* at a time (either main, or child) */
53 : pthread_t thread;
54 : pthread_mutex_t parent_mutex, child_mutex;
55 : pthread_cond_t parent_cond, child_cond;
56 : unsigned int terminate: 1; /* The thread has been started simply to clean itself up and die */
57 : unsigned int has_mutexes: 1;
58 : unsigned int has_thread: 1;
59 : unsigned int has_finished: 1;
60 : unsigned int debug_fpgm: 1;
61 : unsigned int multi_step: 1;
62 : unsigned int found_wp: 1;
63 : unsigned int found_wps: 1;
64 : unsigned int found_wps_uninit: 1;
65 : unsigned int found_wpc: 1;
66 : unsigned int initted_pts: 1;
67 : unsigned int is_bitmap: 1;
68 : int wp_ptindex, wp_cvtindex, wp_storeindex;
69 : real ptsizey, ptsizex;
70 : int dpi;
71 : TT_ExecContext exc;
72 : SplineChar *sc;
73 : int layer;
74 : BpData temp;
75 : BpData breaks[32];
76 : int bcnt;
77 : FT_Vector *oldpts;
78 : FT_Long *oldstore;
79 : uint8 *storetouched;
80 : int storeSize;
81 : FT_Long *oldcvt;
82 : FT_Long oldsval, oldcval;
83 : int n_points;
84 : uint8 *watch; /* exc->pts.n_points */
85 : uint8 *watchstorage; /* exc->storeSize, exc->storage[i] */
86 : uint8 *watchcvt; /* exc->cvtSize, exc->cvt[i] */
87 : int uninit_index;
88 : };
89 :
90 : static int AtWp(struct debugger_context *dc, TT_ExecContext exc ) {
91 : int i, hit=false, h;
92 :
93 : dc->found_wp = false;
94 : if ( dc->watch!=NULL && dc->oldpts!=NULL ) {
95 : for ( i=0; i<exc->pts.n_points; ++i ) {
96 : if ( dc->oldpts[i].x!=exc->pts.cur[i].x || dc->oldpts[i].y!=exc->pts.cur[i].y ) {
97 : dc->oldpts[i] = exc->pts.cur[i];
98 : if ( dc->watch[i] ) {
99 : hit = true;
100 : dc->wp_ptindex = i;
101 : }
102 : }
103 : }
104 : dc->found_wp = hit;
105 : }
106 : if ( dc->found_wps_uninit )
107 : hit = true;
108 : dc->found_wps = false;
109 : if ( dc->watchstorage!=NULL && dc->storetouched!=NULL ) {
110 : h = false;
111 : for ( i=0; i<exc->storeSize; ++i ) {
112 : if ( dc->storetouched[i]&2 ) {
113 : if ( dc->watchstorage[i] ) {
114 : h = true;
115 : dc->wp_storeindex = i;
116 : dc->oldsval = dc->oldstore[i];
117 : }
118 : dc->storetouched[i]&=~2;
119 : dc->oldstore[i] = exc->storage[i];
120 : }
121 : }
122 : dc->found_wps = h;
123 : hit |= h;
124 : }
125 : dc->found_wpc = false;
126 : if ( dc->watchcvt!=NULL && dc->oldcvt!=NULL ) {
127 : h = false;
128 : for ( i=0; i<exc->cvtSize; ++i ) {
129 : if ( dc->oldcvt[i]!=exc->cvt[i] ) {
130 : if ( dc->watchcvt[i] ) {
131 : h = true;
132 : dc->wp_cvtindex = i;
133 : dc->oldcval = dc->oldcvt[i];
134 : }
135 : dc->oldcvt[i] = exc->cvt[i];
136 : }
137 : }
138 : dc->found_wpc = h;
139 : hit |= h;
140 : }
141 : return( hit );
142 : }
143 :
144 : static int AtBp(struct debugger_context *dc, TT_ExecContext exc ) {
145 : int i;
146 :
147 : if ( dc->temp.range==exc->curRange && dc->temp.ip==exc->IP ) {
148 : dc->temp.range = tt_coderange_none;
149 : return( true );
150 : }
151 :
152 : for ( i=0; i<dc->bcnt; ++i ) {
153 : if ( dc->breaks[i].range==exc->curRange && dc->breaks[i].ip==exc->IP )
154 : return( true );
155 : }
156 : return( false );
157 : }
158 :
159 : static void TestStorage( struct debugger_context *dc, TT_ExecContext exc) {
160 : int instr;
161 :
162 : if ( exc->code==NULL || exc->IP==exc->codeSize )
163 : return;
164 : instr = exc->code[exc->IP];
165 : if ( instr==0x42 /* Write store */ && exc->top>=2 ) {
166 : int store_index = exc->stack[exc->top-2];
167 : if ( store_index>=0 && store_index<exc->storeSize )
168 : dc->storetouched[store_index] = 3; /* 2=>written this instr, 1=>ever written */
169 : } else if ( instr==0x43 /* Read Store */ && exc->top>=1 ) {
170 : int store_index = exc->stack[exc->top-1];
171 : if ( store_index>=0 && store_index<exc->storeSize &&
172 : !dc->storetouched[store_index] &&
173 : dc->watchstorage!=NULL && dc->watchstorage[store_index] ) {
174 : dc->found_wps_uninit = true;
175 : dc->uninit_index = store_index;
176 : }
177 : }
178 : }
179 :
180 : static struct debugger_context *massive_kludge;
181 :
182 : static FT_Error PauseIns( TT_ExecContext exc ) {
183 : int ret;
184 : struct debugger_context *dc = massive_kludge;
185 :
186 : if ( dc->terminate )
187 : return( TT_Err_Execution_Too_Long ); /* Some random error code, says we're probably in a infinite loop */
188 : dc->exc = exc;
189 : exc->grayscale = !dc->is_bitmap; /* if we are in 'prep' or 'fpgm' freetype doesn't know this yet */
190 :
191 : /* Set up for watch points */
192 : if ( dc->oldpts==NULL && exc->pts.n_points!=0 ) {
193 : dc->oldpts = calloc(exc->pts.n_points,sizeof(FT_Vector));
194 : dc->n_points = exc->pts.n_points;
195 : }
196 : if ( dc->oldstore==NULL && exc->storeSize!=0 ) {
197 : dc->oldstore = calloc(exc->storeSize,sizeof(FT_Long));
198 : dc->storetouched = calloc(exc->storeSize,sizeof(uint8));
199 : dc->storeSize = exc->storeSize;
200 : }
201 : if ( dc->oldcvt==NULL && exc->cvtSize!=0 )
202 : dc->oldcvt = calloc(exc->cvtSize,sizeof(FT_Long));
203 : if ( !dc->initted_pts ) {
204 : AtWp(dc,exc);
205 : dc->found_wp = false;
206 : dc->found_wps = false;
207 : dc->found_wps_uninit = false;
208 : dc->found_wpc = false;
209 : dc->initted_pts = true;
210 : }
211 :
212 : if ( !dc->debug_fpgm && exc->curRange!=tt_coderange_glyph ) {
213 : exc->instruction_trap = 1;
214 : ret = 0;
215 : while ( exc->curRange!=tt_coderange_glyph ) {
216 : TestStorage(dc,exc);
217 : ret = TT_RunIns(exc);
218 : if ( ret==TT_Err_Code_Overflow )
219 : return( 0 );
220 : if ( ret )
221 : return( ret );
222 : }
223 : return( ret );
224 : }
225 :
226 : pthread_mutex_lock(&dc->parent_mutex);
227 : pthread_cond_signal(&dc->parent_cond);
228 : pthread_mutex_unlock(&dc->parent_mutex);
229 : pthread_cond_wait(&dc->child_cond,&dc->child_mutex);
230 : if ( dc->terminate )
231 : return( TT_Err_Execution_Too_Long );
232 :
233 : do {
234 : exc->instruction_trap = 1;
235 : if (exc->curRange==tt_coderange_glyph && exc->IP==exc->codeSize) {
236 : ret = TT_Err_Code_Overflow;
237 : break;
238 : }
239 : TestStorage(dc,exc);
240 : ret = TT_RunIns(exc);
241 : if ( ret )
242 : break;
243 : /* Signal the parent if we are single stepping, or if we've reached a break-point */
244 : if ( AtWp(dc,exc) || !dc->multi_step || AtBp(dc,exc) ||
245 : (exc->curRange==tt_coderange_glyph && exc->IP==exc->codeSize)) {
246 : if ( dc->found_wp ) {
247 : ff_post_notice(_("Hit Watch Point"),_("Point %d was moved by the previous instruction"),dc->wp_ptindex);
248 : dc->found_wp = false;
249 : }
250 : if ( dc->found_wps ) {
251 : ff_post_notice(_("Watched Store Change"),_("Storage %d was changed from %d (%.2f) to %d (%.2f) by the previous instruction"),
252 : dc->wp_storeindex, dc->oldsval, dc->oldsval/64.0,exc->storage[dc->wp_storeindex],exc->storage[dc->wp_storeindex]/64.0);
253 : dc->found_wps = false;
254 : }
255 : if ( dc->found_wps_uninit ) {
256 : ff_post_notice(_("Read of Uninitialized Store"),_("Storage %d has not been initialized, yet the previous instruction read it"),
257 : dc->uninit_index );
258 : dc->found_wps_uninit = false;
259 : }
260 : if ( dc->found_wpc ) {
261 : ff_post_notice(_("Watched Cvt Change"),_("Cvt %d was changed from %d (%.2f) to %d (%.2f) by the previous instruction"),
262 : dc->wp_cvtindex, dc->oldcval, dc->oldcval/64.0,exc->cvt[dc->wp_cvtindex],exc->cvt[dc->wp_cvtindex]/64.0);
263 : dc->found_wpc = false;
264 : }
265 : pthread_mutex_lock(&dc->parent_mutex);
266 : pthread_cond_signal(&dc->parent_cond);
267 : pthread_mutex_unlock(&dc->parent_mutex);
268 : pthread_cond_wait(&dc->child_cond,&dc->child_mutex);
269 : }
270 : } while ( !dc->terminate );
271 :
272 : if ( ret==TT_Err_Code_Overflow )
273 : ret = 0;
274 :
275 : massive_kludge = dc; /* We set this again in case we are in a composite character where I think we get called several times (and some other thread might have set it) */
276 : if ( dc->terminate )
277 : return( TT_Err_Execution_Too_Long );
278 :
279 : return( ret );
280 : }
281 :
282 : static void *StartChar(void *_dc) {
283 : struct debugger_context *dc = _dc;
284 :
285 : pthread_mutex_lock(&dc->child_mutex);
286 :
287 : massive_kludge = dc;
288 : if ( (dc->ftc = __FreeTypeFontContext(dc->context,dc->sc->parent,dc->sc,NULL,
289 : dc->layer,ff_ttf, 0, NULL))==NULL )
290 : goto finish;
291 : if ( dc->storetouched!=NULL )
292 : memset(dc->storetouched,0,dc->storeSize);
293 :
294 : massive_kludge = dc;
295 : if ( FT_Set_Char_Size(dc->ftc->face,(int) (dc->ptsizex*64),(int) (dc->ptsizey*64), dc->dpi, dc->dpi))
296 : goto finish;
297 :
298 : massive_kludge = dc;
299 : FT_Load_Glyph(dc->ftc->face,dc->ftc->glyph_indeces[dc->sc->orig_pos],
300 : dc->is_bitmap ? (FT_LOAD_NO_AUTOHINT|FT_LOAD_NO_BITMAP|FT_LOAD_TARGET_MONO) : (FT_LOAD_NO_AUTOHINT|FT_LOAD_NO_BITMAP));
301 :
302 : finish:
303 : dc->has_finished = true;
304 : dc->exc = NULL;
305 : pthread_mutex_lock(&dc->parent_mutex);
306 : pthread_cond_signal(&dc->parent_cond); /* Wake up parent and get it to clean up after itself */
307 : pthread_mutex_unlock(&dc->parent_mutex);
308 : pthread_mutex_unlock(&dc->child_mutex);
309 : return( NULL );
310 : }
311 :
312 : void DebuggerTerminate(struct debugger_context *dc) {
313 : if ( dc->has_thread ) {
314 : if ( !dc->has_finished ) {
315 : dc->terminate = true;
316 : pthread_mutex_lock(&dc->child_mutex);
317 : pthread_cond_signal(&dc->child_cond); /* Wake up child and get it to clean up after itself */
318 : pthread_mutex_unlock(&dc->child_mutex);
319 : pthread_mutex_unlock(&dc->parent_mutex);
320 : }
321 : pthread_join(dc->thread,NULL);
322 : dc->has_thread = false;
323 : }
324 : if ( dc->has_mutexes ) {
325 : pthread_cond_destroy(&dc->child_cond);
326 : pthread_cond_destroy(&dc->parent_cond);
327 : pthread_mutex_destroy(&dc->child_mutex);
328 : pthread_mutex_unlock(&dc->parent_mutex); /* Is this actually needed? */
329 : pthread_mutex_destroy(&dc->parent_mutex);
330 : }
331 : if ( dc->ftc!=NULL )
332 : FreeTypeFreeContext(dc->ftc);
333 : if ( dc->context!=NULL )
334 : FT_Done_FreeType( dc->context );
335 : free(dc->watch);
336 : free(dc->oldpts);
337 : free(dc);
338 : }
339 :
340 : void DebuggerReset(struct debugger_context *dc,real ptsizey, real ptsizex,int dpi,int dbg_fpgm, int is_bitmap) {
341 : /* Kill off the old thread, and start up a new one working on the given */
342 : /* pointsize and resolution */ /* I'm not prepared for errors here */
343 : /* Note that if we don't want to look at the fpgm/prep code (and we */
344 : /* usually don't) then we must turn off the debug hook when they get run */
345 :
346 : if ( dc->has_thread ) {
347 : dc->terminate = true;
348 : pthread_mutex_lock(&dc->child_mutex);
349 : pthread_cond_signal(&dc->child_cond); /* Wake up child and get it to clean up after itself */
350 : pthread_mutex_unlock(&dc->child_mutex);
351 : pthread_mutex_unlock(&dc->parent_mutex);
352 :
353 : pthread_join(dc->thread,NULL);
354 : dc->has_thread = false;
355 : }
356 : if ( dc->ftc!=NULL )
357 : FreeTypeFreeContext(dc->ftc);
358 :
359 : dc->debug_fpgm = dbg_fpgm;
360 : dc->ptsizey = ptsizey;
361 : dc->ptsizex = ptsizex;
362 : dc->dpi = dpi;
363 : dc->is_bitmap = is_bitmap;
364 : dc->terminate = dc->has_finished = false;
365 : dc->initted_pts = false;
366 :
367 : pthread_mutex_lock(&dc->parent_mutex);
368 : if ( pthread_create(&dc->thread,NULL,StartChar,(void *) dc)!=0 ) {
369 : DebuggerTerminate(dc);
370 : return;
371 : }
372 : if ( dc->has_finished )
373 : return;
374 : dc->has_thread = true;
375 : pthread_cond_wait(&dc->parent_cond,&dc->parent_mutex);
376 : }
377 :
378 : struct debugger_context *DebuggerCreate(SplineChar *sc,int layer, real ptsizey,real ptsizex,int dpi,int dbg_fpgm, int is_bitmap) {
379 : struct debugger_context *dc;
380 :
381 : if ( !hasFreeTypeDebugger())
382 : return( NULL );
383 :
384 : dc = calloc(1,sizeof(struct debugger_context));
385 : dc->sc = sc;
386 : dc->layer = layer;
387 : dc->debug_fpgm = dbg_fpgm;
388 : dc->ptsizey = ptsizey;
389 : dc->ptsizex = ptsizex;
390 : dc->dpi = dpi;
391 : dc->is_bitmap = is_bitmap;
392 : if ( FT_Init_FreeType( &dc->context )) {
393 : free(dc);
394 : return( NULL );
395 : }
396 :
397 : #if FREETYPE_MINOR >= 5
398 : {
399 : int tt_version = TT_INTERPRETER_VERSION_35;
400 :
401 : if ( FT_Property_Set( dc->context,
402 : "truetype",
403 : "interpreter-version",
404 : &tt_version )) {
405 : free(dc);
406 : return( NULL );
407 : }
408 : }
409 : #endif
410 :
411 : FT_Set_Debug_Hook( dc->context,
412 : FT_DEBUG_HOOK_TRUETYPE,
413 : (FT_DebugHook_Func)PauseIns );
414 :
415 : pthread_mutex_init(&dc->parent_mutex,NULL); pthread_mutex_init(&dc->child_mutex,NULL);
416 : pthread_cond_init(&dc->parent_cond,NULL); pthread_cond_init(&dc->child_cond,NULL);
417 : dc->has_mutexes = true;
418 :
419 : pthread_mutex_lock(&dc->parent_mutex);
420 : if ( pthread_create(&dc->thread,NULL,StartChar,dc)!=0 ) {
421 : DebuggerTerminate( dc );
422 : return( NULL );
423 : }
424 : dc->has_thread = true;
425 : pthread_cond_wait(&dc->parent_cond,&dc->parent_mutex); /* Wait for the child to initialize itself (and stop) then we can look at its status */
426 :
427 : return( dc );
428 : }
429 :
430 : void DebuggerGo(struct debugger_context *dc,enum debug_gotype dgt,DebugView *dv) {
431 : int opcode;
432 :
433 : if ( !dc->has_thread || dc->has_finished || dc->exc==NULL ) {
434 : FreeType_FreeRaster(dv->cv->raster); dv->cv->raster = NULL;
435 : DebuggerReset(dc,dc->ptsizey,dc->ptsizex,dc->dpi,dc->debug_fpgm,dc->is_bitmap);
436 : } else {
437 : switch ( dgt ) {
438 : case dgt_continue:
439 : dc->multi_step = true;
440 : break;
441 : case dgt_stepout:
442 : dc->multi_step = true;
443 : if ( dc->exc->callTop>0 ) {
444 : dc->temp.range = dc->exc->callStack[dc->exc->callTop-1].Caller_Range;
445 : dc->temp.ip = dc->exc->callStack[dc->exc->callTop-1].Caller_IP;
446 : }
447 : break;
448 : case dgt_next:
449 : opcode = dc->exc->code[dc->exc->IP];
450 : /* I've decided that IDEFs will get stepped into */
451 : if ( opcode==0x2b /* call */ || opcode==0x2a /* loopcall */ ) {
452 : dc->temp.range = dc->exc->curRange;
453 : dc->temp.ip = dc->exc->IP+1;
454 : dc->multi_step = true;
455 : } else
456 : dc->multi_step = false;
457 : break;
458 : default:
459 : case dgt_step:
460 : dc->multi_step = false;
461 : break;
462 : }
463 : pthread_mutex_lock(&dc->child_mutex);
464 : pthread_cond_signal(&dc->child_cond); /* Wake up child and get it to clean up after itself */
465 : pthread_mutex_unlock(&dc->child_mutex);
466 : pthread_cond_wait(&dc->parent_cond,&dc->parent_mutex); /* Wait for the child to initialize itself (and stop) then we can look at its status */
467 : }
468 : }
469 :
470 : struct TT_ExecContextRec_ *DebuggerGetEContext(struct debugger_context *dc) {
471 : return( dc->exc );
472 : }
473 :
474 : int DebuggerBpCheck(struct debugger_context *dc,int range,int ip) {
475 : int i;
476 :
477 : for ( i=0; i<dc->bcnt; ++i ) {
478 : if ( dc->breaks[i].range==range && dc->breaks[i].ip==ip )
479 : return( true );
480 : }
481 : return( false );
482 : }
483 :
484 : void DebuggerToggleBp(struct debugger_context *dc,int range,int ip) {
485 : int i;
486 :
487 : /* If the address has a bp, then remove it */
488 : for ( i=0; i<dc->bcnt; ++i ) {
489 : if ( dc->breaks[i].range==range && dc->breaks[i].ip==ip ) {
490 : ++i;
491 : while ( i<dc->bcnt ) {
492 : dc->breaks[i-1].range = dc->breaks[i].range;
493 : dc->breaks[i-1].ip = dc->breaks[i].ip;
494 : ++i;
495 : }
496 : --dc->bcnt;
497 : return;
498 : }
499 : }
500 : /* Else add it */
501 : if ( dc->bcnt>=sizeof(dc->breaks)/sizeof(dc->breaks[0]) ) {
502 : ff_post_error(_("Too Many Breakpoints"),_("Too Many Breakpoints"));
503 : return;
504 : }
505 : i = dc->bcnt++;
506 : dc->breaks[i].range = range;
507 : dc->breaks[i].ip = ip;
508 : }
509 :
510 : void DebuggerSetWatches(struct debugger_context *dc,int n, uint8 *w) {
511 : free(dc->watch); dc->watch=NULL;
512 : if ( n!=dc->n_points ) IError("Bad watchpoint count");
513 : else {
514 : dc->watch = w;
515 : if ( dc->exc ) {
516 : AtWp(dc,dc->exc);
517 : dc->found_wp = false;
518 : dc->found_wpc = false;
519 : dc->found_wps = false;
520 : dc->found_wps_uninit = false;
521 : }
522 : }
523 : }
524 :
525 : uint8 *DebuggerGetWatches(struct debugger_context *dc, int *n) {
526 : *n = dc->n_points;
527 : return( dc->watch );
528 : }
529 :
530 : void DebuggerSetWatchStores(struct debugger_context *dc,int n, uint8 *w) {
531 : free(dc->watchstorage); dc->watchstorage=NULL;
532 : if ( n!=dc->exc->storeSize ) IError("Bad watchpoint count");
533 : else {
534 : dc->watchstorage = w;
535 : if ( dc->exc ) {
536 : AtWp(dc,dc->exc);
537 : dc->found_wp = false;
538 : dc->found_wpc = false;
539 : dc->found_wps = false;
540 : dc->found_wps_uninit = false;
541 : }
542 : }
543 : }
544 :
545 : uint8 *DebuggerGetWatchStores(struct debugger_context *dc, int *n) {
546 : *n = dc->exc->storeSize;
547 : return( dc->watchstorage );
548 : }
549 :
550 : int DebuggerIsStorageSet(struct debugger_context *dc, int index) {
551 : if ( dc->storetouched==NULL )
552 : return( false );
553 : return( dc->storetouched[index]&1 );
554 : }
555 :
556 : void DebuggerSetWatchCvts(struct debugger_context *dc,int n, uint8 *w) {
557 : free(dc->watchcvt); dc->watchcvt=NULL;
558 : if ( n!=dc->exc->cvtSize ) IError("Bad watchpoint count");
559 : else {
560 : dc->watchcvt = w;
561 : if ( dc->exc ) {
562 : AtWp(dc,dc->exc);
563 : dc->found_wp = false;
564 : dc->found_wpc = false;
565 : dc->found_wps = false;
566 : dc->found_wps_uninit = false;
567 : }
568 : }
569 : }
570 :
571 : uint8 *DebuggerGetWatchCvts(struct debugger_context *dc, int *n) {
572 : *n = dc->exc->cvtSize;
573 : return( dc->watchcvt );
574 : }
575 :
576 : int DebuggingFpgm(struct debugger_context *dc) {
577 : return( dc->debug_fpgm );
578 : }
579 :
580 : struct freetype_raster *DebuggerCurrentRaster(TT_ExecContext exc,int depth) {
581 : FT_Outline outline;
582 : FT_Bitmap bitmap;
583 : int i, err, j, k, first, xoff, yoff;
584 : IBounds b;
585 : struct freetype_raster *ret;
586 :
587 : outline.n_contours = exc->pts.n_contours;
588 : outline.tags = (char *) exc->pts.tags;
589 : outline.contours = (short *) exc->pts.contours;
590 : /* Rasterizer gets unhappy if we give it the phantom points */
591 : if ( outline.n_contours==0 )
592 : outline.n_points = 0;
593 : else
594 : outline.n_points = /*exc->pts.n_points*/ outline.contours[outline.n_contours - 1] + 1;
595 : outline.points = exc->pts.cur;
596 : outline.flags = 0;
597 : switch ( exc->GS.scan_type ) {
598 : /* Taken, at Werner's suggestion, from the freetype sources: ttgload.c:1970 */
599 : case 0: /* simple drop-outs including stubs */
600 : outline.flags |= FT_OUTLINE_INCLUDE_STUBS;
601 : break;
602 : case 1: /* simple drop-outs excluding stubs */
603 : /* nothing; it's the default rendering mode */
604 : break;
605 : case 4: /* smart drop-outs including stubs */
606 : outline.flags |= FT_OUTLINE_SMART_DROPOUTS |
607 : FT_OUTLINE_INCLUDE_STUBS;
608 : break;
609 : case 5: /* smart drop-outs excluding stubs */
610 : outline.flags |= FT_OUTLINE_SMART_DROPOUTS;
611 : break;
612 :
613 : default: /* no drop-out control */
614 : outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
615 : break;
616 : }
617 :
618 : if ( exc->metrics.y_ppem < 24 )
619 : outline.flags |= FT_OUTLINE_HIGH_PRECISION;
620 :
621 : first = true;
622 : for ( k=0; k<outline.n_contours; ++k ) {
623 : if ( outline.contours[k] - (k==0?-1:outline.contours[k-1])>1 ) {
624 : /* Single point contours are used for things like point matching */
625 : /* for anchor points, etc. and do not contribute to the bounding */
626 : /* box */
627 : i = (k==0?0:(outline.contours[k-1]+1));
628 : if ( first ) {
629 : b.minx = b.maxx = outline.points[i].x;
630 : b.miny = b.maxy = outline.points[i++].y;
631 : first = false;
632 : }
633 : for ( ; i<=outline.contours[k]; ++i ) {
634 : if ( outline.points[i].x>b.maxx ) b.maxx = outline.points[i].x;
635 : if ( outline.points[i].x<b.minx ) b.minx = outline.points[i].x;
636 : if ( outline.points[i].y>b.maxy ) b.maxy = outline.points[i].y;
637 : if ( outline.points[i].y<b.miny ) b.miny = outline.points[i].y;
638 : }
639 : }
640 : }
641 : if ( first )
642 : memset(&b,0,sizeof(b));
643 :
644 : memset(&bitmap,0,sizeof(bitmap));
645 : bitmap.rows = (((int) (ceil(b.maxy/64.0)-floor(b.miny/64.0)))) +1;
646 : bitmap.width = (((int) (ceil(b.maxx/64.0)-floor(b.minx/64.0)))) +1;
647 :
648 : xoff = 64*floor(b.minx/64.0);
649 : yoff = 64*floor(b.miny/64.0);
650 : for ( i=0; i<outline.n_points; ++i ) {
651 : outline.points[i].x -= xoff;
652 : outline.points[i].y -= yoff;
653 : }
654 :
655 : if ( depth==8 ) {
656 : bitmap.pitch = bitmap.width;
657 : bitmap.num_grays = 256;
658 : bitmap.pixel_mode = ft_pixel_mode_grays;
659 : } else {
660 : bitmap.pitch = (bitmap.width+7)>>3;
661 : bitmap.num_grays = 0;
662 : bitmap.pixel_mode = ft_pixel_mode_mono;
663 : }
664 : bitmap.buffer = calloc(bitmap.pitch*bitmap.rows,sizeof(uint8));
665 :
666 : err = (FT_Outline_Get_Bitmap)(ff_ft_context,&outline,&bitmap);
667 :
668 : for ( i=0; i<outline.n_points; ++i ) {
669 : outline.points[i].x += xoff;
670 : outline.points[i].y += yoff;
671 : }
672 :
673 : ret = malloc(sizeof(struct freetype_raster));
674 : /* I'm not sure why I need these, but it seems I do */
675 : if ( depth==8 ) {
676 : ret->as = floor(b.miny/64.0) + bitmap.rows;
677 : ret->lb = floor(b.minx/64.0);
678 : } else {
679 : for ( k=0; k<bitmap.rows; ++k ) {
680 : for ( j=bitmap.pitch-1; j>=0 && bitmap.buffer[k*bitmap.pitch+j]==0; --j );
681 : if ( j!=-1 )
682 : break;
683 : }
684 : b.maxy += k<<6;
685 : if ( depth==8 ) {
686 : for ( j=0; j<bitmap.pitch; ++j ) {
687 : for ( k=(((int) (b.maxy-b.miny))>>6)-1; k>=0; --k ) {
688 : if ( bitmap.buffer[k*bitmap.pitch+j]!=0 )
689 : break;
690 : }
691 : if ( k!=-1 )
692 : break;
693 : }
694 : } else {
695 : for ( j=0; j<bitmap.pitch; ++j ) {
696 : for ( k=(((int) (b.maxy-b.miny))>>6)-1; k>=0; --k ) {
697 : if ( bitmap.buffer[k*bitmap.pitch+(j>>3)]&(0x80>>(j&7)) )
698 : break;
699 : }
700 : if ( k!=-1 )
701 : break;
702 : }
703 : }
704 : b.minx -= j*64;
705 : ret->as = rint(b.maxy/64.0);
706 : ret->lb = rint(b.minx/64.0);
707 : }
708 : ret->rows = bitmap.rows;
709 : ret->cols = bitmap.width;
710 : ret->bytes_per_row = bitmap.pitch;
711 : ret->num_greys = bitmap.num_grays;
712 : ret->bitmap = bitmap.buffer;
713 : return( ret );
714 : }
715 :
716 : #else /* FIXME: Don't build this stuff if it's not being used, it just makes the compiler emit lots of warnings */
717 : struct debugger_context;
718 :
719 0 : void DebuggerTerminate(struct debugger_context *dc) {
720 0 : }
721 :
722 0 : void DebuggerReset(struct debugger_context *dc,real ptsizey, real ptsizex,int dpi,int dbg_fpgm, int is_bitmap) {
723 0 : }
724 :
725 0 : struct debugger_context *DebuggerCreate(SplineChar *sc,int layer,real pointsizey, real pointsizex,int dpi, int dbg_fpgm, int is_bitmap) {
726 0 : return( NULL );
727 : }
728 :
729 0 : void DebuggerGo(struct debugger_context *dc,enum debug_gotype go,DebugView *dv) {
730 0 : }
731 :
732 0 : struct TT_ExecContextRec_ *DebuggerGetEContext(struct debugger_context *dc) {
733 0 : return( NULL );
734 : }
735 :
736 0 : void DebuggerSetWatches(struct debugger_context *dc,int n, uint8 *w) {
737 0 : }
738 :
739 0 : uint8 *DebuggerGetWatches(struct debugger_context *dc, int *n) {
740 0 : *n = 0;
741 0 : return( NULL );
742 : }
743 :
744 0 : void DebuggerSetWatchStores(struct debugger_context *dc,int n, uint8 *w) {
745 0 : }
746 :
747 0 : uint8 *DebuggerGetWatchStores(struct debugger_context *dc, int *n) {
748 0 : *n = 0;
749 0 : return( NULL );
750 : }
751 :
752 0 : int DebuggerIsStorageSet(struct debugger_context *dc, int index) {
753 0 : return( false );
754 : }
755 :
756 0 : void DebuggerSetWatchCvts(struct debugger_context *dc,int n, uint8 *w) {
757 0 : }
758 :
759 0 : uint8 *DebuggerGetWatchCvts(struct debugger_context *dc, int *n) {
760 0 : *n = 0;
761 0 : return( NULL );
762 : }
763 :
764 0 : int DebuggingFpgm(struct debugger_context *dc) {
765 0 : return( false );
766 : }
767 : #endif /* FREETYPE_HAS_DEBUGGER */
|