diff --git a/ChangeLog b/ChangeLog index dd6849753..9eda81ba2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2016-11-27 Nikolaus Waxweiler + + [autofit] Code shuffling. + + Also improve some comments and remove unused code. + + No functional change. + + * src/autofit/afloader.c (af_loader_load_g): Merged with... + (af_loader_load_glyph): ...this function. + Split off emboldening code into... + (af_loader_embolden_glyph_in_slot): ... this function. + 2016-11-17 Werner Lemberg Better support of LLP64 systems with gcc (and clang). diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c index 64e6df5b3..b9e1f5f42 100644 --- a/src/autofit/afloader.c +++ b/src/autofit/afloader.c @@ -86,161 +86,258 @@ ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) ) - /* Do the main work of `af_loader_load_glyph'. Note that we never */ - /* have to deal with composite glyphs as those get loaded into */ - /* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. */ - /* In the rare cases where FT_LOAD_NO_RECURSE is set, it implies */ - /* FT_LOAD_NO_SCALE and as such the auto-hinter is never called. */ - static FT_Error - af_loader_load_g( AF_Loader loader, - AF_Scaler scaler, - FT_UInt glyph_index, - FT_Int32 load_flags ) + af_loader_embolden_glyph_in_slot( AF_Loader loader, + FT_Face face, + AF_StyleMetrics style_metrics ) { - AF_Module module = loader->globals->module; + FT_Error error = FT_Err_Ok; - FT_Error error; - FT_Face face = loader->face; - AF_StyleMetrics metrics = loader->metrics; - AF_GlyphHints hints = loader->hints; + FT_GlyphSlot slot = face->glyph; + AF_FaceGlobals globals = loader->globals; + AF_WritingSystemClass writing_system_class; + + FT_Pos stdVW = 0; + FT_Pos stdHW = 0; + + FT_Bool size_changed = face->size->metrics.x_ppem + != globals->stem_darkening_for_ppem; + + FT_Fixed em_size = af_intToFixed( face->units_per_EM ); + FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); + + FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; + + + /* Skip stem darkening for broken fonts. */ + if ( !face->units_per_EM ) + { + error = FT_Err_Corrupted_Font_Header; + goto Exit; + } + + /* + * We depend on the writing system (script analyzers) to supply + * standard widths for the script of the glyph we are looking at. If + * it can't deliver, stem darkening is disabled. + */ + writing_system_class = + AF_WRITING_SYSTEM_CLASSES_GET[style_metrics->style_class->writing_system]; + + if ( writing_system_class->style_metrics_getstdw ) + writing_system_class->style_metrics_getstdw( style_metrics, + &stdHW, + &stdVW ); + else + { + error = FT_Err_Unimplemented_Feature; + goto Exit; + } + + if ( size_changed || + ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) + { + FT_Fixed darken_by_font_units_x, darken_x; + + + darken_by_font_units_x = + af_intToFixed( af_loader_compute_darkening( loader, + face, + stdVW ) ); + darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, + face->size->metrics.x_scale ), + em_ratio ); + + globals->standard_vertical_width = stdVW; + globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; + globals->darken_x = af_fixedToInt( darken_x ); + } + + if ( size_changed || + ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) + { + FT_Fixed darken_by_font_units_y, darken_y; + + + darken_by_font_units_y = + af_intToFixed( af_loader_compute_darkening( loader, + face, + stdHW ) ); + darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, + face->size->metrics.y_scale ), + em_ratio ); + + globals->standard_horizontal_width = stdHW; + globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; + globals->darken_y = af_fixedToInt( darken_y ); + + /* + * Scale outlines down on the Y-axis to keep them inside their blue + * zones. The stronger the emboldening, the stronger the downscaling + * (plus heuristical padding to prevent outlines still falling out + * their zones due to rounding). + * + * Reason: `FT_Outline_Embolden' works by shifting the rightmost + * points of stems farther to the right, and topmost points farther + * up. This positions points on the Y-axis outside their + * pre-computed blue zones and leads to distortion when applying the + * hints in the code further below. Code outside this emboldening + * block doesn't know we are presenting it with modified outlines the + * analyzer didn't see! + * + * An unfortunate side effect of downscaling is that the emboldening + * effect is slightly decreased. The loss becomes more pronounced + * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. + */ + globals->scale_down_factor = + FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), + em_size ); + } + + FT_Outline_EmboldenXY( &slot->outline, + globals->darken_x, + globals->darken_y ); + + scale_down_matrix.yy = globals->scale_down_factor; + FT_Outline_Transform( &slot->outline, &scale_down_matrix ); + + Exit: + return error; + } + + + /* Load the glyph at index into the current slot of a face and hint it. */ + + FT_LOCAL_DEF( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + AF_Module module, + FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + + FT_Size size = face->size; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; FT_GlyphLoader gloader = internal->loader; - FT_Int32 flags; + + AF_GlyphHints hints = loader->hints; + AF_ScalerRec scaler; + AF_StyleMetrics style_metrics; + FT_UInt style_options = AF_STYLE_NONE_DFLT; + AF_StyleClass style_class; + AF_WritingSystemClass writing_system_class; + +#ifdef FT_CONFIG_OPTION_PIC + AF_FaceGlobals globals = loader->globals; +#endif - flags = load_flags | FT_LOAD_LINEAR_DESIGN; - error = FT_Load_Glyph( face, glyph_index, flags ); + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + FT_ZERO( &scaler ); + + /* + * TODO: This code currently doesn't support fractional advance widths, + * i.e. placing hinted glyphs at anything other than integer + * x-positions. This is only relevant for the warper code, which + * scales and shifts glyphs to optimize blackness of stems (hinting on + * the x-axis by nature places things on pixel integers, hinting on the + * y-axis only, i.e. LIGHT mode, doesn't touch the x-axis). The delta + * values of the scaler would need to be adjusted. + */ + scaler.face = face; + scaler.x_scale = size->metrics.x_scale; + scaler.x_delta = 0; + scaler.y_scale = size->metrics.y_scale; + scaler.y_delta = 0; + + scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); + scaler.flags = 0; + + error = af_loader_reset( loader, module, face ); + if ( error ) + goto Exit; + +#ifdef FT_OPTION_AUTOFIT2 + /* XXX: undocumented hook to activate the latin2 writing system. */ + if ( load_flags & ( 1UL << 20 ) ) + style_options = AF_STYLE_LTN2_DFLT; +#endif + + /* + * Glyphs (really code points) are assigned to scripts. Script + * analysis is done lazily: For each glyph that passes through here, + * the corresponding script analyzer is called, but returns immediately + * if it has been run already. + */ + error = af_face_globals_get_metrics( loader->globals, glyph_index, + style_options, &style_metrics ); + if ( error ) + goto Exit; + + style_class = style_metrics->style_class; + writing_system_class = + AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; + + loader->metrics = style_metrics; + + if ( writing_system_class->style_metrics_scale ) + writing_system_class->style_metrics_scale( style_metrics, &scaler ); + else + style_metrics->scaler = scaler; + + if ( writing_system_class->style_hints_init ) + { + error = writing_system_class->style_hints_init( hints, + style_metrics ); + if ( error ) + goto Exit; + } + + /* + * Do the main work of `af_loader_load_glyph'. Note that we never have + * to deal with composite glyphs as those get loaded into + * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. + * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies + * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. + */ + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM | + FT_LOAD_LINEAR_DESIGN; + load_flags &= ~FT_LOAD_RENDER; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; /* - * Apply stem darkening (emboldening) here before hints are applied to - * the outline. Glyphs are scaled down proportionally to the - * emboldening so that curve points don't fall outside their precomputed - * blue zones. + * Apply stem darkening (emboldening) here before hints are applied to + * the outline. Glyphs are scaled down proportionally to the + * emboldening so that curve points don't fall outside their + * precomputed blue zones. * - * Any emboldening done by the font driver (e.g., the CFF driver) - * doesn't reach here because the autohinter loads the unprocessed - * glyphs in font units for analysis (functions `af_*_metrics_init_*') - * and then above to prepare it for the rasterizers by itself, - * independently of the font driver. So emboldening must be done here, - * within the autohinter. + * Any emboldening done by the font driver (e.g., the CFF driver) + * doesn't reach here because the autohinter loads the unprocessed + * glyphs in font units for analysis (functions `af_*_metrics_init_*') + * and then above to prepare it for the rasterizers by itself, + * independently of the font driver. So emboldening must be done here, + * within the autohinter. * - * All glyphs to be autohinted pass through here one by one. The - * standard widths can therefore change from one glyph to the next, - * depending on what script a glyph is assigned to (each script has its - * own set of standard widths and other metrics). The darkening amount - * must therefore be recomputed for each size and - * `standard_{vertical,horizontal}_width' change. + * All glyphs to be autohinted pass through here one by one. The + * standard widths can therefore change from one glyph to the next, + * depending on what script a glyph is assigned to (each script has its + * own set of standard widths and other metrics). The darkening amount + * must therefore be recomputed for each size and + * `standard_{vertical,horizontal}_width' change. + * + * Ignore errors and carry on without emboldening. */ if ( !module->no_stem_darkening ) - { - AF_FaceGlobals globals = loader->globals; - AF_WritingSystemClass writing_system_class; + af_loader_embolden_glyph_in_slot( loader, face, style_metrics ); - FT_Pos stdVW = 0; - FT_Pos stdHW = 0; - - FT_Bool size_changed = face->size->metrics.x_ppem - != globals->stem_darkening_for_ppem; - - FT_Fixed em_size = af_intToFixed( face->units_per_EM ); - FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); - - FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; - - - /* Skip stem darkening for broken fonts. */ - if ( !face->units_per_EM ) - goto After_Emboldening; - - /* - * We depend on the writing system (script analyzers) to supply - * standard widths for the script of the glyph we are looking at. If - * it can't deliver, stem darkening is effectively disabled. - */ - writing_system_class = - AF_WRITING_SYSTEM_CLASSES_GET[metrics->style_class->writing_system]; - - if ( writing_system_class->style_metrics_getstdw ) - writing_system_class->style_metrics_getstdw( metrics, - &stdHW, - &stdVW ); - else - goto After_Emboldening; - - - if ( size_changed || - ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) - { - FT_Fixed darken_by_font_units_x, darken_x; - - - darken_by_font_units_x = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdVW ) ); - darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, - face->size->metrics.x_scale ), - em_ratio ); - - globals->standard_vertical_width = stdVW; - globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; - globals->darken_x = af_fixedToInt( darken_x ); - } - - if ( size_changed || - ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) - { - FT_Fixed darken_by_font_units_y, darken_y; - - - darken_by_font_units_y = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdHW ) ); - darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, - face->size->metrics.y_scale ), - em_ratio ); - - globals->standard_horizontal_width = stdHW; - globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; - globals->darken_y = af_fixedToInt( darken_y ); - - /* - * Scale outlines down on the Y-axis to keep them inside their blue - * zones. The stronger the emboldening, the stronger the - * downscaling (plus heuristical padding to prevent outlines still - * falling out their zones due to rounding). - * - * Reason: `FT_Outline_Embolden' works by shifting the rightmost - * points of stems farther to the right, and topmost points farther - * up. This positions points on the Y-axis outside their - * pre-computed blue zones and leads to distortion when applying the - * hints in the code further below. Code outside this emboldening - * block doesn't know we are presenting it with modified outlines - * the analyzer didn't see! - * - * An unfortunate side effect of downscaling is that the emboldening - * effect is slightly decreased. The loss becomes more pronounced - * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. - */ - globals->scale_down_factor = - FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), - em_size ); - } - - FT_Outline_EmboldenXY( &slot->outline, - globals->darken_x, - globals->darken_y ); - - scale_down_matrix.yy = globals->scale_down_factor; - FT_Outline_Transform( &slot->outline, &scale_down_matrix ); - } - - After_Emboldening: loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { @@ -264,8 +361,8 @@ loader->trans_delta.x, loader->trans_delta.y ); - /* compute original horizontal phantom points (and ignore */ - /* vertical ones) */ + /* compute original horizontal phantom points */ + /* (and ignore vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, @@ -276,30 +373,28 @@ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; - /* now load the slot image into the auto-outline and run the */ - /* automatic hinting process */ + /* now load the slot image into the auto-outline */ + /* and run the automatic hinting process */ { #ifdef FT_CONFIG_OPTION_PIC - AF_FaceGlobals globals = loader->globals; + AF_FaceGlobals globals = loader->globals; #endif - AF_StyleClass style_class = metrics->style_class; - AF_WritingSystemClass writing_system_class = - AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; if ( writing_system_class->style_hints_apply ) writing_system_class->style_hints_apply( glyph_index, hints, &gloader->base.outline, - metrics ); + style_metrics ); } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ - if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) { - FT_Pos old_rsb, old_lsb, new_lsb; - FT_Pos pp1x_uh, pp2x_uh; + FT_Pos old_rsb, old_lsb, new_lsb; + FT_Pos pp1x_uh, pp2x_uh; + AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + @@ -313,9 +408,6 @@ old_lsb = edge1->opos /* - loader->pp1.x */; new_lsb = edge1->pos; - /* remember unhinted values to later account */ - /* for rounding errors */ - pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; @@ -381,8 +473,8 @@ vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; - vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); - vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); + vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale ); + vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) @@ -390,12 +482,12 @@ FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } -#if 1 + /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); -#endif + FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); @@ -414,20 +506,14 @@ /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ -#if 0 - if ( !FT_IS_FIXED_WIDTH( slot->face ) ) - slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; - else - slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, - x_scale ); -#else - if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && - metrics->digits_have_same_width ) ) ) + style_metrics->digits_have_same_width ) ) ) { - slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, - metrics->scaler.x_scale ); + slot->metrics.horiAdvance = + FT_MulFix( slot->metrics.horiAdvance, + style_metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ @@ -440,23 +526,13 @@ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } -#endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, - metrics->scaler.y_scale ); + style_metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); -#if 0 - /* reassign all outline fields except flags to protect them */ - slot->outline.n_contours = internal->loader->base.outline.n_contours; - slot->outline.n_points = internal->loader->base.outline.n_points; - slot->outline.points = internal->loader->base.outline.points; - slot->outline.tags = internal->loader->base.outline.tags; - slot->outline.contours = internal->loader->base.outline.contours; -#endif - slot->format = FT_GLYPH_FORMAT_OUTLINE; } @@ -465,85 +541,6 @@ } - /* Load a glyph. */ - - FT_LOCAL_DEF( FT_Error ) - af_loader_load_glyph( AF_Loader loader, - AF_Module module, - FT_Face face, - FT_UInt gindex, - FT_Int32 load_flags ) - { - FT_Error error; - FT_Size size = face->size; - AF_ScalerRec scaler; - - - if ( !size ) - return FT_THROW( Invalid_Size_Handle ); - - FT_ZERO( &scaler ); - - scaler.face = face; - scaler.x_scale = size->metrics.x_scale; - scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ - scaler.y_scale = size->metrics.y_scale; - scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ - - scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); - scaler.flags = 0; /* XXX: fix this */ - - error = af_loader_reset( loader, module, face ); - if ( !error ) - { - AF_StyleMetrics metrics; - FT_UInt options = AF_STYLE_NONE_DFLT; - - -#ifdef FT_OPTION_AUTOFIT2 - /* XXX: undocumented hook to activate the latin2 writing system */ - if ( load_flags & ( 1UL << 20 ) ) - options = AF_STYLE_LTN2_DFLT; -#endif - - error = af_face_globals_get_metrics( loader->globals, gindex, - options, &metrics ); - if ( !error ) - { -#ifdef FT_CONFIG_OPTION_PIC - AF_FaceGlobals globals = loader->globals; -#endif - AF_StyleClass style_class = metrics->style_class; - AF_WritingSystemClass writing_system_class = - AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; - - - loader->metrics = metrics; - - if ( writing_system_class->style_metrics_scale ) - writing_system_class->style_metrics_scale( metrics, &scaler ); - else - metrics->scaler = scaler; - - load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; - load_flags &= ~FT_LOAD_RENDER; - - if ( writing_system_class->style_hints_init ) - { - error = writing_system_class->style_hints_init( loader->hints, - metrics ); - if ( error ) - goto Exit; - } - - error = af_loader_load_g( loader, &scaler, gindex, load_flags ); - } - } - Exit: - return error; - } - - /* * Compute amount of font units the face should be emboldened by, in * analogy to the CFF driver's `cf2_computeDarkening' function. See there