1 /***************************************************************************/
5 /* FreeType PostScript hints recorder (body). */
7 /* Copyright 2001, 2002 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
27 #define FT_COMPONENT trace_pshrec
30 extern PS_Hints ps_debug_hints
= 0;
31 extern int ps_debug_no_horz_hints
= 0;
32 extern int ps_debug_no_vert_hints
= 0;
36 /*************************************************************************/
37 /*************************************************************************/
39 /***** PS_HINT MANAGEMENT *****/
41 /*************************************************************************/
42 /*************************************************************************/
44 /* destroy hints table */
46 ps_hint_table_done( PS_Hint_Table table
,
49 FT_FREE( table
->hints
);
55 /* ensure that a table can contain "count" elements */
57 ps_hint_table_ensure( PS_Hint_Table table
,
61 FT_UInt old_max
= table
->max_hints
;
62 FT_UInt new_max
= count
;
66 if ( new_max
> old_max
)
68 /* try to grow the table */
69 new_max
= ( new_max
+ 7 ) & -8;
70 if ( !FT_RENEW_ARRAY( table
->hints
, old_max
, new_max
) )
71 table
->max_hints
= new_max
;
78 ps_hint_table_alloc( PS_Hint_Table table
,
87 count
= table
->num_hints
;
90 if ( count
>= table
->max_hints
)
92 error
= ps_hint_table_ensure( table
, count
, memory
);
97 hint
= table
->hints
+ count
- 1;
102 table
->num_hints
= count
;
110 /*************************************************************************/
111 /*************************************************************************/
113 /***** PS_MASK MANAGEMENT *****/
115 /*************************************************************************/
116 /*************************************************************************/
120 ps_mask_done( PS_Mask mask
,
123 FT_FREE( mask
->bytes
);
130 /* ensure that a mask can contain "count" bits */
132 ps_mask_ensure( PS_Mask mask
,
136 FT_UInt old_max
= ( mask
->max_bits
+ 7 ) >> 3;
137 FT_UInt new_max
= ( count
+ 7 ) >> 3;
141 if ( new_max
> old_max
)
143 new_max
= ( new_max
+ 7 ) & -8;
144 if ( !FT_RENEW_ARRAY( mask
->bytes
, old_max
, new_max
) )
145 mask
->max_bits
= new_max
* 8;
151 /* test a bit value in a given mask */
153 ps_mask_test_bit( PS_Mask mask
,
156 if ( (FT_UInt
)idx
>= mask
->num_bits
)
159 return mask
->bytes
[idx
>> 3] & ( 0x80 >> ( idx
& 7 ) );
163 /* clear a given bit */
165 ps_mask_clear_bit( PS_Mask mask
,
171 if ( (FT_UInt
)idx
>= mask
->num_bits
)
174 p
= mask
->bytes
+ ( idx
>> 3 );
175 p
[0] = (FT_Byte
)( p
[0] & ~( 0x80 >> ( idx
& 7 ) ) );
179 /* set a given bit, possibly grow the mask */
181 ps_mask_set_bit( PS_Mask mask
,
192 if ( (FT_UInt
)idx
>= mask
->num_bits
)
194 error
= ps_mask_ensure( mask
, idx
+ 1, memory
);
198 mask
->num_bits
= idx
+ 1;
201 p
= mask
->bytes
+ ( idx
>> 3 );
202 p
[0] = (FT_Byte
)( p
[0] | ( 0x80 >> ( idx
& 7 ) ) );
209 /* destroy mask table */
211 ps_mask_table_done( PS_Mask_Table table
,
214 FT_UInt count
= table
->max_masks
;
215 PS_Mask mask
= table
->masks
;
218 for ( ; count
> 0; count
--, mask
++ )
219 ps_mask_done( mask
, memory
);
221 FT_FREE( table
->masks
);
222 table
->num_masks
= 0;
223 table
->max_masks
= 0;
227 /* ensure that a mask table can contain "count" masks */
229 ps_mask_table_ensure( PS_Mask_Table table
,
233 FT_UInt old_max
= table
->max_masks
;
234 FT_UInt new_max
= count
;
238 if ( new_max
> old_max
)
240 new_max
= ( new_max
+ 7 ) & -8;
241 if ( !FT_RENEW_ARRAY( table
->masks
, old_max
, new_max
) )
242 table
->max_masks
= new_max
;
248 /* allocate a new mask in a table */
250 ps_mask_table_alloc( PS_Mask_Table table
,
259 count
= table
->num_masks
;
262 if ( count
> table
->max_masks
)
264 error
= ps_mask_table_ensure( table
, count
, memory
);
269 mask
= table
->masks
+ count
- 1;
272 table
->num_masks
= count
;
280 /* return last hint mask in a table, create one if the table is empty */
282 ps_mask_table_last( PS_Mask_Table table
,
291 count
= table
->num_masks
;
294 error
= ps_mask_table_alloc( table
, memory
, &mask
);
299 mask
= table
->masks
+ count
- 1;
307 /* set a new mask to a given bit range */
309 ps_mask_table_set_bits( PS_Mask_Table table
,
319 /* allocate new mask, and grow it to "bit_count" bits */
320 error
= ps_mask_table_alloc( table
, memory
, &mask
);
324 error
= ps_mask_ensure( mask
, bit_count
, memory
);
328 mask
->num_bits
= bit_count
;
332 FT_Byte
* read
= source
+ ( bit_pos
>> 3 );
333 FT_Int rmask
= 0x80 >> ( bit_pos
& 7 );
334 FT_Byte
* write
= mask
->bytes
;
339 for ( ; bit_count
> 0; bit_count
-- )
341 val
= write
[0] & ~wmask
;
343 if ( read
[0] & rmask
)
346 write
[0] = (FT_Byte
)val
;
369 /* test whether two masks in a table intersect */
371 ps_mask_table_test_intersect( PS_Mask_Table table
,
375 PS_Mask mask1
= table
->masks
+ index1
;
376 PS_Mask mask2
= table
->masks
+ index2
;
377 FT_Byte
* p1
= mask1
->bytes
;
378 FT_Byte
* p2
= mask2
->bytes
;
379 FT_UInt count1
= mask1
->num_bits
;
380 FT_UInt count2
= mask2
->num_bits
;
384 count
= ( count1
<= count2
) ? count1
: count2
;
385 for ( ; count
>= 8; count
-= 8 )
397 return ( p1
[0] & p2
[0] ) & ~( 0xFF >> count
);
401 /* merge two masks, used by ps_mask_table_merge_all */
403 ps_mask_table_merge( PS_Mask_Table table
,
412 /* swap index1 and index2 so that index1 < index2 */
413 if ( index1
> index2
)
420 if ( index1
< index2
&& index1
>= 0 && index2
< (FT_Int
)table
->num_masks
)
422 /* we need to merge the bitsets of index1 and index2 with a */
424 PS_Mask mask1
= table
->masks
+ index1
;
425 PS_Mask mask2
= table
->masks
+ index2
;
426 FT_UInt count1
= mask1
->num_bits
;
427 FT_UInt count2
= mask2
->num_bits
;
438 /* if "count2" is greater than "count1", we need to grow the */
439 /* first bitset, and clear the highest bits */
440 if ( count2
> count1
)
442 error
= ps_mask_ensure( mask1
, count2
, memory
);
446 for ( pos
= count1
; pos
< count2
; pos
++ )
447 ps_mask_clear_bit( mask1
, pos
);
450 /* merge (unite) the bitsets */
452 write
= mask1
->bytes
;
453 pos
= (FT_UInt
)( ( count2
+ 7 ) >> 3 );
455 for ( ; pos
> 0; pos
-- )
457 write
[0] = (FT_Byte
)( write
[0] | read
[0] );
463 /* Now, remove "mask2" from the list. We need to keep the masks */
464 /* sorted in order of importance, so move table elements. */
466 mask2
->end_point
= 0;
468 delta
= table
->num_masks
- 1 - index2
; /* number of masks to move */
471 /* move to end of table for reuse */
472 PS_MaskRec dummy
= *mask2
;
475 ft_memmove( mask2
, mask2
+ 1, delta
* sizeof ( PS_MaskRec
) );
477 mask2
[delta
] = dummy
;
483 FT_ERROR(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
491 /* Try to merge all masks in a given table. This is used to merge */
492 /* all counter masks into independent counter "paths". */
495 ps_mask_table_merge_all( PS_Mask_Table table
,
498 FT_Int index1
, index2
;
502 for ( index1
= table
->num_masks
- 1; index1
> 0; index1
-- )
504 for ( index2
= index1
- 1; index2
>= 0; index2
-- )
506 if ( ps_mask_table_test_intersect( table
, index1
, index2
) )
508 error
= ps_mask_table_merge( table
, index2
, index1
, memory
);
522 /*************************************************************************/
523 /*************************************************************************/
525 /***** PS_DIMENSION MANAGEMENT *****/
527 /*************************************************************************/
528 /*************************************************************************/
531 /* finalize a given dimension */
533 ps_dimension_done( PS_Dimension dimension
,
536 ps_mask_table_done( &dimension
->counters
, memory
);
537 ps_mask_table_done( &dimension
->masks
, memory
);
538 ps_hint_table_done( &dimension
->hints
, memory
);
542 /* initialize a given dimension */
544 ps_dimension_init( PS_Dimension dimension
)
546 dimension
->hints
.num_hints
= 0;
547 dimension
->masks
.num_masks
= 0;
548 dimension
->counters
.num_masks
= 0;
554 /* set a bit at a given index in the current hint mask */
556 ps_dimension_set_mask_bit( PS_Dimension dim
,
564 /* get last hint mask */
565 error
= ps_mask_table_last( &dim
->masks
, memory
, &mask
);
569 error
= ps_mask_set_bit( mask
, idx
, memory
);
577 /* set the end point in a mask, called from "End" & "Reset" methods */
579 ps_dimension_end_mask( PS_Dimension dim
,
582 FT_UInt count
= dim
->masks
.num_masks
;
588 mask
= dim
->masks
.masks
+ count
- 1;
589 mask
->end_point
= end_point
;
594 /* set the end point in the current mask, then create a new empty one */
595 /* (called by "Reset" method) */
597 ps_dimension_reset_mask( PS_Dimension dim
,
604 /* end current mask */
605 ps_dimension_end_mask( dim
, end_point
);
607 /* allocate new one */
608 return ps_mask_table_alloc( &dim
->masks
, memory
, &mask
);
612 /* set a new mask, called from the "T2Stem" method */
614 ps_dimension_set_mask_bits( PS_Dimension dim
,
615 const FT_Byte
* source
,
624 /* reset current mask, if any */
625 error
= ps_dimension_reset_mask( dim
, end_point
, memory
);
629 /* set bits in new mask */
630 error
= ps_mask_table_set_bits( &dim
->masks
, (FT_Byte
*)source
,
631 source_pos
, source_bits
, memory
);
638 /* add a new single stem (called from "T1Stem" method) */
640 ps_dimension_add_t1stem( PS_Dimension dim
,
650 /* detect ghost stem */
653 flags
|= PS_HINT_FLAG_GHOST
;
656 flags
|= PS_HINT_FLAG_BOTTOM
;
665 /* now, lookup stem in the current hints table */
669 FT_UInt max
= dim
->hints
.num_hints
;
670 PS_Hint hint
= dim
->hints
.hints
;
673 for ( idx
= 0; idx
< max
; idx
++, hint
++ )
675 if ( hint
->pos
== pos
&& hint
->len
== len
)
679 /* we need to create a new hint in the table */
682 error
= ps_hint_table_alloc( &dim
->hints
, memory
, &hint
);
691 /* now, store the hint in the current mask */
692 error
= ps_mask_table_last( &dim
->masks
, memory
, &mask
);
696 error
= ps_mask_set_bit( mask
, idx
, memory
);
701 *aindex
= (FT_Int
)idx
;
709 /* add a "hstem3/vstem3" counter to our dimension table */
711 ps_dimension_add_counter( PS_Dimension dim
,
718 FT_UInt count
= dim
->counters
.num_masks
;
719 PS_Mask counter
= dim
->counters
.masks
;
722 /* try to find an existing counter mask that already uses */
723 /* one of these stems here */
724 for ( ; count
> 0; count
--, counter
++ )
726 if ( ps_mask_test_bit( counter
, hint1
) ||
727 ps_mask_test_bit( counter
, hint2
) ||
728 ps_mask_test_bit( counter
, hint3
) )
732 /* creat a new counter when needed */
735 error
= ps_mask_table_alloc( &dim
->counters
, memory
, &counter
);
740 /* now, set the bits for our hints in the counter mask */
741 error
= ps_mask_set_bit( counter
, hint1
, memory
);
745 error
= ps_mask_set_bit( counter
, hint2
, memory
);
749 error
= ps_mask_set_bit( counter
, hint3
, memory
);
758 /* end of recording session for a given dimension */
760 ps_dimension_end( PS_Dimension dim
,
764 /* end hint mask table */
765 ps_dimension_end_mask( dim
, end_point
);
767 /* merge all counter masks into independent "paths" */
768 return ps_mask_table_merge_all( &dim
->counters
, memory
);
772 /*************************************************************************/
773 /*************************************************************************/
775 /***** PS_RECORDER MANAGEMENT *****/
777 /*************************************************************************/
778 /*************************************************************************/
783 ps_hints_done( PS_Hints hints
)
785 FT_Memory memory
= hints
->memory
;
788 ps_dimension_done( &hints
->dimension
[0], memory
);
789 ps_dimension_done( &hints
->dimension
[1], memory
);
797 ps_hints_init( PS_Hints hints
,
800 ft_memset( hints
, 0, sizeof ( *hints
) );
801 hints
->memory
= memory
;
806 /* initialize a hints for a new session */
808 ps_hints_open( PS_Hints hints
,
809 PS_Hint_Type hint_type
)
816 hints
->hint_type
= hint_type
;
818 ps_dimension_init( &hints
->dimension
[0] );
819 ps_dimension_init( &hints
->dimension
[1] );
823 hints
->error
= FT_Err_Invalid_Argument
;
824 hints
->hint_type
= hint_type
;
826 FT_ERROR(( "ps_hints_open: invalid charstring type!\n" ));
832 /* add one or more stems to the current hints table */
834 ps_hints_stem( PS_Hints hints
,
841 /* limit "dimension" to 0..1 */
842 if ( dimension
< 0 || dimension
> 1 )
844 FT_ERROR(( "ps_hints_stem: invalid dimension (%d) used\n",
846 dimension
= ( dimension
!= 0 );
849 /* record the stems in the current hints/masks table */
850 switch ( hints
->hint_type
)
852 case PS_HINT_TYPE_1
: /* Type 1 "hstem" or "vstem" operator */
853 case PS_HINT_TYPE_2
: /* Type 2 "hstem" or "vstem" operator */
855 PS_Dimension dim
= &hints
->dimension
[dimension
];
858 for ( ; count
> 0; count
--, stems
+= 2 )
861 FT_Memory memory
= hints
->memory
;
864 error
= ps_dimension_add_t1stem( dim
, stems
[0], stems
[1],
868 FT_ERROR(( "ps_hints_stem: could not add stem"
869 " (%d,%d) to hints table\n", stems
[0], stems
[1] ));
871 hints
->error
= error
;
879 FT_ERROR(( "ps_hints_stem: called with invalid hint type (%d)\n",
887 /* add one Type1 counter stem to the current hints table */
889 ps_hints_t1stem3( PS_Hints hints
,
899 FT_Memory memory
= hints
->memory
;
904 /* limit "dimension" to 0..1 */
905 if ( dimension
< 0 || dimension
> 1 )
907 FT_ERROR(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
909 dimension
= ( dimension
!= 0 );
912 dim
= &hints
->dimension
[dimension
];
914 /* there must be 6 elements in the 'stem' array */
915 if ( hints
->hint_type
== PS_HINT_TYPE_1
)
917 /* add the three stems to our hints/masks table */
918 for ( count
= 0; count
< 3; count
++, stems
+= 2 )
920 error
= ps_dimension_add_t1stem( dim
, stems
[0], stems
[1],
921 memory
, &idx
[count
] );
926 /* now, add the hints to the counters table */
927 error
= ps_dimension_add_counter( dim
, idx
[0], idx
[1], idx
[2],
934 FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type!\n" ));
935 error
= FT_Err_Invalid_Argument
;
943 FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
944 hints
->error
= error
;
948 /* reset hints (only with Type 1 hints) */
950 ps_hints_t1reset( PS_Hints hints
,
958 FT_Memory memory
= hints
->memory
;
961 if ( hints
->hint_type
== PS_HINT_TYPE_1
)
963 error
= ps_dimension_reset_mask( &hints
->dimension
[0],
968 error
= ps_dimension_reset_mask( &hints
->dimension
[1],
975 /* invalid hint type */
976 error
= FT_Err_Invalid_Argument
;
983 hints
->error
= error
;
987 /* Type2 "hintmask" operator, add a new hintmask to each direction */
989 ps_hints_t2mask( PS_Hints hints
,
992 const FT_Byte
* bytes
)
999 PS_Dimension dim
= hints
->dimension
;
1000 FT_Memory memory
= hints
->memory
;
1001 FT_UInt count1
= dim
[0].hints
.num_hints
;
1002 FT_UInt count2
= dim
[1].hints
.num_hints
;
1005 /* check bit count; must be equal to current total hint count */
1006 if ( bit_count
!= count1
+ count2
)
1008 FT_ERROR(( "ps_hints_t2mask: "
1009 "called with invalid bitcount %d (instead of %d)\n",
1010 bit_count
, count1
+ count2
));
1012 /* simply ignore the operator */
1016 /* set-up new horizontal and vertical hint mask now */
1017 error
= ps_dimension_set_mask_bits( &dim
[0], bytes
, 0, count1
,
1018 end_point
, memory
);
1022 error
= ps_dimension_set_mask_bits( &dim
[1], bytes
, count1
, count2
,
1023 end_point
, memory
);
1030 hints
->error
= error
;
1035 ps_hints_t2counter( PS_Hints hints
,
1037 const FT_Byte
* bytes
)
1042 if ( !hints
->error
)
1044 PS_Dimension dim
= hints
->dimension
;
1045 FT_Memory memory
= hints
->memory
;
1046 FT_UInt count1
= dim
[0].hints
.num_hints
;
1047 FT_UInt count2
= dim
[1].hints
.num_hints
;
1050 /* check bit count, must be equal to current total hint count */
1051 if ( bit_count
!= count1
+ count2
)
1053 FT_ERROR(( "ps_hints_t2counter: "
1054 "called with invalid bitcount %d (instead of %d)\n",
1055 bit_count
, count1
+ count2
));
1057 /* simply ignore the operator */
1061 /* set-up new horizontal and vertical hint mask now */
1062 error
= ps_dimension_set_mask_bits( &dim
[0], bytes
, 0, count1
,
1067 error
= ps_dimension_set_mask_bits( &dim
[1], bytes
, count1
, count2
,
1075 hints
->error
= error
;
1079 /* end recording session */
1081 ps_hints_close( PS_Hints hints
,
1087 error
= hints
->error
;
1090 FT_Memory memory
= hints
->memory
;
1091 PS_Dimension dim
= hints
->dimension
;
1094 error
= ps_dimension_end( &dim
[0], end_point
, memory
);
1097 error
= ps_dimension_end( &dim
[1], end_point
, memory
);
1103 ps_debug_hints
= hints
;
1109 /*************************************************************************/
1110 /*************************************************************************/
1112 /***** TYPE 1 HINTS RECORDING INTERFACE *****/
1114 /*************************************************************************/
1115 /*************************************************************************/
1118 t1_hints_open( T1_Hints hints
)
1120 ps_hints_open( (PS_Hints
)hints
, PS_HINT_TYPE_1
);
1124 t1_hints_stem( T1_Hints hints
,
1128 ps_hints_stem( (PS_Hints
)hints
, dimension
, 1, coords
);
1132 FT_LOCAL_DEF( void )
1133 t1_hints_funcs_init( T1_Hints_FuncsRec
* funcs
)
1135 ft_memset( (char*)funcs
, 0, sizeof ( *funcs
) );
1137 funcs
->open
= (T1_Hints_OpenFunc
) t1_hints_open
;
1138 funcs
->close
= (T1_Hints_CloseFunc
) ps_hints_close
;
1139 funcs
->stem
= (T1_Hints_SetStemFunc
) t1_hints_stem
;
1140 funcs
->stem3
= (T1_Hints_SetStem3Func
)ps_hints_t1stem3
;
1141 funcs
->reset
= (T1_Hints_ResetFunc
) ps_hints_t1reset
;
1142 funcs
->apply
= (T1_Hints_ApplyFunc
) PS_HINTS_APPLY_FUNC
;
1146 /*************************************************************************/
1147 /*************************************************************************/
1149 /***** TYPE 2 HINTS RECORDING INTERFACE *****/
1151 /*************************************************************************/
1152 /*************************************************************************/
1155 t2_hints_open( T2_Hints hints
)
1157 ps_hints_open( (PS_Hints
)hints
, PS_HINT_TYPE_2
);
1162 t2_hints_stems( T2_Hints hints
,
1167 FT_Pos stems
[32], y
, n
, total
= count
;
1173 /* determine number of stems to write */
1178 /* compute integer stem positions in font units */
1179 for ( n
= 0; n
< count
* 2; n
++ )
1182 stems
[n
] = ( y
+ 0x8000 ) >> 16;
1185 /* compute lengths */
1186 for ( n
= 0; n
< count
* 2; n
+= 2 )
1187 stems
[n
+ 1] = stems
[n
+ 1] - stems
[n
];
1189 /* add them to the current dimension */
1190 ps_hints_stem( (PS_Hints
)hints
, dimension
, count
, stems
);
1197 FT_LOCAL_DEF( void )
1198 t2_hints_funcs_init( T2_Hints_FuncsRec
* funcs
)
1200 ft_memset( funcs
, 0, sizeof ( *funcs
) );
1202 funcs
->open
= (T2_Hints_OpenFunc
) t2_hints_open
;
1203 funcs
->close
= (T2_Hints_CloseFunc
) ps_hints_close
;
1204 funcs
->stems
= (T2_Hints_StemsFunc
) t2_hints_stems
;
1205 funcs
->hintmask
= (T2_Hints_MaskFunc
) ps_hints_t2mask
;
1206 funcs
->counter
= (T2_Hints_CounterFunc
)ps_hints_t2counter
;
1207 funcs
->apply
= (T2_Hints_ApplyFunc
) PS_HINTS_APPLY_FUNC
;