1 /***************************************************************************/
5 /* Auto-fitter glyph loading routines (body). */
7 /* Copyright 2003-2009, 2011-2013 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 /***************************************************************************/
27 /* Initialize glyph loader. */
29 FT_LOCAL_DEF( FT_Error
)
30 af_loader_init( AF_Module module
)
32 AF_Loader loader
= module
->loader
;
33 FT_Memory memory
= module
->root
.library
->memory
;
38 af_glyph_hints_init( &loader
->hints
, memory
);
39 #ifdef FT_DEBUG_AUTOFIT
40 _af_debug_hints
= &loader
->hints
;
42 return FT_GlyphLoader_New( memory
, &loader
->gloader
);
46 /* Reset glyph loader and compute globals if necessary. */
48 FT_LOCAL_DEF( FT_Error
)
49 af_loader_reset( AF_Module module
,
52 FT_Error error
= FT_Err_Ok
;
53 AF_Loader loader
= module
->loader
;
57 loader
->globals
= (AF_FaceGlobals
)face
->autohint
.data
;
59 FT_GlyphLoader_Rewind( loader
->gloader
);
61 if ( loader
->globals
== NULL
)
63 error
= af_face_globals_new( face
, &loader
->globals
, module
);
67 (FT_Pointer
)loader
->globals
;
68 face
->autohint
.finalizer
=
69 (FT_Generic_Finalizer
)af_face_globals_free
;
77 /* Finalize glyph loader. */
80 af_loader_done( AF_Module module
)
82 AF_Loader loader
= module
->loader
;
85 af_glyph_hints_done( &loader
->hints
);
88 loader
->globals
= NULL
;
90 #ifdef FT_DEBUG_AUTOFIT
91 _af_debug_hints
= NULL
;
93 FT_GlyphLoader_Done( loader
->gloader
);
94 loader
->gloader
= NULL
;
98 /* Load a single glyph component. This routine calls itself */
99 /* recursively, if necessary, and does the main work of */
100 /* `af_loader_load_glyph.' */
103 af_loader_load_g( AF_Loader loader
,
110 FT_Face face
= loader
->face
;
111 FT_GlyphLoader gloader
= loader
->gloader
;
112 AF_ScriptMetrics metrics
= loader
->metrics
;
113 AF_GlyphHints hints
= &loader
->hints
;
114 FT_GlyphSlot slot
= face
->glyph
;
115 FT_Slot_Internal internal
= slot
->internal
;
119 flags
= load_flags
| FT_LOAD_LINEAR_DESIGN
;
120 error
= FT_Load_Glyph( face
, glyph_index
, flags
);
124 loader
->transformed
= internal
->glyph_transformed
;
125 if ( loader
->transformed
)
130 loader
->trans_matrix
= internal
->glyph_matrix
;
131 loader
->trans_delta
= internal
->glyph_delta
;
133 inverse
= loader
->trans_matrix
;
134 FT_Matrix_Invert( &inverse
);
135 FT_Vector_Transform( &loader
->trans_delta
, &inverse
);
138 switch ( slot
->format
)
140 case FT_GLYPH_FORMAT_OUTLINE
:
141 /* translate the loaded glyph when an internal transform is needed */
142 if ( loader
->transformed
)
143 FT_Outline_Translate( &slot
->outline
,
144 loader
->trans_delta
.x
,
145 loader
->trans_delta
.y
);
147 /* copy the outline points in the loader's current */
148 /* extra points which are used to keep original glyph coordinates */
149 error
= FT_GLYPHLOADER_CHECK_POINTS( gloader
,
150 slot
->outline
.n_points
+ 4,
151 slot
->outline
.n_contours
);
155 FT_ARRAY_COPY( gloader
->current
.outline
.points
,
156 slot
->outline
.points
,
157 slot
->outline
.n_points
);
159 FT_ARRAY_COPY( gloader
->current
.outline
.contours
,
160 slot
->outline
.contours
,
161 slot
->outline
.n_contours
);
163 FT_ARRAY_COPY( gloader
->current
.outline
.tags
,
165 slot
->outline
.n_points
);
167 gloader
->current
.outline
.n_points
= slot
->outline
.n_points
;
168 gloader
->current
.outline
.n_contours
= slot
->outline
.n_contours
;
170 /* compute original horizontal phantom points (and ignore */
172 loader
->pp1
.x
= hints
->x_delta
;
173 loader
->pp1
.y
= hints
->y_delta
;
174 loader
->pp2
.x
= FT_MulFix( slot
->metrics
.horiAdvance
,
175 hints
->x_scale
) + hints
->x_delta
;
176 loader
->pp2
.y
= hints
->y_delta
;
178 /* be sure to check for spacing glyphs */
179 if ( slot
->outline
.n_points
== 0 )
182 /* now load the slot image into the auto-outline and run the */
183 /* automatic hinting process */
185 #ifdef FT_CONFIG_OPTION_PIC
186 AF_FaceGlobals globals
= loader
->globals
;
188 AF_WritingSystemClass writing_system_class
=
189 AF_WRITING_SYSTEM_CLASSES_GET
190 [metrics
->script_class
->writing_system
];
193 if ( writing_system_class
->script_hints_apply
)
194 writing_system_class
->script_hints_apply( hints
,
195 &gloader
->current
.outline
,
199 /* we now need to adjust the metrics according to the change in */
200 /* width/positioning that occurred during the hinting process */
201 if ( scaler
->render_mode
!= FT_RENDER_MODE_LIGHT
)
203 FT_Pos old_rsb
, old_lsb
, new_lsb
;
204 FT_Pos pp1x_uh
, pp2x_uh
;
205 AF_AxisHints axis
= &hints
->axis
[AF_DIMENSION_HORZ
];
206 AF_Edge edge1
= axis
->edges
; /* leftmost edge */
207 AF_Edge edge2
= edge1
+
208 axis
->num_edges
- 1; /* rightmost edge */
211 if ( axis
->num_edges
> 1 && AF_HINTS_DO_ADVANCE( hints
) )
213 old_rsb
= loader
->pp2
.x
- edge2
->opos
;
214 old_lsb
= edge1
->opos
;
215 new_lsb
= edge1
->pos
;
217 /* remember unhinted values to later account */
218 /* for rounding errors */
220 pp1x_uh
= new_lsb
- old_lsb
;
221 pp2x_uh
= edge2
->pos
+ old_rsb
;
223 /* prefer too much space over too little space */
224 /* for very small sizes */
232 loader
->pp1
.x
= FT_PIX_ROUND( pp1x_uh
);
233 loader
->pp2
.x
= FT_PIX_ROUND( pp2x_uh
);
235 if ( loader
->pp1
.x
>= new_lsb
&& old_lsb
> 0 )
238 if ( loader
->pp2
.x
<= edge2
->pos
&& old_rsb
> 0 )
241 slot
->lsb_delta
= loader
->pp1
.x
- pp1x_uh
;
242 slot
->rsb_delta
= loader
->pp2
.x
- pp2x_uh
;
246 FT_Pos pp1x
= loader
->pp1
.x
;
247 FT_Pos pp2x
= loader
->pp2
.x
;
250 loader
->pp1
.x
= FT_PIX_ROUND( pp1x
);
251 loader
->pp2
.x
= FT_PIX_ROUND( pp2x
);
253 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
254 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
259 FT_Pos pp1x
= loader
->pp1
.x
;
260 FT_Pos pp2x
= loader
->pp2
.x
;
263 loader
->pp1
.x
= FT_PIX_ROUND( pp1x
+ hints
->xmin_delta
);
264 loader
->pp2
.x
= FT_PIX_ROUND( pp2x
+ hints
->xmax_delta
);
266 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
267 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
270 /* good, we simply add the glyph to our loader's base */
271 FT_GlyphLoader_Add( gloader
);
274 case FT_GLYPH_FORMAT_COMPOSITE
:
276 FT_UInt nn
, num_subglyphs
= slot
->num_subglyphs
;
277 FT_UInt num_base_subgs
, start_point
;
278 FT_SubGlyph subglyph
;
281 start_point
= gloader
->base
.outline
.n_points
;
283 /* first of all, copy the subglyph descriptors in the glyph loader */
284 error
= FT_GlyphLoader_CheckSubGlyphs( gloader
, num_subglyphs
);
288 FT_ARRAY_COPY( gloader
->current
.subglyphs
,
292 gloader
->current
.num_subglyphs
= num_subglyphs
;
293 num_base_subgs
= gloader
->base
.num_subglyphs
;
295 /* now read each subglyph independently */
296 for ( nn
= 0; nn
< num_subglyphs
; nn
++ )
300 FT_UInt num_points
, num_new_points
, num_base_points
;
303 /* gloader.current.subglyphs can change during glyph loading due */
304 /* to re-allocation -- we must recompute the current subglyph on */
306 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
311 num_base_points
= gloader
->base
.outline
.n_points
;
313 error
= af_loader_load_g( loader
, scaler
, subglyph
->index
,
314 load_flags
, depth
+ 1 );
318 /* recompute subglyph pointer */
319 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
321 if ( subglyph
->flags
& FT_SUBGLYPH_FLAG_USE_MY_METRICS
)
332 num_points
= gloader
->base
.outline
.n_points
;
333 num_new_points
= num_points
- num_base_points
;
335 /* now perform the transformation required for this subglyph */
337 if ( subglyph
->flags
& ( FT_SUBGLYPH_FLAG_SCALE
|
338 FT_SUBGLYPH_FLAG_XY_SCALE
|
339 FT_SUBGLYPH_FLAG_2X2
) )
341 FT_Vector
* cur
= gloader
->base
.outline
.points
+
343 FT_Vector
* limit
= cur
+ num_new_points
;
346 for ( ; cur
< limit
; cur
++ )
347 FT_Vector_Transform( cur
, &subglyph
->transform
);
352 if ( !( subglyph
->flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
) )
354 FT_Int k
= subglyph
->arg1
;
355 FT_UInt l
= subglyph
->arg2
;
360 if ( start_point
+ k
>= num_base_points
||
361 l
>= (FT_UInt
)num_new_points
)
363 error
= FT_THROW( Invalid_Composite
);
367 l
+= num_base_points
;
369 /* for now, only use the current point coordinates; */
370 /* we eventually may consider another approach */
371 p1
= gloader
->base
.outline
.points
+ start_point
+ k
;
372 p2
= gloader
->base
.outline
.points
+ start_point
+ l
;
379 x
= FT_MulFix( subglyph
->arg1
, hints
->x_scale
) + hints
->x_delta
;
380 y
= FT_MulFix( subglyph
->arg2
, hints
->y_scale
) + hints
->y_delta
;
382 x
= FT_PIX_ROUND( x
);
383 y
= FT_PIX_ROUND( y
);
387 FT_Outline dummy
= gloader
->base
.outline
;
390 dummy
.points
+= num_base_points
;
391 dummy
.n_points
= (short)num_new_points
;
393 FT_Outline_Translate( &dummy
, x
, y
);
400 /* we don't support other formats (yet?) */
401 error
= FT_THROW( Unimplemented_Feature
);
411 vvector
.x
= slot
->metrics
.vertBearingX
- slot
->metrics
.horiBearingX
;
412 vvector
.y
= slot
->metrics
.vertBearingY
- slot
->metrics
.horiBearingY
;
413 vvector
.x
= FT_MulFix( vvector
.x
, metrics
->scaler
.x_scale
);
414 vvector
.y
= FT_MulFix( vvector
.y
, metrics
->scaler
.y_scale
);
416 /* transform the hinted outline if needed */
417 if ( loader
->transformed
)
419 FT_Outline_Transform( &gloader
->base
.outline
, &loader
->trans_matrix
);
420 FT_Vector_Transform( &vvector
, &loader
->trans_matrix
);
423 /* we must translate our final outline by -pp1.x and compute */
424 /* the new metrics */
426 FT_Outline_Translate( &gloader
->base
.outline
, -loader
->pp1
.x
, 0 );
428 FT_Outline_Get_CBox( &gloader
->base
.outline
, &bbox
);
430 bbox
.xMin
= FT_PIX_FLOOR( bbox
.xMin
);
431 bbox
.yMin
= FT_PIX_FLOOR( bbox
.yMin
);
432 bbox
.xMax
= FT_PIX_CEIL( bbox
.xMax
);
433 bbox
.yMax
= FT_PIX_CEIL( bbox
.yMax
);
435 slot
->metrics
.width
= bbox
.xMax
- bbox
.xMin
;
436 slot
->metrics
.height
= bbox
.yMax
- bbox
.yMin
;
437 slot
->metrics
.horiBearingX
= bbox
.xMin
;
438 slot
->metrics
.horiBearingY
= bbox
.yMax
;
440 slot
->metrics
.vertBearingX
= FT_PIX_FLOOR( bbox
.xMin
+ vvector
.x
);
441 slot
->metrics
.vertBearingY
= FT_PIX_FLOOR( bbox
.yMax
+ vvector
.y
);
443 /* for mono-width fonts (like Andale, Courier, etc.) we need */
444 /* to keep the original rounded advance width; ditto for */
445 /* digits if all have the same advance width */
447 if ( !FT_IS_FIXED_WIDTH( slot
->face
) )
448 slot
->metrics
.horiAdvance
= loader
->pp2
.x
- loader
->pp1
.x
;
450 slot
->metrics
.horiAdvance
= FT_MulFix( slot
->metrics
.horiAdvance
,
453 if ( scaler
->render_mode
!= FT_RENDER_MODE_LIGHT
&&
454 ( FT_IS_FIXED_WIDTH( slot
->face
) ||
455 ( af_face_globals_is_digit( loader
->globals
, glyph_index
) &&
456 metrics
->digits_have_same_width
) ) )
458 slot
->metrics
.horiAdvance
= FT_MulFix( slot
->metrics
.horiAdvance
,
459 metrics
->scaler
.x_scale
);
461 /* Set delta values to 0. Otherwise code that uses them is */
462 /* going to ruin the fixed advance width. */
468 /* non-spacing glyphs must stay as-is */
469 if ( slot
->metrics
.horiAdvance
)
470 slot
->metrics
.horiAdvance
= loader
->pp2
.x
- loader
->pp1
.x
;
474 slot
->metrics
.vertAdvance
= FT_MulFix( slot
->metrics
.vertAdvance
,
475 metrics
->scaler
.y_scale
);
477 slot
->metrics
.horiAdvance
= FT_PIX_ROUND( slot
->metrics
.horiAdvance
);
478 slot
->metrics
.vertAdvance
= FT_PIX_ROUND( slot
->metrics
.vertAdvance
);
480 /* now copy outline into glyph slot */
481 FT_GlyphLoader_Rewind( internal
->loader
);
482 error
= FT_GlyphLoader_CopyPoints( internal
->loader
, gloader
);
486 /* reassign all outline fields except flags to protect them */
487 slot
->outline
.n_contours
= internal
->loader
->base
.outline
.n_contours
;
488 slot
->outline
.n_points
= internal
->loader
->base
.outline
.n_points
;
489 slot
->outline
.points
= internal
->loader
->base
.outline
.points
;
490 slot
->outline
.tags
= internal
->loader
->base
.outline
.tags
;
491 slot
->outline
.contours
= internal
->loader
->base
.outline
.contours
;
493 slot
->format
= FT_GLYPH_FORMAT_OUTLINE
;
503 FT_LOCAL_DEF( FT_Error
)
504 af_loader_load_glyph( AF_Module module
,
507 FT_Int32 load_flags
)
510 FT_Size size
= face
->size
;
511 AF_Loader loader
= module
->loader
;
516 return FT_THROW( Invalid_Argument
);
521 scaler
.x_scale
= size
->metrics
.x_scale
;
522 scaler
.x_delta
= 0; /* XXX: TODO: add support for sub-pixel hinting */
523 scaler
.y_scale
= size
->metrics
.y_scale
;
524 scaler
.y_delta
= 0; /* XXX: TODO: add support for sub-pixel hinting */
526 scaler
.render_mode
= FT_LOAD_TARGET_MODE( load_flags
);
527 scaler
.flags
= 0; /* XXX: fix this */
529 error
= af_loader_reset( module
, face
);
532 AF_ScriptMetrics metrics
;
533 FT_UInt options
= AF_SCRIPT_DFLT
;
536 #ifdef FT_OPTION_AUTOFIT2
537 /* XXX: undocumented hook to activate the latin2 writing system */
538 if ( load_flags
& ( 1UL << 20 ) )
539 options
= AF_SCRIPT_LTN2
;
542 error
= af_face_globals_get_metrics( loader
->globals
, gindex
,
546 #ifdef FT_CONFIG_OPTION_PIC
547 AF_FaceGlobals globals
= loader
->globals
;
549 AF_WritingSystemClass writing_system_class
=
550 AF_WRITING_SYSTEM_CLASSES_GET
551 [metrics
->script_class
->writing_system
];
554 loader
->metrics
= metrics
;
556 if ( writing_system_class
->script_metrics_scale
)
557 writing_system_class
->script_metrics_scale( metrics
, &scaler
);
559 metrics
->scaler
= scaler
;
561 load_flags
|= FT_LOAD_NO_SCALE
| FT_LOAD_IGNORE_TRANSFORM
;
562 load_flags
&= ~FT_LOAD_RENDER
;
564 if ( writing_system_class
->script_hints_init
)
566 error
= writing_system_class
->script_hints_init( &loader
->hints
,
572 error
= af_loader_load_g( loader
, &scaler
, gindex
, load_flags
, 0 );