1 /***************************************************************************/
5 /* FreeType PostScript hints recorder (body). */
7 /* Copyright 2001, 2002, 2003, 2004, 2007, 2009 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_FREETYPE_H
21 #include FT_INTERNAL_OBJECTS_H
22 #include FT_INTERNAL_DEBUG_H
23 #include FT_INTERNAL_CALC_H
31 #define FT_COMPONENT trace_pshrec
34 PS_Hints ps_debug_hints
= 0;
35 int ps_debug_no_horz_hints
= 0;
36 int ps_debug_no_vert_hints
= 0;
40 /*************************************************************************/
41 /*************************************************************************/
43 /***** PS_HINT MANAGEMENT *****/
45 /*************************************************************************/
46 /*************************************************************************/
48 /* destroy hints table */
50 ps_hint_table_done( PS_Hint_Table table
,
53 FT_FREE( table
->hints
);
59 /* ensure that a table can contain "count" elements */
61 ps_hint_table_ensure( PS_Hint_Table table
,
65 FT_UInt old_max
= table
->max_hints
;
66 FT_UInt new_max
= count
;
67 FT_Error error
= PSH_Err_Ok
;
70 if ( new_max
> old_max
)
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
;
82 ps_hint_table_alloc( PS_Hint_Table table
,
86 FT_Error error
= PSH_Err_Ok
;
91 count
= table
->num_hints
;
94 if ( count
>= table
->max_hints
)
96 error
= ps_hint_table_ensure( table
, count
, memory
);
101 hint
= table
->hints
+ count
- 1;
106 table
->num_hints
= count
;
114 /*************************************************************************/
115 /*************************************************************************/
117 /***** PS_MASK MANAGEMENT *****/
119 /*************************************************************************/
120 /*************************************************************************/
124 ps_mask_done( PS_Mask mask
,
127 FT_FREE( mask
->bytes
);
134 /* ensure that a mask can contain "count" bits */
136 ps_mask_ensure( PS_Mask mask
,
140 FT_UInt old_max
= ( mask
->max_bits
+ 7 ) >> 3;
141 FT_UInt new_max
= ( count
+ 7 ) >> 3;
142 FT_Error error
= PSH_Err_Ok
;
145 if ( new_max
> old_max
)
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;
155 /* test a bit value in a given mask */
157 ps_mask_test_bit( PS_Mask mask
,
160 if ( (FT_UInt
)idx
>= mask
->num_bits
)
163 return mask
->bytes
[idx
>> 3] & ( 0x80 >> ( idx
& 7 ) );
167 /* clear a given bit */
169 ps_mask_clear_bit( PS_Mask mask
,
175 if ( (FT_UInt
)idx
>= mask
->num_bits
)
178 p
= mask
->bytes
+ ( idx
>> 3 );
179 p
[0] = (FT_Byte
)( p
[0] & ~( 0x80 >> ( idx
& 7 ) ) );
183 /* set a given bit, possibly grow the mask */
185 ps_mask_set_bit( PS_Mask mask
,
189 FT_Error error
= PSH_Err_Ok
;
196 if ( (FT_UInt
)idx
>= mask
->num_bits
)
198 error
= ps_mask_ensure( mask
, idx
+ 1, memory
);
202 mask
->num_bits
= idx
+ 1;
205 p
= mask
->bytes
+ ( idx
>> 3 );
206 p
[0] = (FT_Byte
)( p
[0] | ( 0x80 >> ( idx
& 7 ) ) );
213 /* destroy mask table */
215 ps_mask_table_done( PS_Mask_Table table
,
218 FT_UInt count
= table
->max_masks
;
219 PS_Mask mask
= table
->masks
;
222 for ( ; count
> 0; count
--, mask
++ )
223 ps_mask_done( mask
, memory
);
225 FT_FREE( table
->masks
);
226 table
->num_masks
= 0;
227 table
->max_masks
= 0;
231 /* ensure that a mask table can contain "count" masks */
233 ps_mask_table_ensure( PS_Mask_Table table
,
237 FT_UInt old_max
= table
->max_masks
;
238 FT_UInt new_max
= count
;
239 FT_Error error
= PSH_Err_Ok
;
242 if ( new_max
> old_max
)
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
;
252 /* allocate a new mask in a table */
254 ps_mask_table_alloc( PS_Mask_Table table
,
259 FT_Error error
= PSH_Err_Ok
;
263 count
= table
->num_masks
;
266 if ( count
> table
->max_masks
)
268 error
= ps_mask_table_ensure( table
, count
, memory
);
273 mask
= table
->masks
+ count
- 1;
276 table
->num_masks
= count
;
284 /* return last hint mask in a table, create one if the table is empty */
286 ps_mask_table_last( PS_Mask_Table table
,
290 FT_Error error
= PSH_Err_Ok
;
295 count
= table
->num_masks
;
298 error
= ps_mask_table_alloc( table
, memory
, &mask
);
303 mask
= table
->masks
+ count
- 1;
311 /* set a new mask to a given bit range */
313 ps_mask_table_set_bits( PS_Mask_Table table
,
314 const FT_Byte
* source
,
319 FT_Error error
= PSH_Err_Ok
;
323 error
= ps_mask_table_last( table
, memory
, &mask
);
327 error
= ps_mask_ensure( mask
, bit_count
, memory
);
331 mask
->num_bits
= bit_count
;
335 FT_Byte
* read
= (FT_Byte
*)source
+ ( bit_pos
>> 3 );
336 FT_Int rmask
= 0x80 >> ( bit_pos
& 7 );
337 FT_Byte
* write
= mask
->bytes
;
342 for ( ; bit_count
> 0; bit_count
-- )
344 val
= write
[0] & ~wmask
;
346 if ( read
[0] & rmask
)
349 write
[0] = (FT_Byte
)val
;
372 /* test whether two masks in a table intersect */
374 ps_mask_table_test_intersect( PS_Mask_Table table
,
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
;
387 count
= ( count1
<= count2
) ? count1
: count2
;
388 for ( ; count
>= 8; count
-= 8 )
400 return ( p1
[0] & p2
[0] ) & ~( 0xFF >> count
);
404 /* merge two masks, used by ps_mask_table_merge_all */
406 ps_mask_table_merge( PS_Mask_Table table
,
412 FT_Error error
= PSH_Err_Ok
;
415 /* swap index1 and index2 so that index1 < index2 */
416 if ( index1
> index2
)
423 if ( index1
< index2
&& index1
>= 0 && index2
< (FT_Int
)table
->num_masks
)
425 /* we need to merge the bitsets of index1 and index2 with a */
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
;
441 /* if "count2" is greater than "count1", we need to grow the */
442 /* first bitset, and clear the highest bits */
443 if ( count2
> count1
)
445 error
= ps_mask_ensure( mask1
, count2
, memory
);
449 for ( pos
= count1
; pos
< count2
; pos
++ )
450 ps_mask_clear_bit( mask1
, pos
);
453 /* merge (unite) the bitsets */
455 write
= mask1
->bytes
;
456 pos
= (FT_UInt
)( ( count2
+ 7 ) >> 3 );
458 for ( ; pos
> 0; pos
-- )
460 write
[0] = (FT_Byte
)( write
[0] | read
[0] );
466 /* Now, remove "mask2" from the list. We need to keep the masks */
467 /* sorted in order of importance, so move table elements. */
469 mask2
->end_point
= 0;
471 delta
= table
->num_masks
- 1 - index2
; /* number of masks to move */
474 /* move to end of table for reuse */
475 PS_MaskRec dummy
= *mask2
;
478 ft_memmove( mask2
, mask2
+ 1, delta
* sizeof ( PS_MaskRec
) );
480 mask2
[delta
] = dummy
;
486 FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
494 /* Try to merge all masks in a given table. This is used to merge */
495 /* all counter masks into independent counter "paths". */
498 ps_mask_table_merge_all( PS_Mask_Table table
,
501 FT_Int index1
, index2
;
502 FT_Error error
= PSH_Err_Ok
;
505 for ( index1
= table
->num_masks
- 1; index1
> 0; index1
-- )
507 for ( index2
= index1
- 1; index2
>= 0; index2
-- )
509 if ( ps_mask_table_test_intersect( table
, index1
, index2
) )
511 error
= ps_mask_table_merge( table
, index2
, index1
, memory
);
525 /*************************************************************************/
526 /*************************************************************************/
528 /***** PS_DIMENSION MANAGEMENT *****/
530 /*************************************************************************/
531 /*************************************************************************/
534 /* finalize a given dimension */
536 ps_dimension_done( PS_Dimension dimension
,
539 ps_mask_table_done( &dimension
->counters
, memory
);
540 ps_mask_table_done( &dimension
->masks
, memory
);
541 ps_hint_table_done( &dimension
->hints
, memory
);
545 /* initialize a given dimension */
547 ps_dimension_init( PS_Dimension dimension
)
549 dimension
->hints
.num_hints
= 0;
550 dimension
->masks
.num_masks
= 0;
551 dimension
->counters
.num_masks
= 0;
557 /* set a bit at a given index in the current hint mask */
559 ps_dimension_set_mask_bit( PS_Dimension dim
,
564 FT_Error error
= PSH_Err_Ok
;
567 /* get last hint mask */
568 error
= ps_mask_table_last( &dim
->masks
, memory
, &mask
);
572 error
= ps_mask_set_bit( mask
, idx
, memory
);
580 /* set the end point in a mask, called from "End" & "Reset" methods */
582 ps_dimension_end_mask( PS_Dimension dim
,
585 FT_UInt count
= dim
->masks
.num_masks
;
591 mask
= dim
->masks
.masks
+ count
- 1;
592 mask
->end_point
= end_point
;
597 /* set the end point in the current mask, then create a new empty one */
598 /* (called by "Reset" method) */
600 ps_dimension_reset_mask( PS_Dimension dim
,
607 /* end current mask */
608 ps_dimension_end_mask( dim
, end_point
);
610 /* allocate new one */
611 return ps_mask_table_alloc( &dim
->masks
, memory
, &mask
);
615 /* set a new mask, called from the "T2Stem" method */
617 ps_dimension_set_mask_bits( PS_Dimension dim
,
618 const FT_Byte
* source
,
624 FT_Error error
= PSH_Err_Ok
;
627 /* reset current mask, if any */
628 error
= ps_dimension_reset_mask( dim
, end_point
, memory
);
632 /* set bits in new mask */
633 error
= ps_mask_table_set_bits( &dim
->masks
, source
,
634 source_pos
, source_bits
, memory
);
641 /* add a new single stem (called from "T1Stem" method) */
643 ps_dimension_add_t1stem( PS_Dimension dim
,
649 FT_Error error
= PSH_Err_Ok
;
653 /* detect ghost stem */
656 flags
|= PS_HINT_FLAG_GHOST
;
659 flags
|= PS_HINT_FLAG_BOTTOM
;
668 /* now, lookup stem in the current hints table */
672 FT_UInt max
= dim
->hints
.num_hints
;
673 PS_Hint hint
= dim
->hints
.hints
;
676 for ( idx
= 0; idx
< max
; idx
++, hint
++ )
678 if ( hint
->pos
== pos
&& hint
->len
== len
)
682 /* we need to create a new hint in the table */
685 error
= ps_hint_table_alloc( &dim
->hints
, memory
, &hint
);
694 /* now, store the hint in the current mask */
695 error
= ps_mask_table_last( &dim
->masks
, memory
, &mask
);
699 error
= ps_mask_set_bit( mask
, idx
, memory
);
704 *aindex
= (FT_Int
)idx
;
712 /* add a "hstem3/vstem3" counter to our dimension table */
714 ps_dimension_add_counter( PS_Dimension dim
,
720 FT_Error error
= PSH_Err_Ok
;
721 FT_UInt count
= dim
->counters
.num_masks
;
722 PS_Mask counter
= dim
->counters
.masks
;
725 /* try to find an existing counter mask that already uses */
726 /* one of these stems here */
727 for ( ; count
> 0; count
--, counter
++ )
729 if ( ps_mask_test_bit( counter
, hint1
) ||
730 ps_mask_test_bit( counter
, hint2
) ||
731 ps_mask_test_bit( counter
, hint3
) )
735 /* create a new counter when needed */
738 error
= ps_mask_table_alloc( &dim
->counters
, memory
, &counter
);
743 /* now, set the bits for our hints in the counter mask */
744 error
= ps_mask_set_bit( counter
, hint1
, memory
);
748 error
= ps_mask_set_bit( counter
, hint2
, memory
);
752 error
= ps_mask_set_bit( counter
, hint3
, memory
);
761 /* end of recording session for a given dimension */
763 ps_dimension_end( PS_Dimension dim
,
767 /* end hint mask table */
768 ps_dimension_end_mask( dim
, end_point
);
770 /* merge all counter masks into independent "paths" */
771 return ps_mask_table_merge_all( &dim
->counters
, memory
);
775 /*************************************************************************/
776 /*************************************************************************/
778 /***** PS_RECORDER MANAGEMENT *****/
780 /*************************************************************************/
781 /*************************************************************************/
786 ps_hints_done( PS_Hints hints
)
788 FT_Memory memory
= hints
->memory
;
791 ps_dimension_done( &hints
->dimension
[0], memory
);
792 ps_dimension_done( &hints
->dimension
[1], memory
);
794 hints
->error
= PSH_Err_Ok
;
800 ps_hints_init( PS_Hints hints
,
803 FT_MEM_ZERO( hints
, sizeof ( *hints
) );
804 hints
->memory
= memory
;
809 /* initialize a hints for a new session */
811 ps_hints_open( PS_Hints hints
,
812 PS_Hint_Type hint_type
)
818 hints
->error
= PSH_Err_Ok
;
819 hints
->hint_type
= hint_type
;
821 ps_dimension_init( &hints
->dimension
[0] );
822 ps_dimension_init( &hints
->dimension
[1] );
826 hints
->error
= PSH_Err_Invalid_Argument
;
827 hints
->hint_type
= hint_type
;
829 FT_TRACE0(( "ps_hints_open: invalid charstring type\n" ));
835 /* add one or more stems to the current hints table */
837 ps_hints_stem( PS_Hints hints
,
844 /* limit "dimension" to 0..1 */
845 if ( dimension
< 0 || dimension
> 1 )
847 FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n",
849 dimension
= ( dimension
!= 0 );
852 /* record the stems in the current hints/masks table */
853 switch ( hints
->hint_type
)
855 case PS_HINT_TYPE_1
: /* Type 1 "hstem" or "vstem" operator */
856 case PS_HINT_TYPE_2
: /* Type 2 "hstem" or "vstem" operator */
858 PS_Dimension dim
= &hints
->dimension
[dimension
];
861 for ( ; count
> 0; count
--, stems
+= 2 )
864 FT_Memory memory
= hints
->memory
;
867 error
= ps_dimension_add_t1stem(
868 dim
, (FT_Int
)stems
[0], (FT_Int
)stems
[1],
872 FT_ERROR(( "ps_hints_stem: could not add stem"
873 " (%d,%d) to hints table\n", stems
[0], stems
[1] ));
875 hints
->error
= error
;
883 FT_TRACE0(( "ps_hints_stem: called with invalid hint type (%d)\n",
891 /* add one Type1 counter stem to the current hints table */
893 ps_hints_t1stem3( PS_Hints hints
,
897 FT_Error error
= PSH_Err_Ok
;
903 FT_Memory memory
= hints
->memory
;
908 /* limit "dimension" to 0..1 */
909 if ( dimension
< 0 || dimension
> 1 )
911 FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
913 dimension
= ( dimension
!= 0 );
916 dim
= &hints
->dimension
[dimension
];
918 /* there must be 6 elements in the 'stem' array */
919 if ( hints
->hint_type
== PS_HINT_TYPE_1
)
921 /* add the three stems to our hints/masks table */
922 for ( count
= 0; count
< 3; count
++, stems
+= 2 )
924 error
= ps_dimension_add_t1stem( dim
,
925 (FT_Int
)FIXED_TO_INT( stems
[0] ),
926 (FT_Int
)FIXED_TO_INT( stems
[1] ),
927 memory
, &idx
[count
] );
932 /* now, add the hints to the counters table */
933 error
= ps_dimension_add_counter( dim
, idx
[0], idx
[1], idx
[2],
940 FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" ));
941 error
= PSH_Err_Invalid_Argument
;
949 FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
950 hints
->error
= error
;
954 /* reset hints (only with Type 1 hints) */
956 ps_hints_t1reset( PS_Hints hints
,
959 FT_Error error
= PSH_Err_Ok
;
964 FT_Memory memory
= hints
->memory
;
967 if ( hints
->hint_type
== PS_HINT_TYPE_1
)
969 error
= ps_dimension_reset_mask( &hints
->dimension
[0],
974 error
= ps_dimension_reset_mask( &hints
->dimension
[1],
981 /* invalid hint type */
982 error
= PSH_Err_Invalid_Argument
;
989 hints
->error
= error
;
993 /* Type2 "hintmask" operator, add a new hintmask to each direction */
995 ps_hints_t2mask( PS_Hints hints
,
998 const FT_Byte
* bytes
)
1003 if ( !hints
->error
)
1005 PS_Dimension dim
= hints
->dimension
;
1006 FT_Memory memory
= hints
->memory
;
1007 FT_UInt count1
= dim
[0].hints
.num_hints
;
1008 FT_UInt count2
= dim
[1].hints
.num_hints
;
1011 /* check bit count; must be equal to current total hint count */
1012 if ( bit_count
!= count1
+ count2
)
1014 FT_TRACE0(( "ps_hints_t2mask:"
1015 " called with invalid bitcount %d (instead of %d)\n",
1016 bit_count
, count1
+ count2
));
1018 /* simply ignore the operator */
1022 /* set-up new horizontal and vertical hint mask now */
1023 error
= ps_dimension_set_mask_bits( &dim
[0], bytes
, count2
, count1
,
1024 end_point
, memory
);
1028 error
= ps_dimension_set_mask_bits( &dim
[1], bytes
, 0, count2
,
1029 end_point
, memory
);
1036 hints
->error
= error
;
1041 ps_hints_t2counter( PS_Hints hints
,
1043 const FT_Byte
* bytes
)
1048 if ( !hints
->error
)
1050 PS_Dimension dim
= hints
->dimension
;
1051 FT_Memory memory
= hints
->memory
;
1052 FT_UInt count1
= dim
[0].hints
.num_hints
;
1053 FT_UInt count2
= dim
[1].hints
.num_hints
;
1056 /* check bit count, must be equal to current total hint count */
1057 if ( bit_count
!= count1
+ count2
)
1059 FT_TRACE0(( "ps_hints_t2counter:"
1060 " called with invalid bitcount %d (instead of %d)\n",
1061 bit_count
, count1
+ count2
));
1063 /* simply ignore the operator */
1067 /* set-up new horizontal and vertical hint mask now */
1068 error
= ps_dimension_set_mask_bits( &dim
[0], bytes
, 0, count1
,
1073 error
= ps_dimension_set_mask_bits( &dim
[1], bytes
, count1
, count2
,
1081 hints
->error
= error
;
1085 /* end recording session */
1087 ps_hints_close( PS_Hints hints
,
1093 error
= hints
->error
;
1096 FT_Memory memory
= hints
->memory
;
1097 PS_Dimension dim
= hints
->dimension
;
1100 error
= ps_dimension_end( &dim
[0], end_point
, memory
);
1103 error
= ps_dimension_end( &dim
[1], end_point
, memory
);
1109 ps_debug_hints
= hints
;
1115 /*************************************************************************/
1116 /*************************************************************************/
1118 /***** TYPE 1 HINTS RECORDING INTERFACE *****/
1120 /*************************************************************************/
1121 /*************************************************************************/
1124 t1_hints_open( T1_Hints hints
)
1126 ps_hints_open( (PS_Hints
)hints
, PS_HINT_TYPE_1
);
1130 t1_hints_stem( T1_Hints hints
,
1137 stems
[0] = FIXED_TO_INT( coords
[0] );
1138 stems
[1] = FIXED_TO_INT( coords
[1] );
1140 ps_hints_stem( (PS_Hints
)hints
, dimension
, 1, stems
);
1144 FT_LOCAL_DEF( void )
1145 t1_hints_funcs_init( T1_Hints_FuncsRec
* funcs
)
1147 FT_MEM_ZERO( (char*)funcs
, sizeof ( *funcs
) );
1149 funcs
->open
= (T1_Hints_OpenFunc
) t1_hints_open
;
1150 funcs
->close
= (T1_Hints_CloseFunc
) ps_hints_close
;
1151 funcs
->stem
= (T1_Hints_SetStemFunc
) t1_hints_stem
;
1152 funcs
->stem3
= (T1_Hints_SetStem3Func
)ps_hints_t1stem3
;
1153 funcs
->reset
= (T1_Hints_ResetFunc
) ps_hints_t1reset
;
1154 funcs
->apply
= (T1_Hints_ApplyFunc
) ps_hints_apply
;
1158 /*************************************************************************/
1159 /*************************************************************************/
1161 /***** TYPE 2 HINTS RECORDING INTERFACE *****/
1163 /*************************************************************************/
1164 /*************************************************************************/
1167 t2_hints_open( T2_Hints hints
)
1169 ps_hints_open( (PS_Hints
)hints
, PS_HINT_TYPE_2
);
1174 t2_hints_stems( T2_Hints hints
,
1179 FT_Pos stems
[32], y
, n
;
1180 FT_Int total
= count
;
1186 /* determine number of stems to write */
1191 /* compute integer stem positions in font units */
1192 for ( n
= 0; n
< count
* 2; n
++ )
1195 stems
[n
] = FIXED_TO_INT( y
);
1198 /* compute lengths */
1199 for ( n
= 0; n
< count
* 2; n
+= 2 )
1200 stems
[n
+ 1] = stems
[n
+ 1] - stems
[n
];
1202 /* add them to the current dimension */
1203 ps_hints_stem( (PS_Hints
)hints
, dimension
, count
, stems
);
1210 FT_LOCAL_DEF( void )
1211 t2_hints_funcs_init( T2_Hints_FuncsRec
* funcs
)
1213 FT_MEM_ZERO( funcs
, sizeof ( *funcs
) );
1215 funcs
->open
= (T2_Hints_OpenFunc
) t2_hints_open
;
1216 funcs
->close
= (T2_Hints_CloseFunc
) ps_hints_close
;
1217 funcs
->stems
= (T2_Hints_StemsFunc
) t2_hints_stems
;
1218 funcs
->hintmask
= (T2_Hints_MaskFunc
) ps_hints_t2mask
;
1219 funcs
->counter
= (T2_Hints_CounterFunc
)ps_hints_t2counter
;
1220 funcs
->apply
= (T2_Hints_ApplyFunc
) ps_hints_apply
;