[cff] Add `darkening-parameters' property.

* include/freetype/ftcffdrv.h: Document it.

* src/cff/cffdrivr.c (cff_property_set, cff_property_get): Handle
`darkening-parameters' property.

* src/cff/cf2font.h (CF2_FontRec): Add `darkenParams' array.

* src/cff/cf2font.c (cf2_computeDarkening): Add `darkenParams'
argument and use it.
Update all callers.

* src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Copy
`darken_params' values.

* src/cff/cffobjs.h (CFF_DriverRec): Add `darken_params' array.

* src/cff/cffobjs.c (cff_driver_init): Set default values for
`darken_params'.
This commit is contained in:
Werner Lemberg 2013-06-25 23:28:02 +02:00
parent fad93267a2
commit 89ca1fd6d7
9 changed files with 265 additions and 46 deletions

View File

@ -1,3 +1,26 @@
2013-06-25 Werner Lemberg <wl@gnu.org>
[cff] Add `darkening-parameters' property.
* include/freetype/ftcffdrv.h: Document it.
* src/cff/cffdrivr.c (cff_property_set, cff_property_get): Handle
`darkening-parameters' property.
* src/cff/cf2font.h (CF2_FontRec): Add `darkenParams' array.
* src/cff/cf2font.c (cf2_computeDarkening): Add `darkenParams'
argument and use it.
Update all callers.
* src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Copy
`darken_params' values.
* src/cff/cffobjs.h (CFF_DriverRec): Add `darken_params' array.
* src/cff/cffobjs.c (cff_driver_init): Set default values for
`darken_params'.
2013-06-25 Werner Lemberg <wl@gnu.org>
[docmaker] Code shuffling.

View File

