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