OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* pshrec.c */ | |
4 /* */ | |
5 /* FreeType PostScript hints recorder (body). */ | |
6 /* */ | |
7 /* Copyright 2001-2004, 2007, 2009, 2013 by */ | |
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ | |
9 /* */ | |
10 /* This file is part of the FreeType project, and may only be used, */ | |
11 /* modified, and distributed under the terms of the FreeType project */ | |
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | |
13 /* this file you indicate that you have read the license and */ | |
14 /* understand and accept it fully. */ | |
15 /* */ | |
16 /***************************************************************************/ | |
17 | |
18 | |
19 #include "../../include/ft2build.h" | |
20 #include "../../include/freetype/freetype.h" | |
21 #include "../../include/freetype/internal/ftobjs.h" | |
22 #include "../../include/freetype/internal/ftdebug.h" | |
23 #include "../../include/freetype/internal/ftcalc.h" | |
24 | |
25 #include "pshrec.h" | |
26 #include "pshalgo.h" | |
27 | |
28 #include "pshnterr.h" | |
29 | |
30 #undef FT_COMPONENT | |
31 #define FT_COMPONENT trace_pshrec | |
32 | |
33 #ifdef DEBUG_HINTER | |
34 PS_Hints ps_debug_hints = 0; | |
35 int ps_debug_no_horz_hints = 0; | |
36 int ps_debug_no_vert_hints = 0; | |
37 #endif | |
38 | |
39 | |
40 /*************************************************************************/ | |
41 /*************************************************************************/ | |
42 /***** *****/ | |
43 /***** PS_HINT MANAGEMENT *****/ | |
44 /***** *****/ | |
45 /*************************************************************************/ | |
46 /*************************************************************************/ | |
47 | |
48 /* destroy hints table */ | |
49 static void | |
50 ps_hint_table_done( PS_Hint_Table table, | |
51 FT_Memory memory ) | |
52 { | |
53 FT_FREE( table->hints ); | |
54 table->num_hints = 0; | |
55 table->max_hints = 0; | |
56 } | |
57 | |
58 | |
59 /* ensure that a table can contain "count" elements */ | |
60 static FT_Error | |
61 ps_hint_table_ensure( PS_Hint_Table table, | |
62 FT_UInt count, | |
63 FT_Memory memory ) | |
64 { | |
65 FT_UInt old_max = table->max_hints; | |
66 FT_UInt new_max = count; | |
67 FT_Error error = FT_Err_Ok; | |
68 | |
69 | |
70 if ( new_max > old_max ) | |
71 { | |
72 /* try to grow the table */ | |
73 new_max = FT_PAD_CEIL( new_max, 8 ); | |
74 if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) ) | |
75 table->max_hints = new_max; | |
76 } | |
77 return error; | |
78 } | |
79 | |
80 | |
81 static FT_Error | |
82 ps_hint_table_alloc( PS_Hint_Table table, | |
83 FT_Memory memory, | |
84 PS_Hint *ahint ) | |
85 { | |
86 FT_Error error = FT_Err_Ok; | |
87 FT_UInt count; | |
88 PS_Hint hint = 0; | |
89 | |
90 | |
91 count = table->num_hints; | |
92 count++; | |
93 | |
94 if ( count >= table->max_hints ) | |
95 { | |
96 error = ps_hint_table_ensure( table, count, memory ); | |
97 if ( error ) | |
98 goto Exit; | |
99 } | |
100 | |
101 hint = table->hints + count - 1; | |
102 hint->pos = 0; | |
103 hint->len = 0; | |
104 hint->flags = 0; | |
105 | |
106 table->num_hints = count; | |
107 | |
108 Exit: | |
109 *ahint = hint; | |
110 return error; | |
111 } | |
112 | |
113 | |
114 /*************************************************************************/ | |
115 /*************************************************************************/ | |
116 /***** *****/ | |
117 /***** PS_MASK MANAGEMENT *****/ | |
118 /***** *****/ | |
119 /*************************************************************************/ | |
120 /*************************************************************************/ | |
121 | |
122 /* destroy mask */ | |
123 static void | |
124 ps_mask_done( PS_Mask mask, | |
125 FT_Memory memory ) | |
126 { | |
127 FT_FREE( mask->bytes ); | |
128 mask->num_bits = 0; | |
129 mask->max_bits = 0; | |
130 mask->end_point = 0; | |
131 } | |
132 | |
133 | |
134 /* ensure that a mask can contain "count" bits */ | |
135 static FT_Error | |
136 ps_mask_ensure( PS_Mask mask, | |
137 FT_UInt count, | |
138 FT_Memory memory ) | |
139 { | |
140 FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; | |
141 FT_UInt new_max = ( count + 7 ) >> 3; | |
142 FT_Error error = FT_Err_Ok; | |
143 | |
144 | |
145 if ( new_max > old_max ) | |
146 { | |
147 new_max = FT_PAD_CEIL( new_max, 8 ); | |
148 if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) | |
149 mask->max_bits = new_max * 8; | |
150 } | |
151 return error; | |
152 } | |
153 | |
154 | |
155 /* test a bit value in a given mask */ | |
156 static FT_Int | |
157 ps_mask_test_bit( PS_Mask mask, | |
158 FT_Int idx ) | |
159 { | |
160 if ( (FT_UInt)idx >= mask->num_bits ) | |
161 return 0; | |
162 | |
163 return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); | |
164 } | |
165 | |
166 | |
167 /* clear a given bit */ | |
168 static void | |
169 ps_mask_clear_bit( PS_Mask mask, | |
170 FT_Int idx ) | |
171 { | |
172 FT_Byte* p; | |
173 | |
174 | |
175 if ( (FT_UInt)idx >= mask->num_bits ) | |
176 return; | |
177 | |
178 p = mask->bytes + ( idx >> 3 ); | |
179 p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) ); | |
180 } | |
181 | |
182 | |
183 /* set a given bit, possibly grow the mask */ | |
184 static FT_Error | |
185 ps_mask_set_bit( PS_Mask mask, | |
186 FT_Int idx, | |
187 FT_Memory memory ) | |
188 { | |
189 FT_Error error = FT_Err_Ok; | |
190 FT_Byte* p; | |
191 | |
192 | |
193 if ( idx < 0 ) | |
194 goto Exit; | |
195 | |
196 if ( (FT_UInt)idx >= mask->num_bits ) | |
197 { | |
198 error = ps_mask_ensure( mask, idx + 1, memory ); | |
199 if ( error ) | |
200 goto Exit; | |
201 | |
202 mask->num_bits = idx + 1; | |
203 } | |
204 | |
205 p = mask->bytes + ( idx >> 3 ); | |
206 p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); | |
207 | |
208 Exit: | |
209 return error; | |
210 } | |
211 | |
212 | |
213 /* destroy mask table */ | |
214 static void | |
215 ps_mask_table_done( PS_Mask_Table table, | |
216 FT_Memory memory ) | |
217 { | |
218 FT_UInt count = table->max_masks; | |
219 PS_Mask mask = table->masks; | |
220 | |
221 | |
222 for ( ; count > 0; count--, mask++ ) | |
223 ps_mask_done( mask, memory ); | |
224 | |
225 FT_FREE( table->masks ); | |
226 table->num_masks = 0; | |
227 table->max_masks = 0; | |
228 } | |
229 | |
230 | |
231 /* ensure that a mask table can contain "count" masks */ | |
232 static FT_Error | |
233 ps_mask_table_ensure( PS_Mask_Table table, | |
234 FT_UInt count, | |
235 FT_Memory memory ) | |
236 { | |
237 FT_UInt old_max = table->max_masks; | |
238 FT_UInt new_max = count; | |
239 FT_Error error = FT_Err_Ok; | |
240 | |
241 | |
242 if ( new_max > old_max ) | |
243 { | |
244 new_max = FT_PAD_CEIL( new_max, 8 ); | |
245 if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) | |
246 table->max_masks = new_max; | |
247 } | |
248 return error; | |
249 } | |
250 | |
251 | |
252 /* allocate a new mask in a table */ | |
253 static FT_Error | |
254 ps_mask_table_alloc( PS_Mask_Table table, | |
255 FT_Memory memory, | |
256 PS_Mask *amask ) | |
257 { | |
258 FT_UInt count; | |
259 FT_Error error = FT_Err_Ok; | |
260 PS_Mask mask = 0; | |
261 | |
262 | |
263 count = table->num_masks; | |
264 count++; | |
265 | |
266 if ( count > table->max_masks ) | |
267 { | |
268 error = ps_mask_table_ensure( table, count, memory ); | |
269 if ( error ) | |
270 goto Exit; | |
271 } | |
272 | |
273 mask = table->masks + count - 1; | |
274 mask->num_bits = 0; | |
275 mask->end_point = 0; | |
276 table->num_masks = count; | |
277 | |
278 Exit: | |
279 *amask = mask; | |
280 return error; | |
281 } | |
282 | |
283 | |
284 /* return last hint mask in a table, create one if the table is empty */ | |
285 static FT_Error | |
286 ps_mask_table_last( PS_Mask_Table table, | |
287 FT_Memory memory, | |
288 PS_Mask *amask ) | |
289 { | |
290 FT_Error error = FT_Err_Ok; | |
291 FT_UInt count; | |
292 PS_Mask mask; | |
293 | |
294 | |
295 count = table->num_masks; | |
296 if ( count == 0 ) | |
297 { | |
298 error = ps_mask_table_alloc( table, memory, &mask ); | |
299 if ( error ) | |
300 goto Exit; | |
301 } | |
302 else | |
303 mask = table->masks + count - 1; | |
304 | |
305 Exit: | |
306 *amask = mask; | |
307 return error; | |
308 } | |
309 | |
310 | |
311 /* set a new mask to a given bit range */ | |
312 static FT_Error | |
313 ps_mask_table_set_bits( PS_Mask_Table table, | |
314 const FT_Byte* source, | |
315 FT_UInt bit_pos, | |
316 FT_UInt bit_count, | |
317 FT_Memory memory ) | |
318 { | |
319 FT_Error error; | |
320 PS_Mask mask; | |
321 | |
322 | |
323 error = ps_mask_table_last( table, memory, &mask ); | |
324 if ( error ) | |
325 goto Exit; | |
326 | |
327 error = ps_mask_ensure( mask, bit_count, memory ); | |
328 if ( error ) | |
329 goto Exit; | |
330 | |
331 mask->num_bits = bit_count; | |
332 | |
333 /* now, copy bits */ | |
334 { | |
335 FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); | |
336 FT_Int rmask = 0x80 >> ( bit_pos & 7 ); | |
337 FT_Byte* write = mask->bytes; | |
338 FT_Int wmask = 0x80; | |
339 FT_Int val; | |
340 | |
341 | |
342 for ( ; bit_count > 0; bit_count-- ) | |
343 { | |
344 val = write[0] & ~wmask; | |
345 | |
346 if ( read[0] & rmask ) | |
347 val |= wmask; | |
348 | |
349 write[0] = (FT_Byte)val; | |
350 | |
351 rmask >>= 1; | |
352 if ( rmask == 0 ) | |
353 { | |
354 read++; | |
355 rmask = 0x80; | |
356 } | |
357 | |
358 wmask >>= 1; | |
359 if ( wmask == 0 ) | |
360 { | |
361 write++; | |
362 wmask = 0x80; | |
363 } | |
364 } | |
365 } | |
366 | |
367 Exit: | |
368 return error; | |
369 } | |
370 | |
371 | |
372 /* test whether two masks in a table intersect */ | |
373 static FT_Int | |
374 ps_mask_table_test_intersect( PS_Mask_Table table, | |
375 FT_Int index1, | |
376 FT_Int index2 ) | |
377 { | |
378 PS_Mask mask1 = table->masks + index1; | |
379 PS_Mask mask2 = table->masks + index2; | |
380 FT_Byte* p1 = mask1->bytes; | |
381 FT_Byte* p2 = mask2->bytes; | |
382 FT_UInt count1 = mask1->num_bits; | |
383 FT_UInt count2 = mask2->num_bits; | |
384 FT_UInt count; | |
385 | |
386 | |
387 count = FT_MIN( count1, count2 ); | |
388 for ( ; count >= 8; count -= 8 ) | |
389 { | |
390 if ( p1[0] & p2[0] ) | |
391 return 1; | |
392 | |
393 p1++; | |
394 p2++; | |
395 } | |
396 | |
397 if ( count == 0 ) | |
398 return 0; | |
399 | |
400 return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); | |
401 } | |
402 | |
403 | |
404 /* merge two masks, used by ps_mask_table_merge_all */ | |
405 static FT_Error | |
406 ps_mask_table_merge( PS_Mask_Table table, | |
407 FT_Int index1, | |
408 FT_Int index2, | |
409 FT_Memory memory ) | |
410 { | |
411 FT_UInt temp; | |
412 FT_Error error = FT_Err_Ok; | |
413 | |
414 | |
415 /* swap index1 and index2 so that index1 < index2 */ | |
416 if ( index1 > index2 ) | |
417 { | |
418 temp = index1; | |
419 index1 = index2; | |
420 index2 = temp; | |
421 } | |
422 | |
423 if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks ) | |
424 { | |
425 /* we need to merge the bitsets of index1 and index2 with a */ | |
426 /* simple union */ | |
427 PS_Mask mask1 = table->masks + index1; | |
428 PS_Mask mask2 = table->masks + index2; | |
429 FT_UInt count1 = mask1->num_bits; | |
430 FT_UInt count2 = mask2->num_bits; | |
431 FT_Int delta; | |
432 | |
433 | |
434 if ( count2 > 0 ) | |
435 { | |
436 FT_UInt pos; | |
437 FT_Byte* read; | |
438 FT_Byte* write; | |
439 | |
440 | |
441 /* if "count2" is greater than "count1", we need to grow the */ | |
442 /* first bitset, and clear the highest bits */ | |
443 if ( count2 > count1 ) | |
444 { | |
445 error = ps_mask_ensure( mask1, count2, memory ); | |
446 if ( error ) | |
447 goto Exit; | |
448 | |
449 for ( pos = count1; pos < count2; pos++ ) | |
450 ps_mask_clear_bit( mask1, pos ); | |
451 } | |
452 | |
453 /* merge (unite) the bitsets */ | |
454 read = mask2->bytes; | |
455 write = mask1->bytes; | |
456 pos = (FT_UInt)( ( count2 + 7 ) >> 3 ); | |
457 | |
458 for ( ; pos > 0; pos-- ) | |
459 { | |
460 write[0] = (FT_Byte)( write[0] | read[0] ); | |
461 write++; | |
462 read++; | |
463 } | |
464 } | |
465 | |
466 /* Now, remove "mask2" from the list. We need to keep the masks */ | |
467 /* sorted in order of importance, so move table elements. */ | |
468 mask2->num_bits = 0; | |
469 mask2->end_point = 0; | |
470 | |
471 delta = table->num_masks - 1 - index2; /* number of masks to move */ | |
472 if ( delta > 0 ) | |
473 { | |
474 /* move to end of table for reuse */ | |
475 PS_MaskRec dummy = *mask2; | |
476 | |
477 | |
478 ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) ); | |
479 | |
480 mask2[delta] = dummy; | |
481 } | |
482 | |
483 table->num_masks--; | |
484 } | |
485 else | |
486 FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", | |
487 index1, index2 )); | |
488 | |
489 Exit: | |
490 return error; | |
491 } | |
492 | |
493 | |
494 /* Try to merge all masks in a given table. This is used to merge */ | |
495 /* all counter masks into independent counter "paths". */ | |
496 /* */ | |
497 static FT_Error | |
498 ps_mask_table_merge_all( PS_Mask_Table table, | |
499 FT_Memory memory ) | |
500 { | |
501 FT_Int index1, index2; | |
502 FT_Error error = FT_Err_Ok; | |
503 | |
504 | |
505 for ( index1 = table->num_masks - 1; index1 > 0; index1-- ) | |
506 { | |
507 for ( index2 = index1 - 1; index2 >= 0; index2-- ) | |
508 { | |
509 if ( ps_mask_table_test_intersect( table, index1, index2 ) ) | |
510 { | |
511 error = ps_mask_table_merge( table, index2, index1, memory ); | |
512 if ( error ) | |
513 goto Exit; | |
514 | |
515 break; | |
516 } | |
517 } | |
518 } | |
519 | |
520 Exit: | |
521 return error; | |
522 } | |
523 | |
524 | |
525 /*************************************************************************/ | |
526 /*************************************************************************/ | |
527 /***** *****/ | |
528 /***** PS_DIMENSION MANAGEMENT *****/ | |
529 /***** *****/ | |
530 /*************************************************************************/ | |
531 /*************************************************************************/ | |
532 | |
533 | |
534 /* finalize a given dimension */ | |
535 static void | |
536 ps_dimension_done( PS_Dimension dimension, | |
537 FT_Memory memory ) | |
538 { | |
539 ps_mask_table_done( &dimension->counters, memory ); | |
540 ps_mask_table_done( &dimension->masks, memory ); | |
541 ps_hint_table_done( &dimension->hints, memory ); | |
542 } | |
543 | |
544 | |
545 /* initialize a given dimension */ | |
546 static void | |
547 ps_dimension_init( PS_Dimension dimension ) | |
548 { | |
549 dimension->hints.num_hints = 0; | |
550 dimension->masks.num_masks = 0; | |
551 dimension->counters.num_masks = 0; | |
552 } | |
553 | |
554 | |
555 #if 0 | |
556 | |
557 /* set a bit at a given index in the current hint mask */ | |
558 static FT_Error | |
559 ps_dimension_set_mask_bit( PS_Dimension dim, | |
560 FT_UInt idx, | |
561 FT_Memory memory ) | |
562 { | |
563 PS_Mask mask; | |
564 FT_Error error = FT_Err_Ok; | |
565 | |
566 | |
567 /* get last hint mask */ | |
568 error = ps_mask_table_last( &dim->masks, memory, &mask ); | |
569 if ( error ) | |
570 goto Exit; | |
571 | |
572 error = ps_mask_set_bit( mask, idx, memory ); | |
573 | |
574 Exit: | |
575 return error; | |
576 } | |
577 | |
578 #endif | |
579 | |
580 /* set the end point in a mask, called from "End" & "Reset" methods */ | |
581 static void | |
582 ps_dimension_end_mask( PS_Dimension dim, | |
583 FT_UInt end_point ) | |
584 { | |
585 FT_UInt count = dim->masks.num_masks; | |
586 | |
587 | |
588 if ( count > 0 ) | |
589 { | |
590 PS_Mask mask = dim->masks.masks + count - 1; | |
591 | |
592 | |
593 mask->end_point = end_point; | |
594 } | |
595 } | |
596 | |
597 | |
598 /* set the end point in the current mask, then create a new empty one */ | |
599 /* (called by "Reset" method) */ | |
600 static FT_Error | |
601 ps_dimension_reset_mask( PS_Dimension dim, | |
602 FT_UInt end_point, | |
603 FT_Memory memory ) | |
604 { | |
605 PS_Mask mask; | |
606 | |
607 | |
608 /* end current mask */ | |
609 ps_dimension_end_mask( dim, end_point ); | |
610 | |
611 /* allocate new one */ | |
612 return ps_mask_table_alloc( &dim->masks, memory, &mask ); | |
613 } | |
614 | |
615 | |
616 /* set a new mask, called from the "T2Stem" method */ | |
617 static FT_Error | |
618 ps_dimension_set_mask_bits( PS_Dimension dim, | |
619 const FT_Byte* source, | |
620 FT_UInt source_pos, | |
621 FT_UInt source_bits, | |
622 FT_UInt end_point, | |
623 FT_Memory memory ) | |
624 { | |
625 FT_Error error; | |
626 | |
627 | |
628 /* reset current mask, if any */ | |
629 error = ps_dimension_reset_mask( dim, end_point, memory ); | |
630 if ( error ) | |
631 goto Exit; | |
632 | |
633 /* set bits in new mask */ | |
634 error = ps_mask_table_set_bits( &dim->masks, source, | |
635 source_pos, source_bits, memory ); | |
636 | |
637 Exit: | |
638 return error; | |
639 } | |
640 | |
641 | |
642 /* add a new single stem (called from "T1Stem" method) */ | |
643 static FT_Error | |
644 ps_dimension_add_t1stem( PS_Dimension dim, | |
645 FT_Int pos, | |
646 FT_Int len, | |
647 FT_Memory memory, | |
648 FT_Int *aindex ) | |
649 { | |
650 FT_Error error = FT_Err_Ok; | |
651 FT_UInt flags = 0; | |
652 | |
653 | |
654 /* detect ghost stem */ | |
655 if ( len < 0 ) | |
656 { | |
657 flags |= PS_HINT_FLAG_GHOST; | |
658 if ( len == -21 ) | |
659 { | |
660 flags |= PS_HINT_FLAG_BOTTOM; | |
661 pos += len; | |
662 } | |
663 len = 0; | |
664 } | |
665 | |
666 if ( aindex ) | |
667 *aindex = -1; | |
668 | |
669 /* now, lookup stem in the current hints table */ | |
670 { | |
671 PS_Mask mask; | |
672 FT_UInt idx; | |
673 FT_UInt max = dim->hints.num_hints; | |
674 PS_Hint hint = dim->hints.hints; | |
675 | |
676 | |
677 for ( idx = 0; idx < max; idx++, hint++ ) | |
678 { | |
679 if ( hint->pos == pos && hint->len == len ) | |
680 break; | |
681 } | |
682 | |
683 /* we need to create a new hint in the table */ | |
684 if ( idx >= max ) | |
685 { | |
686 error = ps_hint_table_alloc( &dim->hints, memory, &hint ); | |
687 if ( error ) | |
688 goto Exit; | |
689 | |
690 hint->pos = pos; | |
691 hint->len = len; | |
692 hint->flags = flags; | |
693 } | |
694 | |
695 /* now, store the hint in the current mask */ | |
696 error = ps_mask_table_last( &dim->masks, memory, &mask ); | |
697 if ( error ) | |
698 goto Exit; | |
699 | |
700 error = ps_mask_set_bit( mask, idx, memory ); | |
701 if ( error ) | |
702 goto Exit; | |
703 | |
704 if ( aindex ) | |
705 *aindex = (FT_Int)idx; | |
706 } | |
707 | |
708 Exit: | |
709 return error; | |
710 } | |
711 | |
712 | |
713 /* add a "hstem3/vstem3" counter to our dimension table */ | |
714 static FT_Error | |
715 ps_dimension_add_counter( PS_Dimension dim, | |
716 FT_Int hint1, | |
717 FT_Int hint2, | |
718 FT_Int hint3, | |
719 FT_Memory memory ) | |
720 { | |
721 FT_Error error = FT_Err_Ok; | |
722 FT_UInt count = dim->counters.num_masks; | |
723 PS_Mask counter = dim->counters.masks; | |
724 | |
725 | |
726 /* try to find an existing counter mask that already uses */ | |
727 /* one of these stems here */ | |
728 for ( ; count > 0; count--, counter++ ) | |
729 { | |
730 if ( ps_mask_test_bit( counter, hint1 ) || | |
731 ps_mask_test_bit( counter, hint2 ) || | |
732 ps_mask_test_bit( counter, hint3 ) ) | |
733 break; | |
734 } | |
735 | |
736 /* create a new counter when needed */ | |
737 if ( count == 0 ) | |
738 { | |
739 error = ps_mask_table_alloc( &dim->counters, memory, &counter ); | |
740 if ( error ) | |
741 goto Exit; | |
742 } | |
743 | |
744 /* now, set the bits for our hints in the counter mask */ | |
745 error = ps_mask_set_bit( counter, hint1, memory ); | |
746 if ( error ) | |
747 goto Exit; | |
748 | |
749 error = ps_mask_set_bit( counter, hint2, memory ); | |
750 if ( error ) | |
751 goto Exit; | |
752 | |
753 error = ps_mask_set_bit( counter, hint3, memory ); | |
754 if ( error ) | |
755 goto Exit; | |
756 | |
757 Exit: | |
758 return error; | |
759 } | |
760 | |
761 | |
762 /* end of recording session for a given dimension */ | |
763 static FT_Error | |
764 ps_dimension_end( PS_Dimension dim, | |
765 FT_UInt end_point, | |
766 FT_Memory memory ) | |
767 { | |
768 /* end hint mask table */ | |
769 ps_dimension_end_mask( dim, end_point ); | |
770 | |
771 /* merge all counter masks into independent "paths" */ | |
772 return ps_mask_table_merge_all( &dim->counters, memory ); | |
773 } | |
774 | |
775 | |
776 /*************************************************************************/ | |
777 /*************************************************************************/ | |
778 /***** *****/ | |
779 /***** PS_RECORDER MANAGEMENT *****/ | |
780 /***** *****/ | |
781 /*************************************************************************/ | |
782 /*************************************************************************/ | |
783 | |
784 | |
785 /* destroy hints */ | |
786 FT_LOCAL( void ) | |
787 ps_hints_done( PS_Hints hints ) | |
788 { | |
789 FT_Memory memory = hints->memory; | |
790 | |
791 | |
792 ps_dimension_done( &hints->dimension[0], memory ); | |
793 ps_dimension_done( &hints->dimension[1], memory ); | |
794 | |
795 hints->error = FT_Err_Ok; | |
796 hints->memory = 0; | |
797 } | |
798 | |
799 | |
800 FT_LOCAL( FT_Error ) | |
801 ps_hints_init( PS_Hints hints, | |
802 FT_Memory memory ) | |
803 { | |
804 FT_MEM_ZERO( hints, sizeof ( *hints ) ); | |
805 hints->memory = memory; | |
806 return FT_Err_Ok; | |
807 } | |
808 | |
809 | |
810 /* initialize a hints for a new session */ | |
811 static void | |
812 ps_hints_open( PS_Hints hints, | |
813 PS_Hint_Type hint_type ) | |
814 { | |
815 switch ( hint_type ) | |
816 { | |
817 case PS_HINT_TYPE_1: | |
818 case PS_HINT_TYPE_2: | |
819 hints->error = FT_Err_Ok; | |
820 hints->hint_type = hint_type; | |
821 | |
822 ps_dimension_init( &hints->dimension[0] ); | |
823 ps_dimension_init( &hints->dimension[1] ); | |
824 break; | |
825 | |
826 default: | |
827 hints->error = FT_THROW( Invalid_Argument ); | |
828 hints->hint_type = hint_type; | |
829 | |
830 FT_TRACE0(( "ps_hints_open: invalid charstring type\n" )); | |
831 break; | |
832 } | |
833 } | |
834 | |
835 | |
836 /* add one or more stems to the current hints table */ | |
837 static void | |
838 ps_hints_stem( PS_Hints hints, | |
839 FT_Int dimension, | |
840 FT_UInt count, | |
841 FT_Long* stems ) | |
842 { | |
843 if ( !hints->error ) | |
844 { | |
845 /* limit "dimension" to 0..1 */ | |
846 if ( dimension < 0 || dimension > 1 ) | |
847 { | |
848 FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", | |
849 dimension )); | |
850 dimension = ( dimension != 0 ); | |
851 } | |
852 | |
853 /* record the stems in the current hints/masks table */ | |
854 switch ( hints->hint_type ) | |
855 { | |
856 case PS_HINT_TYPE_1: /* Type 1 "hstem" or "vstem" operator */ | |
857 case PS_HINT_TYPE_2: /* Type 2 "hstem" or "vstem" operator */ | |
858 { | |
859 PS_Dimension dim = &hints->dimension[dimension]; | |
860 | |
861 | |
862 for ( ; count > 0; count--, stems += 2 ) | |
863 { | |
864 FT_Error error; | |
865 FT_Memory memory = hints->memory; | |
866 | |
867 | |
868 error = ps_dimension_add_t1stem( | |
869 dim, (FT_Int)stems[0], (FT_Int)stems[1], | |
870 memory, NULL ); | |
871 if ( error ) | |
872 { | |
873 FT_ERROR(( "ps_hints_stem: could not add stem" | |
874 " (%d,%d) to hints table\n", stems[0], stems[1] )); | |
875 | |
876 hints->error = error; | |
877 return; | |
878 } | |
879 } | |
880 break; | |
881 } | |
882 | |
883 default: | |
884 FT_TRACE0(( "ps_hints_stem: called with invalid hint type (%d)\n", | |
885 hints->hint_type )); | |
886 break; | |
887 } | |
888 } | |
889 } | |
890 | |
891 | |
892 /* add one Type1 counter stem to the current hints table */ | |
893 static void | |
894 ps_hints_t1stem3( PS_Hints hints, | |
895 FT_Int dimension, | |
896 FT_Fixed* stems ) | |
897 { | |
898 FT_Error error = FT_Err_Ok; | |
899 | |
900 | |
901 if ( !hints->error ) | |
902 { | |
903 PS_Dimension dim; | |
904 FT_Memory memory = hints->memory; | |
905 FT_Int count; | |
906 FT_Int idx[3]; | |
907 | |
908 | |
909 /* limit "dimension" to 0..1 */ | |
910 if ( dimension < 0 || dimension > 1 ) | |
911 { | |
912 FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", | |
913 dimension )); | |
914 dimension = ( dimension != 0 ); | |
915 } | |
916 | |
917 dim = &hints->dimension[dimension]; | |
918 | |
919 /* there must be 6 elements in the 'stem' array */ | |
920 if ( hints->hint_type == PS_HINT_TYPE_1 ) | |
921 { | |
922 /* add the three stems to our hints/masks table */ | |
923 for ( count = 0; count < 3; count++, stems += 2 ) | |
924 { | |
925 error = ps_dimension_add_t1stem( dim, | |
926 (FT_Int)FIXED_TO_INT( stems[0] ), | |
927 (FT_Int)FIXED_TO_INT( stems[1] ), | |
928 memory, &idx[count] ); | |
929 if ( error ) | |
930 goto Fail; | |
931 } | |
932 | |
933 /* now, add the hints to the counters table */ | |
934 error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], | |
935 memory ); | |
936 if ( error ) | |
937 goto Fail; | |
938 } | |
939 else | |
940 { | |
941 FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); | |
942 error = FT_THROW( Invalid_Argument ); | |
943 goto Fail; | |
944 } | |
945 } | |
946 | |
947 return; | |
948 | |
949 Fail: | |
950 FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); | |
951 hints->error = error; | |
952 } | |
953 | |
954 | |
955 /* reset hints (only with Type 1 hints) */ | |
956 static void | |
957 ps_hints_t1reset( PS_Hints hints, | |
958 FT_UInt end_point ) | |
959 { | |
960 FT_Error error = FT_Err_Ok; | |
961 | |
962 | |
963 if ( !hints->error ) | |
964 { | |
965 FT_Memory memory = hints->memory; | |
966 | |
967 | |
968 if ( hints->hint_type == PS_HINT_TYPE_1 ) | |
969 { | |
970 error = ps_dimension_reset_mask( &hints->dimension[0], | |
971 end_point, memory ); | |
972 if ( error ) | |
973 goto Fail; | |
974 | |
975 error = ps_dimension_reset_mask( &hints->dimension[1], | |
976 end_point, memory ); | |
977 if ( error ) | |
978 goto Fail; | |
979 } | |
980 else | |
981 { | |
982 /* invalid hint type */ | |
983 error = FT_THROW( Invalid_Argument ); | |
984 goto Fail; | |
985 } | |
986 } | |
987 return; | |
988 | |
989 Fail: | |
990 hints->error = error; | |
991 } | |
992 | |
993 | |
994 /* Type2 "hintmask" operator, add a new hintmask to each direction */ | |
995 static void | |
996 ps_hints_t2mask( PS_Hints hints, | |
997 FT_UInt end_point, | |
998 FT_UInt bit_count, | |
999 const FT_Byte* bytes ) | |
1000 { | |
1001 FT_Error error; | |
1002 | |
1003 | |
1004 if ( !hints->error ) | |
1005 { | |
1006 PS_Dimension dim = hints->dimension; | |
1007 FT_Memory memory = hints->memory; | |
1008 FT_UInt count1 = dim[0].hints.num_hints; | |
1009 FT_UInt count2 = dim[1].hints.num_hints; | |
1010 | |
1011 | |
1012 /* check bit count; must be equal to current total hint count */ | |
1013 if ( bit_count != count1 + count2 ) | |
1014 { | |
1015 FT_TRACE0(( "ps_hints_t2mask:" | |
1016 " called with invalid bitcount %d (instead of %d)\n", | |
1017 bit_count, count1 + count2 )); | |
1018 | |
1019 /* simply ignore the operator */ | |
1020 return; | |
1021 } | |
1022 | |
1023 /* set-up new horizontal and vertical hint mask now */ | |
1024 error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, | |
1025 end_point, memory ); | |
1026 if ( error ) | |
1027 goto Fail; | |
1028 | |
1029 error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, | |
1030 end_point, memory ); | |
1031 if ( error ) | |
1032 goto Fail; | |
1033 } | |
1034 return; | |
1035 | |
1036 Fail: | |
1037 hints->error = error; | |
1038 } | |
1039 | |
1040 | |
1041 static void | |
1042 ps_hints_t2counter( PS_Hints hints, | |
1043 FT_UInt bit_count, | |
1044 const FT_Byte* bytes ) | |
1045 { | |
1046 FT_Error error; | |
1047 | |
1048 | |
1049 if ( !hints->error ) | |
1050 { | |
1051 PS_Dimension dim = hints->dimension; | |
1052 FT_Memory memory = hints->memory; | |
1053 FT_UInt count1 = dim[0].hints.num_hints; | |
1054 FT_UInt count2 = dim[1].hints.num_hints; | |
1055 | |
1056 | |
1057 /* check bit count, must be equal to current total hint count */ | |
1058 if ( bit_count != count1 + count2 ) | |
1059 { | |
1060 FT_TRACE0(( "ps_hints_t2counter:" | |
1061 " called with invalid bitcount %d (instead of %d)\n", | |
1062 bit_count, count1 + count2 )); | |
1063 | |
1064 /* simply ignore the operator */ | |
1065 return; | |
1066 } | |
1067 | |
1068 /* set-up new horizontal and vertical hint mask now */ | |
1069 error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, | |
1070 0, memory ); | |
1071 if ( error ) | |
1072 goto Fail; | |
1073 | |
1074 error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, | |
1075 0, memory ); | |
1076 if ( error ) | |
1077 goto Fail; | |
1078 } | |
1079 return; | |
1080 | |
1081 Fail: | |
1082 hints->error = error; | |
1083 } | |
1084 | |
1085 | |
1086 /* end recording session */ | |
1087 static FT_Error | |
1088 ps_hints_close( PS_Hints hints, | |
1089 FT_UInt end_point ) | |
1090 { | |
1091 FT_Error error; | |
1092 | |
1093 | |
1094 error = hints->error; | |
1095 if ( !error ) | |
1096 { | |
1097 FT_Memory memory = hints->memory; | |
1098 PS_Dimension dim = hints->dimension; | |
1099 | |
1100 | |
1101 error = ps_dimension_end( &dim[0], end_point, memory ); | |
1102 if ( !error ) | |
1103 { | |
1104 error = ps_dimension_end( &dim[1], end_point, memory ); | |
1105 } | |
1106 } | |
1107 | |
1108 #ifdef DEBUG_HINTER | |
1109 if ( !error ) | |
1110 ps_debug_hints = hints; | |
1111 #endif | |
1112 return error; | |
1113 } | |
1114 | |
1115 | |
1116 /*************************************************************************/ | |
1117 /*************************************************************************/ | |
1118 /***** *****/ | |
1119 /***** TYPE 1 HINTS RECORDING INTERFACE *****/ | |
1120 /***** *****/ | |
1121 /*************************************************************************/ | |
1122 /*************************************************************************/ | |
1123 | |
1124 static void | |
1125 t1_hints_open( T1_Hints hints ) | |
1126 { | |
1127 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); | |
1128 } | |
1129 | |
1130 static void | |
1131 t1_hints_stem( T1_Hints hints, | |
1132 FT_Int dimension, | |
1133 FT_Fixed* coords ) | |
1134 { | |
1135 FT_Pos stems[2]; | |
1136 | |
1137 | |
1138 stems[0] = FIXED_TO_INT( coords[0] ); | |
1139 stems[1] = FIXED_TO_INT( coords[1] ); | |
1140 | |
1141 ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); | |
1142 } | |
1143 | |
1144 | |
1145 FT_LOCAL_DEF( void ) | |
1146 t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) | |
1147 { | |
1148 FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) ); | |
1149 | |
1150 funcs->open = (T1_Hints_OpenFunc) t1_hints_open; | |
1151 funcs->close = (T1_Hints_CloseFunc) ps_hints_close; | |
1152 funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; | |
1153 funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; | |
1154 funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; | |
1155 funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply; | |
1156 } | |
1157 | |
1158 | |
1159 /*************************************************************************/ | |
1160 /*************************************************************************/ | |
1161 /***** *****/ | |
1162 /***** TYPE 2 HINTS RECORDING INTERFACE *****/ | |
1163 /***** *****/ | |
1164 /*************************************************************************/ | |
1165 /*************************************************************************/ | |
1166 | |
1167 static void | |
1168 t2_hints_open( T2_Hints hints ) | |
1169 { | |
1170 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); | |
1171 } | |
1172 | |
1173 | |
1174 static void | |
1175 t2_hints_stems( T2_Hints hints, | |
1176 FT_Int dimension, | |
1177 FT_Int count, | |
1178 FT_Fixed* coords ) | |
1179 { | |
1180 FT_Pos stems[32], y, n; | |
1181 FT_Int total = count; | |
1182 | |
1183 | |
1184 y = 0; | |
1185 while ( total > 0 ) | |
1186 { | |
1187 /* determine number of stems to write */ | |
1188 count = total; | |
1189 if ( count > 16 ) | |
1190 count = 16; | |
1191 | |
1192 /* compute integer stem positions in font units */ | |
1193 for ( n = 0; n < count * 2; n++ ) | |
1194 { | |
1195 y += coords[n]; | |
1196 stems[n] = FIXED_TO_INT( y ); | |
1197 } | |
1198 | |
1199 /* compute lengths */ | |
1200 for ( n = 0; n < count * 2; n += 2 ) | |
1201 stems[n + 1] = stems[n + 1] - stems[n]; | |
1202 | |
1203 /* add them to the current dimension */ | |
1204 ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); | |
1205 | |
1206 total -= count; | |
1207 } | |
1208 } | |
1209 | |
1210 | |
1211 FT_LOCAL_DEF( void ) | |
1212 t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) | |
1213 { | |
1214 FT_MEM_ZERO( funcs, sizeof ( *funcs ) ); | |
1215 | |
1216 funcs->open = (T2_Hints_OpenFunc) t2_hints_open; | |
1217 funcs->close = (T2_Hints_CloseFunc) ps_hints_close; | |
1218 funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; | |
1219 funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask; | |
1220 funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; | |
1221 funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply; | |
1222 } | |
1223 | |
1224 | |
1225 /* END */ | |
OLD | NEW |