@ -73,7 +73,6 @@ FT_BEGIN_HEADER
*
* {
* FT_Library library;
* FT_Face face;
* FT_UInt hinting_engine = FT_CFF_HINTING_ADOBE;
*
*
@ -124,7 +123,6 @@ FT_BEGIN_HEADER
*
* {
* FT_Library library;
* FT_Face face;
* FT_Bool no_stem_darkening = TRUE;
*
*
@ -140,6 +138,50 @@ FT_BEGIN_HEADER
*/
/**************************************************************************
*
* @property:
* darkening-parameters
*
* @description:
* By default, the Adobe CFF engine darkens stems as follows (if the
* `no-stem-darkening' property isn't set):
*
* {
* stem width <= 0.5px: darkening amount = 0.4px
* stem width = 1px: darkening amount = 0.275px
* stem width = 1.667px: darkening amount = 0.275px
* stem width >= 2.333px: darkening amount = 0px
* }
*
* and piecewise linear in-between. Using the `darkening-parameters'
* property, these four control points can be changed, as the following
* example demonstrates.
*
* {
* FT_Library library;
* FT_Int darken_params[8] = { 500, 300, // x1, y1
* 1000, 200, // x2, y2
* 1500, 100, // x3, y3
* 2000, 0 }; // x4, y4
*
*
* FT_Init_FreeType( &library );
*
* FT_Property_Set( library, "cff",
* "darkening-parameters", darken_params );
* }
*
* The x~values give the stem width, and the y~values the darkening
* amount. All coordinate values must be positive and monotonically
* increasing along the x~axis; the unit is 1000th of pixels.
*
* @note:
* This property can be used with @FT_Property_Get also.
*
*/
/* */
FT_END_HEADER

View File

@ -51,15 +51,57 @@
CF2_Fixed stemWidth,
CF2_Fixed* darkenAmount,
CF2_Fixed boldenAmount,
FT_Bool stemDarkened )
FT_Bool stemDarkened,
FT_Int* darkenParams )
{
/*
* Total darkening amount is computed in 1000 unit character space
* using the modified 5 part curve as Adobe's Avalon rasterizer.
* The darkening amount is smaller for thicker stems.
* It becomes zero when the stem is thicker than 2.333 pixels.
*
* By default, we use
*
* darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels,
* darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
* darkenAmount = 0 pixel if scaledStem >= 2.333 pixels,
*
* and piecewise linear in-between:
*
*
* darkening
* ^
* |
* | (x1,y1)
* |--------+
* | \
* | \
* | \ (x3,y3)
* | +----------+
* | (x2,y2) \
* | \
* | \
* | +-----------------
* | (x4,y4)
* +---------------------------------------------> stem
* thickness
*
*
* This corresponds to the following values for the
* `darkening-parameters' property:
*
* (x1, y1) = (500, 400)
* (x2, y2) = (1000, 275)
* (x3, y3) = (1667, 275)
* (x4, y4) = (2333, 0)
*
*/
/* Internal calculations are done in units per thousand for */
/* convenience. */
CF2_Fixed stemWidthPer1000, scaledStem;
*darkenAmount = 0;
if ( boldenAmount == 0 && !stemDarkened )
return;
@ -69,6 +111,16 @@
if ( stemDarkened )
{
FT_Int x1 = darkenParams[0];
FT_Int y1 = darkenParams[1];
FT_Int x2 = darkenParams[2];
FT_Int y2 = darkenParams[3];
FT_Int x3 = darkenParams[4];
FT_Int y3 = darkenParams[5];
FT_Int x4 = darkenParams[6];
FT_Int y4 = darkenParams[7];
/* convert from true character space to 1000 unit character space; */
/* add synthetic emboldening effect */
@ -81,7 +133,7 @@
stemWidthPer1000 <= ( stemWidth + boldenAmount ) )
{
stemWidthPer1000 = 0; /* to pacify compiler */
scaledStem = cf2_intToFixed( 2333 );
scaledStem = cf2_intToFixed( x4 );
}
else
{
@ -89,39 +141,70 @@
if ( ppem > CF2_FIXED_ONE &&
scaledStem <= stemWidthPer1000 )
scaledStem = cf2_intToFixed( 2333 );
scaledStem = cf2_intToFixed( x4 );
}
/*
* Total darkening amount is computed in 1000 unit character space
* using the modified 5 part curve as Avalon rasterizer.
* The darkening amount is smaller for thicker stems.
* It becomes zero when the stem is thicker than 2.333 pixels.
*
* By default, we use
*
* darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels,
* darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
* darkenAmount = 0 pixel if scaledStem >= 2.333 pixels,
*
* and piecewise linear in-between.
*
*/
if ( scaledStem < cf2_intToFixed( 500 ) )
*darkenAmount = FT_DivFix( cf2_intToFixed( 400 ), ppem );
/* now apply the darkening parameters */
else if ( scaledStem < cf2_intToFixed( 1000 ) )
*darkenAmount = FT_DivFix( cf2_intToFixed( 525 ), ppem ) -
FT_MulFix( stemWidthPer1000,
cf2_floatToFixed( .25 ) );
if ( scaledStem < cf2_intToFixed( x1 ) )
*darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem );
else if ( scaledStem < cf2_intToFixed( 1667 ) )
*darkenAmount = FT_DivFix( cf2_intToFixed( 275 ), ppem );
else if ( scaledStem < cf2_intToFixed( x2 ) )
{
FT_Int xdelta = x2 - x1;
FT_Int ydelta = y2 - y1;
FT_Int x = stemWidthPer1000 -
FT_DivFix( cf2_intToFixed( x1 ), ppem );
else if ( scaledStem < cf2_intToFixed( 2333 ) )
*darkenAmount = FT_DivFix( cf2_intToFixed( 963 ), ppem ) -
FT_MulFix( stemWidthPer1000,
cf2_floatToFixed( .413 ) );
if ( !ydelta )
goto Try_x3;
*darkenAmount = FT_MulFix( x, FT_DivFix( ydelta, xdelta ) ) +
FT_DivFix( cf2_intToFixed( y1 ), ppem );
}
else if ( scaledStem < cf2_intToFixed( x3 ) )
{
Try_x3:
{
FT_Int xdelta = x3 - x2;
FT_Int ydelta = y3 - y2;
FT_Int x = stemWidthPer1000 -
FT_DivFix( cf2_intToFixed( x2 ), ppem );
if ( !ydelta )
goto Try_x4;
*darkenAmount = FT_MulFix( x, FT_DivFix( ydelta, xdelta ) ) +
FT_DivFix( cf2_intToFixed( y2 ), ppem );
}
}
else if ( scaledStem < cf2_intToFixed( x4 ) )
{
Try_x4:
{
FT_Int xdelta = x4 - x3;
FT_Int ydelta = y4 - y3;
FT_Int x = stemWidthPer1000 -
FT_DivFix( cf2_intToFixed( x3 ), ppem );
if ( !ydelta )
goto Use_y4;
*darkenAmount = FT_MulFix( x, FT_DivFix( ydelta, xdelta ) ) +
FT_DivFix( cf2_intToFixed( y3 ), ppem );
}
}
else
{
Use_y4:
*darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem );
}
/* use half the amount on each side and convert back to true */
/* character space */
@ -268,7 +351,8 @@
font->stdVW,
&font->darkenX,
boldenX,
FALSE );
FALSE,
font->darkenParams );
}
else
cf2_computeDarkening( emRatio,
@ -276,7 +360,8 @@
font->stdVW,
&font->darkenX,
0,
font->stemDarkened );
font->stemDarkened,
font->darkenParams );
#if 0
/* since hstem is measured in the y-direction, we use the `d' member */
@ -303,7 +388,8 @@
font->stdHW,
&font->darkenY,
boldenY,
font->stemDarkened );
font->stemDarkened,
font->darkenParams );
if ( font->darkenX != 0 || font->darkenY != 0 )
font->darkened = TRUE;

View File

