From 89ca1fd6d75edf85a093535703707f484e2e8149 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Tue, 25 Jun 2013 23:28:02 +0200 Subject: [PATCH] [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'. --- ChangeLog | 23 +++++ include/freetype/ftcffdrv.h | 46 +++++++++- src/cff/cf2font.c | 156 ++++++++++++++++++++++++++-------- src/cff/cf2font.h | 2 + src/cff/cf2ft.c | 9 ++ src/cff/cffdrivr.c | 60 +++++++++++-- src/cff/cffobjs.c | 11 ++- src/cff/cffobjs.h | 2 + src/tools/docmaker/sources.py | 2 +- 9 files changed, 265 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91f9efd05..2fbf45460 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2013-06-25 Werner Lemberg + + [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 [docmaker] Code shuffling. diff --git a/include/freetype/ftcffdrv.h b/include/freetype/ftcffdrv.h index ccbcbccaa..6235d85f9 100644 --- a/include/freetype/ftcffdrv.h +++ b/include/freetype/ftcffdrv.h @@ -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 diff --git a/src/cff/cf2font.c b/src/cff/cf2font.c index 996db74d6..fe454c3a9 100644 --- a/src/cff/cf2font.c +++ b/src/cff/cf2font.c @@ -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; diff --git a/src/cff/cf2font.h b/src/cff/cf2font.h index f9dd1bbd4..d8860ce8e 100644 --- a/src/cff/cf2font.h +++ b/src/cff/cf2font.h @@ -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 */ diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c index c09a0244a..4abbc9d79 100644 --- a/src/cff/cf2ft.c +++ b/src/cff/cf2ft.c @@ -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 ); diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c index c8ca96ba4..4652f59ad 100644 --- a/src/cff/cffdrivr.c +++ b/src/cff/cffdrivr.c @@ -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; diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c index dd750d104..29c369150 100644 --- a/src/cff/cffobjs.c +++ b/src/cff/cffobjs.c @@ -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; } diff --git a/src/cff/cffobjs.h b/src/cff/cffobjs.h index b375c20c7..dfbf9a96b 100644 --- a/src/cff/cffobjs.h +++ b/src/cff/cffobjs.h @@ -121,6 +121,8 @@ FT_BEGIN_HEADER FT_UInt hinting_engine; FT_Bool no_stem_darkening; + FT_Int darken_params[8]; + } CFF_DriverRec; diff --git a/src/tools/docmaker/sources.py b/src/tools/docmaker/sources.py index df9620886..dab834978 100644 --- a/src/tools/docmaker/sources.py +++ b/src/tools/docmaker/sources.py @@ -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