3 /* originally file `afloader.c' (2011-Mar-28) from FreeType */
5 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
17 /* from file `ftobjs.h' (2011-Mar-28) from FreeType */
18 typedef struct FT_Slot_InternalRec_
20 TA_GlyphLoader loader
;
22 FT_Bool glyph_transformed
;
23 FT_Matrix glyph_matrix
;
24 FT_Vector glyph_delta
;
26 } FT_GlyphSlot_InternalRec
;
29 /* initialize glyph loader */
32 ta_loader_init(TA_Loader loader
)
34 memset(loader
, 0, sizeof (TA_LoaderRec
));
36 ta_glyph_hints_init(&loader
->hints
);
38 _ta_debug_hints
= &loader
->hints
;
40 return TA_GlyphLoader_New(&loader
->gloader
);
44 /* reset glyph loader and compute globals if necessary */
47 ta_loader_reset(TA_Loader loader
,
50 FT_Error error
= FT_Err_Ok
;
54 loader
->globals
= (TA_FaceGlobals
)face
->autohint
.data
;
56 TA_GlyphLoader_Rewind(loader
->gloader
);
58 if (loader
->globals
== NULL
)
60 error
= ta_face_globals_new(face
, &loader
->globals
);
63 face
->autohint
.data
= (FT_Pointer
)loader
->globals
;
64 face
->autohint
.finalizer
= (FT_Generic_Finalizer
)ta_face_globals_free
;
72 /* finalize glyph loader */
75 ta_loader_done(TA_Loader loader
)
77 ta_glyph_hints_done(&loader
->hints
);
80 loader
->globals
= NULL
;
83 _ta_debug_hints
= NULL
;
85 TA_GlyphLoader_Done(loader
->gloader
);
86 loader
->gloader
= NULL
;
90 /* load a single glyph component; this routine calls itself recursively, */
91 /* if necessary, and does the main work of `ta_loader_load_glyph' */
94 ta_loader_load_g(TA_Loader loader
,
101 FT_Face face
= loader
->face
;
102 TA_GlyphLoader gloader
= loader
->gloader
;
103 TA_ScriptMetrics metrics
= loader
->metrics
;
104 TA_GlyphHints hints
= &loader
->hints
;
105 FT_GlyphSlot slot
= face
->glyph
;
107 FT_Slot_Internal internal
= slot
->internal
;
111 error
= FT_Load_Glyph(face
, glyph_index
, load_flags
);
116 loader
->transformed
= internal
->glyph_transformed
;
117 if (loader
->transformed
)
122 loader
->trans_matrix
= internal
->glyph_matrix
;
123 loader
->trans_delta
= internal
->glyph_delta
;
125 inverse
= loader
->trans_matrix
;
126 FT_Matrix_Invert(&inverse
);
127 FT_Vector_Transform(&loader
->trans_delta
, &inverse
);
131 /* set linear metrics */
132 slot
->linearHoriAdvance
= slot
->metrics
.horiAdvance
;
133 slot
->linearVertAdvance
= slot
->metrics
.vertAdvance
;
135 switch (slot
->format
)
137 case FT_GLYPH_FORMAT_OUTLINE
:
138 /* translate the loaded glyph when an internal transform is needed */
139 if (loader
->transformed
)
140 FT_Outline_Translate(&slot
->outline
,
141 loader
->trans_delta
.x
,
142 loader
->trans_delta
.y
);
144 /* copy the outline points in the loader's current extra points */
145 /* which are used to keep original glyph coordinates */
146 error
= TA_GLYPHLOADER_CHECK_POINTS(gloader
,
147 slot
->outline
.n_points
+ 4,
148 slot
->outline
.n_contours
);
152 memcpy(gloader
->current
.outline
.points
,
153 slot
->outline
.points
,
154 slot
->outline
.n_points
* sizeof (FT_Vector
));
155 memcpy(gloader
->current
.outline
.contours
,
156 slot
->outline
.contours
,
157 slot
->outline
.n_contours
* sizeof (short));
158 memcpy(gloader
->current
.outline
.tags
,
160 slot
->outline
.n_points
* sizeof (char));
162 gloader
->current
.outline
.n_points
= slot
->outline
.n_points
;
163 gloader
->current
.outline
.n_contours
= slot
->outline
.n_contours
;
165 /* compute original horizontal phantom points */
166 /* (and ignore vertical ones) */
167 loader
->pp1
.x
= hints
->x_delta
;
168 loader
->pp1
.y
= hints
->y_delta
;
169 loader
->pp2
.x
= FT_MulFix(slot
->metrics
.horiAdvance
,
170 hints
->x_scale
) + hints
->x_delta
;
171 loader
->pp2
.y
= hints
->y_delta
;
173 /* be sure to check for spacing glyphs */
174 if (slot
->outline
.n_points
== 0)
177 /* now load the slot image into the auto-outline */
178 /* and run the automatic hinting process */
179 if (metrics
->clazz
->script_hints_apply
)
180 metrics
->clazz
->script_hints_apply(hints
,
181 &gloader
->current
.outline
,
184 /* we now need to adjust the metrics according to the change in */
185 /* width/positioning that occurred during the hinting process */
186 if (scaler
->render_mode
!= FT_RENDER_MODE_LIGHT
)
188 FT_Pos old_rsb
, old_lsb
, new_lsb
;
189 FT_Pos pp1x_uh
, pp2x_uh
;
190 TA_AxisHints axis
= &hints
->axis
[TA_DIMENSION_HORZ
];
192 TA_Edge edge1
= axis
->edges
; /* leftmost edge */
193 TA_Edge edge2
= edge1
+ axis
->num_edges
- 1; /* rightmost edge */
196 if (axis
->num_edges
> 1 && TA_HINTS_DO_ADVANCE(hints
))
198 old_rsb
= loader
->pp2
.x
- edge2
->opos
;
199 old_lsb
= edge1
->opos
;
200 new_lsb
= edge1
->pos
;
202 /* remember unhinted values to later account */
203 /* for rounding errors */
204 pp1x_uh
= new_lsb
- old_lsb
;
205 pp2x_uh
= edge2
->pos
+ old_rsb
;
207 /* prefer too much space over too little space */
208 /* for very small sizes */
214 loader
->pp1
.x
= TA_PIX_ROUND(pp1x_uh
);
215 loader
->pp2
.x
= TA_PIX_ROUND(pp2x_uh
);
217 if (loader
->pp1
.x
>= new_lsb
220 if (loader
->pp2
.x
<= edge2
->pos
224 slot
->lsb_delta
= loader
->pp1
.x
- pp1x_uh
;
225 slot
->rsb_delta
= loader
->pp2
.x
- pp2x_uh
;
229 FT_Pos pp1x
= loader
->pp1
.x
;
230 FT_Pos pp2x
= loader
->pp2
.x
;
233 loader
->pp1
.x
= TA_PIX_ROUND(pp1x
);
234 loader
->pp2
.x
= TA_PIX_ROUND(pp2x
);
236 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
237 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
242 FT_Pos pp1x
= loader
->pp1
.x
;
243 FT_Pos pp2x
= loader
->pp2
.x
;
246 loader
->pp1
.x
= TA_PIX_ROUND(pp1x
+ hints
->xmin_delta
);
247 loader
->pp2
.x
= TA_PIX_ROUND(pp2x
+ hints
->xmax_delta
);
249 slot
->lsb_delta
= loader
->pp1
.x
- pp1x
;
250 slot
->rsb_delta
= loader
->pp2
.x
- pp2x
;
253 /* good, we simply add the glyph to our loader's base */
254 TA_GlyphLoader_Add(gloader
);
257 case FT_GLYPH_FORMAT_COMPOSITE
:
259 FT_UInt nn
, num_subglyphs
= slot
->num_subglyphs
;
260 FT_UInt num_base_subgs
, start_point
;
261 TA_SubGlyph subglyph
;
264 start_point
= gloader
->base
.outline
.n_points
;
266 /* first of all, copy the subglyph descriptors in the glyph loader */
267 error
= TA_GlyphLoader_CheckSubGlyphs(gloader
, num_subglyphs
);
271 memcpy(gloader
->current
.subglyphs
,
273 num_subglyphs
* sizeof (TA_SubGlyphRec
));
275 gloader
->current
.num_subglyphs
= num_subglyphs
;
276 num_base_subgs
= gloader
->base
.num_subglyphs
;
278 /* now read each subglyph independently */
279 for (nn
= 0; nn
< num_subglyphs
; nn
++)
283 FT_UInt num_points
, num_new_points
, num_base_points
;
286 /* gloader.current.subglyphs can change during glyph loading due */
287 /* to re-allocation -- we must recompute the current subglyph on */
289 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
294 num_base_points
= gloader
->base
.outline
.n_points
;
296 error
= ta_loader_load_g(loader
, scaler
, subglyph
->index
,
297 load_flags
, depth
+ 1);
301 /* recompute subglyph pointer */
302 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
304 if (subglyph
->flags
& FT_SUBGLYPH_FLAG_USE_MY_METRICS
)
315 num_points
= gloader
->base
.outline
.n_points
;
316 num_new_points
= num_points
- num_base_points
;
318 /* now perform the transformation required for this subglyph */
319 if (subglyph
->flags
& (FT_SUBGLYPH_FLAG_SCALE
320 | FT_SUBGLYPH_FLAG_XY_SCALE
321 | FT_SUBGLYPH_FLAG_2X2
))
323 FT_Vector
* cur
= gloader
->base
.outline
.points
+ num_base_points
;
324 FT_Vector
* limit
= cur
+ num_new_points
;
327 for (; cur
< limit
; cur
++)
328 FT_Vector_Transform(cur
, &subglyph
->transform
);
332 if (!(subglyph
->flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
))
334 FT_Int k
= subglyph
->arg1
;
335 FT_UInt l
= subglyph
->arg2
;
340 if (start_point
+ k
>= num_base_points
341 || l
>= (FT_UInt
)num_new_points
)
343 error
= FT_Err_Invalid_Composite
;
347 l
+= num_base_points
;
349 /* for now, only use the current point coordinates; */
350 /* we eventually may consider another approach */
351 p1
= gloader
->base
.outline
.points
+ start_point
+ k
;
352 p2
= gloader
->base
.outline
.points
+ start_point
+ l
;
359 x
= FT_MulFix(subglyph
->arg1
, hints
->x_scale
) + hints
->x_delta
;
360 y
= FT_MulFix(subglyph
->arg2
, hints
->y_scale
) + hints
->y_delta
;
367 FT_Outline dummy
= gloader
->base
.outline
;
370 dummy
.points
+= num_base_points
;
371 dummy
.n_points
= (short)num_new_points
;
373 FT_Outline_Translate(&dummy
, x
, y
);
380 /* we don't support other formats (yet?) */
381 error
= FT_Err_Unimplemented_Feature
;
391 vvector
.x
= slot
->metrics
.vertBearingX
- slot
->metrics
.horiBearingX
;
392 vvector
.y
= slot
->metrics
.vertBearingY
- slot
->metrics
.horiBearingY
;
393 vvector
.x
= FT_MulFix(vvector
.x
, metrics
->scaler
.x_scale
);
394 vvector
.y
= FT_MulFix(vvector
.y
, metrics
->scaler
.y_scale
);
396 /* transform the hinted outline if needed */
397 if (loader
->transformed
)
399 FT_Outline_Transform(&gloader
->base
.outline
, &loader
->trans_matrix
);
400 FT_Vector_Transform(&vvector
, &loader
->trans_matrix
);
403 /* we must translate our final outline by -pp1.x */
404 /* and compute the new metrics */
406 FT_Outline_Translate(&gloader
->base
.outline
, -loader
->pp1
.x
, 0);
408 FT_Outline_Get_CBox(&gloader
->base
.outline
, &bbox
);
410 bbox
.xMin
= TA_PIX_FLOOR(bbox
.xMin
);
411 bbox
.yMin
= TA_PIX_FLOOR(bbox
.yMin
);
412 bbox
.xMax
= TA_PIX_CEIL(bbox
.xMax
);
413 bbox
.yMax
= TA_PIX_CEIL(bbox
.yMax
);
415 slot
->metrics
.width
= bbox
.xMax
- bbox
.xMin
;
416 slot
->metrics
.height
= bbox
.yMax
- bbox
.yMin
;
417 slot
->metrics
.horiBearingX
= bbox
.xMin
;
418 slot
->metrics
.horiBearingY
= bbox
.yMax
;
420 slot
->metrics
.vertBearingX
= TA_PIX_FLOOR(bbox
.xMin
+ vvector
.x
);
421 slot
->metrics
.vertBearingY
= TA_PIX_FLOOR(bbox
.yMax
+ vvector
.y
);
423 /* for mono-width fonts (like Andale, Courier, etc.) we need */
424 /* to keep the original rounded advance width; ditto for */
425 /* digits if all have the same advance width */
426 if (FT_IS_FIXED_WIDTH(slot
->face
)
427 || (ta_face_globals_is_digit(loader
->globals
, glyph_index
)
428 && metrics
->digits_have_same_width
))
430 slot
->metrics
.horiAdvance
= FT_MulFix(slot
->metrics
.horiAdvance
,
431 metrics
->scaler
.x_scale
);
433 /* set delta values to 0, otherwise code that uses them */
434 /* is going to ruin the fixed advance width */
440 /* non-spacing glyphs must stay as-is */
441 if (slot
->metrics
.horiAdvance
)
442 slot
->metrics
.horiAdvance
= loader
->pp2
.x
- loader
->pp1
.x
;
445 slot
->metrics
.vertAdvance
= FT_MulFix(slot
->metrics
.vertAdvance
,
446 metrics
->scaler
.y_scale
);
448 slot
->metrics
.horiAdvance
= TA_PIX_ROUND(slot
->metrics
.horiAdvance
);
449 slot
->metrics
.vertAdvance
= TA_PIX_ROUND(slot
->metrics
.vertAdvance
);
452 /* now copy outline into glyph slot */
453 TA_GlyphLoader_Rewind(internal
->loader
);
454 error
= TA_GlyphLoader_CopyPoints(internal
->loader
, gloader
);
458 slot
->outline
= internal
->loader
->base
.outline
;
459 slot
->format
= FT_GLYPH_FORMAT_OUTLINE
;
464 ta_debug_hinter
= hinter
;
475 ta_loader_load_glyph(TA_Loader loader
,
478 FT_UInt32 load_flags
)
481 FT_Size size
= face
->size
;
486 return FT_Err_Invalid_Argument
;
488 memset(&scaler
, 0, sizeof (TA_ScalerRec
));
491 scaler
.x_scale
= size
->metrics
.x_scale
;
492 scaler
.x_delta
= 0; /* XXX: TODO: add support for sub-pixel hinting */
493 scaler
.y_scale
= size
->metrics
.y_scale
;
494 scaler
.y_delta
= 0; /* XXX: TODO: add support for sub-pixel hinting */
496 scaler
.render_mode
= FT_LOAD_TARGET_MODE(load_flags
);
497 scaler
.flags
= 0; /* XXX: fix this */
499 error
= ta_loader_reset(loader
, face
);
502 TA_ScriptMetrics metrics
;
506 #ifdef FT_OPTION_AUTOFIT2
507 /* XXX: undocumented hook to activate the latin2 hinter */
508 if (load_flags
& (1UL << 20))
512 error
= ta_face_globals_get_metrics(loader
->globals
, gindex
,
516 loader
->metrics
= metrics
;
518 if (metrics
->clazz
->script_metrics_scale
)
519 metrics
->clazz
->script_metrics_scale(metrics
, &scaler
);
521 metrics
->scaler
= scaler
;
523 load_flags
|= FT_LOAD_NO_SCALE
524 | FT_LOAD_IGNORE_TRANSFORM
;
525 load_flags
&= ~FT_LOAD_RENDER
;
527 if (metrics
->clazz
->script_hints_init
)
529 error
= metrics
->clazz
->script_hints_init(&loader
->hints
,
535 error
= ta_loader_load_g(loader
, &scaler
, gindex
, load_flags
, 0);
544 ta_loader_register_hints_recorder(TA_Loader loader
,
545 TA_Hints_Recorder hints_recorder
,
548 loader
->hints
.recorder
= hints_recorder
;
549 loader
->hints
.user
= user
;
552 /* end of taloader.c */