@ -85,6 +85,8 @@ FT_BEGIN_HEADER
/* i.e. darkenX != 0 || darkenY != 0 */
FT_Bool stemDarkened;
FT_Int darkenParams[8]; /* 1000 unit character space */
/* variables that depend on both FontDict and Transform */
CF2_Fixed stdVW; /* in character space; depends on dict entry */
CF2_Fixed stdHW; /* in character space; depends on dict entry */

View File

@ -344,6 +344,15 @@
if ( scaled && !driver->no_stem_darkening )
font->renderingFlags |= CF2_FlagsDarkened;
font->darkenParams[0] = driver->darken_params[0];
font->darkenParams[1] = driver->darken_params[1];
font->darkenParams[2] = driver->darken_params[2];
font->darkenParams[3] = driver->darken_params[3];
font->darkenParams[4] = driver->darken_params[4];
font->darkenParams[5] = driver->darken_params[5];
font->darkenParams[6] = driver->darken_params[6];
font->darkenParams[7] = driver->darken_params[7];
/* now get an outline for this glyph; */
/* also get units per em to validate scale */
font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );

View File

@ -586,7 +586,37 @@
CFF_Driver driver = (CFF_Driver)module;
if ( !ft_strcmp( property_name, "hinting-engine" ) )
if ( !ft_strcmp( property_name, "darkening-parameters" ) )
{
FT_Int* darken_params = (FT_Int*)value;
FT_Int x1 = darken_params[0];
FT_Int y1 = darken_params[1];
FT_Int x2 = darken_params[2];
FT_Int y2 = darken_params[3];
FT_Int x3 = darken_params[4];
FT_Int y3 = darken_params[5];
FT_Int x4 = darken_params[6];
FT_Int y4 = darken_params[7];
if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 ||
y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 ||
x1 > x2 || x2 > x3 || x3 > x4 )
return FT_THROW( Invalid_Argument );
driver->darken_params[0] = x1;
driver->darken_params[1] = y1;
driver->darken_params[2] = x2;
driver->darken_params[3] = y2;
driver->darken_params[4] = x3;
driver->darken_params[5] = y3;
driver->darken_params[6] = x4;
driver->darken_params[7] = y4;
return error;
}
else if ( !ft_strcmp( property_name, "hinting-engine" ) )
{
FT_UInt* hinting_engine = (FT_UInt*)value;
@ -624,13 +654,28 @@
FT_Error error = FT_Err_Ok;
CFF_Driver driver = (CFF_Driver)module;
FT_UInt hinting_engine = driver->hinting_engine;
FT_Bool no_stem_darkening = driver->no_stem_darkening;
if ( !ft_strcmp( property_name, "hinting-engine" ) )
if ( !ft_strcmp( property_name, "darkening-parameters" ) )
{
FT_UInt* val = (FT_UInt*)value;
FT_Int* darken_params = driver->darken_params;
FT_Int* val = (FT_Int*)value;
val[0] = darken_params[0];
val[1] = darken_params[1];
val[2] = darken_params[2];
val[3] = darken_params[3];
val[4] = darken_params[4];
val[5] = darken_params[5];
val[6] = darken_params[6];
val[7] = darken_params[7];
return error;
}
else if ( !ft_strcmp( property_name, "hinting-engine" ) )
{
FT_UInt hinting_engine = driver->hinting_engine;
FT_UInt* val = (FT_UInt*)value;
*val = hinting_engine;
@ -639,7 +684,8 @@
}
else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
{
FT_Bool* val = (FT_Bool*)value;
FT_Bool no_stem_darkening = driver->no_stem_darkening;
FT_Bool* val = (FT_Bool*)value;
*val = no_stem_darkening;

View File

@ -1055,7 +1055,7 @@
CFF_Driver driver = (CFF_Driver)module;
/* set default property values */
/* set default property values, cf `ftcffdrv.h' */
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
driver->hinting_engine = FT_CFF_HINTING_FREETYPE;
#else
@ -1063,6 +1063,15 @@
#endif
driver->no_stem_darkening = FALSE;
driver->darken_params[0] = 500;
driver->darken_params[1] = 400;
driver->darken_params[2] = 1000;
driver->darken_params[3] = 275;
driver->darken_params[4] = 1667;
driver->darken_params[5] = 275;
driver->darken_params[6] = 2333;
driver->darken_params[7] = 0;
return FT_Err_Ok;
}

View File

@ -121,6 +121,8 @@ FT_BEGIN_HEADER
FT_UInt hinting_engine;
FT_Bool no_stem_darkening;
FT_Int darken_params[8];
} CFF_DriverRec;

View File

@ -132,7 +132,7 @@ re_markup_tags = [re_markup_tag1, re_markup_tag2]
#
# used to detect a cross-reference, after markup tags have been stripped
#
re_crossref = re.compile( r'@((?:\w|-)*)(.*)' )
re_crossref = re.compile( r'@((?:\w|-)*)(.*)' ) # @foo
#
# used to detect italic and bold styles in paragraph text