* src/autofit/afloader.c (af_loader_load_g): Implement emboldening.
This commit is contained in:
parent
bf2ba9e3d4
commit
b6fd5bc06c
|
@ -1,3 +1,7 @@
|
||||||
|
2015-11-02 Nikolaus Waxweiler <madigens@gmail.com>
|
||||||
|
|
||||||
|
* src/autofit/afloader.c (af_loader_load_g): Implement emboldening.
|
||||||
|
|
||||||
2015-11-02 Nikolaus Waxweiler <madigens@gmail.com>
|
2015-11-02 Nikolaus Waxweiler <madigens@gmail.com>
|
||||||
|
|
||||||
[autofit] Implement darkening computation function.
|
[autofit] Implement darkening computation function.
|
||||||
|
|
|
@ -76,6 +76,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define af_intToFixed( i ) \
|
||||||
|
( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
|
||||||
|
#define af_fixedToInt( x ) \
|
||||||
|
( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
|
||||||
|
#define af_floatToFixed( f ) \
|
||||||
|
( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
|
||||||
|
|
||||||
|
|
||||||
/* Do the main work of `af_loader_load_glyph'. Note that we never */
|
/* Do the main work of `af_loader_load_glyph'. Note that we never */
|
||||||
/* have to deal with composite glyphs as those get loaded into */
|
/* have to deal with composite glyphs as those get loaded into */
|
||||||
/* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. */
|
/* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. */
|
||||||
|
@ -88,6 +96,8 @@
|
||||||
FT_UInt glyph_index,
|
FT_UInt glyph_index,
|
||||||
FT_Int32 load_flags )
|
FT_Int32 load_flags )
|
||||||
{
|
{
|
||||||
|
AF_Module module = loader->globals->module;
|
||||||
|
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_Face face = loader->face;
|
FT_Face face = loader->face;
|
||||||
AF_StyleMetrics metrics = loader->metrics;
|
AF_StyleMetrics metrics = loader->metrics;
|
||||||
|
@ -103,6 +113,132 @@
|
||||||
if ( error )
|
if ( error )
|
||||||
goto Exit;
|
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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
if ( !module->no_stem_darkening )
|
||||||
|
{
|
||||||
|
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 )
|
||||||
|
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;
|
loader->transformed = internal->glyph_transformed;
|
||||||
if ( loader->transformed )
|
if ( loader->transformed )
|
||||||
{
|
{
|
||||||
|
@ -412,13 +548,6 @@
|
||||||
*
|
*
|
||||||
* XXX: Currently a crude adaption of the original algorithm. Do better?
|
* XXX: Currently a crude adaption of the original algorithm. Do better?
|
||||||
*/
|
*/
|
||||||
#define af_intToFixed( i ) \
|
|
||||||
( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
|
|
||||||
#define af_fixedToInt( x ) \
|
|
||||||
( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
|
|
||||||
#define af_floatToFixed( f ) \
|
|
||||||
( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
|
|
||||||
|
|
||||||
FT_LOCAL_DEF( FT_Int32 )
|
FT_LOCAL_DEF( FT_Int32 )
|
||||||
af_loader_compute_darkening( AF_Loader loader,
|
af_loader_compute_darkening( AF_Loader loader,
|
||||||
FT_Face face,
|
FT_Face face,
|
||||||
|
|
Loading…
Reference in New Issue