4 * Copyright (C) 2011-2017 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 /* originally file `afloader.c' (2011-Mar-28) from FreeType */
18 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
30 /* from file `ftobjs.h' (2011-Mar-28) from FreeType */
31 typedef struct FT_Slot_InternalRec_
33 TA_GlyphLoader loader
;
35 FT_Bool glyph_transformed
;
36 FT_Matrix glyph_matrix
;
37 FT_Vector glyph_delta
;
39 } FT_GlyphSlot_InternalRec
;
42 /* initialize glyph loader */
45 ta_loader_init(FONT
* font
)
47 TA_Loader loader
= font
->loader
;
50 memset(loader
, 0, sizeof (TA_LoaderRec
));
52 ta_glyph_hints_init(&loader
->hints
);
54 _ta_debug_hints
= &loader
->hints
;
56 return TA_GlyphLoader_New(&loader
->gloader
);
60 /* reset glyph loader and compute globals if necessary */
63 ta_loader_reset(FONT
* font
,
66 FT_Error error
= FT_Err_Ok
;
67 TA_Loader loader
= font
->loader
;
71 loader
->globals
= (TA_FaceGlobals
)face
->autohint
.data
;
73 TA_GlyphLoader_Rewind(loader
->gloader
);
77 error
= ta_face_globals_new(face
, &loader
->globals
, font
);
80 face
->autohint
.data
= (FT_Pointer
)loader
->globals
;
81 face
->autohint
.finalizer
= (FT_Generic_Finalizer
)ta_face_globals_free
;
89 /* finalize glyph loader */
92 ta_loader_done(FONT
* font
)
94 TA_Loader loader
= font
->loader
;
97 ta_glyph_hints_done(&loader
->hints
);
100 loader
->globals
= NULL
;
103 _ta_debug_hints
= NULL
;
105 TA_GlyphLoader_Done(loader
->gloader
);
106 loader
->gloader
= NULL
;
110 /* load a single glyph component; this routine calls itself recursively, */
111 /* if necessary, and does the main work of `ta_loader_load_glyph' */
114 ta_loader_load_g(TA_Loader loader
,
121 FT_Face face
= loader
->face
;
122 TA_GlyphLoader gloader
= loader
->gloader
;
123 TA_StyleMetrics metrics
= loader
->metrics
;
124 TA_GlyphHints hints
= &loader
->hints
;
125 FT_GlyphSlot slot
= face
->glyph
;
127 FT_Slot_Internal slot_internal
= slot
->internal
;
132 flags
= load_flags
| FT_LOAD_LINEAR_DESIGN
;
133 error
= FT_Load_Glyph(face
, glyph_index
, flags
);
138 loader
->transformed
= slot_internal
->glyph_transformed
;
139 if (loader
->transformed
)
144 loader
->trans_matrix
= slot_internal
->glyph_matrix
;
145 loader
->trans_delta
= slot_internal
->glyph_delta
;
147 inverse
= loader
->trans_matrix
;
148 if (!FT_Matrix_Invert(&inverse
))
149 FT_Vector_Transform(&loader
->trans_delta
, &inverse
);
153 switch (slot
->format
)
155 case FT_GLYPH_FORMAT_OUTLINE
:
156 /* translate the loaded glyph when an internal transform is needed */
157 if (loader
->transformed
)
158 FT_Outline_Translate(&slot
->outline
,
159 loader
->trans_delta
.x
,
160 loader
->trans_delta
.y
);
162 /* copy the outline points in the loader's current extra points */
163 /* which are used to keep original glyph coordinates */
164 error
= TA_GLYPHLOADER_CHECK_POINTS(gloader
,
165 slot
->outline
.n_points
+ 4,
166 slot
->outline
.n_contours
);
170 memcpy(gloader
->current
.outline
.points
,
171 slot
->outline
.points
,
172 (size_t)slot
->outline
.n_points
* sizeof (FT_Vector
));
173 memcpy(gloader
->current
.outline
.contours
,
174 slot
->outline
.contours
,
175 (size_t)slot
->outline
.n_contours
* sizeof (short));
176 memcpy(gloader
->current
.outline
.tags
,
178 (size_t)slot
->outline
.n_points
* sizeof (char));
180 gloader
->current
.outline
.n_points
= slot
->outline
.n_points
;
181 gloader
->current
.outline
.n_contours
= slot
->outline
.n_contours
;
183 /* compute original horizontal phantom points */
184 /* (and ignore vertical ones) */
185 loader
->pp1
.x
= hints
->x_delta
;
186 loader
->pp1
.y
= hints
->y_delta
;
187 loader
->pp2
.x
= FT_MulFix(slot
->metrics
.horiAdvance
,
188 hints
->x_scale
) + hints
->x_delta
;
189 loader
->pp2
.y
= hints
->y_delta
;
191 /* be sure to check for spacing glyphs */
192 if (slot
->outline
.n_points
== 0)
195 /* now load the slot image into the auto-outline */
196 /* and run the automatic hinting process */
198 TA_StyleClass style_class
= metrics
->style_class
;
199 TA_WritingSystemClass writing_system_class
=
200 ta_writing_system_classes
[style_class
->writing_system
];
203 if (writing_system_class
->style_hints_apply
)
204 writing_system_class
->style_hints_apply(glyph_index
,
206 &gloader
->current
.outline
,
210 /* we now need to adjust the metrics according to the change in */
211 /* width/positioning that occurred during the hinting process */
212 if (scaler
->render_mode
!= FT_RENDER_MODE_LIGHT
)
214 FT_Pos old_rsb
, old_lsb
, new_lsb
;
215 FT_Pos pp1x_uh
, pp2x_uh
;
216 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_HORZ
];
218 TA_Edge edge1
= axis
->edges
; /* leftmost edge */
219 TA_Edge edge2
= edge1
+ axis
->num_edges
- 1; /* rightmost edge */
222 if (axis
->num_edges
> 1 && TA_HINTS_DO_ADVANCE(hints
))
224 old_rsb
= loader
->pp2
.x
- edge2
->opos
;
225 /* loader->pp1.x is always zero at this point of time */
226 old_lsb
= edge1
->opos
/* - loader->pp1.x */;
227 new_lsb
= edge1
->pos
;
229 /* remember unhinted values to later account */
230 /* for rounding errors */
231 pp1x_uh
= new_lsb
- old_lsb
;
232 pp2x_uh
= edge2
->pos
+ old_rsb
;
234 /* prefer too much space over too little space */
235 /* for very small sizes */
241 loader
->pp1
.x
= TA_PIX_ROUND(pp1x_uh
);
242 loader
->pp2
.x
= TA_PIX_ROUND(pp2x_uh
);
244 if (loader
->pp1
.x
>= new_lsb
247 if (loader
->pp2
.x
<= edge2
->pos
251 slot
->lsb_delta
= loader
->pp1
.x
- pp1x_uh
;
252 slot
->rsb_delta
= loader
->pp2
.x
- pp2x_uh
;
256 FT_Pos pp1x
= loader
->pp1
.x
;
257 FT_Pos pp2x
= loader
->pp2
.x
;
260 loader
->pp1
.x
= TA_PIX_ROUND(pp1x
+ hints
->xmin_delta
);
261 loader
->pp2
.x
= TA_PIX_ROUND(pp2x
+ hints
->xmax_delta
);
263 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
264 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
267 /* `light' mode uses integer advance widths */
268 /* but sets `lsb_delta' and `rsb_delta' */
271 FT_Pos pp1x
= loader
->pp1
.x
;
272 FT_Pos pp2x
= loader
->pp2
.x
;
275 loader
->pp1
.x
= TA_PIX_ROUND(pp1x
);
276 loader
->pp2
.x
= TA_PIX_ROUND(pp2x
);
278 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
279 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
282 /* good, we simply add the glyph to our loader's base */
283 TA_GlyphLoader_Add(gloader
);
286 case FT_GLYPH_FORMAT_COMPOSITE
:
288 FT_UInt nn
, num_subglyphs
= slot
->num_subglyphs
;
289 FT_UInt num_base_subgs
, start_point
;
290 TA_SubGlyph subglyph
;
293 start_point
= (FT_UInt
)gloader
->base
.outline
.n_points
;
295 /* first of all, copy the subglyph descriptors in the glyph loader */
296 error
= TA_GlyphLoader_CheckSubGlyphs(gloader
, num_subglyphs
);
300 memcpy(gloader
->current
.subglyphs
,
302 num_subglyphs
* sizeof (TA_SubGlyphRec
));
304 gloader
->current
.num_subglyphs
= num_subglyphs
;
306 /* stop processing if list of composites is requested */
307 if ( load_flags
& FT_LOAD_NO_RECURSE
)
310 num_base_subgs
= gloader
->base
.num_subglyphs
;
312 /* now read each subglyph independently */
313 for (nn
= 0; nn
< num_subglyphs
; nn
++)
317 FT_UInt num_points
, num_new_points
, num_base_points
;
320 /* gloader.current.subglyphs can change during glyph loading due */
321 /* to re-allocation -- we must recompute the current subglyph on */
323 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
328 num_base_points
= (FT_UInt
)gloader
->base
.outline
.n_points
;
330 error
= ta_loader_load_g(loader
, scaler
, (FT_UInt
)subglyph
->index
,
331 load_flags
, depth
+ 1);
335 /* recompute subglyph pointer */
336 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
338 if (!(subglyph
->flags
& FT_SUBGLYPH_FLAG_USE_MY_METRICS
))
344 num_points
= (FT_UInt
)gloader
->base
.outline
.n_points
;
345 num_new_points
= num_points
- num_base_points
;
347 /* now perform the transformation required for this subglyph */
348 if (subglyph
->flags
& (FT_SUBGLYPH_FLAG_SCALE
349 | FT_SUBGLYPH_FLAG_XY_SCALE
350 | FT_SUBGLYPH_FLAG_2X2
))
352 FT_Vector
* cur
= gloader
->base
.outline
.points
+ num_base_points
;
353 FT_Vector
* limit
= cur
+ num_new_points
;
356 for (; cur
< limit
; cur
++)
357 FT_Vector_Transform(cur
, &subglyph
->transform
);
361 if (!(subglyph
->flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
363 FT_UInt k
= (FT_UInt
)subglyph
->arg1
;
364 FT_UInt l
= (FT_UInt
)subglyph
->arg2
;
369 if (start_point
+ k
>= num_base_points
370 || l
>= num_new_points
)
372 error
= FT_Err_Invalid_Composite
;
376 l
+= num_base_points
;
378 /* for now, only use the current point coordinates; */
379 /* we eventually may consider another approach */
380 p1
= gloader
->base
.outline
.points
+ start_point
+ k
;
381 p2
= gloader
->base
.outline
.points
+ start_point
+ l
;
388 x
= FT_MulFix(subglyph
->arg1
, hints
->x_scale
) + hints
->x_delta
;
389 y
= FT_MulFix(subglyph
->arg2
, hints
->y_scale
) + hints
->y_delta
;
396 FT_Outline dummy
= gloader
->base
.outline
;
399 dummy
.points
+= num_base_points
;
400 dummy
.n_points
= (short)num_new_points
;
402 FT_Outline_Translate(&dummy
, x
, y
);
409 /* we don't support other formats (yet?) */
410 error
= FT_Err_Unimplemented_Feature
;
420 vvector
.x
= slot
->metrics
.vertBearingX
- slot
->metrics
.horiBearingX
;
421 vvector
.y
= slot
->metrics
.vertBearingY
- slot
->metrics
.horiBearingY
;
422 vvector
.x
= FT_MulFix(vvector
.x
, metrics
->scaler
.x_scale
);
423 vvector
.y
= FT_MulFix(vvector
.y
, metrics
->scaler
.y_scale
);
425 /* transform the hinted outline if needed */
426 if (loader
->transformed
)
428 FT_Outline_Transform(&gloader
->base
.outline
, &loader
->trans_matrix
);
429 FT_Vector_Transform(&vvector
, &loader
->trans_matrix
);
432 /* we must translate our final outline by -pp1.x */
433 /* and compute the new metrics */
435 FT_Outline_Translate(&gloader
->base
.outline
, -loader
->pp1
.x
, 0);
437 FT_Outline_Get_CBox(&gloader
->base
.outline
, &bbox
);
439 bbox
.xMin
= TA_PIX_FLOOR(bbox
.xMin
);
440 bbox
.yMin
= TA_PIX_FLOOR(bbox
.yMin
);
441 bbox
.xMax
= TA_PIX_CEIL(bbox
.xMax
);
442 bbox
.yMax
= TA_PIX_CEIL(bbox
.yMax
);
444 slot
->metrics
.width
= bbox
.xMax
- bbox
.xMin
;
445 slot
->metrics
.height
= bbox
.yMax
- bbox
.yMin
;
446 slot
->metrics
.horiBearingX
= bbox
.xMin
;
447 slot
->metrics
.horiBearingY
= bbox
.yMax
;
449 slot
->metrics
.vertBearingX
= TA_PIX_FLOOR(bbox
.xMin
+ vvector
.x
);
450 slot
->metrics
.vertBearingY
= TA_PIX_FLOOR(bbox
.yMax
+ vvector
.y
);
452 /* for mono-width fonts (like Andale, Courier, etc.) we need */
453 /* to keep the original rounded advance width; ditto for */
454 /* digits if all have the same advance width */
455 if (scaler
->render_mode
!= FT_RENDER_MODE_LIGHT
456 && (FT_IS_FIXED_WIDTH(slot
->face
)
457 || (ta_face_globals_is_digit(loader
->globals
, glyph_index
)
458 && metrics
->digits_have_same_width
)))
460 slot
->metrics
.horiAdvance
= FT_MulFix(slot
->metrics
.horiAdvance
,
461 metrics
->scaler
.x_scale
);
463 /* set delta values to 0, otherwise code that uses them */
464 /* is going to ruin the fixed advance width */
470 /* non-spacing glyphs must stay as-is */
471 if (slot
->metrics
.horiAdvance
)
472 slot
->metrics
.horiAdvance
= loader
->pp2
.x
- loader
->pp1
.x
;
475 slot
->metrics
.vertAdvance
= FT_MulFix(slot
->metrics
.vertAdvance
,
476 metrics
->scaler
.y_scale
);
478 slot
->metrics
.horiAdvance
= TA_PIX_ROUND(slot
->metrics
.horiAdvance
);
479 slot
->metrics
.vertAdvance
= TA_PIX_ROUND(slot
->metrics
.vertAdvance
);
482 /* now copy outline into glyph slot */
483 TA_GlyphLoader_Rewind(internal
->loader
);
484 error
= TA_GlyphLoader_CopyPoints(internal
->loader
, gloader
);
488 /* reassign all outline fields except flags to protect them */
489 slot
->outline
.n_contours
= internal
->loader
->base
.outline
.n_contours
;
490 slot
->outline
.n_points
= internal
->loader
->base
.outline
.n_points
;
491 slot
->outline
.points
= internal
->loader
->base
.outline
.points
;
492 slot
->outline
.tags
= internal
->loader
->base
.outline
.tags
;
493 slot
->outline
.contours
= internal
->loader
->base
.outline
.contours
;
495 slot
->format
= FT_GLYPH_FORMAT_OUTLINE
;
507 ta_loader_load_glyph(FONT
* font
,
513 FT_Size size
= face
->size
;
514 TA_Loader loader
= font
->loader
;
519 return FT_Err_Invalid_Size_Handle
;
521 memset(&scaler
, 0, sizeof (TA_ScalerRec
));
524 scaler
.x_scale
= size
->metrics
.x_scale
;
526 scaler
.y_scale
= size
->metrics
.y_scale
;
529 scaler
.render_mode
= FT_LOAD_TARGET_MODE(load_flags
);
530 scaler
.flags
= 0; /* XXX: fix this */
532 /* XXX this is an ugly hack of ttfautohint: */
533 /* bit 29 triggers vertical hinting only */
534 if (load_flags
& (1 << 29))
535 scaler
.flags
|= TA_SCALER_FLAG_NO_HORIZONTAL
;
537 /* note that the fallback style can't be changed anymore */
538 /* after the first call of `ta_loader_load_glyph' */
539 error
= ta_loader_reset(font
, face
);
542 TA_StyleMetrics metrics
;
543 FT_UInt options
= TA_STYLE_NONE_DFLT
;
546 #ifdef FT_OPTION_AUTOFIT2
547 /* XXX: undocumented hook to activate the latin2 hinter */
548 if (load_flags
& (1UL << 20))
549 options
= TA_STYLE_LTN2_DFLT
;
552 error
= ta_face_globals_get_metrics(loader
->globals
, gindex
,
556 TA_StyleClass style_class
= metrics
->style_class
;
557 TA_WritingSystemClass writing_system_class
=
558 ta_writing_system_classes
[style_class
->writing_system
];
561 loader
->metrics
= metrics
;
563 if (writing_system_class
->style_metrics_scale
)
564 writing_system_class
->style_metrics_scale(metrics
, &scaler
);
566 metrics
->scaler
= scaler
;
568 load_flags
|= FT_LOAD_NO_SCALE
569 | FT_LOAD_IGNORE_TRANSFORM
;
570 load_flags
&= ~FT_LOAD_RENDER
;
572 if (writing_system_class
->style_hints_init
)
574 error
= writing_system_class
->style_hints_init(&loader
->hints
,
580 error
= ta_loader_load_g(loader
, &scaler
, gindex
, load_flags
, 0);
589 ta_loader_register_hints_recorder(TA_Loader loader
,
590 TA_Hints_Recorder hints_recorder
,
593 loader
->hints
.recorder
= hints_recorder
;
594 loader
->hints
.user
= user
;
597 /* end of taloader.c */