1 /***************************************************************************/ |
1 /**************************************************************************** |
2 /* */ |
2 * |
3 /* afloader.c */ |
3 * afloader.c |
4 /* */ |
4 * |
5 /* Auto-fitter glyph loading routines (body). */ |
5 * Auto-fitter glyph loading routines (body). |
6 /* */ |
6 * |
7 /* Copyright 2003-2018 by */ |
7 * Copyright (C) 2003-2019 by |
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
8 * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 /* */ |
9 * |
10 /* This file is part of the FreeType project, and may only be used, */ |
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 */ |
11 * modified, and distributed under the terms of the FreeType project |
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 /* this file you indicate that you have read the license and */ |
13 * this file you indicate that you have read the license and |
14 /* understand and accept it fully. */ |
14 * understand and accept it fully. |
15 /* */ |
15 * |
16 /***************************************************************************/ |
16 */ |
17 |
17 |
18 |
18 |
19 #include "afglobal.h" |
19 #include "afglobal.h" |
20 #include "afloader.h" |
20 #include "afloader.h" |
21 #include "afhints.h" |
21 #include "afhints.h" |
22 #include "aferrors.h" |
22 #include "aferrors.h" |
23 #include "afmodule.h" |
23 #include "afmodule.h" |
24 #include "afpic.h" |
|
25 |
24 |
26 #include FT_INTERNAL_CALC_H |
25 #include FT_INTERNAL_CALC_H |
27 |
26 |
28 |
27 |
29 /* Initialize glyph loader. */ |
28 /* Initialize glyph loader. */ |
117 error = FT_ERR( Corrupted_Font_Header ); |
116 error = FT_ERR( Corrupted_Font_Header ); |
118 goto Exit; |
117 goto Exit; |
119 } |
118 } |
120 |
119 |
121 /* |
120 /* |
122 * We depend on the writing system (script analyzers) to supply |
121 * We depend on the writing system (script analyzers) to supply |
123 * standard widths for the script of the glyph we are looking at. If |
122 * standard widths for the script of the glyph we are looking at. If |
124 * it can't deliver, stem darkening is disabled. |
123 * it can't deliver, stem darkening is disabled. |
125 */ |
124 */ |
126 writing_system_class = |
125 writing_system_class = |
127 AF_WRITING_SYSTEM_CLASSES_GET[style_metrics->style_class->writing_system]; |
126 af_writing_system_classes[style_metrics->style_class->writing_system]; |
128 |
127 |
129 if ( writing_system_class->style_metrics_getstdw ) |
128 if ( writing_system_class->style_metrics_getstdw ) |
130 writing_system_class->style_metrics_getstdw( style_metrics, |
129 writing_system_class->style_metrics_getstdw( style_metrics, |
131 &stdHW, |
130 &stdHW, |
132 &stdVW ); |
131 &stdVW ); |
172 globals->standard_horizontal_width = stdHW; |
171 globals->standard_horizontal_width = stdHW; |
173 globals->stem_darkening_for_ppem = size_metrics->x_ppem; |
172 globals->stem_darkening_for_ppem = size_metrics->x_ppem; |
174 globals->darken_y = af_fixedToInt( darken_y ); |
173 globals->darken_y = af_fixedToInt( darken_y ); |
175 |
174 |
176 /* |
175 /* |
177 * Scale outlines down on the Y-axis to keep them inside their blue |
176 * Scale outlines down on the Y-axis to keep them inside their blue |
178 * zones. The stronger the emboldening, the stronger the downscaling |
177 * zones. The stronger the emboldening, the stronger the downscaling |
179 * (plus heuristical padding to prevent outlines still falling out |
178 * (plus heuristical padding to prevent outlines still falling out |
180 * their zones due to rounding). |
179 * their zones due to rounding). |
181 * |
180 * |
182 * Reason: `FT_Outline_Embolden' works by shifting the rightmost |
181 * Reason: `FT_Outline_Embolden' works by shifting the rightmost |
183 * points of stems farther to the right, and topmost points farther |
182 * points of stems farther to the right, and topmost points farther |
184 * up. This positions points on the Y-axis outside their |
183 * up. This positions points on the Y-axis outside their |
185 * pre-computed blue zones and leads to distortion when applying the |
184 * pre-computed blue zones and leads to distortion when applying the |
186 * hints in the code further below. Code outside this emboldening |
185 * hints in the code further below. Code outside this emboldening |
187 * block doesn't know we are presenting it with modified outlines the |
186 * block doesn't know we are presenting it with modified outlines the |
188 * analyzer didn't see! |
187 * analyzer didn't see! |
189 * |
188 * |
190 * An unfortunate side effect of downscaling is that the emboldening |
189 * An unfortunate side effect of downscaling is that the emboldening |
191 * effect is slightly decreased. The loss becomes more pronounced |
190 * effect is slightly decreased. The loss becomes more pronounced |
192 * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. |
191 * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. |
193 */ |
192 */ |
194 globals->scale_down_factor = |
193 globals->scale_down_factor = |
195 FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), |
194 FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), |
196 em_size ); |
195 em_size ); |
197 } |
196 } |
229 AF_ScalerRec scaler; |
228 AF_ScalerRec scaler; |
230 AF_StyleMetrics style_metrics; |
229 AF_StyleMetrics style_metrics; |
231 FT_UInt style_options = AF_STYLE_NONE_DFLT; |
230 FT_UInt style_options = AF_STYLE_NONE_DFLT; |
232 AF_StyleClass style_class; |
231 AF_StyleClass style_class; |
233 AF_WritingSystemClass writing_system_class; |
232 AF_WritingSystemClass writing_system_class; |
234 |
|
235 #ifdef FT_CONFIG_OPTION_PIC |
|
236 AF_FaceGlobals globals = loader->globals; |
|
237 #endif |
|
238 |
233 |
239 |
234 |
240 if ( !size ) |
235 if ( !size ) |
241 return FT_THROW( Invalid_Size_Handle ); |
236 return FT_THROW( Invalid_Size_Handle ); |
242 |
237 |
280 } |
275 } |
281 #endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ |
276 #endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ |
282 } |
277 } |
283 |
278 |
284 /* |
279 /* |
285 * TODO: This code currently doesn't support fractional advance widths, |
280 * TODO: This code currently doesn't support fractional advance widths, |
286 * i.e., placing hinted glyphs at anything other than integer |
281 * i.e., placing hinted glyphs at anything other than integer |
287 * x-positions. This is only relevant for the warper code, which |
282 * x-positions. This is only relevant for the warper code, which |
288 * scales and shifts glyphs to optimize blackness of stems (hinting on |
283 * scales and shifts glyphs to optimize blackness of stems (hinting on |
289 * the x-axis by nature places things on pixel integers, hinting on the |
284 * the x-axis by nature places things on pixel integers, hinting on the |
290 * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta |
285 * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta |
291 * values of the scaler would need to be adjusted. |
286 * values of the scaler would need to be adjusted. |
292 */ |
287 */ |
293 scaler.face = face; |
288 scaler.face = face; |
294 scaler.x_scale = size_internal->autohint_metrics.x_scale; |
289 scaler.x_scale = size_internal->autohint_metrics.x_scale; |
295 scaler.x_delta = 0; |
290 scaler.x_delta = 0; |
296 scaler.y_scale = size_internal->autohint_metrics.y_scale; |
291 scaler.y_scale = size_internal->autohint_metrics.y_scale; |
310 if ( load_flags & ( 1UL << 20 ) ) |
305 if ( load_flags & ( 1UL << 20 ) ) |
311 style_options = AF_STYLE_LTN2_DFLT; |
306 style_options = AF_STYLE_LTN2_DFLT; |
312 #endif |
307 #endif |
313 |
308 |
314 /* |
309 /* |
315 * Glyphs (really code points) are assigned to scripts. Script |
310 * Glyphs (really code points) are assigned to scripts. Script |
316 * analysis is done lazily: For each glyph that passes through here, |
311 * analysis is done lazily: For each glyph that passes through here, |
317 * the corresponding script analyzer is called, but returns immediately |
312 * the corresponding script analyzer is called, but returns immediately |
318 * if it has been run already. |
313 * if it has been run already. |
319 */ |
314 */ |
320 error = af_face_globals_get_metrics( loader->globals, glyph_index, |
315 error = af_face_globals_get_metrics( loader->globals, glyph_index, |
321 style_options, &style_metrics ); |
316 style_options, &style_metrics ); |
322 if ( error ) |
317 if ( error ) |
323 goto Exit; |
318 goto Exit; |
324 |
319 |
325 style_class = style_metrics->style_class; |
320 style_class = style_metrics->style_class; |
326 writing_system_class = |
321 writing_system_class = |
327 AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; |
322 af_writing_system_classes[style_class->writing_system]; |
328 |
323 |
329 loader->metrics = style_metrics; |
324 loader->metrics = style_metrics; |
330 |
325 |
331 if ( writing_system_class->style_metrics_scale ) |
326 if ( writing_system_class->style_metrics_scale ) |
332 writing_system_class->style_metrics_scale( style_metrics, &scaler ); |
327 writing_system_class->style_metrics_scale( style_metrics, &scaler ); |
340 if ( error ) |
335 if ( error ) |
341 goto Exit; |
336 goto Exit; |
342 } |
337 } |
343 |
338 |
344 /* |
339 /* |
345 * Do the main work of `af_loader_load_glyph'. Note that we never have |
340 * Do the main work of `af_loader_load_glyph'. Note that we never have |
346 * to deal with composite glyphs as those get loaded into |
341 * to deal with composite glyphs as those get loaded into |
347 * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. |
342 * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. |
348 * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies |
343 * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies |
349 * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. |
344 * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. |
350 */ |
345 */ |
351 load_flags |= FT_LOAD_NO_SCALE | |
346 load_flags |= FT_LOAD_NO_SCALE | |
352 FT_LOAD_IGNORE_TRANSFORM | |
347 FT_LOAD_IGNORE_TRANSFORM | |
353 FT_LOAD_LINEAR_DESIGN; |
348 FT_LOAD_LINEAR_DESIGN; |
354 load_flags &= ~FT_LOAD_RENDER; |
349 load_flags &= ~FT_LOAD_RENDER; |
356 error = FT_Load_Glyph( face, glyph_index, load_flags ); |
351 error = FT_Load_Glyph( face, glyph_index, load_flags ); |
357 if ( error ) |
352 if ( error ) |
358 goto Exit; |
353 goto Exit; |
359 |
354 |
360 /* |
355 /* |
361 * Apply stem darkening (emboldening) here before hints are applied to |
356 * Apply stem darkening (emboldening) here before hints are applied to |
362 * the outline. Glyphs are scaled down proportionally to the |
357 * the outline. Glyphs are scaled down proportionally to the |
363 * emboldening so that curve points don't fall outside their |
358 * emboldening so that curve points don't fall outside their |
364 * precomputed blue zones. |
359 * precomputed blue zones. |
365 * |
360 * |
366 * Any emboldening done by the font driver (e.g., the CFF driver) |
361 * Any emboldening done by the font driver (e.g., the CFF driver) |
367 * doesn't reach here because the autohinter loads the unprocessed |
362 * doesn't reach here because the autohinter loads the unprocessed |
368 * glyphs in font units for analysis (functions `af_*_metrics_init_*') |
363 * glyphs in font units for analysis (functions `af_*_metrics_init_*') |
369 * and then above to prepare it for the rasterizers by itself, |
364 * and then above to prepare it for the rasterizers by itself, |
370 * independently of the font driver. So emboldening must be done here, |
365 * independently of the font driver. So emboldening must be done here, |
371 * within the autohinter. |
366 * within the autohinter. |
372 * |
367 * |
373 * All glyphs to be autohinted pass through here one by one. The |
368 * All glyphs to be autohinted pass through here one by one. The |
374 * standard widths can therefore change from one glyph to the next, |
369 * standard widths can therefore change from one glyph to the next, |
375 * depending on what script a glyph is assigned to (each script has its |
370 * depending on what script a glyph is assigned to (each script has its |
376 * own set of standard widths and other metrics). The darkening amount |
371 * own set of standard widths and other metrics). The darkening amount |
377 * must therefore be recomputed for each size and |
372 * must therefore be recomputed for each size and |
378 * `standard_{vertical,horizontal}_width' change. |
373 * `standard_{vertical,horizontal}_width' change. |
379 * |
374 * |
380 * Ignore errors and carry on without emboldening. |
375 * Ignore errors and carry on without emboldening. |
381 * |
376 * |
382 */ |
377 */ |
383 |
378 |
384 /* stem darkening only works well in `light' mode */ |
379 /* stem darkening only works well in `light' mode */ |
385 if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && |
380 if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && |
424 goto Hint_Metrics; |
419 goto Hint_Metrics; |
425 |
420 |
426 /* now load the slot image into the auto-outline */ |
421 /* now load the slot image into the auto-outline */ |
427 /* and run the automatic hinting process */ |
422 /* and run the automatic hinting process */ |
428 if ( writing_system_class->style_hints_apply ) |
423 if ( writing_system_class->style_hints_apply ) |
429 writing_system_class->style_hints_apply( glyph_index, |
424 { |
430 hints, |
425 error = writing_system_class->style_hints_apply( |
431 &gloader->base.outline, |
426 glyph_index, |
432 style_metrics ); |
427 hints, |
|
428 &gloader->base.outline, |
|
429 style_metrics ); |
|
430 if ( error ) |
|
431 goto Exit; |
|
432 } |
433 |
433 |
434 /* we now need to adjust the metrics according to the change in */ |
434 /* we now need to adjust the metrics according to the change in */ |
435 /* width/positioning that occurred during the hinting process */ |
435 /* width/positioning that occurred during the hinting process */ |
436 if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) |
436 if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) |
437 { |
437 { |
438 FT_Pos old_rsb, old_lsb, new_lsb; |
|
439 FT_Pos pp1x_uh, pp2x_uh; |
|
440 |
|
441 AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; |
438 AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; |
442 AF_Edge edge1 = axis->edges; /* leftmost edge */ |
|
443 AF_Edge edge2 = edge1 + |
|
444 axis->num_edges - 1; /* rightmost edge */ |
|
445 |
439 |
446 |
440 |
447 if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) |
441 if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) |
448 { |
442 { |
449 old_rsb = loader->pp2.x - edge2->opos; |
443 AF_Edge edge1 = axis->edges; /* leftmost edge */ |
|
444 AF_Edge edge2 = edge1 + |
|
445 axis->num_edges - 1; /* rightmost edge */ |
|
446 |
|
447 FT_Pos old_rsb = loader->pp2.x - edge2->opos; |
450 /* loader->pp1.x is always zero at this point of time */ |
448 /* loader->pp1.x is always zero at this point of time */ |
451 old_lsb = edge1->opos /* - loader->pp1.x */; |
449 FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */ |
452 new_lsb = edge1->pos; |
450 FT_Pos new_lsb = edge1->pos; |
453 |
451 |
454 /* remember unhinted values to later account */ |
452 /* remember unhinted values to later account */ |
455 /* for rounding errors */ |
453 /* for rounding errors */ |
456 pp1x_uh = new_lsb - old_lsb; |
454 FT_Pos pp1x_uh = new_lsb - old_lsb; |
457 pp2x_uh = edge2->pos + old_rsb; |
455 FT_Pos pp2x_uh = edge2->pos + old_rsb; |
|
456 |
458 |
457 |
459 /* prefer too much space over too little space */ |
458 /* prefer too much space over too little space */ |
460 /* for very small sizes */ |
459 /* for very small sizes */ |
461 |
460 |
462 if ( old_lsb < 24 ) |
461 if ( old_lsb < 24 ) |