1 /***************************************************************************/
5 /* Type 1 Glyph Loader (body). */
7 /* Copyright 1996-2000 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 /***************************************************************************/
19 #ifdef FT_FLAT_COMPILE
23 #ifndef T1_CONFIG_OPTION_DISABLE_HINTER
27 #else /* FT_FLAT_COMPILE */
29 #include <type1/t1gload.h>
31 #ifndef T1_CONFIG_OPTION_DISABLE_HINTER
32 #include <type1/t1hinter.h>
35 #endif /* FT_FLAT_COMPILE */
38 #include <freetype/internal/ftdebug.h>
39 #include <freetype/internal/ftstream.h>
40 #include <freetype/ftoutln.h>
42 #include <string.h> /* for strcmp() */
45 /*************************************************************************/
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
52 #define FT_COMPONENT trace_t1gload
55 /*************************************************************************/
56 /*************************************************************************/
57 /*************************************************************************/
58 /********** *********/
59 /********** *********/
60 /********** GENERIC CHARSTRING PARSING *********/
61 /********** *********/
62 /********** *********/
63 /*************************************************************************/
64 /*************************************************************************/
65 /*************************************************************************/
69 void T1_Reset_Builder( T1_Builder
* builder
,
75 builder
->left_bearing
.x
= 0;
76 builder
->left_bearing
.y
= 0;
77 builder
->advance
.x
= 0;
78 builder
->advance
.y
= 0;
81 builder
->hint_point
= 0;
83 if ( builder
->loader
)
86 FT_GlyphLoader_Rewind( builder
->loader
);
88 FT_GlyphLoader_Prepare( builder
->loader
);
93 /*************************************************************************/
99 /* Initializes a given glyph builder. */
102 /* builder :: A pointer to the glyph builder to initialize. */
105 /* face :: The current face object. */
107 /* size :: The current size object. */
109 /* glyph :: The current glyph object. */
111 /* funcs :: Glyph builder functions (or `methods'). */
114 void T1_Init_Builder( T1_Builder
* builder
,
118 const T1_Builder_Funcs
* funcs
)
120 builder
->funcs
= *funcs
;
121 builder
->path_begun
= 0;
122 builder
->load_points
= 1;
124 builder
->face
= face
;
125 builder
->size
= size
;
126 builder
->glyph
= glyph
;
127 builder
->memory
= face
->root
.memory
;
131 FT_GlyphLoader
* loader
= FT_SLOT( glyph
)->loader
;
134 builder
->loader
= loader
;
135 builder
->base
= &loader
->base
.outline
;
136 builder
->current
= &loader
->current
.outline
;
141 builder
->scale_x
= size
->root
.metrics
.x_scale
;
142 builder
->scale_y
= size
->root
.metrics
.y_scale
;
145 T1_Reset_Builder( builder
, 1 );
149 /*************************************************************************/
152 /* T1_Done_Builder */
155 /* Finalizes a given glyph builder. Its contents can still be used */
156 /* after the call, but the function saves important information */
157 /* within the corresponding glyph slot. */
160 /* builder :: A pointer to the glyph builder to finalize. */
163 void T1_Done_Builder( T1_Builder
* builder
)
165 T1_GlyphSlot glyph
= builder
->glyph
;
169 glyph
->root
.outline
= *builder
->base
;
173 /*************************************************************************/
176 /* T1_Init_Decoder */
179 /* Initializes a given glyph decoder. */
182 /* decoder :: A pointer to the glyph builder to initialize. */
185 /* funcs :: The hinting functions interface. */
188 void T1_Init_Decoder( T1_Decoder
* decoder
,
189 const T1_Hinter_Funcs
* funcs
)
191 decoder
->hinter
= *funcs
; /* copy hinter interface */
195 decoder
->flex_state
= 0;
196 decoder
->num_flex_vectors
= 0;
199 MEM_Set( &decoder
->builder
, 0, sizeof ( decoder
->builder
) );
203 /*************************************************************************/
206 /* lookup_glyph_by_stdcharcode */
209 /* Looks up a given glyph by its StandardEncoding charcode. Used */
210 /* to implement the SEAC Type 1 operator. */
213 /* face :: The current face object. */
215 /* charcode :: The character code to look for. */
218 /* A glyph index in the font face. Returns -1 if the corresponding */
219 /* glyph wasn't found. */
222 FT_Int
lookup_glyph_by_stdcharcode( T1_Face face
,
226 const FT_String
* glyph_name
;
227 PSNames_Interface
* psnames
= (PSNames_Interface
*)face
->psnames
;
230 /* check range of standard char code */
231 if ( charcode
< 0 || charcode
> 255 )
234 glyph_name
= psnames
->adobe_std_strings(
235 psnames
->adobe_std_encoding
[charcode
] );
237 for ( n
= 0; n
< face
->type1
.num_glyphs
; n
++ )
239 FT_String
* name
= (FT_String
*)face
->type1
.glyph_names
[n
];
242 if ( name
&& strcmp( name
, glyph_name
) == 0 )
250 /*************************************************************************/
253 /* t1operator_seac */
256 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
259 /* decoder :: The current CID decoder. */
261 /* asb :: The accent's side bearing. */
263 /* adx :: The horizontal offset of the accent. */
265 /* ady :: The vertical offset of the accent. */
267 /* bchar :: The base character's StandardEncoding charcode. */
269 /* achar :: The accent character's StandardEncoding charcode. */
272 /* FreeType error code. 0 means success. */
275 FT_Error
t1operator_seac( T1_Decoder
* decoder
,
283 FT_Int bchar_index
, achar_index
, n_base_points
;
284 FT_Outline
* base
= decoder
->builder
.base
;
285 FT_Vector left_bearing
, advance
;
286 T1_Face face
= decoder
->builder
.face
;
287 T1_Font
* type1
= &face
->type1
;
290 bchar_index
= lookup_glyph_by_stdcharcode( face
, bchar
);
291 achar_index
= lookup_glyph_by_stdcharcode( face
, achar
);
293 if ( bchar_index
< 0 || achar_index
< 0 )
295 FT_ERROR(( "t1operator_seac:" ));
296 FT_ERROR(( " invalid seac character code arguments\n" ));
297 return T1_Err_Syntax_Error
;
300 /* if we are trying to load a composite glyph, do not load the */
301 /* accent character and return the array of subglyphs. */
302 if ( decoder
->builder
.no_recurse
)
304 FT_GlyphSlot glyph
= (FT_GlyphSlot
)decoder
->builder
.glyph
;
305 FT_GlyphLoader
* loader
= glyph
->loader
;
309 /* reallocate subglyph array if necessary */
310 error
= FT_GlyphLoader_Check_Subglyphs( loader
, 2 );
314 subg
= loader
->current
.subglyphs
;
316 /* subglyph 0 = base character */
317 subg
->index
= bchar_index
;
318 subg
->flags
= FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
|
319 FT_SUBGLYPH_FLAG_USE_MY_METRICS
;
324 /* subglyph 1 = accent character */
325 subg
->index
= achar_index
;
326 subg
->flags
= FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
;
327 subg
->arg1
= adx
- asb
;
330 /* set up remaining glyph fields */
331 glyph
->num_subglyphs
= 2;
332 glyph
->subglyphs
= loader
->current
.subglyphs
;
333 glyph
->format
= ft_glyph_format_composite
;
335 loader
->current
.num_subglyphs
= 2;
339 /* First load `bchar' in builder */
340 /* now load the unscaled outline */
342 if ( decoder
->builder
.loader
)
343 FT_GlyphLoader_Prepare( decoder
->builder
.loader
); /* prepare loader */
345 error
= T1_Parse_CharStrings( decoder
,
346 type1
->charstrings
[bchar_index
],
347 type1
->charstrings_len
[bchar_index
],
354 n_base_points
= base
->n_points
;
356 /* save the left bearing and width of the base character */
357 /* as they will be erased by the next load. */
359 left_bearing
= decoder
->builder
.left_bearing
;
360 advance
= decoder
->builder
.advance
;
362 decoder
->builder
.left_bearing
.x
= 0;
363 decoder
->builder
.left_bearing
.y
= 0;
365 /* Now load `achar' on top of the base outline */
366 error
= T1_Parse_CharStrings( decoder
,
367 type1
->charstrings
[achar_index
],
368 type1
->charstrings_len
[achar_index
],
375 /* restore the left side bearing and */
376 /* advance width of the base character */
378 decoder
->builder
.left_bearing
= left_bearing
;
379 decoder
->builder
.advance
= advance
;
381 /* Finally, move the accent */
382 if ( decoder
->builder
.load_points
)
387 dummy
.n_points
= base
->n_points
- n_base_points
;
388 dummy
.points
= base
->points
+ n_base_points
;
390 FT_Outline_Translate( &dummy
, adx
- asb
, ady
);
398 /*************************************************************************/
401 /* t1operator_flex */
404 /* Implements the `flex' Type 1 operator for a Type 1 decoder. */
407 /* decoder :: The current Type 1 decoder. */
408 /* threshold :: The threshold. */
409 /* end_x :: The horizontal position of the final flex point. */
410 /* end_y :: The vertical position of the final flex point. */
413 /* FreeType error code. 0 means success. */
416 FT_Error
t1operator_flex( T1_Decoder
* decoder
,
422 FT_Vector
* flex
= decoder
->flex_vectors
;
425 FT_UNUSED( threshold
);
430 /* we don't even try to test the threshold in the non-hinting */
431 /* builder, even if the flex operator is said to be a path */
432 /* construction statement in the specification. This is better */
433 /* left to the hinter. */
435 flex
= decoder
->flex_vectors
;
438 for ( n
= 0; n
< 6; n
++ )
446 flex
= decoder
->flex_vectors
;
448 return decoder
->builder
.funcs
.rcurve_to( &decoder
->builder
,
449 flex
[0].x
, flex
[0].y
,
450 flex
[1].x
, flex
[1].y
,
451 flex
[2].x
, flex
[2].y
) ||
453 decoder
->builder
.funcs
.rcurve_to( &decoder
->builder
,
454 flex
[3].x
, flex
[3].y
,
455 flex
[4].x
, flex
[4].y
,
456 flex
[5].x
, flex
[5].y
);
460 /*************************************************************************/
463 /* T1_Parse_CharStrings */
466 /* Parses a given Type 1 charstrings program. */
469 /* decoder :: The current Type 1 decoder. */
471 /* charstring_base :: The base address of the charstring stream. */
473 /* charstring_len :: The length in bytes of the charstring stream. */
475 /* num_subrs :: The number of sub-routines. */
477 /* subrs_base :: An array of sub-routines addresses. */
479 /* subrs_len :: An array of sub-routines lengths. */
482 /* Free error code. 0 means success. */
485 FT_Error
T1_Parse_CharStrings( T1_Decoder
* decoder
,
486 FT_Byte
* charstring_base
,
487 FT_Int charstring_len
,
489 FT_Byte
** subrs_base
,
493 T1_Decoder_Zone
* zone
;
496 T1_Builder
* builder
= &decoder
->builder
;
497 T1_Builder_Funcs
* builds
= &builder
->funcs
;
498 T1_Hinter_Funcs
* hints
= &decoder
->hinter
;
501 const FT_Int args_count
[op_max
] =
524 -1, /* callothersubr */
528 2 /* setcurrentpoint */
532 /* First of all, initialize the decoder */
533 decoder
->top
= decoder
->stack
;
534 decoder
->zone
= decoder
->zones
;
535 zone
= decoder
->zones
;
537 builder
->path_begun
= 0;
539 zone
->base
= charstring_base
;
540 limit
= zone
->limit
= charstring_base
+ charstring_len
;
541 ip
= zone
->cursor
= zone
->base
;
545 /* now, execute loop */
548 FT_Int
* top
= decoder
->top
;
549 T1_Operator op
= op_none
;
553 /* Start with the decompression of operator or value */
612 FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+EOF)\n" ));
637 op
= op_callothersubr
;
643 op
= op_setcurrentpoint
;
647 FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n",
653 case 255: /* four bytes integer */
654 if ( ip
+ 4 > limit
)
656 FT_ERROR(( "T1_Parse_CharStrings: unexpected EOF in integer\n" ));
660 value
= ( (FT_Long
)ip
[0] << 24 ) |
661 ( (FT_Long
)ip
[1] << 16 ) |
662 ( (FT_Long
)ip
[2] << 8 ) |
671 value
= (FT_Long
)ip
[-1] - 139;
676 FT_ERROR(( "T1_Parse_CharStrings:" ));
677 FT_ERROR(( " unexpected EOF in integer\n" ));
682 value
= ((FT_Long
)( ip
[-2] - 247 ) << 8 ) + ip
[-1] + 108;
684 value
= -( ( ( (FT_Long
)ip
[-2] - 251 ) << 8 ) + ip
[-1] + 108 );
689 FT_ERROR(( "T1_Parse_CharStrings: invalid byte (%d)\n",
695 /* push value if necessary */
698 if ( top
- decoder
->stack
>= T1_MAX_CHARSTRINGS_OPERANDS
)
700 FT_ERROR(( "T1_Parse_CharStrings: stack overflow!\n" ));
708 else if ( op
== op_callothersubr
) /* check arguments differently */
710 if ( top
- decoder
->stack
< 2 )
711 goto Stack_Underflow
;
717 case 1: /* start flex feature */
719 goto Unexpected_OtherSubr
;
721 decoder
->flex_state
= 1;
722 decoder
->num_flex_vectors
= 0;
723 decoder
->flex_vectors
[0].x
= 0;
724 decoder
->flex_vectors
[0].y
= 0;
727 case 2: /* add flex vector */
734 goto Unexpected_OtherSubr
;
737 if ( top
< decoder
->stack
)
738 goto Stack_Underflow
;
740 index
= decoder
->num_flex_vectors
++;
743 FT_ERROR(( "T1_Parse_CharStrings: too many flex vectors!\n" ));
747 flex
= decoder
->flex_vectors
+ index
;
753 case 0: /* end flex feature */
754 if ( decoder
->flex_state
== 0 ||
755 decoder
->num_flex_vectors
!= 7 )
757 FT_ERROR(( "T1_Parse_CharStrings: unexpected flex end\n" ));
762 goto Unexpected_OtherSubr
;
765 if ( top
< decoder
->stack
)
766 goto Stack_Underflow
;
768 /* now consume the remaining `pop pop setcurrentpoint' */
769 if ( ip
+ 6 > limit
||
770 ip
[0] != 12 || ip
[1] != 17 || /* pop */
771 ip
[2] != 12 || ip
[3] != 17 || /* pop */
772 ip
[4] != 12 || ip
[5] != 33 ) /* setcurrentpoint */
774 FT_ERROR(( "T1_Parse_CharStrings: invalid flex charstring\n" ));
778 decoder
->flex_state
= 0;
781 error
= t1operator_flex( decoder
, top
[0], top
[1], top
[2] );
784 case 3: /* change hints */
786 goto Unexpected_OtherSubr
;
788 /* eat the following `pop' */
789 if ( ip
+ 2 > limit
)
791 FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n",
796 if ( ip
[0] != 12 || ip
[1] != 17 )
798 FT_ERROR(( "T1_Parse_CharStrings:" ));
799 FT_ERROR(( " `pop' expected, found (%d %d)\n", ip
[0], ip
[1] ));
805 error
= hints
->change_hints( builder
);
809 /* invalid OtherSubrs call */
810 Unexpected_OtherSubr
:
811 FT_ERROR(( "T1_Parse_CharStrings: unexpected OtherSubrs [%d %d]\n",
819 FT_Int num_args
= args_count
[op
];
822 if ( top
- decoder
->stack
< num_args
)
823 goto Stack_Underflow
;
830 error
= builds
->end_char( builder
);
834 error
= builds
->set_bearing_point( builder
, top
[0], 0,
839 /* return immediately after the processing */
840 return t1operator_seac( decoder
, top
[0], top
[1],
841 top
[2], top
[3], top
[4] );
844 error
= builds
->set_bearing_point( builder
, top
[0], top
[1],
849 error
= builds
->close_path( builder
);
853 error
= builds
->rline_to( builder
, top
[0], 0 );
857 error
= builds
->rmove_to( builder
, top
[0], 0 );
861 error
= builds
->rcurve_to( builder
, top
[0], 0,
867 error
= builds
->rline_to( builder
, top
[0], top
[1] );
871 /* ignore operator when in flex mode */
872 if ( decoder
->flex_state
== 0 )
873 error
= builds
->rmove_to( builder
, top
[0], top
[1] );
879 error
= builds
->rcurve_to( builder
, top
[0], top
[1],
885 error
= builds
->rcurve_to( builder
, 0, top
[0],
891 error
= builds
->rline_to( builder
, 0, top
[0] );
895 error
= builds
->rmove_to( builder
, 0, top
[0] );
899 error
= hints
->dot_section( builder
);
903 error
= hints
->stem( builder
, top
[0], top
[1], 0 );
907 error
= hints
->stem3( builder
, top
[0], top
[1], top
[2],
908 top
[3], top
[4], top
[5], 0 );
912 error
= hints
->stem( builder
, top
[0], top
[1], 1 );
916 error
= hints
->stem3( builder
, top
[0], top
[1], top
[2],
917 top
[3], top
[4], top
[5], 1 );
923 *top
= top
[0] / top
[1];
928 FT_ERROR(( "T1_Parse_CHarStrings: division by 0\n" ));
935 FT_Int index
= top
[0];
938 if ( index
< 0 || index
>= num_subrs
)
940 FT_ERROR(( "T1_Parse_CharStrings: invalid subrs index\n" ));
944 if ( zone
- decoder
->zones
>= T1_MAX_SUBRS_CALLS
)
946 FT_ERROR(( "T1_Parse_CharStrings: too many nested subrs\n" ));
950 zone
->cursor
= ip
; /* save current instruction pointer */
953 zone
->base
= subrs_base
[index
];
954 zone
->limit
= zone
->base
+ subrs_len
[index
];
955 zone
->cursor
= zone
->base
;
959 FT_ERROR(( "T1_Parse_CharStrings: invoking empty subrs!\n" ));
963 decoder
->zone
= zone
;
970 FT_ERROR(( "T1_Parse_CharStrings: unexpected POP\n" ));
974 if ( zone
<= decoder
->zones
)
976 FT_ERROR(( "T1_Parse_CharStrings: unexpected return\n" ));
983 decoder
->zone
= zone
;
986 case op_setcurrentpoint
:
987 FT_ERROR(( "T1_Parse_CharStrings:" ));
988 FT_ERROR(( " unexpected `setcurrentpoint'\n" ));
993 FT_ERROR(( "T1_Parse_CharStrings: unhandled opcode %d\n", op
));
1004 return T1_Err_Syntax_Error
;
1007 return T1_Err_Stack_Underflow
;
1011 /*************************************************************************/
1017 /* Checks that there is enough room in the current load glyph outline */
1018 /* to accept `num_points' additional outline points. If not, this */
1019 /* function grows the load outline's arrays accordingly. */
1022 /* builder :: A pointer to the glyph builder object. */
1024 /* num_points :: The number of points that will be added later. */
1027 /* FreeType error code. 0 means success. */
1030 /* This function does NOT update the points count in the glyph */
1031 /* builder. This must be done by the caller itself, after this */
1032 /* function has been invoked. */
1035 FT_Error
T1_Add_Points( T1_Builder
* builder
,
1038 return FT_GlyphLoader_Check_Points( builder
->loader
, num_points
, 0 );
1042 /*************************************************************************/
1045 /* T1_Add_Contours */
1048 /* Checks that there is enough room in the current load glyph outline */
1049 /* to accept `num_contours' additional contours. If not, this */
1050 /* function grows the load outline's arrays accordingly. */
1053 /* builder :: A pointer to the glyph builder object. */
1055 /* num_contours :: The number of contours that will be added later. */
1058 /* FreeType error code. 0 means success. */
1061 /* This function does NOT update the contours count in the load glyph */
1062 /* This must be done by the caller itself, after this function is */
1066 FT_Error
T1_Add_Contours( T1_Builder
* builder
,
1067 FT_Int num_contours
)
1069 return FT_GlyphLoader_Check_Points( builder
->loader
, 0, num_contours
);
1073 /*************************************************************************/
1074 /*************************************************************************/
1075 /*************************************************************************/
1076 /********** *********/
1077 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
1078 /********** *********/
1079 /********** The following code is in charge of computing *********/
1080 /********** the maximum advance width of the font. It *********/
1081 /********** quickly processes each glyph charstring to *********/
1082 /********** extract the value from either a `sbw' or `seac' *********/
1083 /********** operator. *********/
1084 /********** *********/
1085 /*************************************************************************/
1086 /*************************************************************************/
1087 /*************************************************************************/
1091 FT_Error
maxadv_sbw( T1_Decoder
* decoder
,
1101 if ( wx
> decoder
->builder
.advance
.x
)
1102 decoder
->builder
.advance
.x
= wx
;
1104 return -1; /* return an error code to exit the Type 1 parser */
1110 FT_Int
maxadv_error( void )
1112 /* we should never reach this code, unless with a buggy font */
1117 /* the maxadv_gbuilder_interface is used when computing the maximum */
1118 /* advance width of all glyphs in a given font. We only process the */
1119 /* `sbw' operator here, and return an error for all others. */
1121 /* Note that `seac' is processed by the T1_Decoder. */
1123 const T1_Builder_Funcs maxadv_builder_interface
=
1125 (T1_Builder_EndChar
) maxadv_error
,
1126 (T1_Builder_Sbw
) maxadv_sbw
,
1127 (T1_Builder_ClosePath
)maxadv_error
,
1128 (T1_Builder_RLineTo
) maxadv_error
,
1129 (T1_Builder_RMoveTo
) maxadv_error
,
1130 (T1_Builder_RCurveTo
) maxadv_error
1134 /* the maxadv_hinter_interface always return an error. */
1136 const T1_Hinter_Funcs maxadv_hinter_interface
=
1138 (T1_Hinter_DotSection
) maxadv_error
,
1139 (T1_Hinter_ChangeHints
)maxadv_error
,
1140 (T1_Hinter_Stem
) maxadv_error
,
1141 (T1_Hinter_Stem3
) maxadv_error
,
1146 FT_Error
T1_Compute_Max_Advance( T1_Face face
,
1147 FT_Int
* max_advance
)
1152 T1_Font
* type1
= &face
->type1
;
1157 /* Initialize load decoder */
1158 T1_Init_Decoder( &decoder
, &maxadv_hinter_interface
);
1160 T1_Init_Builder( &decoder
.builder
, face
, 0, 0,
1161 &maxadv_builder_interface
);
1163 /* For each glyph, parse the glyph charstring and extract */
1164 /* the advance width. */
1165 for ( glyph_index
= 0; glyph_index
< type1
->num_glyphs
; glyph_index
++ )
1167 /* now get load the unscaled outline */
1168 error
= T1_Parse_CharStrings( &decoder
,
1169 type1
->charstrings
[glyph_index
],
1170 type1
->charstrings_len
[glyph_index
],
1174 /* ignore the error if one occured - skip to next glyph */
1177 *max_advance
= decoder
.builder
.advance
.x
;
1182 /*************************************************************************/
1183 /*************************************************************************/
1184 /*************************************************************************/
1185 /********** *********/
1186 /********** UNHINTED GLYPH LOADER *********/
1187 /********** *********/
1188 /********** The following code is in charge of loading a *********/
1189 /********** single outline. It completely ignores hinting *********/
1190 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
1191 /********** *********/
1192 /********** The Type 1 hinter is located in `t1hint.c' *********/
1193 /********** *********/
1194 /*************************************************************************/
1195 /*************************************************************************/
1196 /*************************************************************************/
1200 FT_Error
close_open_path( T1_Builder
* builder
)
1203 FT_Outline
* cur
= builder
->current
;
1208 /* Some fonts, like Hershey, are made of `open paths' which are */
1209 /* now managed directly by FreeType. In this case, it is necessary */
1210 /* to close the path by duplicating its points in reverse order, */
1211 /* which is precisely the purpose of this function. */
1213 /* first compute the number of points to duplicate */
1214 if ( cur
->n_contours
> 1 )
1215 first_point
= cur
->contours
[cur
->n_contours
- 2] + 1;
1219 num_points
= cur
->n_points
- first_point
- 2;
1220 if ( num_points
> 0 )
1222 FT_Vector
* source_point
;
1228 error
= T1_Add_Points( builder
, num_points
);
1232 point
= cur
->points
+ cur
->n_points
;
1233 tags
= cur
->tags
+ cur
->n_points
;
1235 source_point
= point
- 2;
1236 source_tags
= tags
- 2;
1238 cur
->n_points
+= num_points
;
1240 if ( builder
->load_points
)
1243 *point
++ = *source_point
--;
1244 *tags
++ = *source_tags
--;
1247 } while ( num_points
> 0 );
1250 builder
->path_begun
= 0;
1256 FT_Error
gload_closepath( T1_Builder
* builder
)
1258 FT_Outline
* cur
= builder
->current
;
1261 /* XXXX: We must not include the last point in the path if it */
1262 /* is located on the first point. */
1263 if ( cur
->n_points
> 1 )
1266 FT_Vector
* p1
= cur
->points
+ first
;
1267 FT_Vector
* p2
= cur
->points
+ cur
->n_points
- 1;
1270 if ( cur
->n_contours
> 1 )
1272 first
= cur
->contours
[cur
->n_contours
- 2] + 1;
1273 p1
= cur
->points
+ first
;
1276 if ( p1
->x
== p2
->x
&& p1
->y
== p2
->y
)
1280 /* save current contour, if any */
1281 if ( cur
->n_contours
> 0 )
1282 cur
->contours
[cur
->n_contours
- 1] = cur
->n_points
- 1;
1284 #ifndef T1_CONFIG_OPTION_DISABLE_HINTER
1285 /* hint last points if necessary -- this is not strictly required */
1286 /* there, but it helps for debugging, and doesn't affect performance */
1287 if ( builder
->pass
== 1 )
1288 T1_Hint_Points( builder
);
1291 builder
->path_begun
= 0;
1297 FT_Error
gload_endchar( T1_Builder
* builder
)
1302 /* close path if needed */
1303 if ( builder
->path_begun
)
1305 error
= close_open_path( builder
);
1310 error
= gload_closepath( builder
);
1312 FT_GlyphLoader_Add( builder
->loader
);
1319 FT_Error
gload_sbw( T1_Builder
* builder
,
1325 builder
->left_bearing
.x
+= sbx
;
1326 builder
->left_bearing
.y
+= sby
;
1327 builder
->advance
.x
= wx
;
1328 builder
->advance
.y
= wy
;
1330 builder
->last
.x
= sbx
;
1331 builder
->last
.y
= sby
;
1338 FT_Error
gload_rlineto( T1_Builder
* builder
,
1343 FT_Outline
* cur
= builder
->current
;
1347 /* grow buffer if necessary */
1348 error
= T1_Add_Points( builder
, 1 );
1352 if ( builder
->load_points
)
1355 vec
.x
= builder
->last
.x
+ dx
;
1356 vec
.y
= builder
->last
.y
+ dy
;
1358 cur
->points
[cur
->n_points
] = vec
;
1359 cur
->tags
[cur
->n_points
] = FT_Curve_Tag_On
;
1361 builder
->last
= vec
;
1365 builder
->path_begun
= 1;
1372 FT_Error
gload_rmoveto( T1_Builder
* builder
,
1377 FT_Outline
* cur
= builder
->current
;
1381 /* in the case where `path_begun' is set, we have an `rmoveto' */
1382 /* after some normal path definition. If the face's paint type */
1383 /* is set to 1, this means that we have an `open path', also */
1384 /* called a `stroke'. The FreeType raster doesn't support */
1385 /* opened paths, so we'll close it explicitely there. */
1387 if ( builder
->path_begun
&& builder
->face
->type1
.paint_type
== 1 )
1389 if ( builder
->face
->type1
.paint_type
== 1 )
1391 error
= close_open_path( builder
);
1397 /* grow buffer if necessary */
1398 error
= T1_Add_Contours( builder
, 1 ) ||
1399 T1_Add_Points ( builder
, 1 );
1403 /* save current contour, if any */
1404 if ( cur
->n_contours
> 0 )
1405 cur
->contours
[cur
->n_contours
- 1] = cur
->n_points
- 1;
1407 if ( builder
->load_points
)
1410 vec
.x
= builder
->last
.x
+ dx
;
1411 vec
.y
= builder
->last
.y
+ dy
;
1412 cur
->points
[cur
->n_points
] = vec
;
1413 cur
->tags
[cur
->n_points
] = FT_Curve_Tag_On
;
1415 builder
->last
= vec
;
1426 FT_Error
gload_rrcurveto( T1_Builder
* builder
,
1435 FT_Outline
* cur
= builder
->current
;
1441 /* grow buffer if necessary */
1442 error
= T1_Add_Points( builder
, 3 );
1446 if ( builder
->load_points
)
1449 points
= cur
->points
+ cur
->n_points
;
1450 tags
= cur
->tags
+ cur
->n_points
;
1452 vec
.x
= builder
->last
.x
+ dx1
;
1453 vec
.y
= builder
->last
.y
+ dy1
;
1455 tags
[0] = FT_Curve_Tag_Cubic
;
1460 tags
[1] = FT_Curve_Tag_Cubic
;
1465 tags
[2] = FT_Curve_Tag_On
;
1467 builder
->last
= vec
;
1471 builder
->path_begun
= 1;
1478 FT_Error
gload_ignore( void )
1485 const T1_Builder_Funcs gload_builder_interface
=
1497 const T1_Builder_Funcs gload_builder_interface_null
=
1499 (T1_Builder_EndChar
) gload_ignore
,
1500 (T1_Builder_Sbw
) gload_sbw
, /* record left bearing */
1501 (T1_Builder_ClosePath
)gload_ignore
,
1502 (T1_Builder_RLineTo
) gload_ignore
,
1503 (T1_Builder_RMoveTo
) gload_ignore
,
1504 (T1_Builder_RCurveTo
) gload_ignore
1509 const T1_Hinter_Funcs gload_hinter_interface
=
1511 (T1_Hinter_DotSection
) gload_ignore
, /* dotsection */
1512 (T1_Hinter_ChangeHints
)gload_ignore
, /* changehints */
1513 (T1_Hinter_Stem
) gload_ignore
, /* hstem & vstem */
1514 (T1_Hinter_Stem3
) gload_ignore
, /* hstem3 & vestem3 */
1518 #ifndef T1_CONFIG_OPTION_DISABLE_HINTER
1521 /*************************************************************************/
1523 /* Hinter overview: */
1525 /* This is a two-pass hinter. On the first pass, the hints are all */
1526 /* recorded by the hinter, and no point is loaded in the outline. */
1528 /* When the first pass is finished, all stems hints are grid-fitted */
1531 /* Then, a second pass is performed to load the outline points as */
1532 /* well as hint/scale them correctly. */
1534 /*************************************************************************/
1538 FT_Error
t1_load_hinted_glyph( T1_Decoder
* decoder
,
1539 FT_UInt glyph_index
,
1542 T1_Builder
* builder
= &decoder
->builder
;
1543 T1_GlyphSlot glyph
= builder
->glyph
;
1544 T1_Font
* type1
= &builder
->face
->type1
;
1545 FT_UInt old_points
, old_contours
;
1546 FT_GlyphLoader
* loader
= decoder
->builder
.loader
;
1550 /* Pass 1 -- try to load first glyph, simply recording points */
1551 old_points
= loader
->base
.outline
.n_points
;
1552 old_contours
= loader
->base
.outline
.n_contours
;
1554 FT_GlyphLoader_Prepare( decoder
->builder
.loader
);
1556 T1_Reset_Builder( builder
, 0 );
1558 builder
->no_recurse
= recurse
;
1560 glyph
->hints
->hori_stems
.num_stems
= 0;
1561 glyph
->hints
->vert_stems
.num_stems
= 0;
1563 error
= T1_Parse_CharStrings( decoder
,
1564 type1
->charstrings
[glyph_index
],
1565 type1
->charstrings_len
[glyph_index
],
1572 /* check for composite (i.e. `seac' operator) */
1573 if ( glyph
->root
.format
== ft_glyph_format_composite
)
1575 /* this is a composite glyph, we must then load the first one, */
1576 /* then load the second one on top of it and translate it by a */
1578 FT_UInt n_base_points
;
1579 FT_SubGlyph
* subglyph
= loader
->base
.subglyphs
;
1580 T1_Size size
= builder
->size
;
1582 FT_Vector left_bearing
, advance
;
1585 /* clean glyph format */
1586 glyph
->root
.format
= ft_glyph_format_none
;
1588 /* First load `bchar' in builder */
1589 builder
->no_recurse
= 0;
1590 error
= t1_load_hinted_glyph( decoder
, subglyph
->index
, 0 );
1594 /* save the left bearing and width of the base character */
1595 /* as they will be erased by the next load */
1596 left_bearing
= builder
->left_bearing
;
1597 advance
= builder
->advance
;
1599 /* Then load `achar' in builder */
1600 n_base_points
= builder
->base
->n_points
;
1602 error
= t1_load_hinted_glyph( decoder
, subglyph
->index
, 0 );
1606 /* Finally, move the accent */
1607 dx
= FT_MulFix( subglyph
->arg1
, size
->root
.metrics
.x_scale
);
1608 dy
= FT_MulFix( subglyph
->arg2
, size
->root
.metrics
.y_scale
);
1609 dx
= ( dx
+ 32 ) & -64;
1610 dy
= ( dy
+ 32 ) & -64;
1615 dummy
.n_points
= loader
->base
.outline
.n_points
- n_base_points
;
1616 dummy
.points
= loader
->base
.outline
.points
+ n_base_points
;
1618 FT_Outline_Translate( &dummy
, dx
, dy
);
1621 /* restore the left side bearing and */
1622 /* advance width of the base character */
1623 builder
->left_bearing
= left_bearing
;
1624 builder
->advance
= advance
;
1628 /* All right, pass 1 is finished, now grid-fit all stem hints */
1629 T1_Hint_Stems( &decoder
->builder
);
1631 /* undo the end-char */
1632 builder
->base
->n_points
= old_points
;
1633 builder
->base
->n_contours
= old_contours
;
1635 /* Pass 2 -- record and scale/hint the points */
1636 T1_Reset_Builder( builder
, 0 );
1639 builder
->no_recurse
= 0;
1641 error
= T1_Parse_CharStrings( decoder
,
1642 type1
->charstrings
[glyph_index
],
1643 type1
->charstrings_len
[glyph_index
],
1649 /* save new glyph tables */
1651 T1_Done_Builder( builder
);
1658 #endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */
1662 FT_Error
T1_Load_Glyph( T1_GlyphSlot glyph
,
1669 T1_Face face
= (T1_Face
)glyph
->root
.face
;
1671 T1_Font
* type1
= &face
->type1
;
1674 if ( load_flags
& FT_LOAD_NO_RECURSE
)
1675 load_flags
|= FT_LOAD_NO_SCALE
| FT_LOAD_NO_HINTING
;
1677 glyph
->x_scale
= size
->root
.metrics
.x_scale
;
1678 glyph
->y_scale
= size
->root
.metrics
.y_scale
;
1680 glyph
->root
.outline
.n_points
= 0;
1681 glyph
->root
.outline
.n_contours
= 0;
1683 glyph
->root
.format
= ft_glyph_format_outline
; /* by default */
1687 #ifndef T1_CONFIG_OPTION_DISABLE_HINTER
1689 hinting
= ( load_flags
& ( FT_LOAD_NO_SCALE
| FT_LOAD_NO_HINTING
) ) == 0;
1693 T1_Init_Decoder( &decoder
, &t1_hinter_funcs
);
1694 T1_Init_Builder( &decoder
.builder
, face
, size
, glyph
,
1695 &gload_builder_interface
);
1697 error
= t1_load_hinted_glyph( &decoder
, glyph_index
, 1 );
1701 #endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */
1704 T1_Init_Decoder( &decoder
, &gload_hinter_interface
);
1706 T1_Init_Builder( &decoder
.builder
, face
, size
, glyph
,
1707 &gload_builder_interface
);
1709 decoder
.builder
.no_recurse
= ( load_flags
& FT_LOAD_NO_RECURSE
) != 0;
1711 /* now load the unscaled outline */
1712 error
= T1_Parse_CharStrings( &decoder
,
1713 type1
->charstrings
[glyph_index
],
1714 type1
->charstrings_len
[glyph_index
],
1719 /* save new glyph tables */
1720 T1_Done_Builder( &decoder
.builder
);
1723 /* Now, set the metrics -- this is rather simple, as */
1724 /* the left side bearing is the xMin, and the top side */
1725 /* bearing the yMax */
1728 /* for composite glyphs, return only the left side bearing and the */
1730 if ( glyph
->root
.format
== ft_glyph_format_composite
)
1732 glyph
->root
.metrics
.horiBearingX
= decoder
.builder
.left_bearing
.x
;
1733 glyph
->root
.metrics
.horiAdvance
= decoder
.builder
.advance
.x
;
1738 FT_Glyph_Metrics
* metrics
= &glyph
->root
.metrics
;
1741 /* apply the font matrix */
1742 FT_Outline_Transform( &glyph
->root
.outline
,
1743 &face
->type1
.font_matrix
);
1745 FT_Outline_Get_CBox( &glyph
->root
.outline
, &cbox
);
1747 /* grid fit the bounding box if necessary */
1752 cbox
.xMax
= ( cbox
.xMax
+ 63 ) & -64;
1753 cbox
.yMax
= ( cbox
.yMax
+ 63 ) & -64;
1756 metrics
->width
= cbox
.xMax
- cbox
.xMin
;
1757 metrics
->height
= cbox
.yMax
- cbox
.yMin
;
1759 metrics
->horiBearingX
= cbox
.xMin
;
1760 metrics
->horiBearingY
= cbox
.yMax
;
1762 /* copy the _unscaled_ advance width */
1763 metrics
->horiAdvance
= decoder
.builder
.advance
.x
;
1765 /* make up vertical metrics */
1766 metrics
->vertBearingX
= 0;
1767 metrics
->vertBearingY
= 0;
1768 metrics
->vertAdvance
= 0;
1770 glyph
->root
.format
= ft_glyph_format_outline
;
1772 glyph
->root
.outline
.flags
= 0;
1774 if ( size
->root
.metrics
.y_ppem
< 24 )
1775 glyph
->root
.outline
.flags
|= ft_outline_high_precision
;
1777 glyph
->root
.outline
.flags
|= ft_outline_reverse_fill
;
1781 /* adjust the advance width */
1782 /* XXX TODO: consider stem hints grid-fit */
1783 metrics
->horiAdvance
= FT_MulFix( metrics
->horiAdvance
,
1786 else if ( ( load_flags
& FT_LOAD_NO_SCALE
) == 0 )
1788 /* scale the outline and the metrics */
1790 FT_Outline
* cur
= decoder
.builder
.base
;
1791 FT_Vector
* vec
= cur
->points
;
1792 FT_Fixed x_scale
= glyph
->x_scale
;
1793 FT_Fixed y_scale
= glyph
->y_scale
;
1796 /* First of all, scale the points */
1797 for ( n
= cur
->n_points
; n
> 0; n
--, vec
++ )
1799 vec
->x
= FT_MulFix( vec
->x
, x_scale
);
1800 vec
->y
= FT_MulFix( vec
->y
, y_scale
);
1803 /* Then scale the metrics */
1804 metrics
->width
= FT_MulFix( metrics
->width
, x_scale
);
1805 metrics
->height
= FT_MulFix( metrics
->height
, y_scale
);
1807 metrics
->horiBearingX
= FT_MulFix( metrics
->horiBearingX
, x_scale
);
1808 metrics
->horiBearingY
= FT_MulFix( metrics
->horiBearingY
, y_scale
);
1810 metrics
->vertBearingX
= FT_MulFix( metrics
->vertBearingX
, x_scale
);
1811 metrics
->vertBearingY
= FT_MulFix( metrics
->vertBearingY
, y_scale
);
1813 metrics
->horiAdvance
= FT_MulFix( metrics
->horiAdvance
, x_scale
);
1814 metrics
->vertAdvance
= FT_MulFix( metrics
->vertAdvance
, y_scale
);