shithub: freetype+ttf2subf

Download patch

ref: 89ca1fd6d75edf85a093535703707f484e2e8149
parent: fad93267a250db53552a1d20ae5840118be5dc3d
author: Werner Lemberg <[email protected]>
date: Tue Jun 25 19:28:02 EDT 2013

[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'.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
 2013-06-25  Werner Lemberg  <[email protected]>
 
+	[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  <[email protected]>
+
 	[docmaker] Code shuffling.
 
 	* src/tools/docmaker/tohtml.py (re_url): Move regexp...
--- a/include/freetype/ftcffdrv.h
+++ b/include/freetype/ftcffdrv.h
@@ -73,7 +73,6 @@
    *
    *   {
    *     FT_Library  library;
-   *     FT_Face     face;
    *     FT_UInt     hinting_engine = FT_CFF_HINTING_ADOBE;
    *
    *
@@ -124,7 +123,6 @@
    *
    *   {
    *     FT_Library  library;
-   *     FT_Face     face;
    *     FT_Bool     no_stem_darkening = TRUE;
    *
    *
@@ -133,6 +131,50 @@
    *     FT_Property_Set( library, "cff",
    *                               "no-stem-darkening", &no_stem_darkening );
    *   }
+   *
+   * @note:
+   *   This property can be used with @FT_Property_Get also.
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @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.
--- 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,40 +141,71 @@
 
         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                                           */
       *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio );
@@ -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;
--- a/src/cff/cf2font.h
+++ b/src/cff/cf2font.h
@@ -85,6 +85,8 @@
                              /* 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 */
--- 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 );
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -586,8 +586,38 @@
     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, "darkening-parameters" ) )
+    {
+      FT_Int*  darken_params = driver->darken_params;
+      FT_Int*  val           = (FT_Int*)value;
 
-    if ( !ft_strcmp( property_name, "hinting-engine" ) )
+
+      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*  val = (FT_UInt*)value;
+      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;
--- 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
@@ -1062,6 +1062,15 @@
     driver->hinting_engine    = FT_CFF_HINTING_ADOBE;
 #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;
   }
--- a/src/cff/cffobjs.h
+++ b/src/cff/cffobjs.h
@@ -121,6 +121,8 @@
     FT_UInt  hinting_engine;
     FT_Bool  no_stem_darkening;
 
+    FT_Int  darken_params[8];
+
   } CFF_DriverRec;
 
 
--- a/src/tools/docmaker/sources.py
+++ b/src/tools/docmaker/sources.py
@@ -132,7 +132,7 @@
 #
 # 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