Commit 410f3799b6a193e20b34c574e6f0f2be2428b1eb

Alexei Podtelezhnikov 2017-03-09T00:08:38

[smooth] Harmony LCD rendering. This is a new technology for LCD-optimized rendering. It capitalizes on the fact that each color channel grid is shifted by a third of a pixel. Therefore it is logical to render 3 separate monochrome bitmaps shifting the outline by 1/3 pixel, and then combine them. Importantly, the resulting output does not require additional LCD filtering. * src/smooth/ftsmooth.c (ft_smooth_render_generic) [!FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Implement new LCD-optimized rendering. * include/freetype/ftlcdfil.h, include/freetype/freetype.h, include/freetype/config/ftoption.h, devel/ftoption.h: Updated documentation.

diff --git a/ChangeLog b/ChangeLog
index d40137f..6c64854 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
 2017-08-08  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
+	[smooth] Harmony LCD rendering.
+
+	This is a new technology for LCD-optimized rendering. It capitalizes
+	on the fact that each color channel grid is shifted by a third of a
+	pixel.  Therefore it is logical to render 3 separate monochrome
+	bitmaps shifting the outline by 1/3 pixel, and then combine them.
+	Importantly, the resulting output does not require additional LCD
+	filtering.
+
+	* src/smooth/ftsmooth.c (ft_smooth_render_generic)
+	[!FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Implement new LCD-optimized
+	rendering.
+
+	* include/freetype/ftlcdfil.h, include/freetype/freetype.h,
+	include/freetype/config/ftoption.h, devel/ftoption.h: Updated
+	documentation.
+
+2017-08-08  Alexei Podtelezhnikov  <apodtele@gmail.com>
+
 	* src/smooth/ftsmooth.c (ft_smooth_render_generic): Clean up.
 
 2017-08-08  Alexei Podtelezhnikov  <apodtele@gmail.com>
diff --git a/devel/ftoption.h b/devel/ftoption.h
index a690ea2..9f9cac1 100644
--- a/devel/ftoption.h
+++ b/devel/ftoption.h
@@ -107,22 +107,19 @@ FT_BEGIN_HEADER
 
   /*************************************************************************/
   /*                                                                       */
-  /* Uncomment the line below if you want to activate sub-pixel rendering  */
-  /* (a.k.a. LCD rendering, or ClearType) in this build of the library.    */
+  /* Uncomment the line below if you want to activate LCD rendering        */
+  /* technology similar to ClearType in this build of the library.  This   */
+  /* technology triples the resolution in the direction color subpixels.   */
+  /* To mitigate color fringes inherent to this technology, you also need  */
+  /* to explicitly set up LCD filtering.                                   */
   /*                                                                       */
   /* Note that this feature is covered by several Microsoft patents        */
   /* and should not be activated in any default build of the library.      */
+  /* When this macro is not defined, FreeType offers alternative LCD       */
+  /* rendering technology that produces excellent output without LCD       */
+  /* filtering.                                                            */
   /*                                                                       */
-  /* This macro has no impact on the FreeType API, only on its             */
-  /* _implementation_.  For example, using FT_RENDER_MODE_LCD when calling */
-  /* FT_Render_Glyph still generates a bitmap that is 3 times wider than   */
-  /* the original size in case this macro isn't defined; however, each     */
-  /* triplet of subpixels has R=G=B.                                       */
-  /*                                                                       */
-  /* This is done to allow FreeType clients to run unmodified, forcing     */
-  /* them to display normal gray-level anti-aliased glyphs.                */
-  /*                                                                       */
-#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
 
   /*************************************************************************/
diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
index 935e20d..2fbe80b 100644
--- a/include/freetype/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
@@ -107,20 +107,17 @@ FT_BEGIN_HEADER
 
   /*************************************************************************/
   /*                                                                       */
-  /* Uncomment the line below if you want to activate sub-pixel rendering  */
-  /* (a.k.a. LCD rendering, or ClearType) in this build of the library.    */
+  /* Uncomment the line below if you want to activate LCD rendering        */
+  /* technology similar to ClearType in this build of the library.  This   */
+  /* technology triples the resolution in the direction color subpixels.   */
+  /* To mitigate color fringes inherent to this technology, you also need  */
+  /* to explicitly set up LCD filtering.                                   */
   /*                                                                       */
   /* Note that this feature is covered by several Microsoft patents        */
   /* and should not be activated in any default build of the library.      */
-  /*                                                                       */
-  /* This macro has no impact on the FreeType API, only on its             */
-  /* _implementation_.  For example, using FT_RENDER_MODE_LCD when calling */
-  /* FT_Render_Glyph still generates a bitmap that is 3 times wider than   */
-  /* the original size in case this macro isn't defined; however, each     */
-  /* triplet of subpixels has R=G=B.                                       */
-  /*                                                                       */
-  /* This is done to allow FreeType clients to run unmodified, forcing     */
-  /* them to display normal gray-level anti-aliased glyphs.                */
+  /* When this macro is not defined, FreeType offers alternative LCD       */
+  /* rendering technology that produces excellent output without LCD       */
+  /* filtering.                                                            */
   /*                                                                       */
 /* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index 34ad48a..a57fb35 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3131,11 +3131,13 @@ FT_BEGIN_HEADER
   /*      glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode.   */
   /*                                                                       */
   /* <Note>                                                                */
-  /*    The LCD-optimized glyph bitmaps produced by `FT_Render_Glyph' can  */
-  /*    be filtered to reduce color-fringes by using                       */
-  /*    @FT_Library_SetLcdFilter (not active in the default builds).  It   */
-  /*    is up to the caller to either call `FT_Library_SetLcdFilter' (if   */
-  /*    available) or do the filtering itself.                             */
+  /*    Should you define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your      */
+  /*    `ftoption.h', which enables patented ClearType-style rendering,    */
+  /*    the LCD-optimized glyph bitmaps should be filtered to reduce color */
+  /*    fringes inherent to this technology.  You can either set up LCD    */
+  /*    filtering with @FT_Library_SetLcdFilter or @FT_Face_Properties,    */
+  /*    or do the filtering yourself.  The default FreeType LCD rendering  */
+  /*    technology does not require filtering.                             */
   /*                                                                       */
   /*    The selected render mode only affects vector glyphs of a font.     */
   /*    Embedded bitmaps often have a different pixel mode like            */
diff --git a/include/freetype/ftlcdfil.h b/include/freetype/ftlcdfil.h
index 680bd90..bdaf9af 100644
--- a/include/freetype/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -44,9 +44,16 @@ FT_BEGIN_HEADER
    *   Reduce color fringes of subpixel-rendered bitmaps.
    *
    * @description:
-   *   Subpixel rendering exploits the color-striped structure of LCD
-   *   pixels, increasing the available resolution in the direction of the
-   *   stripe (usually horizontal RGB) by a factor of~3.  Since these
+   *   Should you #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your
+   *   `ftoption.h', which enables patented ClearType-style rendering,
+   *   the LCD-optimized glyph bitmaps should be filtered to reduce color
+   *   fringes inherent to this technology.  The default FreeType LCD
+   *   rendering uses different technology, and API described below,
+   *   although available, does nothing.
+   *
+   *   ClearType-style LCD rendering exploits the color-striped structure of
+   *   LCD pixels, increasing the available resolution in the direction of
+   *   the stripe (usually horizontal RGB) by a factor of~3.  Since these
    *   subpixels are color pixels, using them unfiltered creates severe
    *   color fringes.  Use the @FT_Library_SetLcdFilter API to specify a
    *   low-pass filter, which is then applied to subpixel-rendered bitmaps
@@ -54,12 +61,6 @@ FT_BEGIN_HEADER
    *   the higher resolution to reduce color fringes, making the glyph image
    *   slightly blurrier.  Positional improvements will remain.
    *
-   *   Note that no filter is active by default, and that this function is
-   *   *not* implemented in default builds of the library.  You need to
-   *   #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file
-   *   in order to activate it and explicitly call @FT_Library_SetLcdFilter
-   *   to enable it.
-   *
    *   A filter should have two properties:
    *
    *   1) It should be normalized, meaning the sum of the 5~components
diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
index 11a739a..4b81d34 100644
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -190,7 +190,23 @@
     /* taking into account the origin shift     */
     FT_Outline_Get_CBox( outline, &cbox );
 
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+    /* add minimal padding for LCD rendering */
+    if ( hmul )
+    {
+      cbox.xMax += 21;
+      cbox.xMin -= 21;
+    }
+
+    if ( vmul )
+    {
+      cbox.yMax += 21;
+      cbox.yMin -= 21;
+    }
+
+#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
     /* add minimal padding for LCD filter depending on specific weights */
     if ( lcd_filter_func )
     {
@@ -210,7 +226,8 @@
                                     : lcd_weights[1] ? 22 : 0;
       }
     }
-#endif
+
+#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
     cbox.xMin = FT_PIX_FLOOR( cbox.xMin + x_shift );
     cbox.yMin = FT_PIX_FLOOR( cbox.yMin + y_shift );
@@ -339,57 +356,97 @@
 
 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
-    /* render outline into bitmap */
-    error = render->raster_render( render->raster, &params );
-    if ( error )
-      goto Exit;
-
-    /* expand it horizontally */
-    if ( hmul )
+    if ( hmul )  /* lcd */
     {
-      FT_Byte*  line = bitmap->buffer;
-      FT_UInt   hh;
+      FT_Byte*  line;
+      FT_Byte*  temp;
+      FT_Int    i, j;
 
+      /* Render 3 separate monochrome bitmaps, shifting the outline  */
+      /* by 1/3 pixel.                                               */
+      width /= 3;
 
-      for ( hh = height; hh > 0; hh--, line += pitch )
-      {
-        FT_UInt   xx;
-        FT_Byte*  end = line + width;
+      FT_Outline_Translate( outline,  21, 0 );
 
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
 
-        for ( xx = width / 3; xx > 0; xx-- )
-        {
-          FT_UInt  pixel = line[xx-1];
+      FT_Outline_Translate( outline, -21, 0 );
+      bitmap->buffer += width;
 
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
 
-          end[-3] = (FT_Byte)pixel;
-          end[-2] = (FT_Byte)pixel;
-          end[-1] = (FT_Byte)pixel;
-          end    -= 3;
+      FT_Outline_Translate( outline, -21, 0 );
+      bitmap->buffer += width;
+
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
+
+      FT_Outline_Translate( outline,  21, 0 );
+      bitmap->buffer -= 2 * width;
+
+      /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
+      /* XXX: It is more efficient to render every third byte above. */
+
+      if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
+        goto Exit;
+
+      for ( i = 0; i < height; i++ )
+      {
+        line = bitmap->buffer + i * pitch;
+        for ( j = 0; j < width; j++ )
+        {
+          temp[3 * j    ] = line[j];
+          temp[3 * j + 1] = line[j + width];
+          temp[3 * j + 2] = line[j + width + width];
         }
+        FT_MEM_COPY( line, temp, pitch );
       }
-    }
 
-    /* expand it vertically */
-    if ( vmul )
+      FT_FREE( temp );
+    }
+    else if ( vmul )  /* lcd_v */
     {
-      FT_Byte*  read  = bitmap->buffer + ( height - height / 3 ) * pitch;
-      FT_Byte*  write = bitmap->buffer;
-      FT_UInt   hh;
+      /* Render 3 separate monochrome bitmaps, shifting the outline  */
+      /* by 1/3 pixel. Triple the pitch to render on each third row. */
+      bitmap->pitch *= 3;
+      bitmap->rows  /= 3;
 
+      FT_Outline_Translate( outline, 0,  21 );
+      bitmap->buffer += 2 * pitch;
 
-      for ( hh = height / 3; hh > 0; hh-- )
-      {
-        ft_memcpy( write, read, pitch );
-        write += pitch;
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
 
-        ft_memcpy( write, read, pitch );
-        write += pitch;
+      FT_Outline_Translate( outline, 0, -21 );
+      bitmap->buffer -= pitch;
 
-        ft_memcpy( write, read, pitch );
-        write += pitch;
-        read  += pitch;
-      }
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
+
+      FT_Outline_Translate( outline, 0, -21 );
+      bitmap->buffer -= pitch;
+
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
+
+      FT_Outline_Translate( outline, 0,  21 );
+
+      bitmap->pitch /= 3;
+      bitmap->rows  *= 3;
+    }
+    else  /* grayscale */
+    {
+      error = render->raster_render( render->raster, &params );
+      if ( error )
+        goto Exit;
     }
 
 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */