summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO58
-rw-r--r--0001-Enable-table-validation-modules.patch45
-rw-r--r--0002-infinality-2.10.0-2019.03.15.patch6229
-rw-r--r--0004-Enable-long-PCF-family-names.patch27
-rw-r--r--0005-freetype-2.5.2-more-demos.patch17
-rw-r--r--0006-infinality-remix-tweaks.patch139
-rw-r--r--PKGBUILD106
-rw-r--r--freetype2.install0
-rwxr-xr-xfreetype2.sh12
-rwxr-xr-xinfinality-settings.sh65
-rwxr-xr-xxft-settings.sh15
11 files changed, 6713 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..ed966d2b8a04
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,58 @@
+pkgbase = freetype2-infinality-remix
+ pkgdesc = TrueType font rendering library with Infinality Remix patches
+ pkgver = 2.10.0
+ pkgrel = 1
+ url = http://www.freetype.org/
+ install = freetype2.install
+ arch = i686
+ arch = x86_64
+ license = GPL
+ makedepends = libx11
+ makedepends = libpng
+ makedepends = harfbuzz
+ source = https://download.savannah.gnu.org/releases/freetype/freetype-2.10.0.tar.bz2
+ source = https://download.savannah.gnu.org/releases/freetype/freetype-doc-2.10.0.tar.bz2
+ source = https://download-mirror.savannah.gnu.org/releases/freetype/ft2demos-2.10.0.tar.bz2
+ source = 0001-Enable-table-validation-modules.patch
+ source = 0002-infinality-2.10.0-2019.03.15.patch
+ source = 0004-Enable-long-PCF-family-names.patch
+ source = 0005-freetype-2.5.2-more-demos.patch
+ source = 0006-infinality-remix-tweaks.patch
+ source = freetype2.sh
+ source = infinality-settings.sh
+ source = xft-settings.sh
+ sha256sums = fccc62928c65192fff6c98847233b28eb7ce05f12d2fea3f6cc90e8b4e5fbe06
+ sha256sums = 5fdc0fd118a0a82ff36054988b82ea2fc0da2302962b51d14ca2880ee4959fb2
+ sha256sums = 0466f9c2cd609349b0bd1f1b7b85b1bffc52f72eb492a7195552d86e666d06ba
+ sha256sums = ac11a24b62a6c044cc245ea9fa2a0cbd9e2e62f2371873dd33084c28a76e7176
+ sha256sums = b2d511399924452297e4f2c039f3b85d22a5e17d115e5d865c27704887d6c519
+ sha256sums = 54800d4da18611cf9232aad8b63d74a83153a51bb56dd39191678c738ffc8b53
+ sha256sums = 36484db4b926ed026e7f32570573493b5a9793a129f08d54383a26d65a6af89b
+ sha256sums = 94493ed2865fd32e5ef8ef3493fcb2ccaaf8be4c9e0eaa7b417fcbc47fe4314d
+ sha256sums = f7f8e09c44f7552c883846e9a6a1efc50377c4932234e74adc4a8ff750606467
+ sha256sums = 1a5c12aa96e2ee66f7316b8ccb7012520b231a2d8ee21cfe4064aa28db35a57c
+ sha256sums = 4842d1461c240cd0f60a7247ee038271fdb1067107bea9024be6bdbb218d1bd4
+
+pkgname = freetype2-infinality-remix
+ groups = infinality-remix
+ depends = zlib
+ depends = bzip2
+ depends = sh
+ depends = libpng
+ depends = harfbuzz
+ provides = freetype2=2.10.0
+ provides = freetype2-infinality
+ provides = libfreetype.so
+ conflicts = freetype2
+ conflicts = freetype2-infinality
+ conflicts = freetype2-infinality-ultimate
+
+pkgname = freetype2-demos-infinality-remix
+ pkgdesc = Freetype tools and demos
+ depends = freetype2
+ depends = libx11
+ conflicts = freetype2-demos
+ conflicts = freetype2-demos-git
+ conflicts = freetype2-demos-infinality
+ conflicts = freetype2-infinality-ultimate
+
diff --git a/0001-Enable-table-validation-modules.patch b/0001-Enable-table-validation-modules.patch
new file mode 100644
index 000000000000..6b78bcd7985c
--- /dev/null
+++ b/0001-Enable-table-validation-modules.patch
@@ -0,0 +1,45 @@
+From b609203df7333beea20dbfd604262a9486f01497 Mon Sep 17 00:00:00 2001
+Message-Id: <b609203df7333beea20dbfd604262a9486f01497.1552648361.git.jan.steffens@gmail.com>
+From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
+Date: Tue, 23 Jun 2015 08:40:29 +0200
+Subject: [PATCH 1/4] Enable table validation modules
+
+---
+ modules.cfg | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/modules.cfg b/modules.cfg
+index dc6c8d42d..2ab145016 100644
+--- a/modules.cfg
++++ b/modules.cfg
+@@ -111,26 +111,26 @@ AUX_MODULES += cache
+
+ # TrueType GX/AAT table validation. Needs `ftgxval.c' below.
+ #
+-# AUX_MODULES += gxvalid
++AUX_MODULES += gxvalid
+
+ # Support for streams compressed with gzip (files with suffix .gz).
+ #
+ # See include/freetype/ftgzip.h for the API.
+ AUX_MODULES += gzip
+
+ # Support for streams compressed with LZW (files with suffix .Z).
+ #
+ # See include/freetype/ftlzw.h for the API.
+ AUX_MODULES += lzw
+
+ # Support for streams compressed with bzip2 (files with suffix .bz2).
+ #
+ # See include/freetype/ftbzip2.h for the API.
+ AUX_MODULES += bzip2
+
+ # OpenType table validation. Needs `ftotval.c' below.
+ #
+-# AUX_MODULES += otvalid
++AUX_MODULES += otvalid
+
+ # Auxiliary PostScript driver component to share common code.
+ #
+--
+2.21.0
diff --git a/0002-infinality-2.10.0-2019.03.15.patch b/0002-infinality-2.10.0-2019.03.15.patch
new file mode 100644
index 000000000000..81af15ac8481
--- /dev/null
+++ b/0002-infinality-2.10.0-2019.03.15.patch
@@ -0,0 +1,6229 @@
+diff --git a/builds/freetype.mk b/builds/freetype.mk
+index 2b0ffaedd..a2bc85ba4 100644
+--- a/builds/freetype.mk
++++ b/builds/freetype.mk
+@@ -164,6 +164,7 @@ FT_CFLAGS = $(CPPFLAGS) \
+ $(CFLAGS) \
+ $DFT2_BUILD_LIBRARY \
+ $DFT_CONFIG_MODULES_H="<ftmodule.h>" \
++ $D_GNU_SOURCE \
+ $(FTOPTION_FLAG)
+
+
+diff --git a/configure b/configure
+index 9a64f69c4..6161c0f3a 100755
+--- a/configure
++++ b/configure
+@@ -13,6 +13,8 @@
+ # Call the `configure' script located in `builds/unix'.
+ #
+
++export LDFLAGS="$LDFLAGS -lm"
++
+ rm -f config.mk builds/unix/unix-def.mk builds/unix/unix-cc.mk
+
+ # respect GNUMAKE environment variable for backward compatibility
+diff --git a/devel/ftoption.h b/devel/ftoption.h
+index 16cf4e126..f75552db5 100644
+--- a/devel/ftoption.h
++++ b/devel/ftoption.h
+@@ -601,6 +601,16 @@ FT_BEGIN_HEADER
+ */
+ #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
++ /*************************************************************************/
++ /* */
++ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */
++ /* all additional infinality patches, which are configured via env */
++ /* variables. */
++ /* */
++ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */
++ /* defined. */
++ /* */
++#define FT_CONFIG_OPTION_INFINALITY_PATCHSET
+
+ /**************************************************************************
+ *
+diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
+index 12f47a82e..946a2fb93 100644
+--- a/include/freetype/config/ftoption.h
++++ b/include/freetype/config/ftoption.h
+@@ -113,20 +113,21 @@ FT_BEGIN_HEADER
+ #define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
+
+
+- /**************************************************************************
+- *
+- * 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.
+- */
+-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
++ /*************************************************************************/
++ /* */
++ /* 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. */
++ /* */
++#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+
+ /**************************************************************************
+@@ -601,6 +602,17 @@ FT_BEGIN_HEADER
+ */
+ #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
++ /*************************************************************************/
++ /* */
++ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */
++ /* all additional infinality patches, which are configured via env */
++ /* variables. */
++ /* */
++ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */
++ /* defined. */
++ /* */
++#define FT_CONFIG_OPTION_INFINALITY_PATCHSET
++
+
+ /**************************************************************************
+ *
+@@ -658,8 +670,8 @@ FT_BEGIN_HEADER
+ * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
+ */
+ /* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */
+-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2
+-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */
++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */
++#define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 )
+
+
+ /**************************************************************************
+diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
+index f3a41b35a..da08ed9ef 100644
+--- a/include/freetype/internal/ftobjs.h
++++ b/include/freetype/internal/ftobjs.h
+@@ -910,6 +910,7 @@ FT_BEGIN_HEADER
+ FT_DebugHook_Func debug_hooks[4];
+
+ #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ FT_Int lcd_extra; /* number of extra pixels */
+ FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */
+ FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
+ #else
+diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
+index dccdcaf34..dfe144e94 100644
+--- a/src/autofit/aflatin.c
++++ b/src/autofit/aflatin.c
+@@ -23,7 +23,10 @@
+ #include "afglobal.h"
+ #include "aflatin.h"
+ #include "aferrors.h"
+-
++#include "strings.h"
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "../base/ftinf.h"
++#endif
+
+ #ifdef AF_CONFIG_OPTION_USE_WARPER
+ #include "afwarp.h"
+@@ -39,6 +42,10 @@
+ #undef FT_COMPONENT
+ #define FT_COMPONENT aflatin
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++FT_Pos infinality_cur_width = 0;
++#endif
++
+
+ /* needed for computation of round vs. flat segments */
+ #define FLAT_THRESHOLD( x ) ( x / 14 )
+@@ -1145,7 +1152,10 @@
+ FT_Pos delta;
+ AF_LatinAxis axis;
+ FT_UInt nn;
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Bool adjust_heights = FALSE;
++ if(ftinf) adjust_heights=ftinf->autohint_increase_glyph_heights;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+@@ -1173,7 +1183,7 @@
+ {
+ AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
+ AF_LatinBlue blue = NULL;
+-
++ int threshold = 40;
+
+ for ( nn = 0; nn < Axis->blue_count; nn++ )
+ {
+@@ -1183,7 +1193,12 @@
+ break;
+ }
+ }
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( adjust_heights &&
++ metrics->root.scaler.face->size->metrics.x_ppem < 15 &&
++ metrics->root.scaler.face->size->metrics.x_ppem > 5 )
++ threshold = 52;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ if ( blue )
+ {
+ FT_Pos scaled;
+@@ -1339,7 +1354,13 @@
+
+ /* a blue zone is only active if it is less than 3/4 pixels tall */
+ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
++
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* Do at low ppems ( ~< 200 ), in order to prevent fringes */
++ if ( dist <= 256 && dist >= -256 )
++#else
+ if ( dist <= 48 && dist >= -48 )
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ {
+ #if 0
+ FT_Pos delta1;
+@@ -1390,7 +1411,12 @@
+ delta2 = -delta2;
+
+ blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* Round to prevent fringes */
++ blue->shoot.fit = FT_PIX_ROUND( blue->ref.fit - delta2 );
++#else
+ blue->shoot.fit = blue->ref.fit - delta2;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+ #endif
+
+@@ -2528,7 +2554,10 @@
+ dist = edge->fpos - blue->shoot.org;
+ if ( dist < 0 )
+ dist = -dist;
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* round down to pixels */
++ /*dist = FT_MulFix( dist, scale ) & ~63;*/
++#endif
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+@@ -2704,8 +2733,17 @@
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+ FT_Int vertical = ( dim == AF_DIMENSION_VERT );
+-
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Int infinality_dist = 0;
++ FT_UInt autohint_snap_stem_height = 0;
++ if( ftinf ) autohint_snap_stem_height=ftinf->autohint_snap_stem_height;
++ if ( autohint_snap_stem_height > 100 )
++ autohint_snap_stem_height = 100;
++ else if ( autohint_snap_stem_height < 0 )
++ autohint_snap_stem_height = 0;
++
++ if ( autohint_snap_stem_height == 0 )
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
+ axis->extra_light )
+ return width;
+@@ -2715,9 +2753,76 @@
+ dist = -width;
+ sign = 1;
+ }
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* Calculate snap value differently than standard freetype */
++ if ( autohint_snap_stem_height > 0 &&
++ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
++ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
++ {
++ infinality_dist = af_latin_snap_width( axis->widths,
++ axis->width_count, dist );
++
++ if ( metrics->root.scaler.face->size->metrics.x_ppem > 9 &&
++ axis->width_count > 0 &&
++ abs( axis->widths[0].cur - infinality_dist ) < 32 &&
++ axis->widths[0].cur > 52 )
++ {
++ const char *style_name=metrics->root.scaler.face->style_name;
++ if ( style_name!=NULL &&
++ ( strstr( style_name, "Regular" ) ||
++ strstr( style_name, "Book" ) ||
++ strstr( style_name, "Medium" ) ||
++ strcmp( style_name, "Italic" ) == 0 ||
++ strcmp( style_name, "Oblique" ) == 0 )
++ )
++ {
++ /* regular weight */
++ if ( axis->widths[0].cur < 64 )
++ infinality_dist = 64;
++ else if ( axis->widths[0].cur < 88 )
++ infinality_dist = 64;
++ else if ( axis->widths[0].cur < 160 )
++ infinality_dist = 128;
++ else if ( axis->widths[0].cur < 240 )
++ infinality_dist = 190;
++ else infinality_dist = ( infinality_dist ) & ~63;
++ }
++ else
++ {
++ /* bold gets a different threshold */
++ if ( axis->widths[0].cur < 64 )
++ infinality_dist = 64 ;
++ else if ( axis->widths[0].cur < 108 )
++ infinality_dist = 64;
++ else if ( axis->widths[0].cur < 160 )
++ infinality_dist = 128;
++ else if ( axis->widths[0].cur < 222 )
++ infinality_dist = 190;
++ else if ( axis->widths[0].cur < 288 )
++ infinality_dist = 254;
++ else infinality_dist = ( infinality_dist + 16 ) & ~63;
++ }
+
+- if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
++ }
++ if ( infinality_dist < 52 )
++ {
++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 )
++ {
++ if ( infinality_dist < 32 )
++ infinality_dist = 32;
++ }
++ else
++ infinality_dist = 64;
++ }
++ }
++ else if ( autohint_snap_stem_height < 100 &&
++ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
++ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
++#else
++
++ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+
+@@ -2809,6 +2914,9 @@
+ }
+ }
+ else
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( autohint_snap_stem_height < 100 )
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+
+@@ -2816,7 +2924,10 @@
+
+
+ dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( autohint_snap_stem_height > 0 )
++ goto Done_Width;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ if ( vertical )
+ {
+ /* in the case of vertical hinting, always round */
+@@ -2879,6 +2990,32 @@
+ }
+
+ Done_Width:
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( axis->widths[0].cur > 42 )
++ /* weighted average */
++ dist = (dist * ( 100 - autohint_snap_stem_height )
++ + infinality_dist * autohint_snap_stem_height ) / 100;
++
++ {
++ int factor = 100;
++ if ( axis->standard_width < 100 )
++ factor = axis->standard_width;
++
++ if ( metrics->root.scaler.face->size->metrics.x_ppem >= 9 && dist < 52 )
++ dist += ( (52 - dist) * factor ) / 100;
++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 && dist < 32 )
++ dist += ( (32 - dist) * factor ) / 100;
++
++ if ( axis->standard_width > 100 &&
++ metrics->root.scaler.face->size->metrics.x_ppem >= 11 &&
++ dist < 64 )
++ dist = 64;
++ if ( axis->standard_width > 100 &&
++ metrics->root.scaler.face->size->metrics.x_ppem >= 9 &&
++ dist < 52 )
++ dist = 52;
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ if ( sign )
+ dist = -dist;
+
+@@ -2897,6 +3034,8 @@
+ FT_Pos dist, base_delta;
+ FT_Pos fitted_width;
+
++/* if fitted_width causes stem_edge->pos to land basically on top of an existing
++ * stem_edge->pos, then add or remove 64. Need to figure out a way to do this */
+
+ dist = stem_edge->opos - base_edge->opos;
+ base_delta = base_edge->pos - base_edge->opos;
+@@ -3504,8 +3643,11 @@
+ int dim;
+
+ AF_LatinAxis axis;
+-
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Int emboldening_strength = 0;
++ FT_Bool use_various_tweaks = FALSE;
++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ error = af_glyph_hints_reload( hints, outline );
+ if ( error )
+ goto Exit;
+@@ -3569,7 +3711,11 @@
+ }
+
+ af_glyph_hints_save( hints, outline );
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ {
++ infinality_cur_width = metrics->axis->widths[0].cur;
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ Exit:
+ return error;
+ }
+diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h
+index 40479538c..c86ea813f 100644
+--- a/src/autofit/aflatin.h
++++ b/src/autofit/aflatin.h
+@@ -64,6 +64,9 @@ FT_BEGIN_HEADER
+
+ #define AF_LATIN_MAX_WIDTHS 16
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ extern FT_Pos infinality_cur_width;
++#endif
+
+ #define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */
+ #define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */
+diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c
+index 3e46a3655..9d35874d3 100644
+--- a/src/autofit/afmodule.c
++++ b/src/autofit/afmodule.c
+@@ -21,6 +21,10 @@
+ #include "afloader.h"
+ #include "aferrors.h"
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "../base/ftinf.h"
++#endif
++
+ #ifdef FT_DEBUG_AUTOFIT
+
+ #ifndef FT_MAKE_OPTION_SINGLE_OBJECT
+@@ -451,6 +455,9 @@
+ module->warping = 0;
+ #endif
+ module->no_stem_darkening = TRUE;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if(ftinf) module->no_stem_darkening = !ftinf->stem_darkening_autofit;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+ module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
+ module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
+diff --git a/src/base/Jamfile b/src/base/Jamfile
+index 8e1ec4275..f6f60e677 100644
+--- a/src/base/Jamfile
++++ b/src/base/Jamfile
+@@ -59,6 +59,7 @@ SubDir FT2_TOP $(FT2_SRC_DIR) base ;
+ ftglyph
+ ftgxval
+ ftinit
++ ftinf
+ ftmm
+ ftotval
+ ftpatent
+diff --git a/src/base/ftbase.c b/src/base/ftbase.c
+index fb8cbfcc2..6db31550f 100644
+--- a/src/base/ftbase.c
++++ b/src/base/ftbase.c
+@@ -37,6 +37,9 @@
+ #include "ftstream.c"
+ #include "fttrigon.c"
+ #include "ftutil.c"
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "ftinf.c"
++#endif
+
+
+ /* END */
+diff --git a/src/base/ftinf.c b/src/base/ftinf.c
+new file mode 100644
+index 000000000..5d6b7f682
+--- /dev/null
++++ b/src/base/ftinf.c
+@@ -0,0 +1,363 @@
++#include <stdlib.h>
++#include "ftinf.h"
++#define true 1
++#define false 0
++
++#define on 1
++#define off 0
++#define end (-128)
++
++#define sw2pv 18 /* STEM_WIDTH_2_PPEM */
++#define maxp 100 /* MAX_PPEM */
++
++typedef signed char pv; /* ppm and values type */
++/* the arrays start with existence flag + values */
++typedef struct sa_rules_s {
++ const char *name;
++ pv always_use_100[1+4+1];
++ pv brightness[1+2+1];
++ pv contrast[1+2+1];
++ pv edge_detection[1+4+1];
++ pv m[1+4+1];
++ pv bearing_correction[1+2+1];
++ pv spacing[1+5+1];
++ pv start[1+5+1];
++ pv stem_scaling[1+6+1];
++ pv stem_translating[1+2+1];
++ pv stem_translating_only[1+10+1];
++ pv stem_widths[1+4]; /* these end with maxp */
++ pv synthesize_stems[1+2+1];
++} sa_rules_t;
++
++#pragma GCC diagnostic ignored "-Wpedantic" /* C99 struct initializer tags are needed */
++#pragma GCC diagnostic ignored "-Wunused-function"
++
++const ftinf_t *ftinf;
++/* final settings, updated from environment */
++ftinf_t _env;
++
++/* rules and hashing function */
++#include "ftinf_rh.c"
++
++/* rules selection */
++void ftinf_fill_stem_values( Stem_Data *stem_values,
++ const char *family, int ppem, int use_known ){
++ /* set the defaults */
++ stem_values->bearing_correction = TRUE;
++ stem_values->brightness = 0.0;
++ stem_values->contrast = 0.0;
++ stem_values->edge_detection = FALSE;
++ stem_values->m = -1;
++ stem_values->stem_scaling = -1;
++ stem_values->stem_spacing = -1;
++ stem_values->stem_start = -1;
++ stem_values->stem_translating = 0;
++ stem_values->stem_translating_only = -1024;
++ stem_values->stem_width = -1;
++ stem_values->synth_stems = FALSE;
++ stem_values->use_100 = FALSE;
++ /* pick from known rules if requested and they exist for current family */
++ if( !use_known )
++ return;
++ else {
++ const sa_rules_t *r=ftinf_rules( family );
++ int i;
++ if( r==NULL ) return;
++ if( r->stem_widths[0]==on )
++ for( i=1; r->stem_widths[i]!=maxp; ++i )
++ if( ppem < r->stem_widths[i] ){
++ stem_values->stem_width = i-1;
++ break;
++ }
++
++ if( r->stem_scaling[0]==on )
++ for( i=1; r->stem_scaling[i]!=end; i+=2 )
++ if( ppem==r->stem_scaling[i] ){
++ stem_values->stem_scaling = r->stem_scaling[i+1];
++ break;
++ }
++
++ if( r->m[0]==on )
++ for( i=1; r->m[i]!=end; i+=2 )
++ if( ppem==r->m[i] ){
++ stem_values->m = r->m[i+1];
++ break;
++ }
++
++ if( r->stem_translating_only[0]==on )
++ for( i=1; r->stem_translating_only[i]!=end; i+=2 )
++ if( ppem==r->stem_translating_only[i] || r->stem_translating_only[i]==0 ){
++ stem_values->stem_translating_only = r->stem_translating_only[i+1];
++ break;
++ }
++
++ if( r->stem_translating[0]==on )
++ for( i=1; r->stem_translating[i]!=end; i+=2 )
++ if( ppem==r->stem_translating[i] || r->stem_translating[i]==0 ){
++ stem_values->stem_translating = r->stem_translating[i+1];
++ break;
++ }
++
++ if( r->always_use_100[0]==on )
++ for( i=1; r->always_use_100[i]!=end; i+=2 )
++ if( ppem>=r->always_use_100[i] && ppem<=r->always_use_100[i+1] ){
++ stem_values->use_100 = TRUE;
++ break;
++ }
++
++ if( r->synthesize_stems[0]==on )
++ for( i=1; r->synthesize_stems[i]!=end; i+=2 )
++ if( ppem>=r->synthesize_stems[i] && ppem<=r->synthesize_stems[i+1] ){
++ stem_values->synth_stems = TRUE;
++ break;
++ }
++
++ if( r->edge_detection[0]==on )
++ for( i=1; r->edge_detection[i]!=end; i+=2 )
++ if( ppem>=r->edge_detection[i] && ppem<=r->edge_detection[i+1] ){
++ stem_values->edge_detection = TRUE;
++ break;
++ }
++
++ if( r->bearing_correction[0]==on )
++ for( i=1; r->bearing_correction[i]!=end; i+=2 )
++ if( ppem>=r->bearing_correction[i] && ppem<=r->bearing_correction[i+1] ){
++ stem_values->bearing_correction = FALSE;
++ break;
++ }
++
++#if(0)
++ if( r->brightness[0]==on )
++ for( i=1; r->brightness[i]!=end; i+=2 )
++ if( ppem==r->brightness[i]||r->brightness[i]==0 ){
++ stem_values->brightness=r->brightness[i+1]*(1.0f/300.0f);
++ break;
++ }
++
++ if( r->contrast[0]==on )
++ for( i=1; r->contrast[i]!=end; i+=2 )
++ if( ppem==r->contrast[i]||r->contrast[i]==0 ){
++ stem_values->contrast=r->contrast[i+1]*(1.0f/300.0f);
++ break;
++ }
++ if( r->spacing[0]==on ){
++ /* not used by original code */
++ }
++ if( r->start[0]==on ){
++ /* not used by original code */
++ }
++#endif
++ }
++ return;
++}
++
++void ftinf_get_bc( const char *family, int ppem, float *brightness, float *contrast ){
++ const sa_rules_t *r=ftinf_rules( family );
++ *brightness=0;
++ *contrast=0;
++ if( r ){
++ int i;
++ if( r->brightness[0]==on )
++ for( i=1; r->brightness[i]!=end; i+=2 )
++ if( ppem==r->brightness[i]||r->brightness[i]==0 ){
++ *brightness=r->brightness[i+1]*(1.0f/300.0f);
++ break;
++ }
++
++ if( r->contrast[0]==on )
++ for( i=1; r->contrast[i]!=end; i+=2 )
++ if( ppem==r->contrast[i]||r->contrast[i]==0 ){
++ *contrast=r->contrast[i+1]*(1.0f/300.0f);
++ break;
++ }
++ }
++ return;
++}
++
++static int
++bool_val( const char *s ){
++ if ( s != NULL )
++ return strcasecmp(s, "true") == 0
++ || strcasecmp(s, "1") == 0
++ || strcasecmp(s, "on") == 0
++ || strcasecmp(s, "yes") ==0;
++ else
++ return 0;
++}
++
++static int
++int_val( const char *s, int min, int max ){
++ int val;
++ sscanf ( s, "%d", &val );
++ if ( val > max )
++ val = max;
++ else if ( val < min )
++ val = min;
++ return val;
++}
++
++/* settings and hashing function */
++#include "ftinf_sh.c"
++
++/*
++ Get active Infinality settings
++ */
++void ftinf_env(){
++ const char *s;
++ ftinf=ftinf_settings( getenv( "INFINALITY_FT" ) );
++
++ if( ftinf==NULL ){
++ ftinf=ftinf_settings( "ultimate3" );
++ /* this should always succeed */
++#if(0)
++ if( ftinf==NULL ){
++ /* put an error here */
++ exit(-1);
++ }
++#endif
++ }
++ _env=ftinf[0]; /* copy as defaults */
++
++ /* check if custom environment values are set and update with them */
++ s=getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" );
++ if( s ) _env.autohint_increase_glyph_heights=bool_val( s );
++ s=getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" );
++ if( s ) _env.autohint_snap_stem_height=int_val( s, 0, 100 );
++ s=getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
++ if( s ) _env.use_various_tweaks=bool_val( s );
++ s=getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
++ if( s ) _env.use_known_settings_on_selected_fonts=bool_val(s);
++#if(0) /* not used (naming error also) */
++ s=getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" );
++ if( s ) _env.autohint_minimum_stem_height=int_val( s, 0, 100 );
++#endif
++ s=getenv( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" );
++ if( s ) sscanf( s, "%d", &_env.stem_snapping_sliding_scale );
++ s=getenv( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.stem_alignment_strength );
++ s=getenv( "INFINALITY_FT_STEM_DARKENING_AUTOFIT" );
++ if( s ) _env.stem_darkening_autofit=bool_val( s );
++ s=getenv( "INFINALITY_FT_STEM_DARKENING_CFF" );
++ if( s ) _env.stem_darkening_cff=bool_val( s );
++ s=getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.stem_fitting_strength );
++ s=getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" );
++ if( s ) _env.chromeos_style_sharpening_strength=int_val( s, 0, 100 );
++ s=getenv( "INFINALITY_FT_BRIGHTNESS" );
++ if( s ) sscanf( s, "%d", &_env.brightness );
++ s=getenv( "INFINALITY_FT_CONTRAST" );
++ if( s ) sscanf( s, "%d", &_env.contrast );
++ s=getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" );
++ if( s ) _env.windows_style_sharpening_strength=int_val( s, 0, 100 );
++ s=getenv( "INFINALITY_FT_GAMMA_CORRECTION" );
++ if( s ){
++ float *f=_env.gamma_correction;
++ sscanf ( s, "%f %f", &f[0], &f[1] );
++ if( f[1] < 1.0f ) f[1]=1.0f;
++ }
++ s=getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.fringe_filter_strength );
++ s=getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.grayscale_filter_strength );
++ s=getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.autohint_horizontal_stem_darken_strength );
++ s=getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" );
++ if( s ) sscanf( s, "%d", &_env.autohint_vertical_stem_darken_strength );
++ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" );
++ if( s ) sscanf( s, "%d", &_env.global_embolden_x_value );
++ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" );
++ if( s ) sscanf( s, "%d", &_env.global_embolden_y_value );
++ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" );
++ if( s ) sscanf( s, "%d", &_env.bold_embolden_x_value );
++ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" );
++ if( s ) sscanf( s, "%d", &_env.bold_embolden_y_value );
++ s=getenv( "INFINALITY_FT_FILTER_PARAMS" );
++ if( s ) {
++ int *f=_env.filter_params;
++ if( sscanf( s, "%d %d %d %d %d", f+1, f+2, f+3, f+4, f+5 )==5 )
++ f[0]=on;
++ else
++ f[0]=off; /* FIXME: put a warning? */
++ }
++ /* do the range verifications as in original code */
++ if ( _env.stem_snapping_sliding_scale > maxp )
++ _env.stem_snapping_sliding_scale = 0;
++ else if ( _env.stem_snapping_sliding_scale < 0 )
++ _env.stem_snapping_sliding_scale = 0;
++ if (_env.stem_snapping_sliding_scale < 11 &&
++ _env.stem_snapping_sliding_scale > 0 )
++ _env.stem_snapping_sliding_scale = 11;
++
++ if ( _env.stem_alignment_strength > 100 )
++ _env.stem_alignment_strength = 100;
++ else if ( _env.stem_alignment_strength < 0 )
++ _env.stem_alignment_strength = 0;
++
++ if ( _env.stem_fitting_strength > 100 )
++ _env.stem_fitting_strength = 100;
++ else if ( _env.stem_fitting_strength < 0 )
++ _env.stem_fitting_strength = 0;
++
++ if ( _env.chromeos_style_sharpening_strength > 100 )
++ _env.chromeos_style_sharpening_strength = 100;
++ else if ( _env.chromeos_style_sharpening_strength < 0 )
++ _env.chromeos_style_sharpening_strength = 0;
++
++ if ( _env.brightness > 100 )
++ _env.brightness = 100;
++ else if ( _env.brightness < -100 )
++ _env.brightness = 0;
++
++ if ( _env.contrast > 100 )
++ _env.contrast = 100;
++ else if ( _env.contrast < -100 )
++ _env.contrast = 0;
++
++ if ( _env.windows_style_sharpening_strength > 100 )
++ _env.windows_style_sharpening_strength = 100;
++ else if ( _env.windows_style_sharpening_strength < 0 )
++ _env.windows_style_sharpening_strength = 0;
++
++ if ( _env.fringe_filter_strength > 100 )
++ _env.fringe_filter_strength = 100;
++ else if ( _env.fringe_filter_strength < 0 )
++ _env.fringe_filter_strength = 0;
++
++ if ( _env.grayscale_filter_strength > 100 )
++ _env.grayscale_filter_strength = 100;
++ else if ( _env.grayscale_filter_strength < 0 )
++ _env.grayscale_filter_strength = 0;
++
++ if ( _env.autohint_horizontal_stem_darken_strength > 100 )
++ _env.autohint_horizontal_stem_darken_strength = 100;
++ else if ( _env.autohint_horizontal_stem_darken_strength < 0 )
++ _env.autohint_horizontal_stem_darken_strength = 0;
++
++ if ( _env.autohint_vertical_stem_darken_strength > 100 )
++ _env.autohint_vertical_stem_darken_strength = 100;
++ else if ( _env.autohint_horizontal_stem_darken_strength < 0 )
++ _env.autohint_vertical_stem_darken_strength = 0;
++
++ if ( _env.global_embolden_x_value > 128 )
++ _env.global_embolden_x_value = 128;
++ else if ( _env.global_embolden_x_value < -128 )
++ _env.global_embolden_x_value = -128;
++
++ if ( _env.global_embolden_y_value > 128 )
++ _env.global_embolden_y_value = 128;
++ else if ( _env.global_embolden_y_value < -128 )
++ _env.global_embolden_y_value = -128;
++
++ if ( _env.bold_embolden_x_value > 128 )
++ _env.bold_embolden_x_value = 128;
++ else if (_env.bold_embolden_x_value < -128 )
++ _env.bold_embolden_x_value = -128;
++
++ if ( _env.bold_embolden_y_value > 128 )
++ _env.bold_embolden_y_value = 128;
++ else if ( _env.bold_embolden_y_value < -128 )
++ _env.bold_embolden_y_value = -128;
++
++ /* point to the combined and checked settings */
++ ftinf=&_env;
++}
+diff --git a/src/base/ftinf.h b/src/base/ftinf.h
+new file mode 100644
+index 000000000..fbe1bd19d
+--- /dev/null
++++ b/src/base/ftinf.h
+@@ -0,0 +1,66 @@
++#ifndef _FTINF_H_
++#define _FTINF_H_
++/*
++ Stem snapping rules
++ (base freetype typedefs assumed already included)
++ */
++typedef struct
++{
++ FT_Int stem_width;
++ FT_Int stem_spacing;
++ FT_Int stem_start;
++ FT_Int stem_scaling;
++ FT_Int stem_translating_only;
++ FT_Int stem_translating;
++ float brightness;
++ float contrast;
++ FT_Bool use_100;
++ FT_Bool synth_stems;
++ FT_Bool edge_detection;
++ FT_Bool bearing_correction;
++ FT_Int m;
++} Stem_Data;
++
++/*
++ Infinality settings
++ */
++typedef struct ftinf_s {
++ const char *name;
++ int autohint_horizontal_stem_darken_strength;
++ int autohint_snap_stem_height;
++ int autohint_increase_glyph_heights;
++ int autohint_vertical_stem_darken_strength;
++ int bold_embolden_x_value;
++ int bold_embolden_y_value;
++ int brightness;
++ int chromeos_style_sharpening_strength;
++ int contrast;
++ int filter_params[6]; /* 1st one used as existence flag */
++ int fringe_filter_strength;
++ float gamma_correction[2];
++ int global_embolden_x_value;
++ int global_embolden_y_value;
++ int grayscale_filter_strength;
++ int stem_alignment_strength;
++ int stem_darkening_autofit;
++ int stem_darkening_cff;
++ int stem_fitting_strength;
++ int stem_snapping_sliding_scale;
++ int use_known_settings_on_selected_fonts;
++ int use_various_tweaks;
++ int windows_style_sharpening_strength;
++} ftinf_t;
++
++extern FT_Pos infinality_cur_width; /* defined in aflatin.c */
++
++extern const ftinf_t *ftinf; /* active settings */
++
++extern void ftinf_fill_stem_values( Stem_Data *stem_values,
++ const char *family, int ppem, int use_known );
++extern void ftinf_get_bc( const char *family, int ppem,
++ float *brightness, float *contrast );
++
++/* get values from environment (FIXME: maybe update with using user files) */
++extern void ftinf_env();
++
++#endif
+diff --git a/src/base/ftinf_rh.c b/src/base/ftinf_rh.c
+new file mode 100644
+index 000000000..606b5671a
+--- /dev/null
++++ b/src/base/ftinf_rh.c
+@@ -0,0 +1,626 @@
++/* ANSI-C code produced by gperf version 3.1 */
++/* Command-line: gperf --output-file=ftinf_rh.c ftinf_rh.gperf */
++/* Computed positions: -k'1,$' */
++
++#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
++ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
++ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
++ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
++ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
++ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
++ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
++ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
++ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
++ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
++ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
++ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
++ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
++ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
++ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
++ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
++ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
++ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
++ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
++ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
++ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
++ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
++ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
++/* The character set is not based on ISO-646. */
++#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
++#endif
++
++#line 9 "ftinf_rh.gperf"
++
++#include <ctype.h>
++static const struct sa_rules_s* _rules_get( const char*str, unsigned len );
++/* maximum key range = 82, duplicates = 0 */
++
++#ifdef __GNUC__
++__inline
++#else
++#ifdef __cplusplus
++inline
++#endif
++#endif
++static unsigned int
++_rules_hash (register const char *str, register unsigned int len)
++{
++ static const unsigned char asso_values[] =
++ {
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 0, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 5, 45, 5,
++ 35, 25, 35, 35, 50, 45, 85, 85, 0, 25,
++ 40, 5, 0, 85, 50, 20, 20, 0, 10, 10,
++ 85, 10, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
++ 85, 85, 85, 85, 85, 85
++ };
++ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
++}
++
++#ifdef __GNUC__
++__inline
++#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
++__attribute__ ((__gnu_inline__))
++#endif
++#endif
++const struct sa_rules_s *
++_rules_get (register const char *str, register unsigned int len)
++{
++ enum
++ {
++ TOTAL_KEYWORDS = 58,
++ MIN_WORD_LENGTH = 3,
++ MAX_WORD_LENGTH = 24,
++ MIN_HASH_VALUE = 3,
++ MAX_HASH_VALUE = 84
++ };
++
++ static const struct sa_rules_s wordlist[] =
++ {
++#line 15 "ftinf_rh.gperf"
++{ .name="---",
++ .synthesize_stems={on, 13, 13, end}
++},
++#line 253 "ftinf_rh.gperf"
++{ .name="ubuntu",
++ .always_use_100={on, 12, 13, 15, 15, end}
++},
++#line 31 "ftinf_rh.gperf"
++{ .name="arial",
++ .always_use_100={on, 0, maxp, end},
++ .edge_detection={on, 11, 11, 13, 13, end},
++ .spacing={on, 10, 11, 23, 25, 30, end},
++ .start={on, 11, 18, 23, 30, 30, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end}
++},
++#line 87 "ftinf_rh.gperf"
++{ .name="corbel",
++ .stem_translating_only={on, 10, 16, end},
++ .stem_widths={on, 10, 21, maxp}
++},
++#line 71 "ftinf_rh.gperf"
++{ .name="canwell",
++ .stem_scaling={on, 13, 0, end}
++},
++#line 216 "ftinf_rh.gperf"
++{ .name="pragmata",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 67 "ftinf_rh.gperf"
++{ .name="cantarell",
++ .stem_translating_only={on, 11, 0, 12, 0, end},
++ .stem_widths={on, 10, 22, maxp,}
++},
++#line 39 "ftinf_rh.gperf"
++{ .name="arimo",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}
++},
++#line 207 "ftinf_rh.gperf"
++{ .name="optima",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end},
++ .stem_scaling={on, 17, 1, end},
++ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end}
++},
++#line 63 "ftinf_rh.gperf"
++{ .name="candara",
++ .stem_scaling={on, 14, 1, 17, 1, end},
++ .stem_translating_only={on, 10, 16, end}
++},
++#line 77 "ftinf_rh.gperf"
++{ .name="comfortaa",
++ .stem_widths={on, 10, 19, 22, maxp},
++ .stem_scaling={on, 11, 0, end}
++},
++#line 161 "ftinf_rh.gperf"
++{ .name="liberation mono",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 18 "ftinf_rh.gperf"
++{ .name="andale mono",
++ .always_use_100={on, 0, maxp, end},
++ .stem_scaling={on, 11, 1, end},
++ .stem_widths={on, 10, 21, maxp,}
++},
++#line 256 "ftinf_rh.gperf"
++{ .name="verdana",
++ .always_use_100={on, 0, 14, 16, maxp, end},
++ .stem_scaling={on, 12, 1, 15, 1, end},
++ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end}
++},
++#line 74 "ftinf_rh.gperf"
++{ .name="century gothic",
++ .stem_widths={on, 10, 22, maxp,}
++},
++#line 91 "ftinf_rh.gperf"
++{ .name="courier new",
++ .always_use_100={on, 12, 12, end},
++ .edge_detection={on, 10, 12, end},
++ .m={on, 13, 1, 14, 1, end}
++},
++#line 23 "ftinf_rh.gperf"
++{ .name="arial narrow",
++ .stem_widths={on, 10, 21, maxp,}
++},
++#line 185 "ftinf_rh.gperf"
++{ .name="luxi sans",
++ .always_use_100={on, 13, 13, end},
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++#line 225 "ftinf_rh.gperf"
++{ .name="samba",
++ .stem_scaling={on, 11, 0, end}
++},
++#line 233 "ftinf_rh.gperf"
++{ .name="tahoma",
++ .always_use_100={on, 11, 11, 14, maxp, end},
++ .edge_detection={on, 11, 11, end},
++ .spacing={on, 10, 12, 18, 18, 30, end},
++ .start={on, 14, 17, 30, 100, 100, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end},
++},
++#line 164 "ftinf_rh.gperf"
++{ .name="liberation sans narrow",
++ .stem_widths={on,10, 22, maxp,}
++},
++#line 81 "ftinf_rh.gperf"
++{ .name="consolas",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 8, 32, 9, 32, end},
++ .stem_widths={on, 10, 20, maxp,},
++ .stem_scaling={on, 11, 1, end}
++},
++#line 203 "ftinf_rh.gperf"
++{ .name="open sans",
++ .stem_translating_only={on, 10, 16, 9, 16, end},
++ .stem_widths={on, 10, 20, maxp,}
++},
++#line 167 "ftinf_rh.gperf"
++{ .name="liberation sans",
++ .edge_detection={on, 11, 11, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end},
++ .stem_widths={on,10, 19, maxp,}
++},
++#line 193 "ftinf_rh.gperf"
++{ .name="monaco",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 101 "ftinf_rh.gperf"
++{ .name="cousine",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 176 "ftinf_rh.gperf"
++{ .name="lucida grande",
++ .stem_scaling={on, 13, 1, end},
++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
++ .stem_widths={on, 10, 16, sw2pv, maxp},
++},
++#line 173 "ftinf_rh.gperf"
++{ .name="lucida console",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 196 "ftinf_rh.gperf"
++{ .name="myriad pro",
++ .stem_scaling={on, 14, 1, 17, 1, end},
++ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end}
++},
++#line 26 "ftinf_rh.gperf"
++{ .name="arial unicode ms",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
++},
++#line 213 "ftinf_rh.gperf"
++{ .name="palatino linotype",
++ .edge_detection={on, 0, 100, end}
++},
++#line 181 "ftinf_rh.gperf"
++{ .name="lucida sans unicode",
++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
++ .stem_widths={on,10, 16, sw2pv, maxp,}
++},
++#line 140 "ftinf_rh.gperf"
++{ .name="futura",
++ .stem_widths={on, 10, 14, sw2pv, maxp,}
++},
++#line 147 "ftinf_rh.gperf"
++{ .name="georgia",
++ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end}
++},
++#line 125 "ftinf_rh.gperf"
++{ .name="freemono",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 200 "ftinf_rh.gperf"
++{ .name="nina",
++ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end}
++},
++#line 121 "ftinf_rh.gperf"
++{ .name="essential pragmatapro",
++ .always_use_100={on, 0, maxp, end},
++ .m={on, 13, 0, 14, 0, end}
++},
++#line 247 "ftinf_rh.gperf"
++{ .name="trebuchet ms",
++ .always_use_100={on, 13, 13, end},
++ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end},
++ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end},
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++#line 114 "ftinf_rh.gperf"
++{ .name="droid sans mono",
++ .m={on, 12, 0, end}
++},
++#line 104 "ftinf_rh.gperf"
++{ .name="dejavu sans mono",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end}
++},
++#line 57 "ftinf_rh.gperf"
++{ .name="calibri",
++ .always_use_100={on, 23, maxp, end},
++ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end},
++ .stem_translating_only={on, 10, 16, 15, 0, end},
++ .stem_widths={on, 1, 10, 19, maxp,}
++},
++#line 156 "ftinf_rh.gperf"
++{ .name="inconsolata",
++ .stem_scaling={on, 12, 1, 15, 1, end},
++ .stem_translating_only={on, 10, 24, 9, 32, end},
++ .stem_widths={on, 10, 23, maxp,},
++},
++#line 96 "ftinf_rh.gperf"
++{ .name="courier",
++ .always_use_100={on, 0, maxp, end},
++ .m={on, 13, 1, 14, 1, end},
++ .stem_translating_only={on, 13, 16, 15, 0, end}
++},
++#line 128 "ftinf_rh.gperf"
++{ .name="freesans",
++ .always_use_100={on, 0, maxp, end},
++ .edge_detection={on, 11, 11, 13, 13, end},
++ .spacing={on, 10, 12, 18, 18, 30, end},
++ .start={on, 10, 18, 18, 25, 30, end},
++ .stem_scaling={on, 16, 0, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 9, 8, end}
++},
++#line 150 "ftinf_rh.gperf"
++{ .name="gill sans",
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++#line 117 "ftinf_rh.gperf"
++{ .name="droid sans",
++ .always_use_100={on, 12, 12, 15, 15, end},
++ .stem_translating_only={on, 8, 16, 9, 16, end}
++},
++#line 108 "ftinf_rh.gperf"
++{ .name="dejavu sans",
++ .always_use_100={on, 10, 14, 16, 17, end},
++ .m={on, 12, 0, end},
++ .stem_scaling={on, 12, 1, end},
++ .stem_translating_only={on, 8, 16, 15, -20, end}
++},
++#line 219 "ftinf_rh.gperf"
++{ .name="raleway",
++ .stem_scaling={on, 15, 0, end}
++},
++#line 153 "ftinf_rh.gperf"
++{ .name="helvetica cy",
++ .stem_widths={on, 10, 23, maxp,}
++},
++#line 228 "ftinf_rh.gperf"
++{ .name="segoe ui",
++ .always_use_100={on, 11, 12, 14, 14, end},
++ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end},
++ .stem_widths={on, 10, 23, maxp,}
++},
++#line 48 "ftinf_rh.gperf"
++{ .name="bitstream vera sans mono",
++ .always_use_100={on, 0, maxp, end}
++},
++#line 241 "ftinf_rh.gperf"
++{ .name="times new roman",
++ .always_use_100={on, 14, 14, 16, 16, end},
++ .bearing_correction={0, 100, end},
++ .stem_scaling={on, 17, 1, end},
++ .stem_translating_only={on, 17, 8, end}
++},
++#line 222 "ftinf_rh.gperf"
++{ .name="rokkitt",
++ .stem_widths={on, 10, 21, maxp,}
++},
++#line 143 "ftinf_rh.gperf"
++{ .name="garamond",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end}
++},
++#line 137 "ftinf_rh.gperf"
++{ .name="freeserif",
++ .stem_scaling={on, 13, 1, 17, 1, end}
++},
++#line 189 "ftinf_rh.gperf"
++{ .name="microsoft sans serif",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
++},
++#line 44 "ftinf_rh.gperf"
++{ .name="baskerville",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end}
++},
++#line 51 "ftinf_rh.gperf"
++{ .name="bitstream vera sans",
++ .always_use_100={on, 10, 14, 16, 17, end},
++ .m={on, 12, 0, end},
++ .stem_scaling={on ,12, 1, end},
++ .stem_translating_only={on, 8, 16, end}
++}
++ };
++
++ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
++ {
++ register int key = _rules_hash (str, len);
++
++ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
++ {
++ register const struct sa_rules_s *resword;
++
++ switch (key - 3)
++ {
++ case 0:
++ resword = &wordlist[0];
++ goto compare;
++ case 3:
++ resword = &wordlist[1];
++ goto compare;
++ case 7:
++ resword = &wordlist[2];
++ goto compare;
++ case 8:
++ resword = &wordlist[3];
++ goto compare;
++ case 9:
++ resword = &wordlist[4];
++ goto compare;
++ case 10:
++ resword = &wordlist[5];
++ goto compare;
++ case 11:
++ resword = &wordlist[6];
++ goto compare;
++ case 12:
++ resword = &wordlist[7];
++ goto compare;
++ case 13:
++ resword = &wordlist[8];
++ goto compare;
++ case 14:
++ resword = &wordlist[9];
++ goto compare;
++ case 16:
++ resword = &wordlist[10];
++ goto compare;
++ case 17:
++ resword = &wordlist[11];
++ goto compare;
++ case 18:
++ resword = &wordlist[12];
++ goto compare;
++ case 19:
++ resword = &wordlist[13];
++ goto compare;
++ case 21:
++ resword = &wordlist[14];
++ goto compare;
++ case 23:
++ resword = &wordlist[15];
++ goto compare;
++ case 24:
++ resword = &wordlist[16];
++ goto compare;
++ case 26:
++ resword = &wordlist[17];
++ goto compare;
++ case 27:
++ resword = &wordlist[18];
++ goto compare;
++ case 28:
++ resword = &wordlist[19];
++ goto compare;
++ case 29:
++ resword = &wordlist[20];
++ goto compare;
++ case 30:
++ resword = &wordlist[21];
++ goto compare;
++ case 31:
++ resword = &wordlist[22];
++ goto compare;
++ case 32:
++ resword = &wordlist[23];
++ goto compare;
++ case 33:
++ resword = &wordlist[24];
++ goto compare;
++ case 34:
++ resword = &wordlist[25];
++ goto compare;
++ case 35:
++ resword = &wordlist[26];
++ goto compare;
++ case 36:
++ resword = &wordlist[27];
++ goto compare;
++ case 37:
++ resword = &wordlist[28];
++ goto compare;
++ case 38:
++ resword = &wordlist[29];
++ goto compare;
++ case 39:
++ resword = &wordlist[30];
++ goto compare;
++ case 41:
++ resword = &wordlist[31];
++ goto compare;
++ case 43:
++ resword = &wordlist[32];
++ goto compare;
++ case 44:
++ resword = &wordlist[33];
++ goto compare;
++ case 45:
++ resword = &wordlist[34];
++ goto compare;
++ case 46:
++ resword = &wordlist[35];
++ goto compare;
++ case 48:
++ resword = &wordlist[36];
++ goto compare;
++ case 49:
++ resword = &wordlist[37];
++ goto compare;
++ case 52:
++ resword = &wordlist[38];
++ goto compare;
++ case 53:
++ resword = &wordlist[39];
++ goto compare;
++ case 54:
++ resword = &wordlist[40];
++ goto compare;
++ case 58:
++ resword = &wordlist[41];
++ goto compare;
++ case 59:
++ resword = &wordlist[42];
++ goto compare;
++ case 60:
++ resword = &wordlist[43];
++ goto compare;
++ case 61:
++ resword = &wordlist[44];
++ goto compare;
++ case 62:
++ resword = &wordlist[45];
++ goto compare;
++ case 63:
++ resword = &wordlist[46];
++ goto compare;
++ case 64:
++ resword = &wordlist[47];
++ goto compare;
++ case 69:
++ resword = &wordlist[48];
++ goto compare;
++ case 70:
++ resword = &wordlist[49];
++ goto compare;
++ case 71:
++ resword = &wordlist[50];
++ goto compare;
++ case 72:
++ resword = &wordlist[51];
++ goto compare;
++ case 74:
++ resword = &wordlist[52];
++ goto compare;
++ case 75:
++ resword = &wordlist[53];
++ goto compare;
++ case 76:
++ resword = &wordlist[54];
++ goto compare;
++ case 77:
++ resword = &wordlist[55];
++ goto compare;
++ case 78:
++ resword = &wordlist[56];
++ goto compare;
++ case 81:
++ resword = &wordlist[57];
++ goto compare;
++ }
++ return 0;
++ compare:
++ {
++ register const char *s = resword->name;
++
++ if (*str == *s && !strcmp (str + 1, s + 1))
++ return resword;
++ }
++ }
++ }
++ return 0;
++}
++#line 261 "ftinf_rh.gperf"
++
++
++static const sa_rules_t*
++ftinf_rules( const char *name ){
++ if( name ){
++ enum {
++ max_wlen=31
++ };
++ char buf[max_wlen+1];
++ int len=strlen( name );
++ if( len <= max_wlen ){
++ int i;
++ for( i=0; i<len; ++i )
++ buf[i]=tolower( name[i] );
++ buf[len]='\0';
++ return _rules_get( buf, len );
++ }
++ }
++ return NULL;
++}
++/*
++ gperf --output-file=ftinf_rh.c ftinf_rh.gperf
++*/
+diff --git a/src/base/ftinf_rh.gperf b/src/base/ftinf_rh.gperf
+new file mode 100644
+index 000000000..9fd8aab95
+--- /dev/null
++++ b/src/base/ftinf_rh.gperf
+@@ -0,0 +1,283 @@
++%struct-type
++%define slot-name name
++%enum
++%switch=1
++%readonly-tables
++%omit-struct-type
++%define lookup-function-name _rules_get
++%define hash-function-name _rules_hash
++%{
++#include <ctype.h>
++static const struct sa_rules_s* _rules_get( const char*str, unsigned len );
++%}
++struct sa_rules_s;
++%%
++{ .name="---",
++ .synthesize_stems={on, 13, 13, end}
++},
++{ .name="andale mono",
++ .always_use_100={on, 0, maxp, end},
++ .stem_scaling={on, 11, 1, end},
++ .stem_widths={on, 10, 21, maxp,}
++},
++{ .name="arial narrow",
++ .stem_widths={on, 10, 21, maxp,}
++},
++{ .name="arial unicode ms",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
++},
++{ .name="arial",
++ .always_use_100={on, 0, maxp, end},
++ .edge_detection={on, 11, 11, 13, 13, end},
++ .spacing={on, 10, 11, 23, 25, 30, end},
++ .start={on, 11, 18, 23, 30, 30, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end}
++},
++{ .name="arimo",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}
++},
++{ .name="baskerville",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end}
++},
++{ .name="bitstream vera sans mono",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="bitstream vera sans",
++ .always_use_100={on, 10, 14, 16, 17, end},
++ .m={on, 12, 0, end},
++ .stem_scaling={on ,12, 1, end},
++ .stem_translating_only={on, 8, 16, end}
++},
++{ .name="calibri",
++ .always_use_100={on, 23, maxp, end},
++ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end},
++ .stem_translating_only={on, 10, 16, 15, 0, end},
++ .stem_widths={on, 1, 10, 19, maxp,}
++},
++{ .name="candara",
++ .stem_scaling={on, 14, 1, 17, 1, end},
++ .stem_translating_only={on, 10, 16, end}
++},
++{ .name="cantarell",
++ .stem_translating_only={on, 11, 0, 12, 0, end},
++ .stem_widths={on, 10, 22, maxp,}
++},
++{ .name="canwell",
++ .stem_scaling={on, 13, 0, end}
++},
++{ .name="century gothic",
++ .stem_widths={on, 10, 22, maxp,}
++},
++{ .name="comfortaa",
++ .stem_widths={on, 10, 19, 22, maxp},
++ .stem_scaling={on, 11, 0, end}
++},
++{ .name="consolas",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 8, 32, 9, 32, end},
++ .stem_widths={on, 10, 20, maxp,},
++ .stem_scaling={on, 11, 1, end}
++},
++{ .name="corbel",
++ .stem_translating_only={on, 10, 16, end},
++ .stem_widths={on, 10, 21, maxp}
++},
++{ .name="courier new",
++ .always_use_100={on, 12, 12, end},
++ .edge_detection={on, 10, 12, end},
++ .m={on, 13, 1, 14, 1, end}
++},
++{ .name="courier",
++ .always_use_100={on, 0, maxp, end},
++ .m={on, 13, 1, 14, 1, end},
++ .stem_translating_only={on, 13, 16, 15, 0, end}
++},
++{ .name="cousine",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="dejavu sans mono",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end}
++},
++{ .name="dejavu sans",
++ .always_use_100={on, 10, 14, 16, 17, end},
++ .m={on, 12, 0, end},
++ .stem_scaling={on, 12, 1, end},
++ .stem_translating_only={on, 8, 16, 15, -20, end}
++},
++{ .name="droid sans mono",
++ .m={on, 12, 0, end}
++},
++{ .name="droid sans",
++ .always_use_100={on, 12, 12, 15, 15, end},
++ .stem_translating_only={on, 8, 16, 9, 16, end}
++},
++{ .name="essential pragmatapro",
++ .always_use_100={on, 0, maxp, end},
++ .m={on, 13, 0, 14, 0, end}
++},
++{ .name="freemono",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="freesans",
++ .always_use_100={on, 0, maxp, end},
++ .edge_detection={on, 11, 11, 13, 13, end},
++ .spacing={on, 10, 12, 18, 18, 30, end},
++ .start={on, 10, 18, 18, 25, 30, end},
++ .stem_scaling={on, 16, 0, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 16, 9, 8, end}
++},
++{ .name="freeserif",
++ .stem_scaling={on, 13, 1, 17, 1, end}
++},
++{ .name="futura",
++ .stem_widths={on, 10, 14, sw2pv, maxp,}
++},
++{ .name="garamond",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end}
++},
++{ .name="georgia",
++ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end}
++},
++{ .name="gill sans",
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++{ .name="helvetica cy",
++ .stem_widths={on, 10, 23, maxp,}
++},
++{ .name="inconsolata",
++ .stem_scaling={on, 12, 1, 15, 1, end},
++ .stem_translating_only={on, 10, 24, 9, 32, end},
++ .stem_widths={on, 10, 23, maxp,},
++},
++{ .name="liberation mono",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="liberation sans narrow",
++ .stem_widths={on,10, 22, maxp,}
++},
++{ .name="liberation sans",
++ .edge_detection={on, 11, 11, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end},
++ .stem_widths={on,10, 19, maxp,}
++},
++{ .name="lucida console",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="lucida grande",
++ .stem_scaling={on, 13, 1, end},
++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
++ .stem_widths={on, 10, 16, sw2pv, maxp},
++},
++{ .name="lucida sans unicode",
++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
++ .stem_widths={on,10, 16, sw2pv, maxp,}
++},
++{ .name="luxi sans",
++ .always_use_100={on, 13, 13, end},
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++{ .name="microsoft sans serif",
++ .always_use_100={on, 0, maxp, end},
++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
++},
++{ .name="monaco",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="myriad pro",
++ .stem_scaling={on, 14, 1, 17, 1, end},
++ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end}
++},
++{ .name="nina",
++ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end}
++},
++{ .name="open sans",
++ .stem_translating_only={on, 10, 16, 9, 16, end},
++ .stem_widths={on, 10, 20, maxp,}
++},
++{ .name="optima",
++ .brightness={on, 0, -20, end},
++ .contrast={on, 0, 25, end},
++ .stem_scaling={on, 17, 1, end},
++ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end}
++},
++{ .name="palatino linotype",
++ .edge_detection={on, 0, 100, end}
++},
++{ .name="pragmata",
++ .always_use_100={on, 0, maxp, end}
++},
++{ .name="raleway",
++ .stem_scaling={on, 15, 0, end}
++},
++{ .name="rokkitt",
++ .stem_widths={on, 10, 21, maxp,}
++},
++{ .name="samba",
++ .stem_scaling={on, 11, 0, end}
++},
++{ .name="segoe ui",
++ .always_use_100={on, 11, 12, 14, 14, end},
++ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end},
++ .stem_widths={on, 10, 23, maxp,}
++},
++{ .name="tahoma",
++ .always_use_100={on, 11, 11, 14, maxp, end},
++ .edge_detection={on, 11, 11, end},
++ .spacing={on, 10, 12, 18, 18, 30, end},
++ .start={on, 14, 17, 30, 100, 100, end},
++ .stem_translating={on, 11, 32, end},
++ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end},
++},
++{ .name="times new roman",
++ .always_use_100={on, 14, 14, 16, 16, end},
++ .bearing_correction={0, 100, end},
++ .stem_scaling={on, 17, 1, end},
++ .stem_translating_only={on, 17, 8, end}
++},
++{ .name="trebuchet ms",
++ .always_use_100={on, 13, 13, end},
++ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end},
++ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end},
++ .stem_widths={on, 10, 17, sw2pv, maxp,}
++},
++{ .name="ubuntu",
++ .always_use_100={on, 12, 13, 15, 15, end}
++},
++{ .name="verdana",
++ .always_use_100={on, 0, 14, 16, maxp, end},
++ .stem_scaling={on, 12, 1, 15, 1, end},
++ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end}
++},
++%%
++
++static const sa_rules_t*
++ftinf_rules( const char *name ){
++ if( name ){
++ enum {
++ max_wlen=31
++ };
++ char buf[max_wlen+1];
++ int len=strlen( name );
++ if( len <= max_wlen ){
++ int i;
++ for( i=0; i<len; ++i )
++ buf[i]=tolower( name[i] );
++ buf[len]='\0';
++ return _rules_get( buf, len );
++ }
++ }
++ return NULL;
++}
++/*
++ gperf --output-file=ftinf_rh.c ftinf_rh.gperf
++*/
+diff --git a/src/base/ftinf_sh.c b/src/base/ftinf_sh.c
+new file mode 100644
+index 000000000..87d2ff8bd
+--- /dev/null
++++ b/src/base/ftinf_sh.c
+@@ -0,0 +1,463 @@
++/* ANSI-C code produced by gperf version 3.1 */
++/* Command-line: gperf --output-file=ftinf_sh.c ftinf_sh.gperf */
++/* Computed positions: -k'1,$' */
++
++#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
++ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
++ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
++ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
++ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
++ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
++ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
++ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
++ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
++ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
++ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
++ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
++ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
++ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
++ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
++ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
++ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
++ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
++ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
++ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
++ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
++ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
++ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
++/* The character set is not based on ISO-646. */
++#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
++#endif
++
++#line 9 "ftinf_sh.gperf"
++
++#include <ctype.h>
++static const struct ftinf_s* _settings_get( const char*str, unsigned len);
++/* maximum key range = 37, duplicates = 0 */
++
++#ifdef __GNUC__
++__inline
++#else
++#ifdef __cplusplus
++inline
++#endif
++#endif
++static unsigned int
++_settings_hash (register const char *str, register unsigned int len)
++{
++ static const unsigned char asso_values[] =
++ {
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 13,
++ 8, 30, 25, 20, 40, 10, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 5, 40, 0,
++ 0, 0, 40, 40, 10, 0, 40, 40, 15, 5,
++ 10, 0, 10, 40, 40, 0, 0, 0, 0, 0,
++ 0, 0, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40
++ };
++ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
++}
++
++#ifdef __GNUC__
++__inline
++#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
++__attribute__ ((__gnu_inline__))
++#endif
++#endif
++const struct ftinf_s *
++_settings_get (register const char *str, register unsigned int len)
++{
++ enum
++ {
++ TOTAL_KEYWORDS = 22,
++ MIN_WORD_LENGTH = 3,
++ MAX_WORD_LENGTH = 14,
++ MIN_HASH_VALUE = 3,
++ MAX_HASH_VALUE = 39
++ };
++
++ static const struct ftinf_s wordlist[] =
++ {
++#line 76 "ftinf_sh.gperf"
++{ .name="osx",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .bold_embolden_x_value=16,
++ .brightness=10,
++ .contrast=20,
++ .filter_params={on, 3, 32, 38, 32, 3},
++ .gamma_correction={1000, 80},
++ .global_embolden_y_value=8,
++ .grayscale_filter_strength=25,
++},
++#line 37 "ftinf_sh.gperf"
++{ .name="ipad",
++ .filter_params={on, 0, 0, 100, 0, 0},
++ .gamma_correction={1000, 80},
++ .grayscale_filter_strength=100
++},
++#line 114 "ftinf_sh.gperf"
++{ .name="shove",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=100,
++ .stem_fitting_strength=100,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++#line 126 "ftinf_sh.gperf"
++{ .name="ubuntu",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=-10,
++ .contrast=15,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={1000, 80},
++ .use_various_tweaks=true
++},
++#line 27 "ftinf_sh.gperf"
++{ .name="classic",
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .filter_params={on, 6, 25, 38, 25, 6},
++ .gamma_correction={0, 100},
++ .use_various_tweaks=true
++},
++#line 34 "ftinf_sh.gperf"
++{ .name="disabled",
++ .gamma_correction={0, 100},
++},
++#line 100 "ftinf_sh.gperf"
++{ .name="sharpened",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=25,
++ .stem_snapping_sliding_scale=40,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++#line 42 "ftinf_sh.gperf"
++{ .name="infinality",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=25,
++ .stem_snapping_sliding_scale=40,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=5
++},
++#line 15 "ftinf_sh.gperf"
++{ .name="custom",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 8, 24, 48, 24, 8},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=75,
++ .stem_fitting_strength=50,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++#line 180 "ftinf_sh.gperf"
++{ .name="vanilla",
++ .filter_params={on, 6, 25, 38, 25, 6},
++ .gamma_correction={0, 100},
++},
++#line 184 "ftinf_sh.gperf"
++{ .name="windows7light",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .contrast=20,
++ .filter_params={on, 20, 25, 38, 25, 05},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 160},
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=100
++},
++#line 226 "ftinf_sh.gperf"
++{ .name="windowsxplight",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=20,
++ .contrast=30,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 120},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++#line 64 "ftinf_sh.gperf"
++{ .name="nudge",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_various_tweaks=true,
++},
++#line 144 "ftinf_sh.gperf"
++{ .name="ultimate2",
++ .filter_params={on, 6, 22, 36, 22, 6},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++#line 197 "ftinf_sh.gperf"
++{ .name="windows7",
++ .filter_params={on, 20, 25, 42, 25, 06},
++ .fringe_filter_strength=100,
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .windows_style_sharpening_strength=65,
++ .gamma_correction={1000, 120},
++ .brightness=10,
++ .contrast=20,
++ .use_various_tweaks=true,
++ .autohint_snap_stem_height=100,
++ .use_known_settings_on_selected_fonts=true,
++},
++#line 210 "ftinf_sh.gperf"
++{ .name="windowsxp",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=10,
++ .contrast=20,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 120},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++#line 56 "ftinf_sh.gperf"
++{ .name="linux",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .gamma_correction={0, 100},
++ .use_various_tweaks=true
++},
++#line 135 "ftinf_sh.gperf"
++{ .name="ultimate1",
++ .filter_params={on, 4, 22, 38, 22, 4},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++#line 87 "ftinf_sh.gperf"
++{ .name="push",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=75,
++ .stem_fitting_strength=50,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++#line 171 "ftinf_sh.gperf"
++{ .name="ultimate5",
++ .filter_params={on, 12, 28, 42, 28, 12},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++#line 162 "ftinf_sh.gperf"
++{ .name="ultimate4",
++ .filter_params={on, 10, 25, 37, 25, 10},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++#line 153 "ftinf_sh.gperf"
++{ .name="ultimate3",
++ .filter_params={on, 8, 24, 36, 24, 8},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++}
++ };
++
++ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
++ {
++ register int key = _settings_hash (str, len);
++
++ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
++ {
++ register const struct ftinf_s *resword;
++
++ switch (key - 3)
++ {
++ case 0:
++ resword = &wordlist[0];
++ goto compare;
++ case 1:
++ resword = &wordlist[1];
++ goto compare;
++ case 2:
++ resword = &wordlist[2];
++ goto compare;
++ case 3:
++ resword = &wordlist[3];
++ goto compare;
++ case 4:
++ resword = &wordlist[4];
++ goto compare;
++ case 5:
++ resword = &wordlist[5];
++ goto compare;
++ case 6:
++ resword = &wordlist[6];
++ goto compare;
++ case 7:
++ resword = &wordlist[7];
++ goto compare;
++ case 8:
++ resword = &wordlist[8];
++ goto compare;
++ case 9:
++ resword = &wordlist[9];
++ goto compare;
++ case 10:
++ resword = &wordlist[10];
++ goto compare;
++ case 11:
++ resword = &wordlist[11];
++ goto compare;
++ case 12:
++ resword = &wordlist[12];
++ goto compare;
++ case 14:
++ resword = &wordlist[13];
++ goto compare;
++ case 15:
++ resword = &wordlist[14];
++ goto compare;
++ case 16:
++ resword = &wordlist[15];
++ goto compare;
++ case 17:
++ resword = &wordlist[16];
++ goto compare;
++ case 19:
++ resword = &wordlist[17];
++ goto compare;
++ case 21:
++ resword = &wordlist[18];
++ goto compare;
++ case 26:
++ resword = &wordlist[19];
++ goto compare;
++ case 31:
++ resword = &wordlist[20];
++ goto compare;
++ case 36:
++ resword = &wordlist[21];
++ goto compare;
++ }
++ return 0;
++ compare:
++ {
++ register const char *s = resword->name;
++
++ if (*str == *s && !strcmp (str + 1, s + 1))
++ return resword;
++ }
++ }
++ }
++ return 0;
++}
++#line 242 "ftinf_sh.gperf"
++
++
++static const ftinf_t*
++ftinf_settings( const char *name ){
++ if( name ){
++ enum {
++ max_wlen=31
++ };
++ char buf[max_wlen+1];
++ int len=strlen( name );
++ if( len <= max_wlen ){
++ int i;
++ for( i=0; i<len; ++i )
++ buf[i]=tolower( name[i] );
++ buf[len]='\0';
++ return _settings_get( buf, len );
++ }
++ }
++ return NULL;
++}
++/*
++ gperf --output-file=ftinf_sh.c ftinf_sh.gperf
++*/
+diff --git a/src/base/ftinf_sh.gperf b/src/base/ftinf_sh.gperf
+new file mode 100644
+index 000000000..5f6e0ae62
+--- /dev/null
++++ b/src/base/ftinf_sh.gperf
+@@ -0,0 +1,264 @@
++%struct-type
++%define slot-name name
++%enum
++%switch=1
++%readonly-tables
++%omit-struct-type
++%define lookup-function-name _settings_get
++%define hash-function-name _settings_hash
++%{
++#include <ctype.h>
++static const struct ftinf_s* _settings_get( const char*str, unsigned len);
++%}
++struct ftinf_s;
++%%
++{ .name="custom",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 8, 24, 48, 24, 8},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=75,
++ .stem_fitting_strength=50,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++{ .name="classic",
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .filter_params={on, 6, 25, 38, 25, 6},
++ .gamma_correction={0, 100},
++ .use_various_tweaks=true
++},
++{ .name="disabled",
++ .gamma_correction={0, 100},
++},
++{ .name="ipad",
++ .filter_params={on, 0, 0, 100, 0, 0},
++ .gamma_correction={1000, 80},
++ .grayscale_filter_strength=100
++},
++{ .name="infinality",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=25,
++ .stem_snapping_sliding_scale=40,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=5
++},
++{ .name="linux",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .gamma_correction={0, 100},
++ .use_various_tweaks=true
++},
++{ .name="nudge",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_various_tweaks=true,
++},
++{ .name="osx",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .bold_embolden_x_value=16,
++ .brightness=10,
++ .contrast=20,
++ .filter_params={on, 3, 32, 38, 32, 3},
++ .gamma_correction={1000, 80},
++ .global_embolden_y_value=8,
++ .grayscale_filter_strength=25,
++},
++{ .name="push",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=75,
++ .stem_fitting_strength=50,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++{ .name="sharpened",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=25,
++ .stem_fitting_strength=25,
++ .stem_snapping_sliding_scale=40,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++{ .name="shove",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_increase_glyph_heights=true,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=100,
++ .stem_fitting_strength=100,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true
++},
++{ .name="ubuntu",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=-10,
++ .contrast=15,
++ .filter_params={on, 11, 22, 38, 22, 11},
++ .gamma_correction={1000, 80},
++ .use_various_tweaks=true
++},
++{ .name="ultimate1",
++ .filter_params={on, 4, 22, 38, 22, 4},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++{ .name="ultimate2",
++ .filter_params={on, 6, 22, 36, 22, 6},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++{ .name="ultimate3",
++ .filter_params={on, 8, 24, 36, 24, 8},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++{ .name="ultimate4",
++ .filter_params={on, 10, 25, 37, 25, 10},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++{ .name="ultimate5",
++ .filter_params={on, 12, 28, 42, 28, 12},
++ .fringe_filter_strength=25,
++ .gamma_correction={0, 100},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=25
++},
++{ .name="vanilla",
++ .filter_params={on, 6, 25, 38, 25, 6},
++ .gamma_correction={0, 100},
++},
++{ .name="windows7light",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .contrast=20,
++ .filter_params={on, 20, 25, 38, 25, 05},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 160},
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=100
++},
++{ .name="windows7",
++ .filter_params={on, 20, 25, 42, 25, 06},
++ .fringe_filter_strength=100,
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_vertical_stem_darken_strength=25,
++ .windows_style_sharpening_strength=65,
++ .gamma_correction={1000, 120},
++ .brightness=10,
++ .contrast=20,
++ .use_various_tweaks=true,
++ .autohint_snap_stem_height=100,
++ .use_known_settings_on_selected_fonts=true,
++},
++{ .name="windowsxp",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=10,
++ .contrast=20,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 120},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++{ .name="windowsxplight",
++ .autohint_horizontal_stem_darken_strength=10,
++ .autohint_snap_stem_height=100,
++ .autohint_vertical_stem_darken_strength=25,
++ .brightness=20,
++ .contrast=30,
++ .filter_params={on, 6, 25, 44, 25, 6},
++ .fringe_filter_strength=100,
++ .gamma_correction={1000, 120},
++ .stem_alignment_strength=15,
++ .stem_fitting_strength=15,
++ .stem_snapping_sliding_scale=30,
++ .use_known_settings_on_selected_fonts=true,
++ .use_various_tweaks=true,
++ .windows_style_sharpening_strength=65
++},
++%%
++
++static const ftinf_t*
++ftinf_settings( const char *name ){
++ if( name ){
++ enum {
++ max_wlen=31
++ };
++ char buf[max_wlen+1];
++ int len=strlen( name );
++ if( len <= max_wlen ){
++ int i;
++ for( i=0; i<len; ++i )
++ buf[i]=tolower( name[i] );
++ buf[len]='\0';
++ return _settings_get( buf, len );
++ }
++ }
++ return NULL;
++}
++/*
++ gperf --output-file=ftinf_sh.c ftinf_sh.gperf
++*/
+diff --git a/src/base/ftinit.c b/src/base/ftinit.c
+index 9d524effa..5332fd958 100644
+--- a/src/base/ftinit.c
++++ b/src/base/ftinit.c
+@@ -43,6 +43,10 @@
+ #include FT_INTERNAL_DEBUG_H
+ #include FT_MODULE_H
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "ftinf.h"
++#endif
++
+
+ /**************************************************************************
+ *
+@@ -217,10 +221,14 @@
+ error = FT_New_Library( memory, alibrary );
+ if ( error )
+ FT_Done_Memory( memory );
+- else
++ else {
+ FT_Add_Default_Modules( *alibrary );
+-
+- FT_Set_Default_Properties( *alibrary );
++ FT_Set_Default_Properties( *alibrary );
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* get Infinality settings */
++ ftinf_env();
++#endif
++ }
+
+ return error;
+ }
+diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
+index 9fb49ba11..e03fbc081 100644
+--- a/src/base/ftlcdfil.c
++++ b/src/base/ftlcdfil.c
+@@ -22,7 +22,10 @@
+ #include FT_LCD_FILTER_H
+ #include FT_IMAGE_H
+ #include FT_INTERNAL_OBJECTS_H
+-
++#include <math.h>
++#include <string.h>
++#include <strings.h>
++#include "ftinf.h"
+
+ #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+@@ -299,6 +302,7 @@
+
+ ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
+ library->lcd_filter_func = ft_lcd_filter_fir;
++ library->lcd_extra = 2;
+
+ return FT_Err_Ok;
+ }
+@@ -310,11 +314,37 @@
+ FT_Library_SetLcdFilter( FT_Library library,
+ FT_LcdFilter filter )
+ {
+- static const FT_LcdFiveTapFilter default_weights =
+- { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
+ static const FT_LcdFiveTapFilter light_weights =
+ { 0x00, 0x55, 0x56, 0x55, 0x00 };
+
++#ifndef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ static const FT_LcdFiveTapFilter default_weights =
++ { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
++#else
++ FT_LcdFiveTapFilter default_weights;
++ if( ftinf && ftinf->filter_params[0] )
++ {
++ const int *f=ftinf->filter_params;
++ /* Assume we were given integers [0-100] get them to [0-255] */
++ int val; /* 2611=2.55*1024 */
++ val=(f[1]*2611+512)>>10; if( val > 255 ) val=255;
++ default_weights[0] = (FT_Byte) val;
++ val=(f[2]*2611+512)>>10; if( val > 255 ) val=255;
++ default_weights[1] = (FT_Byte) val;
++ val=(f[3]*2611+512)>>10; if( val > 255 ) val=255;
++ default_weights[2] = (FT_Byte) val;
++ val=(f[4]*2611+512)>>10; if( val > 255 ) val=255;
++ default_weights[3] = (FT_Byte) val;
++ val=(f[5]*2611+512)>>10; if( val > 255 ) val=255;
++ default_weights[4] = (FT_Byte) val;
++ } else {
++ default_weights[0]=0x08;
++ default_weights[1]=0x4d;
++ default_weights[2]=0x56;
++ default_weights[3]=0x4d;
++ default_weights[4]=0x08;
++ }
++#endif
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+@@ -323,6 +353,7 @@
+ {
+ case FT_LCD_FILTER_NONE:
+ library->lcd_filter_func = NULL;
++ library->lcd_extra = 0;
+ break;
+
+ case FT_LCD_FILTER_DEFAULT:
+@@ -330,6 +361,7 @@
+ default_weights,
+ FT_LCD_FILTER_FIVE_TAPS );
+ library->lcd_filter_func = ft_lcd_filter_fir;
++ library->lcd_extra = 2;
+ break;
+
+ case FT_LCD_FILTER_LIGHT:
+@@ -337,6 +369,7 @@
+ light_weights,
+ FT_LCD_FILTER_FIVE_TAPS );
+ library->lcd_filter_func = ft_lcd_filter_fir;
++ library->lcd_extra = 2;
+ break;
+
+ #ifdef USE_LEGACY
+@@ -344,6 +377,7 @@
+ case FT_LCD_FILTER_LEGACY:
+ case FT_LCD_FILTER_LEGACY1:
+ library->lcd_filter_func = _ft_lcd_filter_legacy;
++ library->lcd_extra = 0;
+ break;
+
+ #endif
+diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
+index 3f8619d3b..d8fd36c81 100644
+--- a/src/base/ftobjs.c
++++ b/src/base/ftobjs.c
+@@ -46,7 +46,9 @@
+ #ifdef FT_CONFIG_OPTION_MAC_FONTS
+ #include "ftbase.h"
+ #endif
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "ftinf.h"
++#endif
+
+ #ifdef FT_DEBUG_LEVEL_TRACE
+
+@@ -96,6 +98,11 @@
+
+ #define GRID_FIT_METRICS
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include <strings.h>
++#include <stdlib.h>
++#include "../autofit/aflatin.h"
++#endif
+
+ /* forward declaration */
+ static FT_Error
+@@ -739,6 +746,25 @@
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot );
+
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ static void
++ ft_glyphslot_enlarge_metrics( FT_GlyphSlot slot,
++ FT_Render_Mode mode )
++ {
++ FT_Glyph_Metrics* metrics = &slot->metrics;
++ FT_Pos enlarge_cbox = 0;
++
++
++ /* enlarge for grayscale rendering */
++ if ( mode == FT_RENDER_MODE_NORMAL )
++ enlarge_cbox = 64;
++
++ metrics->horiBearingX -= enlarge_cbox;
++ metrics->width += 2 * enlarge_cbox;
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
++
++
+ #ifdef GRID_FIT_METRICS
+ static void
+ ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot,
+@@ -805,8 +831,18 @@
+ FT_Bool autohint = FALSE;
+ FT_Module hinter;
+ TT_Face ttface = (TT_Face)face;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+
++ FT_Bool use_various_tweaks = FALSE;
++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
+
++ /* Force autohint if no tt instructions */
++ /* NOTE: NEEDS TO BE RUN LATER IN CODE???? */
++ /*if ( use_various_tweaks &&
++ ttface->num_locations &&
++ ttface->max_profile.maxSizeOfInstructions == 0 )
++ load_flags |= FT_LOAD_FORCE_AUTOHINT;*/
++#endif
+ if ( !face || !face->size || !face->glyph )
+ return FT_THROW( Invalid_Face_Handle );
+
+@@ -908,6 +944,18 @@
+ {
+ FT_AutoHinter_Interface hinting;
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( use_various_tweaks )
++ {
++ /* Force slight hinting over full hinting always */
++ load_flags &= ~FT_LOAD_TARGET_LCD;
++ load_flags &= ~FT_LOAD_TARGET_LCD_V;
++ load_flags &= ~FT_LOAD_TARGET_MONO;
++ load_flags &= ~FT_LOAD_TARGET_NORMAL;
++ load_flags |= FT_LOAD_TARGET_LIGHT;
++ /*printf("%d ", load_flags);*/
++ }
++#endif
+
+ /* try to load embedded bitmaps first if available */
+ /* */
+@@ -953,6 +1001,18 @@
+ if ( error )
+ goto Exit;
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ infinality_cur_width = 0;
++
++ {
++ /* fix for sdl_ttf */
++ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
++
++ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
++ ft_glyphslot_enlarge_metrics( slot, mode );
++ }
++#endif
++
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* check that the loaded outline is correct */
+@@ -5292,6 +5352,11 @@
+ /* That's ok now */
+ *alibrary = library;
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* get Infinality settings */
++ ftinf_env();
++#endif
++
+ return FT_Err_Ok;
+ }
+
+diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
+index 00329b46c..fcf45d58f 100644
+--- a/src/base/ftoutln.c
++++ b/src/base/ftoutln.c
+@@ -22,7 +22,9 @@
+ #include FT_INTERNAL_CALC_H
+ #include FT_INTERNAL_DEBUG_H
+ #include FT_TRIGONOMETRY_H
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "ftinf.h"
++#endif
+
+ /**************************************************************************
+ *
+@@ -897,10 +899,16 @@
+ FT_Pos xstrength,
+ FT_Pos ystrength )
+ {
+- FT_Vector* points;
+- FT_Int c, first, last;
+- FT_Orientation orientation;
+-
++ FT_Vector* points;
++ FT_Int c, first, last;
++ FT_Int orientation;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Bool use_various_tweaks = FALSE;
++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
++
++ if ( use_various_tweaks )
++ ystrength = FT_PIX_FLOOR ( ystrength );
++#endif
+
+ if ( !outline )
+ return FT_THROW( Invalid_Outline );
+diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c
+index f87ed65e7..620d57f07 100644
+--- a/src/base/ftsynth.c
++++ b/src/base/ftsynth.c
+@@ -22,7 +22,9 @@
+ #include FT_INTERNAL_OBJECTS_H
+ #include FT_OUTLINE_H
+ #include FT_BITMAP_H
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "ftinf.h"
++#endif
+
+ /**************************************************************************
+ *
+@@ -93,7 +95,10 @@
+ FT_Face face;
+ FT_Error error;
+ FT_Pos xstr, ystr;
+-
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Bool use_various_tweaks = FALSE;
++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
++#endif
+
+ if ( !slot )
+ return;
+@@ -111,8 +116,16 @@
+ ystr = xstr;
+
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
++ {
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( use_various_tweaks )
++ (void)FT_Outline_EmboldenXY( &slot->outline,
++ xstr,
++ FT_PIX_FLOOR( ystr ) );
++ else
++#endif
+ FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
+-
++ }
+ else /* slot->format == FT_GLYPH_FORMAT_BITMAP */
+ {
+ /* round to full pixels */
+@@ -150,6 +163,9 @@
+
+ slot->metrics.width += xstr;
+ slot->metrics.height += ystr;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( !use_various_tweaks )
++#endif
+ slot->metrics.horiAdvance += xstr;
+ slot->metrics.vertAdvance += ystr;
+ slot->metrics.horiBearingY += ystr;
+diff --git a/src/base/rules.mk b/src/base/rules.mk
+index 4b24c6dce..b8771b9ca 100644
+--- a/src/base/rules.mk
++++ b/src/base/rules.mk
+@@ -44,6 +44,7 @@ BASE_SRC := $(BASE_DIR)/ftadvanc.c \
+ $(BASE_DIR)/ftfntfmt.c \
+ $(BASE_DIR)/ftgloadr.c \
+ $(BASE_DIR)/fthash.c \
++ $(BASE_DIR)/ftinf.c \
+ $(BASE_DIR)/ftlcdfil.c \
+ $(BASE_DIR)/ftobjs.c \
+ $(BASE_DIR)/ftoutln.c \
+diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c
+index 1a1030c06..fd368a539 100644
+--- a/src/cff/cffobjs.c
++++ b/src/cff/cffobjs.c
+@@ -43,6 +43,9 @@
+ #include FT_INTERNAL_POSTSCRIPT_AUX_H
+ #include FT_SERVICE_CFF_TABLE_LOAD_H
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include "../base/ftinf.h"
++#endif
+
+ /**************************************************************************
+ *
+@@ -1170,6 +1173,9 @@
+ #endif
+
+ driver->no_stem_darkening = TRUE;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if(ftinf) driver->no_stem_darkening = !ftinf->stem_darkening_cff;
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+ driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
+ driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
+diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
+index c8b6bb751..e82c15c25 100644
+--- a/src/smooth/ftsmooth.c
++++ b/src/smooth/ftsmooth.c
+@@ -1,19 +1,19 @@
+-/****************************************************************************
+- *
+- * ftsmooth.c
+- *
+- * Anti-aliasing renderer interface (body).
+- *
+- * Copyright (C) 2000-2019 by
+- * David Turner, Robert Wilhelm, and Werner Lemberg.
+- *
+- * This file is part of the FreeType project, and may only be used,
+- * modified, and distributed under the terms of the FreeType project
+- * license, LICENSE.TXT. By continuing to use, modify, or distribute
+- * this file you indicate that you have read the license and
+- * understand and accept it fully.
+- *
+- */
++/***************************************************************************/
++/* */
++/* ftsmooth.c */
++/* */
++/* Anti-aliasing renderer interface (body). */
++/* */
++/* Copyright 2000-2017 by */
++/* David Turner, Robert Wilhelm, and Werner Lemberg. */
++/* */
++/* This file is part of the FreeType project, and may only be used, */
++/* modified, and distributed under the terms of the FreeType project */
++/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
++/* this file you indicate that you have read the license and */
++/* understand and accept it fully. */
++/* */
++/***************************************************************************/
+
+
+ #include <ft2build.h>
+@@ -25,88 +25,2293 @@
+
+ #include "ftsmerrs.h"
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include <math.h>
++#include FT_BITMAP_H
++#include <string.h>
++#include <strings.h>
++#include FT_OUTLINE_H
++#include "../base/ftinf.h"
++
++#define verbose FALSE
++#define STVALUES if (verbose) \
++ printf ( "scale:%f translate:%ld ", *scale_value, *translate_value );
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+ ft_smooth_init( FT_Renderer render )
+ {
++ render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
++
++ return 0;
++ }
++
++
++ /* sets render-specific mode */
++ static FT_Error
++ ft_smooth_set_mode( FT_Renderer render,
++ FT_ULong mode_tag,
++ FT_Pointer data )
++ {
++ /* we simply pass it to the raster */
++ return render->clazz->raster_class->raster_set_mode( render->raster,
++ mode_tag,
++ data );
++ }
++
++ /* transform a given glyph image */
++ static FT_Error
++ ft_smooth_transform( FT_Renderer render,
++ FT_GlyphSlot slot,
++ const FT_Matrix* matrix,
++ const FT_Vector* delta )
++ {
++ FT_Error error = FT_Err_Ok;
++
++
++ if ( slot->format != render->glyph_format )
++ {
++ error = FT_THROW( Invalid_Argument );
++ goto Exit;
++ }
++
++ if ( matrix )
++ FT_Outline_Transform( &slot->outline, matrix );
++
++ if ( delta )
++ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
++
++ Exit:
++ return error;
++ }
++
++
++ /* return the glyph's control box */
++ static void
++ ft_smooth_get_cbox( FT_Renderer render,
++ FT_GlyphSlot slot,
++ FT_BBox* cbox )
++ {
++ FT_ZERO( cbox );
++
++ if ( slot->format == render->glyph_format )
++ FT_Outline_Get_CBox( &slot->outline, cbox );
++ }
++
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ static FT_Fixed FT_FixedFromFloat(float f)
++ {
++ short value = f;
++ unsigned short fract = (f - value) * 0xFFFF;
++
++
++ return (FT_Fixed)((long)value << 16 | (unsigned long)fract );
++ }
++
++
++ /* ChromeOS sharpening algorithm */
++ /* soften the sub-pixel anti-aliasing and sharpen */
++ static void
++ _ft_lcd_chromeos_sharpen( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_Byte cutoff,
++ double gamma_value )
++ {
++ static FT_Bool initialized_gamma = FALSE;
++ static unsigned short gamma_ramp[256];
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ int ii;
++
++ if ( !initialized_gamma )
++ {
++ initialized_gamma = TRUE;
++ /* linear to voltage */
++ for ( ii = 0; ii < 256; ii++ )
++ {
++ gamma_ramp[ii] = (unsigned char)
++ ( pow( (double)ii / 255.0, gamma_value ) * 255.0f );
++ if ( gamma_ramp[ii] < cutoff )
++ gamma_ramp[ii] = 0;
++ }
++ }
++
++ /* horizontal in-place sub-pixel sharpening filter */
++ if ( mode == FT_RENDER_MODE_LCD )
++ {
++ FT_Byte* line = bitmap->buffer;
++
++
++ for ( ; height > 0; height--, line += bitmap->pitch )
++ {
++ FT_UInt xx;
++
++
++ for ( xx = 0; xx < width; xx++ )
++ line[xx] = gamma_ramp[line[xx]];
++ }
++ }
++ }
++
++ /* simple linear scale to handle various sliding values */
++ float
++ sliding_scale ( int min_value,
++ int max_value,
++ float min_amount,
++ float max_amount,
++ int cur_value )
++ {
++
++ float m = ( min_amount - max_amount ) / (float)( min_value - max_value );
++ float result = ( ( (float)cur_value * m) + ( max_amount - max_value * m ) ) ;
++
++ if ( min_amount < max_amount )
++ {
++ if ( result < min_amount )
++ return min_amount;
++ if ( result > max_amount )
++ return max_amount;
++ }
++ else
++ {
++ if ( result < max_amount )
++ return max_amount;
++ if ( result > min_amount )
++ return min_amount;
++ }
++
++ return result;
++ }
++
++
++ /* brightness and contrast adjustment on the bitmap */
++ static FT_Bool
++ _ft_bitmap_bc ( FT_Bitmap* bitmap,
++ float brightness,
++ float contrast )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* line = bitmap->buffer;
++ FT_UInt xx;
++
++
++ if ( brightness == 0 && contrast == 0 )
++ return FALSE;
++
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch )
++ {
++ for ( xx = 0; xx < width - 1; xx += 1 )
++ {
++ if ( line[xx] > 0)
++ {
++ float value = (float)( 255 - line[xx] ) / 256.0;
++ FT_Int result = 0;
++
++ if ( brightness < 0.0 )
++ value = value * ( 1.0 + brightness );
++ else
++ value = value + ( ( 1.0 - value ) * brightness );
++
++ value = ( value - 0.5 ) *
++ ( tan ( ( contrast + 1.0 ) * 3.141592/4.0 ) ) + 0.5;
++
++ result = (FT_Int)( 255.0 - value * 256.0 );
++
++ if ( result < 0 )
++ result = 0;
++ if ( result > 255 )
++ result = 255;
++
++ line[xx] = result;
++ }
++ }
++ }
++ return TRUE;
++ }
++
++
++ /* Filter to mimic Windows-style sharpening */
++ /* Determined via 100% experimentation. */
++ static void
++ _ft_lcd_windows_sharpen( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_Bitmap new_bitmap;
++
++
++ FT_Bitmap_Init( &new_bitmap );
++ FT_Bitmap_Copy( library, bitmap, &new_bitmap );
++ new_line = (&new_bitmap)->buffer;
++
++ if (strength > 0)
++ for (height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ FT_UInt xx, threshold = 128;
++ FT_Byte* prevline = line - bitmap->pitch;
++ FT_Byte* nextline = line + bitmap->pitch;
++ FT_Byte* new_prevline = new_line - bitmap->pitch;
++ FT_Byte* new_nextline = new_line + bitmap->pitch;
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ /* subpixel grid sp11 sp21 sp31 */
++ /* where sp22 is sp12 sp22 sp32 */
++ /* current subpixel. sp13 sp23 sp33 */
++
++ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
++ prevdiff, nextdiff, sp11, sp21, sp31, sp12, sp22, sp32,
++ sp13, sp23, sp33;
++
++ sp12 = line [xx-1];
++ sp22 = line [xx];
++ sp32 = line [xx+1];
++
++ if ( height == bitmap->rows )
++ {
++ prevtotal = sp11 = sp21 = sp31 = 0;
++ prevdiff = sp22;
++ lefttotal = sp12 + sp13;
++ righttotal = sp32 + sp33;
++ }
++ else
++ {
++ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
++ sp11 = prevline [xx-1];
++ sp21 = prevline [xx];
++ sp31 = prevline [xx+1];
++ prevdiff = sp22 - sp21;
++ lefttotal = sp11 + sp12 + sp13;
++ righttotal = sp31 + sp32 + sp33;
++ }
++
++ if ( height == 1 )
++ {
++ nexttotal = sp13 = sp23 = sp33 = 0;
++ nextdiff = sp22;
++ lefttotal = sp11 + sp12;
++ righttotal = sp31 + sp32;
++ }
++ else
++ {
++ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
++ sp13 = nextline [xx-1];
++ sp23 = nextline [xx];
++ sp33 = nextline [xx+1];
++ nextdiff = sp23 - sp22;
++ lefttotal = sp11 + sp12 + sp13;
++ righttotal = sp31 + sp32 + sp33;
++ }
++
++ sidesdiff = lefttotal - righttotal;
++
++ if ( sidesdiff < 0 )
++ sidesdiff *= -1;
++
++ if ( prevdiff < 0 )
++ prevdiff *= -1;
++
++ if ( nextdiff < 0 )
++ nextdiff *= -1;
++
++ /* if the current pixel is less than threshold, and greater than 0 */
++ if ( sp22 <= threshold && sp22 > 0 )
++ {
++ /* A pixel is horizontally isolated if: */
++ /* 1: All upper adjecent pixels are >= threshold */
++ if ( prevtotal >= nexttotal &&
++ abs( sp11 - sp12 ) > 5 &&
++ abs( sp21 - sp22 ) > 5 &&
++ abs( sp31 - sp32 ) > 5 && /* not a vert stem end */
++ sp11 >= threshold &&
++ sp21 >= threshold &&
++ sp31 >= threshold &&
++ abs( sp23 - sp22 ) > 15 ) /* not on a vert stem */
++ {
++ /* darken upper adjacent subpixel; lighten current */
++ if ( height != (FT_UInt)bitmap->rows )
++ new_prevline[xx] += ( ( 255 - new_prevline[xx] )
++ * strength ) / 100 ;
++
++ new_line[xx] -= ( new_line[xx] * strength ) / 100;
++
++ if ( height != 1 && height != (FT_UInt)bitmap->rows )
++ if ( new_nextline[xx] > 155 + ( 100 - strength ) )
++ new_prevline[xx] = 255;
++
++ }
++ else if ( nexttotal > prevtotal &&
++ abs( sp13 - sp12 ) > 5 &&
++ abs( sp23 - sp22 ) > 5 &&
++ abs( sp33 - sp32 ) > 5 &&
++ /* 2: All lower adjecent pixels are >= threshold */
++ sp13 >= threshold &&
++ sp23 >= threshold &&
++ sp33 >= threshold &&
++ abs( sp22 - sp21 ) > 15 )
++ {
++ /* darken lower adjacent subpixel; lighten current */
++ if ( height != 1 )
++ new_nextline[xx] += ( 255 - new_nextline[xx] ) * strength / 100;
++
++ new_line[xx] -= ( new_line[xx] * strength ) / 100;
++
++ if ( height != 1 )
++ if ( new_nextline[xx] > 155 + ( 100 - strength ) )
++ new_nextline[xx] = 255;
++
++ }
++ }
++ else if ( sp22 > threshold && sp22 < 255 )
++ {
++ if ( sp11 <= threshold &&
++ abs( sp13 - sp12 ) > 5 &&
++ abs( sp23 - sp22 ) > 5 &&
++ abs( sp33 - sp32 ) > 5 &&
++ sp21 <= threshold &&
++ sp31 <= threshold &&
++ prevtotal <= nexttotal &&
++ abs( sp22 - sp21 ) > 15 )
++ {
++ /* bring this subpixel 1/3 of the way to 255 at 100% strength */
++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
++
++ if ( height != (FT_UInt)bitmap->rows )
++ new_prevline[xx] -= ( new_prevline[xx] * strength ) / 300;
++ }
++ else if ( sp13 <= threshold &&
++ abs( sp11 - sp12 ) > 5 &&
++ abs( sp21 - sp22 ) > 5 &&
++ abs( sp31 - sp32 ) > 5 &&
++ sp23 <= threshold &&
++ sp33 <= threshold &&
++ nexttotal < prevtotal &&
++ abs( sp23 - sp22 ) > 15 )
++ {
++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
++
++ if ( height != 1 )
++ new_nextline[xx] -= ( new_nextline[xx] * strength ) / 300;
++ }
++ }
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap);
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++
++ static void
++ _ft_lcd_darken_x ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_Bitmap new_bitmap;
++ int factor1, factor2;
++ int bias = 0;
++
++ FT_Bitmap_Init( &new_bitmap );
++
++ FT_Bitmap_Copy( library, bitmap, &new_bitmap );
++ new_line = (&new_bitmap)->buffer;
++
++ if ( strength > 0 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ FT_UInt xx;
++ FT_Byte* prevline = line - bitmap->pitch;
++ FT_Byte* nextline = line + bitmap->pitch;
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ /* subpixel grid sp11 sp21 sp31 */
++ /* where sp22 is sp12 sp22 sp32 */
++ /* current subpixel. sp13 sp23 sp33 */
++
++ FT_Int sp21, sp12, sp22, sp32, sp23;
++
++ sp12 = line [xx-1];
++ sp22 = line [xx];
++ sp32 = line [xx+1];
++
++ if ( height == bitmap->rows )
++ sp21 = 0;
++ else
++ sp21 = prevline [xx];
++
++ if ( height == 1 )
++ sp23 = 0;
++ else
++ sp23 = nextline [xx];
++
++ /* darken subpixel if neighbor above and below are much less than */
++ /* safer but less effective */
++ factor1 = 5;
++ factor2 = 5;
++
++ /* make matches in the middle of glyph slightly darker */
++ /*if (height > 1 && height < (FT_UInt)bitmap->rows) bias = 1;*/
++
++ if ( sp22 > factor1 * sp21 &&
++ sp22 > factor1 * sp23 &&
++ sp22 > factor2 &&
++ sp12 > 16 &&
++ sp32 > 16 )
++ if ( new_line[xx] < ( strength * 255 ) / 100 )
++ new_line[xx] = (strength * 255 ) / 100
++ + bias * ( 255 - ( strength * 255 ) / 100 ) / 3;
++
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap );
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++
++ static void
++ _ft_lcd_darken_y ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_Bitmap new_bitmap;
++
++
++ FT_Bitmap_Init( &new_bitmap );
++ FT_Bitmap_Copy( library, bitmap, &new_bitmap );
++ new_line = (&new_bitmap)->buffer;
++
++ if ( strength > 0 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ FT_UInt xx;
++
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ if ( line[xx] > line[xx-1] && line[xx] > line[xx+1] )
++ {
++ if (new_line[xx] > 0)
++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
++ new_line[xx-1] += ( strength * ( 255 - line[xx-1] ) ) / 100;
++ new_line[xx+1] += ( strength * ( 255 - line[xx+1] ) ) / 100;
++ }
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap );
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++
++ static void
++ _ft_bitmap_cap ( FT_Bitmap* bitmap,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_UInt cur_value = 0;
++ FT_Bitmap new_bitmap;
++
++
++ FT_Bitmap_Init( &new_bitmap );
++ FT_Bitmap_Copy( library, bitmap, &new_bitmap );
++ new_line = (&new_bitmap)->buffer;
++
++ if ( strength > 0 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ FT_UInt xx;
++
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ cur_value = ( new_line[xx-1] + new_line[xx] + new_line[xx+1] ) / 3;
++ if ( cur_value > ( strength * 255 ) / 100 )
++ {
++ FT_UInt new_factor = ( strength * 255 ) / 100;
++ new_line[xx] = ( new_line[xx] * new_factor ) / cur_value;
++ new_line[xx+1] = ( new_line[xx+1] * new_factor ) / cur_value;
++ new_line[xx-1] = ( new_line[xx-1] * new_factor ) / cur_value;
++ }
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap );
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++ static int
++ pseudo_gamma ( int val, float value )
++ {
++ return 256 * ( 1.0f - powf( ( 1.0f - val * (1.0f/256.0f) ), 1.0f / value ) );
++ }
++
++#if(0)
++ static void
++ _ft_bitmap_embolden ( FT_Bitmap* bitmap,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_Bitmap new_bitmap;
++ FT_UInt xx;
++
++
++ FT_Bitmap_Init(&new_bitmap);
++ FT_Bitmap_Copy(library, bitmap, &new_bitmap);
++ new_line = (&new_bitmap)->buffer;
++
++ if ( strength > 0 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ FT_Int new_value = 0;
++
++
++ new_value = ( strength * line [xx-1] ) / 100
++ + pseudo_gamma( line [xx], .75 )
++ + (strength * line [xx+1] ) / 100;
++ if ( new_value > 255 )
++ new_value = 255;
++
++ new_line[xx] = new_value;
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap );
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++
++
++ static void
++ _ft_bitmap_gamma ( FT_Bitmap* bitmap,
++ float strength )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* line = bitmap->buffer;
++ FT_UInt xx;
++
++
++ if ( strength > 0 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch )
++ {
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ if ( abs( line[xx-1] - line[xx] ) < 20 ||
++ abs( line[xx+1] - line[xx] ) < 20 )
++ line [xx] = pseudo_gamma( line [xx], strength ) ;
++ }
++ }
++ }
++#endif
++
++ /* Fringe filter */
++ static void
++ _ft_lcd_fringe_filter ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* new_line;
++ FT_Byte* line = bitmap->buffer;
++ FT_Bitmap new_bitmap;
++
++
++ FT_Bitmap_Init(&new_bitmap);
++
++ line = bitmap->buffer;
++ FT_Bitmap_Copy( library, bitmap, &new_bitmap );
++ new_line = (&new_bitmap)->buffer;
++
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch, new_line += bitmap->pitch )
++ {
++ /* Threshold set to 1/2 pixel intensity */
++ FT_UInt xx, threshold = 128;
++
++ /* Hack to make this work when bitmap is at first or last line */
++ FT_Int fudge = bitmap->pitch * (height == (FT_UInt)bitmap->rows);
++
++ FT_Byte* prevline = line - bitmap->pitch + fudge;
++ FT_Byte* nextline = line + bitmap->pitch;
++
++
++ for ( xx = 1; xx < width - 1; xx += 1 )
++ {
++ /* subpixel grid sp11 sp21 sp31 */
++ /* where sp22 is sp12 sp22 sp32 */
++ /* current subpixel. sp13 sp23 sp33 */
++
++ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
++ leftdiff, rightdiff, prevdiff, nextdiff, sp11, sp21, sp31,
++ sp12, sp22, sp32, sp13, sp23, sp33;
++
++ sp12 = line [xx-1];
++ sp22 = line [xx];
++ sp32 = line [xx+1];
++
++ /* if at max height fake out some values */
++ if ( height == (FT_UInt)bitmap->rows )
++ {
++ prevtotal = sp11 = sp21 = sp31 = 0;
++ prevdiff = sp22;
++ lefttotal = sp12 + sp13;
++ righttotal = sp32 + sp33;
++ }
++ else
++ {
++ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
++ sp11 = prevline [xx-1];
++ sp21 = prevline [xx];
++ sp31 = prevline [xx+1];
++ prevdiff = sp22 - sp21;
++ lefttotal = sp11 + sp12 + sp13;
++ righttotal = sp31 + sp32 + sp33;
++ }
++
++ /* if at min height fake out some values */
++ if ( height == 1 )
++ {
++ nexttotal = sp13 = sp23 = sp33 = 0;
++ nextdiff = sp22;
++ lefttotal = sp11 + sp12;
++ righttotal = sp31 + sp32;
++ }
++ else
++ {
++ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
++ sp13 = nextline [xx-1];
++ sp23 = nextline [xx];
++ sp33 = nextline [xx+1];
++ nextdiff = sp23 - sp22;
++ lefttotal = sp11 + sp12 + sp13;
++ righttotal = sp31 + sp32 + sp33;
++ }
++
++ sidesdiff = lefttotal - righttotal;
++ leftdiff = sp22 - sp12;
++ rightdiff = sp32 - sp22;
++
++ if ( sidesdiff < 0 )
++ sidesdiff *= -1;
++
++ if ( prevdiff < 0 )
++ prevdiff *= -1;
++
++ if ( nextdiff < 0 )
++ nextdiff *= -1;
++
++ if ( leftdiff < 0 )
++ leftdiff *= -1;
++
++ if ( rightdiff < 0 )
++ rightdiff *= -1;
++
++ /* if the current subpixel is less than threshold, and varies only
++ slightly to left or right, lighten it */
++ if ( sp22 <= threshold && sp22 > 0 &&
++ ( leftdiff < 10 || rightdiff < 10 ) )
++ {
++ /* A pixel is horizontally isolated if: */
++ /* 1: All upper adjecent subpixels are >= threshold and all lower
++ adjacent ones are essentially white */
++ if ( prevtotal >= nexttotal &&
++ sp11 >= threshold &&
++ sp21 >= threshold &&
++ sp31 >= threshold &&
++ sp13 < 2 &&
++ sp23 < 2 &&
++ sp33 < 2 )
++
++ {
++ new_line[xx] -= ( new_line[xx] * strength ) / 100;
++
++ if ( leftdiff < 10 )
++ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */
++ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200;
++
++ if ( rightdiff < 10 )
++ /* OPPORTUNITY FOR IMPROVEMENT */
++ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200;
++ }
++ else if ( nexttotal > prevtotal &&
++ /* 2: the inverse of above */
++ sp13 >= threshold &&
++ sp23 >= threshold &&
++ sp33 >= threshold &&
++ sp11 < 2 &&
++ sp21 < 2 &&
++ sp31 < 2 )
++ {
++ new_line[xx] -= ( new_line[xx] * strength ) / 100;
++
++ if ( leftdiff < 10 )
++ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */
++ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200;
++
++ if ( rightdiff < 10 )
++ /* OPPORTUNITY FOR IMPROVEMENT */
++ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200;
++ }
++ }
++ /* otherwise if the current subpixel is more than threshold, and varies
++ slightly to left or right, darken it */
++ else if ( sp22 > threshold &&
++ sp22 < 255 &&
++ ( leftdiff < 10 ||
++ rightdiff < 10 ) )
++ {
++ if ( sp11 <= 2 &&
++ sp21 <= 2 &&
++ sp31 <= 2 &&
++ sp13 >= threshold &&
++ sp23 >= threshold &&
++ sp33 >= threshold &&
++ prevtotal < nexttotal )
++ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100;
++
++ else if ( sp13 <= 2 &&
++ sp23 <= 2 &&
++ sp33 <= 2 &&
++ nexttotal < prevtotal &&
++ sp11 >= threshold &&
++ sp21 >= threshold &&
++ sp31 >= threshold )
++ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100;
++
++ }
++ }
++ }
++ FT_Bitmap_Copy( library, &new_bitmap, bitmap );
++ FT_Bitmap_Done( library, &new_bitmap );
++ }
++
++
++ /* Grayscale filter */
++ static void
++ _ft_lcd_grayscale_filter ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_UInt strength,
++ FT_Library library )
++ {
++
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* line = bitmap->buffer;
++
++
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch )
++ {
++ FT_UInt xx;
++
++
++ for ( xx = 0; xx < width - 1; xx += 3 )
++ {
++ FT_UInt total = line [xx] + line [xx + 1] + line [xx + 2];
++ line[xx] = ( ( 100 - strength ) * line[xx]
++ + strength * ( total / 3 ) ) / 100;
++ line[xx+1] = ( ( 100 - strength ) * line[xx+1]
++ + strength * ( total / 3 ) ) / 100;
++ line[xx+2] = ( ( 100 - strength ) * line[xx+2]
++ + strength * ( total / 3 ) ) / 100;
++ }
++ }
++ }
++
++/*
++ These need to be in sync with params inside ftinf.c
++ (not ideal but perhaps better than making these public)
++ */
++#define STEM_WIDTH_2_PPEM 18
++#define MAX_PPEM 100
++
++ typedef struct Stem_Segment_
++ {
++ FT_Long x1;
++ FT_Long x2;
++ FT_Int y;
++ } Stem_Segment;
++
++ typedef struct Stem_Center_
++ {
++ FT_Long x;
++ FT_Long y;
++ FT_Long w;
++ FT_Long x1;
++ FT_Long x2;
++ } Stem_Center;
++
++ typedef struct Stem_
++ {
++ FT_Long center;
++ FT_Long count;
++ FT_Long rcount; /* used to count within a range in possible stems */
++ FT_Long width;
++ FT_Long height;
++ FT_Short zone; /* 1 2 or 3 */
++ FT_Bool generated;
++ } Stem;
++
++ static void
++ swap_stem ( Stem* s1, Stem* s2 )
++ {
++ Stem s;
++ s.center = s1->center;
++ s.count = s1->count;
++ s.rcount = s1->rcount;
++ s.width = s1->width;
++ s.zone = s1->zone;
++ s.generated = s1->generated;
++
++ s1->center = s2->center;
++ s1->count = s2->count;
++ s1->rcount = s2->rcount;
++ s1->width = s2->width;
++ s1->zone = s2->zone;
++ s1->generated = s2->generated;
++
++ s2->center = s.center;
++ s2->count = s.count;
++ s2->rcount = s.rcount;
++ s2->width = s.width;
++ s2->zone = s.zone;
++ s2->generated = s.generated;
++ }
++
++ /* Stem alignment for bitmaps; A hack with very nice results */
++ /* Ideally this could be implemented on the outline, prior to
++ * rasterization. Possible future enhancement is to use the
++ * warper code to achieve this */
++ static void
++ _lcd_stem_align ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_GlyphSlot slot,
++ FT_Long* translate_value,
++ float* scale_value,
++ FT_UInt alignment_strength,
++ FT_UInt fitting_strength,
++ float* embolden_value
++ )
++ {
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++
++ Stem_Segment* segments;
++ Stem_Segment* leftmost_segment;
++ Stem_Segment* rightmost_segment;
++ Stem_Segment* leftmost_segment_not_extrema;
++ Stem_Segment* rightmost_segment_not_extrema;
++ Stem* stems;
++ Stem* possible_stems;
++ Stem* leftmost_stem;
++ Stem* rightmost_stem;
++ Stem_Data* known_stem_values;
++ Stem_Center* centers;
++ FT_Long leftmost_point = width * 256;
++ FT_Long rightmost_point = 0;
++ FT_Long leftmost_point_not_extrema = width * 256;
++ FT_Long rightmost_point_not_extrema = 0;
++ FT_Long num_segments = 0;
++ FT_Long num_centers = 0;
++ FT_Long *stem_centers;
++ FT_UInt h;
++ FT_ULong valid_stems = 0, valid_possible_stems = 0;
++ FT_Long center, stem_matches, stem_matches_ledge;
++ FT_Long stem_matches_redge, next_center, last_matching_center;
++ FT_Long last_matching_ledge, last_matching_redge, this_center;
++ FT_Int max_strength;
++ FT_Byte* line = bitmap->buffer;
++ FT_UInt current_value = 0;
++ FT_UInt xx;
++ FT_Long linearHoriAdvance = slot->linearHoriAdvance >> 10;
++
++ FT_Int m_horiBearingX = slot->metrics.horiBearingX;
++ FT_Int m_horiAdvance = slot->metrics.horiAdvance;
++ FT_Int m_width = slot->metrics.width;
++ FT_Pos one_pixel = 768;
++ FT_Pos one_third_pixel = 256;
++ FT_Int columns_per_pixel = 3;
++ /*FT_Int extra_columns = 6;*/
++
++ /* on / off flags for testing different features */
++ FT_Bool strategy_translate_using_closest_stem = TRUE;
++ FT_Bool strategy_scale_to_closest_centers = FALSE;
++ FT_Bool strategy_scale_to_closest_centers_up_only = FALSE;
++ FT_Bool strategy_always_use_distance_ceiling = FALSE;
++ FT_Bool strategy_auto_change_center_offset = TRUE;
++ FT_Bool strategy_use_m_control = FALSE;
++ FT_Bool strategy_correct_out_of_bounds_outlines = FALSE;
++ FT_Bool strategy_also_use_edge_detection_for_stems = FALSE;
++ FT_Bool strategy_use_strengths = TRUE;
++ FT_Bool strategy_synthesize_stems = FALSE;
++ FT_Bool strategy_bearing_correction = TRUE;
++ FT_Bool strategy_use_d_correction = TRUE;
++ FT_Bool strategy_fit_to_width = FALSE;
++ /*FT_Bool strategy_center_glyph = FALSE;*/
++
++ const FT_Int MIN_PPEM = 7;
++ /*const FT_Int MAX_PPEM = 100;*/
++ const FT_Int MAX_STEMS = 3;
++ FT_Int ppem = 0;
++
++ Stem_Data stem_data;
++
++ /* reset to default */
++ *scale_value = 1.0;
++
++ /* Simply return in odd cases where these don't seem to be set */
++ /* Flash and some pdf viewers will crash otherwise */
++ if ( !slot->face ||
++ !slot->face->size ||
++ !slot->face->size->metrics.x_ppem )
++ return;
++
++ if ( slot->face->size->metrics.x_ppem > MAX_PPEM )
++ return;
++
++ if ( slot->face->size->metrics.x_ppem < MIN_PPEM )
++ return;
++
++ if ( !FT_IS_SCALABLE( slot->face ) )
++ return;
++
++ ppem = slot->face->size->metrics.x_ppem;
++
++ if ( ppem < 9 )
++ return;
++ if ( ppem > 20 )
++ strategy_use_m_control = TRUE;
++
++ /* only perform alignment on styles we know, that aren't bold or italic */
++ /* perhaps detection could be added on those that are not set? */
++ /* Require certain ppems for narrow and light fonts */
++ if( slot->face->style_name )
++ {
++ if ( strcasestr( slot->face->style_name, "Italic" ) ||
++ strcasestr( slot->face->style_name, "Oblique" ) ||
++ strcasestr( slot->face->style_name, "Script" ) ||
++ strcasestr( slot->face->style_name, "Handwriting" ) ||
++ strcasestr( slot->face->style_name, "Bold" ) ||
++ strcasestr( slot->face->style_name, "Black" ) ||
++ ( ( strcasestr( slot->face->style_name, "Extra Thin" ) ||
++ strcasestr( slot->face->style_name, "Extra Light" ) ) &&
++ ppem < 10 ) ||
++ ( strcasestr( slot->face->style_name, "Thin" )
++ && ppem < 10 ) ||
++ ( strcasestr( slot->face->style_name, "Light" )
++ && ppem < 10 ) ||
++ ( strcasestr( slot->face->style_name, "Narrow" )
++ && ppem < 15 ) ||
++ ( strcasestr( slot->face->style_name, "Condensed" )
++ && ppem < 20 ) )
++ return;
++ }
++
++ if( slot->face->family_name )
++ {
++ if ( strcasestr( slot->face->family_name, "Italic" ) ||
++ strcasestr( slot->face->family_name, "Oblique" ) ||
++ strcasestr( slot->face->family_name, "Script" ) ||
++ strcasestr( slot->face->family_name, "Handwriting" ) ||
++ strcasestr( slot->face->family_name, "Bold" ) ||
++ strcasestr( slot->face->family_name, "Black" ) ||
++ ( ( strcasestr( slot->face->family_name, "Extra Thin" ) ||
++ strcasestr( slot->face->family_name, "Extra Light" ) ) &&
++ ppem < 10 ) ||
++ ( strcasestr( slot->face->family_name, "Thin" )
++ && ppem < 10 ) ||
++ ( strcasestr( slot->face->family_name, "Light" )
++ && ppem < 10 ) ||
++ ( strcasestr( slot->face->family_name, "Narrow" )
++ && ppem < 15 ) ||
++ ( strcasestr( slot->face->family_name, "Condensed" )
++ && ppem < 20 ) )
++ return;
++ }
++ else if ( slot->face->style_flags )
++ {
++ if ( slot->face->style_flags & FT_STYLE_FLAG_ITALIC ||
++ slot->face->style_flags & FT_STYLE_FLAG_BOLD ||
++ FT_IS_TRICKY( slot->face ) )
++ return;
++ }
++ else return;
++
++ if ( mode != FT_RENDER_MODE_LCD )
++ {
++ columns_per_pixel = 1;
++ one_pixel = 256;
++ one_third_pixel = 85;
++ /*extra_columns = 0;*/
++ /* until this can be figured out just return */
++ /* There are issues with missing glyphs */
++ return;
++ }
++
++ known_stem_values=&stem_data;
++ if ( ftinf && ftinf->use_known_settings_on_selected_fonts )
++ {
++ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, TRUE );
++ /* translate value may be set for < 10 */
++ if (known_stem_values->stem_translating_only > -1024 )
++ {
++ *translate_value = known_stem_values->stem_translating_only;
++ return;
++ }
++ if( known_stem_values->bearing_correction == FALSE )
++ strategy_bearing_correction = FALSE;
++ } else
++ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, FALSE );
++
++ if ( known_stem_values->use_100 ||
++ known_stem_values->m >= 0 )
++ {
++ alignment_strength = fitting_strength = 100;
++ strategy_use_m_control = TRUE;
++ }
++
++ if ( known_stem_values->edge_detection )
++ strategy_also_use_edge_detection_for_stems = TRUE;
++
++ /* Allocate */
++ segments = NULL;
++ leftmost_segment = (Stem_Segment*) malloc( 4*sizeof ( Stem_Segment ) );
++ leftmost_segment_not_extrema = leftmost_segment+1;
++ rightmost_segment = leftmost_segment+2;
++ rightmost_segment_not_extrema = leftmost_segment+3;
++
++ stems = (Stem*) malloc ( (2*MAX_STEMS+2) * sizeof ( Stem ) );
++ possible_stems = stems+MAX_STEMS;
++ leftmost_stem = possible_stems+MAX_STEMS;
++ rightmost_stem = leftmost_stem + 1;
++ centers = NULL;
++
++ if ( verbose )
++ printf("\n");
++
++ /* Initialize */
++ stem_centers=(FT_Long*)calloc( width * 256, sizeof(stem_centers[0]) );
++
++ rightmost_segment->x1 = 0;
++ rightmost_segment->x2 = 0;
++ rightmost_segment->y = 0;
++ leftmost_segment->x1 = 99999999;
++ leftmost_segment->x2 = 0;
++ leftmost_segment->y = 0;
++
++ rightmost_segment_not_extrema->x1 = 0;
++ rightmost_segment_not_extrema->x2 = 0;
++ rightmost_segment_not_extrema->y = 0;
++ leftmost_segment_not_extrema->x1 = 99999999;
++ leftmost_segment_not_extrema->x2 = 0;
++ leftmost_segment_not_extrema->y = 0;
++
++ /* Locate stem centers for later processing */
++ for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch )
++ {
++ current_value = 0;
++ /* Calculate various sums and stem widths of glyph */
++ for ( xx = 0; xx < width; xx += 1 )
++ {
++ /* Reallocate (in blocks of 64) */
++ if( num_segments % 64 == 0 )
++ segments = (Stem_Segment*) realloc
++ ( segments, ( num_segments + 64 ) * sizeof ( Stem_Segment ) );
++
++ /* if line is white, and now has color, it's the start of a stem */
++ if ( current_value == 0 && line[xx] > 0 )
++ {
++ /* start of stem */
++ segments[num_segments].x1 = 256 * xx + ( 255 - line[xx] );
++ segments[num_segments].y = h;
++ }
++
++ /* otherwise, if it's currently black and the new value is 0,
++ it's the end of a stem */
++ else if ( ( current_value > 0 && line[xx] == 0 ) ||
++ ( current_value > 0 && xx == width - 1 ) )
++ {
++ FT_Long stem_center_x;
++ segments[num_segments].x2 = 256 * ( xx - 1 ) + line[xx-1];
++
++ if ( xx == width - 1 )
++ segments[num_segments].x2 += line[xx];
++
++ /*stem center is average of start and end of stem */
++ stem_center_x = ( segments[num_segments].x2
++ + segments[num_segments].x1 ) / 2;
++
++ /* Reallocate (in blocks of 32) */
++ if( num_centers % 32 == 0 )
++ centers = (Stem_Center*) realloc
++ ( centers, ( num_centers + 32 ) * sizeof ( Stem_Center ) );
++ centers[num_centers].x = stem_center_x;
++ centers[num_centers].y = h;
++ centers[num_centers].x1 = segments[num_segments].x1;
++ centers[num_centers].x2 = segments[num_segments].x2;
++
++ num_centers++;
++
++ stem_centers[stem_center_x] += 1;
++
++ /* Find left and rightmost points for later calculations */
++ /* OR - Favor ones that aren't on the top or bottom if */
++ /* possible to prevent v and w from getting caught later */
++ if ( segments[num_segments].x1 < leftmost_segment->x1 ||
++ ( segments[num_segments].y > 1 &&
++ segments[num_segments].y < height &&
++ segments[num_segments].x1 == leftmost_segment->x1 ) )
++ {
++ leftmost_segment->x1 = segments[num_segments].x1;
++ leftmost_segment->x2 = segments[num_segments].x2;
++ leftmost_segment->y = h;
++ }
++ if ( segments[num_segments].x2 > rightmost_segment->x2 ||
++ ( segments[num_segments].y > 1 &&
++ segments[num_segments].y < height &&
++ segments[num_segments].x1 == rightmost_segment->x1 ) )
++ {
++ rightmost_segment->x1 = segments[num_segments].x1;
++ rightmost_segment->x2 = segments[num_segments].x2;
++ rightmost_segment->y = h;
++ }
++
++ if ( segments[num_segments].x1
++ < leftmost_segment_not_extrema->x1 ||
++ ( segments[num_segments].y > 1 &&
++ segments[num_segments].y < height &&
++ segments[num_segments].x1
++ == leftmost_segment_not_extrema->x1 &&
++ h < (FT_UInt)bitmap->rows && h > 0 ) )
++ {
++ leftmost_segment_not_extrema->x1 = segments[num_segments].x1;
++ leftmost_segment_not_extrema->x2 = segments[num_segments].x2;
++ leftmost_segment_not_extrema->y = h;
++ }
++ if ( segments[num_segments].x2
++ > rightmost_segment_not_extrema->x2 ||
++ ( segments[num_segments].y > 1 &&
++ segments[num_segments].y < height &&
++ segments[num_segments].x1
++ == rightmost_segment_not_extrema->x1 &&
++ h < (FT_UInt)bitmap->rows && h > 0 ) )
++ {
++ rightmost_segment_not_extrema->x1 = segments[num_segments].x1;
++ rightmost_segment_not_extrema->x2 = segments[num_segments].x2;
++ rightmost_segment_not_extrema->y = h;
++ }
++
++ if ( segments[num_segments].x1 < leftmost_point )
++ leftmost_point = segments[num_segments].x1;
++
++ if ( segments[num_segments].x2 > rightmost_point )
++ rightmost_point = segments[num_segments].x2;
++
++ if ( segments[num_segments].x1 < leftmost_point_not_extrema &&
++ h < (FT_UInt)bitmap->rows && h > 0 )
++ leftmost_point_not_extrema = segments[num_segments].x1;
++
++ if ( segments[num_segments].x2 > rightmost_point_not_extrema &&
++ h < (FT_UInt)bitmap->rows && h > 0 )
++ rightmost_point_not_extrema = segments[num_segments].x2;
++
++ num_segments++;
++ }
++ /* else - other conditions - need some error checking here */
++ current_value = line[xx];
++ }
++ }
++
++ /* initialize */
++ for ( xx = 0; xx < MAX_STEMS; xx +=1 )
++ {
++ stems[xx].center = 0;
++ stems[xx].count = 0;
++ stems[xx].width = 0;
++ stems[xx].height = 0;
++ possible_stems[xx].center = 0;
++ possible_stems[xx].count = 0;
++ possible_stems[xx].width = 0;
++ possible_stems[xx].height = 0;
++ }
++
++ valid_stems = 0;
++ valid_possible_stems = 0;
++
++ /* Determine which centers belong to stems */
++ center = 0;
++
++ while ( center < num_centers )
++ {
++ /* slope at within which to consider a point part of a stem */
++ /*const FT_UInt slope = 1;
++ const FT_UInt topslope = (256 * 3) / 10; */
++
++ /* 10 to 20 with 4 matches seems good, */
++ /* but 1 or 2 with 3 stems needs to somehow get included */
++ FT_Int deviation1 = 5;
++ FT_Int deviation2=-1, requirement1 = 4, stem_match_requirement = 3;
++ FT_Int center_difference_in_height;
++ FT_Int center_difference_in_width, valid_center_average;
++ FT_Int smallest_width_ledge, smallest_width_redge;
++ FT_Int x1_difference_in_width, x2_difference_in_width;
++ FT_Bool no_gap_found = FALSE;
++ FT_Bool no_gap_found_ledge = FALSE;
++ FT_Bool no_gap_found_redge = FALSE;
++ FT_Bool stem_detected = FALSE;
++ FT_Int set_width_to, set_center_to;
++
++ /* seems to not do damage */
++ /* May not be effective */
++ requirement1 = height / 4;
++ if ( requirement1 < 5 )
++ requirement1 = 5;
++ deviation1 = 20;
++ deviation2 = 20;
++
++ if ( columns_per_pixel == 1 )
++ deviation1 = deviation2 = 10;
++
++ if ( (FT_Int)bitmap->rows <= 6 )
++ deviation1 = 25;
++
++ if ( (FT_Int)bitmap->rows <= 6 )
++ deviation2 = 25;
++
++ if ( columns_per_pixel == 1 &&
++ (FT_Int)bitmap->rows <= 6 )
++ deviation1 = deviation2 = 12;
++
++ valid_center_average = 0;
++
++ no_gap_found = no_gap_found_ledge = no_gap_found_redge = FALSE;
++ stem_detected = FALSE;
++
++ if ( ppem < 11 )
++ requirement1 = 4;
++
++ if ( ppem > 18 )
++ {
++ stem_match_requirement = height / 4;
++ if ( stem_match_requirement < 3 )
++ stem_match_requirement = 3;
++ }
++
++ smallest_width_ledge = smallest_width_redge = width * 256;
++ stem_matches = 0;
++ stem_matches_ledge = 0;
++ stem_matches_redge = 0;
++ last_matching_center = -1;
++ last_matching_ledge = -1;
++ last_matching_redge = -1;
++
++ /* set currently looked at center to center value */
++ this_center = center;
++ next_center = 0;
++
++ /* For each center, compare with all other centers to see if others */
++ /* match the properties of this one */
++ while ( next_center < num_centers )
++ {
++
++ /* calculate differences */
++ center_difference_in_width = abs ( centers[this_center].x
++ - centers[next_center].x );
++ center_difference_in_height = abs ( centers[this_center].y
++ - centers[next_center].y );
++ x1_difference_in_width = abs ( centers[this_center].x1
++ - centers[next_center].x1 );
++ x2_difference_in_width = abs ( centers[this_center].x2
++ - centers[next_center].x2 );
++
++
++ /* property - stem center points that align */
++ /* if the center is within range, the center is less than */
++ /* 1/2 the height away, and at least one edge is also within range */
++ if ( center_difference_in_width
++ < center_difference_in_height * deviation1 &&
++ center_difference_in_height
++ <= (FT_Int)bitmap->rows / 2 &&
++ /* prevents w from getting caught ---- but also kills m */
++ ( x1_difference_in_width
++ < center_difference_in_height * deviation2 ||
++ x2_difference_in_width
++ < center_difference_in_height * deviation2 ) )
++ {
++ stem_matches += 1;
++ valid_center_average += centers[next_center].x;
++
++ /* try to find where the matching centers are far apart */
++ if ( last_matching_center >= 0 &&
++ abs( centers[last_matching_center].y
++ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 )
++
++ /* try to find where matching centers are next to each other */
++ if ( last_matching_center >= 0 &&
++ abs( centers[last_matching_center].y
++ - centers[next_center].y ) == 1 )
++ no_gap_found = TRUE;
++
++ last_matching_center = next_center;
++ }
++
++ if ( strategy_also_use_edge_detection_for_stems )
++ {
++ /* property - stem left edge points that align */
++ /* if the center is within range, */
++ /* the center is less than 1/2 the height away */
++ if ( x1_difference_in_width
++ < center_difference_in_height * deviation1 &&
++ center_difference_in_height <= (FT_Int)bitmap->rows / 2 )
++ {
++ stem_matches_ledge += 1;
++ /* may not need for edges */
++ /*valid_center_average += centers[next_center].x; */
++
++ if ( centers[next_center].x2 - centers[next_center].x1
++ < smallest_width_ledge )
++ smallest_width_ledge = centers[next_center].x2
++ - centers[next_center].x1;
++
++ /* try to find where the matching centers are far apart */
++ if ( last_matching_ledge >= 0 &&
++ abs( centers[last_matching_ledge].y
++ - centers[next_center].y)
++ >= (FT_Int)bitmap->rows / 2 )
++
++ /* try to find where matching centers are next to each other */
++ if ( last_matching_ledge >= 0 &&
++ abs( centers[last_matching_ledge].y
++ - centers[next_center].y ) == 1 )
++ no_gap_found_ledge = TRUE;
++ last_matching_ledge = next_center;
++ }
++ }
++
++ if ( strategy_also_use_edge_detection_for_stems )
++ {
++ /* property - stem right edge points that align */
++ /* if the center is within range, the center is less than 1/2 */
++ /* the height away */
++ if ( x2_difference_in_width
++ < center_difference_in_height * deviation1 &&
++ center_difference_in_height
++ <= (FT_Int)bitmap->rows / 2 )
++ {
++ stem_matches_redge += 1;
++ /* may not need for edges */
++ /*valid_center_average += centers[next_center].x; */
++
++ if ( centers[next_center].x2 - centers[next_center].x1
++ < smallest_width_redge )
++ smallest_width_redge = centers[next_center].x2
++ - centers[next_center].x1;
++
++ /* try to find where the matching centers are far apart */
++ if ( last_matching_redge >= 0 &&
++ abs( centers[last_matching_redge].y
++ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 )
++
++ /* try to find where matching centers are next to each other */
++ if ( last_matching_redge >= 0 &&
++ abs( centers[last_matching_redge].y
++ - centers[next_center].y ) == 1 )
++ no_gap_found_redge = TRUE;
++
++ last_matching_redge = next_center;
++ }
++ }
++
++ next_center++;
++ }
++
++ if ( stem_matches > 0 )
++ valid_center_average /= stem_matches;
++
++ if ( ( stem_matches >= stem_match_requirement ||
++ ( ( (FT_Int)bitmap->rows <= 6 || ppem < 11 ) &&
++ stem_matches >= 2 &&
++ abs ( valid_center_average
++ - centers[center].x) < deviation1 /2 ) ||
++ /* try to catch tightly aligned stuff where the matching centers */
++ /* are next to each other only */
++ ( stem_matches == 2 &&
++ abs( valid_center_average
++ - centers[center].x) <= deviation1 /2 &&
++ no_gap_found &&
++ ppem < 18 ) ) &&
++ /* catches things like times 16 u but gets a lot of w's too */
++ /* stem width is less than 1/3 of the bitmap width, */
++ /* or bitmap_width is small */
++ ( centers[center].x2 - centers[center].x1
++ < (m_horiAdvance * 12) / 2 ||
++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) )
++ {
++ stem_detected = TRUE;
++ set_width_to = centers[center].x2 - centers[center].x1;
++ set_center_to = centers[center].x;
++ }
++
++ /* see if edges found anything */
++ if ( strategy_also_use_edge_detection_for_stems && !stem_detected )
++ {
++ /* Require no gap for edges */
++ /* stem width less than 1/3 bitmap width, or bitmap_width is small */
++ /* The stem occurs on the left side of glyph only */
++ if ( ( stem_matches_ledge >= stem_match_requirement &&
++ no_gap_found_ledge ) &&
++ ( centers[center].x2 - centers[center].x1
++ < ( m_horiAdvance * 12 ) / 2 ||
++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) &&
++ centers[center].x < ( m_horiAdvance * 12 ) / 2 )
++ {
++ stem_detected = TRUE;
++ set_width_to = smallest_width_ledge;
++ set_center_to = centers[center].x1 + set_width_to / 2;
++ stem_matches = stem_matches_ledge;
++ }
++ /* Require no gap for edges */
++ /* stem width is less than 1/3 bitmap width, or bitmap_width is small */
++ /* The stem occurs on the right side of glyph only */
++ else if ( ( stem_matches_redge >= stem_match_requirement &&
++ no_gap_found_redge ) &&
++ ( centers[center].x2 - centers[center].x1
++ < ( m_horiAdvance * 12 ) / 2 ||
++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) &&
++ centers[center].x > (m_horiAdvance * 12) / 2 )
++ {
++ stem_detected = TRUE;
++ set_width_to = smallest_width_redge;
++ set_center_to = centers[center].x2 - set_width_to / 2;
++ stem_matches = stem_matches_redge;
++ }
++ }
++
++
++ /*store and/or replace highest occurrences with 3 or more centers */
++ /* because this matched, it will become the top dog regardless */
++ if ( stem_detected && (stem_matches > possible_stems[0].height) )
++ {
++ /* if this is the first stem just go ahead */
++ if ( valid_possible_stems == 0 )
++ {
++ valid_possible_stems = 1;
++ possible_stems[0].center = set_center_to;
++ possible_stems[0].count = stem_matches;
++ possible_stems[0].width = set_width_to;
++ possible_stems[0].height = stem_matches;
++ }
++
++ /* otherwise, if there is already a stem */
++ else if ( valid_possible_stems == 1 )
++ {
++ /* if stem is within range of existing one, replace existing one */
++
++ /* if the stem isn't within the range of this one swap it with */
++ /* next one first */
++ if ( abs ( set_center_to - possible_stems[0].center )
++ >= one_pixel * 2 )
++ {
++ swap_stem ( &possible_stems[0], &possible_stems[1] );
++ valid_possible_stems = 2;
++ }
++ possible_stems[0].center = set_center_to;
++ possible_stems[0].count = stem_matches;
++ possible_stems[0].width = set_width_to;
++ possible_stems[0].height = stem_matches;
++ }
++
++ /* otherwise if there are already 2 stems */
++ else if ( valid_possible_stems >= 2 )
++ {
++ /* if the stem is within the range of existing one, replace */
++ /* existing one */
++ if ( abs ( set_center_to - possible_stems[0].center )
++ <= one_pixel * 2 )
++ {
++ possible_stems[0].center = set_center_to;
++ possible_stems[0].count = stem_matches;
++ possible_stems[0].width = set_width_to;
++ possible_stems[0].height = stem_matches;
++ }
++ /* if the stem isn't within the range of this one */
++ else
++ {
++ /* see if within range of next one and swap if so and proceed */
++ /* overwriting it */
++ if ( abs ( set_center_to - possible_stems[1].center )
++ <= one_pixel * 2 )
++ swap_stem ( &possible_stems[0], &possible_stems[1] );
++
++ /* otherwise see if in range of third one */
++ else if ( abs ( set_center_to - possible_stems[2].center )
++ <= one_pixel * 2 )
++ swap_stem ( &possible_stems[0], &possible_stems[2] );
++
++ /* otherwise this is the new top dog, so demote everything */
++ else
++ {
++ swap_stem ( &possible_stems[1], &possible_stems[2] );
++ swap_stem ( &possible_stems[0], &possible_stems[1] );
++ valid_possible_stems += 1;
++ }
++ possible_stems[0].center = set_center_to;
++ possible_stems[0].count = stem_matches;
++ possible_stems[0].width = set_width_to;
++ possible_stems[0].height = stem_matches;
++ }
++ }
++ }
++
++ else if ( stem_matches > possible_stems[1].height &&
++ set_center_to != 0 )
++ {
++
++ /* make sure it doesn't match the first stem */
++ if ( abs ( set_center_to - possible_stems[0].center ) >= one_pixel * 2 )
++ {
++
++ /* if this is the second stem */
++ if ( valid_possible_stems == 1 )
++ valid_possible_stems = 2;
++
++ /* otherwise if there is already a stem here */
++ else if ( valid_possible_stems >= 2 )
++ {
++ /* if it doesn't match the second stem, proceed to swap out */
++ /* with the third. if it does, replace it */
++ if ( abs ( set_center_to - possible_stems[1].center )
++ >= one_pixel * 2 )
++ {
++ swap_stem ( &possible_stems[1], &possible_stems[2] );
++ valid_possible_stems +=1;
++ }
++ }
++ possible_stems[1].center = set_center_to;
++ possible_stems[1].count = stem_matches;
++ possible_stems[1].width = set_width_to;
++ possible_stems[1].height = stem_matches;
++ }
++ }
++
++ else if ( stem_matches > possible_stems[2].height &&
++ set_center_to != 0 )
++ {
++ /* if it doesn't match the first or second one */
++ if ( abs( set_center_to - possible_stems[0].center) >= one_pixel * 2 &&
++ abs( set_center_to - possible_stems[1].center) >= one_pixel * 2 )
++ {
++ if ( valid_possible_stems == 2 )
++ valid_possible_stems += 1;
++
++ possible_stems[2].center = set_center_to;
++ possible_stems[2].count = stem_matches;
++ possible_stems[2].width = set_width_to;
++ possible_stems[1].height = stem_matches;
++ }
++ }
++
++ if ( valid_possible_stems > 3 )
++ valid_possible_stems = 3;
++
++ center++;
++ }
++
++ /* promote to stem */
++ if ( valid_possible_stems > 0 )
++ {
++ stems[0].center = possible_stems[0].center;
++ stems[0].count = possible_stems[0].count;
++ stems[0].width = possible_stems[0].width;
++ stems[0].height = possible_stems[0].height;
++ stems[0].generated = FALSE;
++ valid_stems++;
++ }
++
++ if ( valid_stems == 1 &&
++ valid_possible_stems > 1 )
++ {
++ stems[1].center = possible_stems[1].center;
++ stems[1].count = possible_stems[1].count;
++ stems[1].width = possible_stems[1].width;
++ stems[1].height = possible_stems[1].height;
++ stems[1].generated = FALSE;
++ valid_stems++;
++ }
++
++ if ( valid_stems == 2 &&
++ valid_possible_stems > 2 &&
++ possible_stems[2].center != 0 )
++ {
++ stems[2].center = possible_stems[2].center;
++ stems[2].count = possible_stems[2].count;
++ stems[2].width = possible_stems[2].width;
++ stems[2].height = possible_stems[2].height;
++ stems[2].generated = FALSE;
++ valid_stems++;
++ }
++
++ /* sort stems in x direction */
++ if ( valid_stems == 3 )
++ {
++ if ( stems[0].center > stems[1].center )
++ swap_stem ( &stems[0], &stems[1] );
++
++ if ( stems[0].center > stems[2].center )
++ swap_stem ( &stems[1], &stems[2] );
++
++ if ( stems[1].center > stems[2].center )
++ swap_stem ( &stems[1], &stems[2] );
++
++ if ( stems[0].center > stems[1].center )
++ swap_stem ( &stems[0], &stems[1] );
++
++ /* only look at first and last stem for now */
++ swap_stem ( &stems[1], &stems[2] );
++ }
++
++ /* synthesize stems - Works, but needs work */
++ if ( ( strategy_synthesize_stems ||
++ known_stem_values->synth_stems ) &&
++ valid_stems == 0 &&
++ ppem > 10 )
++ {
++ /* if the leftmost segment's leftmost point is the same as the glyph's */
++ /* leftmost point, and it is of reasonable width, and is not on the */
++ /* top or bottom of the bitmap */
++ if ( leftmost_segment_not_extrema->x1
++ == leftmost_point_not_extrema &&
++ abs ( leftmost_segment_not_extrema->x2
++ - leftmost_segment_not_extrema->x1 )
++ < ( rightmost_point_not_extrema
++ - leftmost_point_not_extrema ) / 3 &&
++ leftmost_segment_not_extrema->y < height &&
++ leftmost_segment_not_extrema->y > 1 )
++ {
++ stems[valid_stems].center = ( leftmost_segment_not_extrema->x2
++ + leftmost_segment_not_extrema->x1 ) / 2;
++ stems[valid_stems].width = leftmost_segment_not_extrema->x2
++ - leftmost_segment_not_extrema->x1;
++ stems[valid_stems].generated = TRUE;
++ valid_stems += 1;
++ }
++
++
++ if ( rightmost_segment_not_extrema->x2
++ == rightmost_point_not_extrema &&
++ abs ( rightmost_segment_not_extrema->x2
++ - rightmost_segment_not_extrema->x1 )
++ < ( rightmost_point_not_extrema
++ - leftmost_point_not_extrema ) / 3 &&
++ rightmost_segment_not_extrema->y < height &&
++ rightmost_segment_not_extrema->y > 1 )
++ {
++ stems[valid_stems].center = ( rightmost_segment_not_extrema->x2
++ + rightmost_segment_not_extrema->x1 ) / 2;
++ stems[valid_stems].width = rightmost_segment_not_extrema->x2
++ - rightmost_segment_not_extrema->x1;
++ stems[valid_stems].generated = TRUE;
++ valid_stems += 1;
++ }
++
++ }
++
++ /* sort stems in x direction */
++ if ( valid_stems > 1 && stems[0].center > stems[1].center )
++ swap_stem ( &stems[0], &stems[1] );
++
++ if ( valid_stems == 0 && known_stem_values->stem_translating != 0 )
++ {
++ *translate_value += known_stem_values->stem_translating;
++
++ if ( strategy_use_strengths )
++ {
++ /* consider 1/2 pixel the max when strength is at 100%,
++ unless translate is already greater than that */
++ FT_Int strength_cutoff = 32;
++
++
++ if ( abs ( *translate_value ) > strength_cutoff)
++ strength_cutoff = *translate_value;
++
++ max_strength = ( strength_cutoff * alignment_strength ) / 100;
++
++ if ( *translate_value < -max_strength )
++ *translate_value = -max_strength;
++ else if ( *translate_value > max_strength )
++ *translate_value = max_strength;
++ }
++ }
++ else
++ /* Start snapping */
++ {
++ FT_Int center_offset;
++ FT_Int modulus;
++ FT_Int delta, delta2;
++ FT_Long stem_distance = 1, new_distance = 1;
++ FT_Int distance_floor, distance_ceiling;
++ FT_Int translate_value2 = 0;
++ FT_Int main_stem = 0;
++ FT_Int lbearing = m_horiBearingX * 12;
++ FT_Int bitmap_stem_location = stems[0].center;
++ FT_Int advance_stem_location = bitmap_stem_location
++ + lbearing - one_pixel;
++ FT_Int advance_width = m_horiAdvance * 12;
++ FT_Int original_advance_width = 12 * ( slot->linearHoriAdvance >> 10 );
++ FT_Int glyph_width = rightmost_point - leftmost_point;
++ FT_Int stem_width = stems[0].width;
++ FT_Int advance_leftmost_location = leftmost_point
++ + lbearing - one_pixel;
++ FT_Int advance_rightmost_location = rightmost_point
++ + lbearing - one_pixel;
++
++#define proposed_transformed_point(point) \
++ point * (float)(new_distance) / (float)(stem_distance) \
++ + *translate_value * 12 - ( stems[main_stem].center * (float)(new_distance) \
++ / (float)(stem_distance) - stems[main_stem].center)
++
++#define proposed_translated_point(point) point + *translate_value * 12
++
++ center_offset = one_pixel / 2; /* half pixel */
++ modulus = one_pixel; /* whole pixel */
++
++ /* Determine center_offset via known values */
++ if ( known_stem_values->stem_width >= 0 )
++ {
++ if ( known_stem_values->stem_width % 2 == 0 )
++ center_offset = 0;
++ else
++ center_offset = one_pixel / 2;
++ }
++ /* otherwise do intelligent guessing, if set */
++ else if ( strategy_auto_change_center_offset &&
++ ppem >= STEM_WIDTH_2_PPEM &&
++ stems[0].width < one_pixel * 1.45 )
++ center_offset = one_pixel / 2;
++ else if ( strategy_auto_change_center_offset &&
++ ppem >= STEM_WIDTH_2_PPEM &&
++ stems[0].width >= one_pixel * 1.45 &&
++ stems[0].width < one_pixel * 2.6 )
++ center_offset = 0;
++ else if ( strategy_auto_change_center_offset &&
++ ppem >= STEM_WIDTH_2_PPEM &&
++ stems[0].width >= one_pixel * 2.6 &&
++ stems[0].width < one_pixel * 3.6 )
++ center_offset = one_pixel / 2;
++ else if ( strategy_auto_change_center_offset &&
++ ppem >= STEM_WIDTH_2_PPEM )
++ center_offset =
++ ( one_pixel
++ * ( ( ( (int)( stems[0].width + one_pixel / 2 ) )
++ / one_pixel ) % 2 ) ) / 2;
++
++ /* Snap to closest translate and scale values by default */
++ if ( valid_stems >= 1 )
++ {
++ /* closest snapping point for stem 0 */
++ delta = ( stems[0].center + center_offset ) % modulus;
++
++ if ( delta < modulus / 2 )
++ /* snap left */
++ *translate_value = -delta / ( columns_per_pixel * 4 );
++ else
++ /* snap right */
++ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 );
++ }
++
++ if ( strategy_use_d_correction )
++ {
++ /* if the only stem is in the last 1/3 of glyph width, the advance */
++ /* is 6 pixels, the ppem 11, and doing so doesn't violate bitmap , */
++ /* boundaries force it to snap right */
++ if ( valid_stems == 1 &&
++ advance_stem_location > (advance_width * 2) / 3 &&
++ advance_width == 6 * one_pixel &&
++ rightmost_point + modulus - delta
++ <= ( width - (columns_per_pixel * 2) / 3) * 256 &&
++ ppem == 11 )
++ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 );
++ }
+
+-#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ if ( strategy_use_strengths )
++ {
++ /* consider 1/2 pixel the max when strength is at 100%,
++ unless translate is already greater than that */
++ FT_Int strength_cutoff = 32;
++ if ( abs ( *translate_value ) > strength_cutoff )
++ strength_cutoff = *translate_value;
++
++ max_strength = ( strength_cutoff * alignment_strength ) / 100;
++
++ if ( *translate_value < -max_strength )
++ *translate_value = -max_strength;
++ else if ( *translate_value > max_strength )
++ *translate_value = max_strength;
++ }
+
+- FT_Vector* sub = render->root.library->lcd_geometry;
++ /* If 2 stems is detected, scale distance
++ between in order to land on pixels */
++ if ( valid_stems >= 2 )
++ {
++ stem_distance = abs ( stems[1].center - stems[0].center );
++
++ delta = stem_distance % modulus;
++ new_distance = stem_distance - delta;
++
++ distance_floor = stem_distance - delta;
++ distance_ceiling = stem_distance + ( modulus - delta );
++
++ if ( delta < modulus / 2 )
++ new_distance = distance_floor;
++ else
++ new_distance = distance_ceiling;
++
++ if ( columns_per_pixel == 3 &&
++ valid_stems == 3 &&
++ strategy_use_m_control &&
++ ( width - 2 * columns_per_pixel ) > 6 * columns_per_pixel &&
++ ppem > 8 &&
++ ( advance_stem_location - advance_leftmost_location )
++ < stems[main_stem].width * 2 )
++ {
++ /* Possibly use 2 only when compatible widths is on? */
++ FT_Int mod_factor = 2;
++
++ if ( verbose )
++ printf ( "USING M CONTROL ");
++
++ distance_floor = stem_distance
++ - stem_distance % ( modulus * mod_factor ) ;
++ distance_ceiling = distance_floor + modulus * mod_factor;
++
++ new_distance = distance_ceiling;
++
++ /* force certain ideal situations */
++ /* these 2 are mostly safe to do */
++ if ( distance_ceiling
++ + one_pixel * columns_per_pixel == advance_width &&
++ stem_width < one_pixel * 1.25 )
++ new_distance = distance_ceiling;
++ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER
++ THAT NUDGE IS UP OR DOWN */
++ else if ( stem_distance + one_pixel * 2.6 >= advance_width &&
++ stem_width < one_pixel * 1.25 )
++ new_distance = distance_ceiling;
++
++ if ( proposed_transformed_point ( leftmost_point )
++ < one_third_pixel * 2 ||
++ proposed_transformed_point ( rightmost_point )
++ > ( width -2 ) * one_third_pixel )
++ new_distance = distance_floor;
++
++ /* NEED TO IGNORE SERIF Ms HERE */
++ /* perhaps check bitmap boundaries instead??? */
++ if ( strategy_bearing_correction && new_distance == distance_ceiling )
++ {
++ /* Correct if bearings are made substantially worse
++ (more than 1/3 a pixel beyond advance) */
++ if ( proposed_transformed_point( advance_rightmost_location )
++ > advance_width + one_third_pixel &&
++ proposed_transformed_point( advance_rightmost_location )
++ > advance_rightmost_location &&
++ -proposed_transformed_point( advance_leftmost_location )
++ < advance_rightmost_location - advance_width )
++ new_distance = distance_floor;
++ }
++
++ if ( known_stem_values->m >= 0 )
++ {
++ if ( known_stem_values->m == 0 )
++ new_distance = distance_floor;
++ else
++ new_distance = distance_ceiling;
++ }
++
++ if ( ( rightmost_point - leftmost_point) -
++ ( ( rightmost_point * *scale_value)
++ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 )
++ {
++ *scale_value = 1.0;
++ *translate_value = 0;
++ goto Exit;
++ }
+
++ }
++ else if ( columns_per_pixel == 1 &&
++ valid_stems == 3 &&
++ strategy_use_m_control && valid_stems == 3 &&
++ width >= 6 * columns_per_pixel &&
++ ppem > 8 &&
++ ( advance_stem_location - advance_leftmost_location )
++ < stems[main_stem].width * 2 )
++ {
++ /* Possibly use 2 only when compatible widths is on? */
++ FT_Int mod_factor = 2;
++
++ if ( verbose )
++ printf ("USING M CONTROL ");
++ distance_floor = stem_distance - stem_distance
++ % ( modulus * mod_factor) ;
++ distance_ceiling = distance_floor + modulus * mod_factor;
++
++ new_distance = distance_ceiling;
++
++ /* force certain ideal situations */
++ /* these 2 are mostly safe to do */
++ if ( distance_ceiling
++ + one_pixel * columns_per_pixel == advance_width &&
++ stem_width < one_pixel * 1.25 )
++ new_distance = distance_ceiling;
++ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER
++ THAT NUDGE IS UP OR DOWN */
++ else if ( stem_distance + one_pixel * 2.6 >= advance_width &&
++ stem_width < one_pixel * 1.25 )
++ new_distance = distance_ceiling;
++
++ if ( proposed_transformed_point( leftmost_point ) < 0 ||
++ proposed_transformed_point( rightmost_point )
++ > width * one_pixel - 2 * one_third_pixel )
++ new_distance = distance_floor;
++
++ /* NEED TO IGNORE SERIF Ms HERE */
++ /* perhaps check bitmap boundaries instead??? */
++ if ( strategy_bearing_correction && new_distance == distance_ceiling )
++ {
++ /* Correct if bearings are made substantially worse
++ (more than 1/3 a pixel beyond advance) */
++ if ( proposed_transformed_point( advance_rightmost_location )
++ > advance_width + one_third_pixel &&
++ proposed_transformed_point( advance_rightmost_location )
++ > advance_rightmost_location &&
++ -proposed_transformed_point( advance_leftmost_location )
++ < advance_rightmost_location - advance_width )
++ new_distance = distance_floor;
++ }
++
++ if ( known_stem_values->m >= 0 )
++ {
++ if ( known_stem_values->m == 0 )
++ new_distance = distance_floor;
++ else
++ new_distance = distance_ceiling;
++ }
++
++
++ if ( ( rightmost_point - leftmost_point )
++ - ( ( rightmost_point * *scale_value )
++ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 )
++ {
++ *scale_value = 1.0;
++ *translate_value = 0;
++ goto Exit;
++ }
+
+- /* set up default subpixel geometry for striped RGB panels. */
+- sub[0].x = -21;
+- sub[0].y = 0;
+- sub[1].x = 0;
+- sub[1].y = 0;
+- sub[2].x = 21;
+- sub[2].y = 0;
++ }
++ else
++ {
++ if ( strategy_fit_to_width )
++ new_distance = advance_width - 3 * one_pixel;
++ else if ( known_stem_values->stem_scaling >= 0 )
++ {
++ if ( known_stem_values->stem_scaling > 0 )
++ new_distance = distance_ceiling;
++ else
++ new_distance = distance_floor;
++
++ /* enforce advance width boundaries */
++ /* TOO RESTRICTIVE ON SERIF FONTS */
++ if ( proposed_transformed_point( advance_rightmost_location )
++ >= advance_width ||
++ proposed_transformed_point( advance_leftmost_location )
++ <= 0 )
++ new_distance = distance_floor;
++
++ /* enforce literal bitmap boundaries if no translate room */
++ if ( ( proposed_transformed_point(rightmost_point) >= width * 256
++ || proposed_transformed_point(leftmost_point ) <= one_pixel )
++ && new_distance + one_pixel * 3 > advance_width )
++ new_distance = distance_floor;
++
++ }
++ else if ( strategy_translate_using_closest_stem )
++ {
++ /* closest snapping point for stem 1 */
++ delta2 = ( stems[1].center + center_offset ) % modulus;
++
++ if ( delta2 < modulus / 2 )
++ /* snap left */
++ translate_value2 = -delta2 / ( columns_per_pixel * 4 );
++ else
++ /* snap right */
++ translate_value2 = ( modulus - delta2 )
++ / ( columns_per_pixel * 4 );
++
++ if ( abs ( translate_value2 ) < abs ( *translate_value ) )
++ {
++ *translate_value = translate_value2;
++ main_stem = 1;
++ }
++
++ }
++ else if ( strategy_scale_to_closest_centers )
++ {
++ /* closest snapping point for stem 0 */
++ delta = ( stems[0].center + center_offset ) % modulus;
++ delta2 = ( stems[1].center + center_offset ) % modulus;
++
++ if ( delta < modulus / 2 )
++ /* stretch left */
++ new_distance = delta + stem_distance;
++ else
++ /* stretch right */
++ new_distance = delta - modulus + stem_distance;
++
++ if ( delta2 < modulus / 2 )
++ new_distance -= delta2; /* stretch left */
++ else
++ new_distance += modulus - delta2; /* stretch right */
++
++ }
++ else if ( strategy_scale_to_closest_centers_up_only )
++ {
++ FT_Int net_change = 0;
++
++ /* closest snapping point for stem 0 */
++ delta = ( stems[0].center + center_offset ) % modulus;
++ delta2 = ( stems[1].center + center_offset ) % modulus;
++
++ if ( delta < modulus / 2 )
++ net_change = delta; /* stretch left */
++ else
++ net_change = -( modulus - delta ); /* stretch right */
++
++ if ( delta2 < modulus / 2 )
++ net_change -= delta2; /* stretch left */
++ else
++ net_change += modulus - delta2; /* stretch right */
++
++ if ( net_change > 0 &&
++ proposed_transformed_point( advance_rightmost_location )
++ < advance_width &&
++ proposed_transformed_point( advance_leftmost_location ) > 0 )
++ new_distance = distance_ceiling;
++ }
++
++ else if ( strategy_always_use_distance_ceiling )
++ {
++ if ( proposed_transformed_point( advance_rightmost_location )
++ < advance_width &&
++ proposed_transformed_point( advance_leftmost_location ) > 0 )
++ new_distance = distance_ceiling;
++ }
++ }
+
+-#elif 0 /* or else, once ClearType patents expire */
++ if ( strategy_use_strengths )
++ {
++ FT_Int strength_cutoff = center_offset;
+
+- FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
+
+-#endif
++ delta2 = new_distance - stem_distance;
+
+- render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
++ if ( abs ( delta2 ) > strength_cutoff )
++ strength_cutoff = delta2;
+
+- return 0;
+- }
++ max_strength = ( strength_cutoff * fitting_strength ) / 100;
+
++ if ( delta2 < -max_strength )
++ new_distance = stem_distance - max_strength;
++ else if ( delta2 > max_strength )
++ new_distance = stem_distance + max_strength;
++ }
+
+- /* sets render-specific mode */
+- static FT_Error
+- ft_smooth_set_mode( FT_Renderer render,
+- FT_ULong mode_tag,
+- FT_Pointer data )
+- {
+- /* we simply pass it to the raster */
+- return render->clazz->raster_class->raster_set_mode( render->raster,
+- mode_tag,
+- data );
+- }
++ *scale_value = (float)( new_distance ) / (float)( stem_distance );
++ *translate_value = *translate_value
++ - ( (float)( stems[main_stem].center * (float)new_distance )
++ / (float)stem_distance - stems[main_stem].center ) / 12;
+
+- /* transform a given glyph image */
+- static FT_Error
+- ft_smooth_transform( FT_Renderer render,
+- FT_GlyphSlot slot,
+- const FT_Matrix* matrix,
+- const FT_Vector* delta )
+- {
+- FT_Error error = FT_Err_Ok;
++ if ( valid_stems == 2 )
++ *embolden_value = ( 64.0 / *scale_value - 64.0 );
+
++ if ( valid_stems == 3 )
++ *embolden_value = ( 64.0 / *scale_value - 64.0 ) / 1.5;
++ }
+
+- if ( slot->format != render->glyph_format )
+- {
+- error = FT_THROW( Invalid_Argument );
++ if ( verbose )
++ printf ( "%lu stems:", valid_stems );
++
++ if ( valid_stems == 1 && verbose )
++ printf ( "1 stem: bitmapwidth:%d glyphwidth:%f glyph_width:%f center:%f bearing:%f advance:%f lhadvance:%f stemwidth:%f %d %d",
++ (width - 6) / columns_per_pixel,
++ (float)m_width / 64.0,
++ (float)glyph_width / (float)one_pixel,
++ (float)( (float)advance_stem_location ) / (float)one_pixel,
++ (float)m_horiBearingX / 64.0,
++ (float)m_horiAdvance / 64.0,
++ (float)linearHoriAdvance / 64.0,
++ (float)stems[0].width / (float)one_pixel,
++ advance_width, original_advance_width );
++ else if ( valid_stems >= 2 && verbose )
++ printf ( "%lu stems: bitmapwidth:%d center1:%f center2:%f difference:%f bearing:%f advance:%f advstemloc:%f ",
++ valid_stems,
++ (width - 6) / columns_per_pixel,
++ ( (float)advance_stem_location ) / (float)one_pixel,
++ ( (float)advance_stem_location
++ + (float)abs ( stems[1].center
++ - stems[0].center) ) / (float)one_pixel,
++ ( (float)abs ( stems[1].center
++ - stems[0].center ) ) / (float)one_pixel,
++ (float)m_horiBearingX / 64.0,
++ (float)m_horiAdvance / 64.0,
++ (float)advance_stem_location / (float)one_pixel );
++
++ if ( strategy_bearing_correction )
++ {
++ /* Correct if negative bearings are made substantially worse */
++ /* (more than 1/3 a pixel) */
++ if ( proposed_transformed_point( advance_rightmost_location )
++ > advance_width &&
++ proposed_transformed_point( advance_rightmost_location )
++ > advance_rightmost_location &&
++ -proposed_transformed_point( advance_leftmost_location )
++ < advance_rightmost_location - advance_width &&
++ *translate_value
++ > one_third_pixel / ( columns_per_pixel * 4 ) )
++ {
++ *translate_value -=64 ;
++ if ( verbose )
++ printf ( "TRANSLATING -64 " );
++ }
++ }
+ goto Exit;
+ }
+
+- if ( matrix )
+- FT_Outline_Transform( &slot->outline, matrix );
++ Exit:
+
+- if ( delta )
+- FT_Outline_Translate( &slot->outline, delta->x, delta->y );
++#define transformed_point( point ) point * *scale_value + *translate_value * 12
+
+- Exit:
+- return error;
++ if ( strategy_correct_out_of_bounds_outlines )
++ {
++ /* Correct if outside bitmap */
++ if ( transformed_point( rightmost_point )
++ >= width * 256 - 2 * one_third_pixel &&
++ transformed_point( leftmost_point )
++ > one_pixel + 2 * one_third_pixel )
++ *translate_value -=64 ;
++ else if ( transformed_point( leftmost_point )
++ <= one_pixel / 2 &&
++ transformed_point( rightmost_point )
++ <= width * 256 - ( one_pixel + one_pixel / 2 ) )
++ *translate_value += 64;
++ }
++
++ STVALUES
++ free ( centers );
++ free ( segments );
++ free ( stem_centers );
++ free ( stems );
++ free ( leftmost_segment );
+ }
+
+
+- /* return the glyph's control box */
++ /* Gamma correction */
+ static void
+- ft_smooth_get_cbox( FT_Renderer render,
+- FT_GlyphSlot slot,
+- FT_BBox* cbox )
++ _ft_lcd_gamma_correction_correction ( FT_Bitmap* bitmap,
++ FT_Render_Mode mode,
++ FT_GlyphSlot slot,
++ float gamma_correction_lt,
++ float gamma_correction_value )
+ {
+- FT_ZERO( cbox );
++ if ( gamma_correction_value != 1.0 )
++ {
++ FT_UInt width = (FT_UInt)bitmap->width;
++ FT_UInt height = (FT_UInt)bitmap->rows;
++ FT_Byte* line = bitmap->buffer;
++ float ppem = (float)slot->face->size->metrics.x_ppem;
+
+- if ( slot->format == render->glyph_format )
+- FT_Outline_Get_CBox( &slot->outline, cbox );
++
++ if ( !slot->face || !slot->face->size ) return;
++
++ if ( ppem >= 5 )
++ for ( height = (FT_UInt)bitmap->rows;
++ height > 0;
++ height--, line += bitmap->pitch )
++ {
++ FT_UInt xx;
++
++
++ for ( xx = 0; xx < width; xx += 1 )
++ {
++ /*normal*/
++ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value );*/
++
++ /* sloped */
++ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5
++ * (1-gamma_correction_value)/(gamma_correction_lt -5)
++ + ((1-gamma_correction_value)/(gamma_correction_lt -5)) * ppem );*/
++
++ /* 1/3-sloped */
++ line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5
++ * ( ( 1 - gamma_correction_value )
++ / ( 3 * ( gamma_correction_lt -5 ) ) )
++ + ( ( 1 - gamma_correction_value )
++ / ( 3 * ( gamma_correction_lt -5) ) ) * ppem );
++ }
++ }
++ }
+ }
+
++#endif
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+@@ -116,17 +2321,218 @@
+ const FT_Vector* origin,
+ FT_Render_Mode required_mode )
+ {
+- FT_Error error = FT_Err_Ok;
+- FT_Outline* outline = &slot->outline;
++ FT_Error error;
++ FT_Outline* outline = NULL;
++ FT_Outline* outline_orig = NULL;
++ FT_BBox cbox;
++ FT_Pos width, height, pitch, ppem;
++#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ FT_Pos height_org, width_org;
++#endif
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_Memory memory = render->root.memory;
+- FT_Pos x_shift = 0;
+- FT_Pos y_shift = 0;
+ FT_Int hmul = ( mode == FT_RENDER_MODE_LCD );
+ FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V );
++ FT_Pos x_shift = 0;
++ FT_Pos y_shift = 0;
++ FT_Pos x_left, y_top;
+
+ FT_Raster_Params params;
+
++ FT_Bool have_translated_origin = FALSE;
++ FT_Bool have_outline_shifted = FALSE;
++ FT_Bool have_buffer = FALSE;
++
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Matrix scaleMat;
++ FT_Long translate_value = 0;
++ float scale_value = 1.0;
++ FT_Int align_called = 0;
++
++
++ int chromeos_style_sharpening_strength = 0;
++ int alignment_strength = 0;
++ int fitting_strength = 0;
++ int fringe_filter_strength = 0;
++ int grayscale_filter_strength = 0;
++
++ int autohint_horizontal_stem_darken_strength = 0;
++ int autohint_vertical_stem_darken_strength = 0;
++
++ int windows_style_sharpening_strength = 0;
++ float gamma_correction_value = 1;
++ float gamma_correction_lt = 0;
++
++ FT_Int brightness_value = 0.0;
++ FT_Int contrast_value = 0.0;
++
++ FT_Int snapping_sliding_scale_value = 0;
++
++ FT_Int global_embolden_x_value = 0;
++ FT_Int global_embolden_y_value = 0;
++
++ FT_Int bold_embolden_x_value = 0;
++ FT_Int bold_embolden_y_value = 0;
++
++ FT_Byte chromeos_cutoff;
++ double chromeos_gamma_value;
++
++ float embolden_value = 0.0;
++ FT_Bool autohinted = FALSE;
++ FT_Bool use_various_tweaks = FALSE;
++ FT_Pos cur_width = infinality_cur_width;
++
++ const FT_Int MIN_PPEM = 1;
++ /*const FT_Int MAX_PPEM = 100; */
++
++ FT_Bool use_known_settings_on_selected_fonts;
++
++ if ( slot->face &&
++ slot->face->size &&
++ slot->face->size->metrics.x_ppem )
++ ppem = slot->face->size->metrics.x_ppem;
++ else
++ ppem = 0;
++
++ if ( cur_width )
++ {
++ autohinted = TRUE;
++ }
++ if( ftinf ){
++ const float *f=ftinf->gamma_correction;
++
++ use_known_settings_on_selected_fonts=ftinf->use_known_settings_on_selected_fonts;
++ use_various_tweaks=ftinf->use_various_tweaks;
++ snapping_sliding_scale_value=ftinf->stem_snapping_sliding_scale;
++
++ alignment_strength=ftinf->stem_alignment_strength;
++ if ( snapping_sliding_scale_value != 0 )
++ alignment_strength = sliding_scale(10, snapping_sliding_scale_value, alignment_strength, 100, ppem);
++
++ fitting_strength=ftinf->stem_fitting_strength;
++ if ( snapping_sliding_scale_value != 0 )
++ fitting_strength = sliding_scale(10, snapping_sliding_scale_value, fitting_strength, 100, ppem);
++
++ chromeos_style_sharpening_strength=ftinf->chromeos_style_sharpening_strength;
++
++ if ( ppem > 10 )
++ chromeos_style_sharpening_strength =
++ ( chromeos_style_sharpening_strength * ppem ) / 10;
++
++ if ( chromeos_style_sharpening_strength > 100 )
++ chromeos_style_sharpening_strength = 100;
++
++ brightness_value=ftinf->brightness;
++ contrast_value=ftinf->contrast;
++
++ windows_style_sharpening_strength=ftinf->windows_style_sharpening_strength;
++
++ /* Decrease effect slightly to have a more linear increase in sharpness */
++ windows_style_sharpening_strength =
++ ( ( windows_style_sharpening_strength
++ * windows_style_sharpening_strength ) / 100
++ + windows_style_sharpening_strength ) / 2;
++
++ gamma_correction_lt = f[0];
++ gamma_correction_value = f[1] / 100.0f;
++
++ fringe_filter_strength=ftinf->fringe_filter_strength;
++ grayscale_filter_strength=ftinf->grayscale_filter_strength;
++
++ autohint_horizontal_stem_darken_strength=ftinf->autohint_horizontal_stem_darken_strength;
++ autohint_vertical_stem_darken_strength=ftinf->autohint_vertical_stem_darken_strength;
++
++ global_embolden_x_value=ftinf->global_embolden_x_value;
++ global_embolden_y_value=ftinf->global_embolden_y_value;
++
++ bold_embolden_x_value=ftinf->bold_embolden_x_value;
++ bold_embolden_y_value=ftinf->bold_embolden_y_value;
++ } else {
++ use_known_settings_on_selected_fonts=FALSE;
++ }
++
++ /* set gamma value to 1 if out of range */
++ if ( slot->face &&
++ slot->face->size &&
++ slot->face->size->metrics.x_ppem )
++ {
++ if ( slot->face->size->metrics.x_ppem >= gamma_correction_lt )
++ gamma_correction_value = 1;
++ }
++ else
++ gamma_correction_value = 1;
++
++ if( use_various_tweaks &&
++ slot->face &&
++ slot->face->style_name )
++ {
++ /* needs to also check for artifical italics */
++ if ( strcasestr(slot->face->style_name, "Italic" ) ||
++ strcasestr(slot->face->style_name, "Oblique" ) )
++ {
++ windows_style_sharpening_strength = 0;
++ chromeos_style_sharpening_strength = 0;
++ }
++ }
++
++ /*if (fitting_strength == 100) scale_value = 1.1;*/
++
++#endif
++
++#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++
++ FT_Int lcd_extra = 0;
++ FT_LcdFiveTapFilter lcd_weights = { 0 };
++ FT_Bool have_custom_weight = FALSE;
++ FT_Bitmap_LcdFilterFunc lcd_filter_func = NULL;
++
++
++ if ( slot->face )
++ {
++ FT_Char i;
++
++
++ for ( i = 0; i < FT_LCD_FILTER_FIVE_TAPS; i++ )
++ if ( slot->face->internal->lcd_weights[i] != 0 )
++ {
++ have_custom_weight = TRUE;
++ break;
++ }
++ }
++
++ /*
++ * The LCD filter can be set library-wide and per-face. Face overrides
++ * library. If the face filter weights are all zero (the default), it
++ * means that the library default should be used.
++ */
++ if ( have_custom_weight )
++ {
++ /*
++ * A per-font filter is set. It always uses the default 5-tap
++ * in-place FIR filter that needs 2 extra pixels.
++ */
++ ft_memcpy( lcd_weights,
++ slot->face->internal->lcd_weights,
++ FT_LCD_FILTER_FIVE_TAPS );
++ lcd_filter_func = ft_lcd_filter_fir;
++ lcd_extra = 2;
++ }
++ else
++ {
++ /*
++ * The face's lcd_weights is {0, 0, 0, 0, 0}, meaning `use library
++ * default'. If the library is set to use no LCD filtering
++ * (lcd_filter_func == NULL), `lcd_filter_func' here is also set to
++ * NULL and the tests further below pass over the filtering process.
++ */
++ ft_memcpy( lcd_weights,
++ slot->library->lcd_weights,
++ FT_LCD_FILTER_FIVE_TAPS );
++ lcd_filter_func = slot->library->lcd_filter_func;
++ lcd_extra = slot->library->lcd_extra;
++ }
++
++#endif /*FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+@@ -142,6 +2548,128 @@
+ goto Exit;
+ }
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++RERENDER:
++ if ( align_called == 1 )
++ {
++ scaleMat.xx = FT_FixedFromFloat(scale_value);
++ scaleMat.xy = 0;
++ scaleMat.yx = 0;
++ scaleMat.yy = ( 1 << 16 );
++
++ FT_Outline_Copy(outline_orig, outline);
++
++ if ( scale_value != 1.0 )
++ FT_Outline_Transform( outline, &scaleMat );
++
++ FT_Outline_Translate( outline, translate_value, 0 );
++
++ FT_Outline_EmboldenXY( outline, embolden_value, 0 );
++ }
++ else
++ {
++#endif
++ outline = &slot->outline;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* Need to get this PRIOR to embolden, otherwise bad things happen */
++ FT_Outline_Get_CBox( outline, &cbox );
++
++ /* Various hacks that need to be turned into a new rule set */
++ /*if ( !autohinted
++ && use_known_settings_on_selected_fonts
++ && mode == FT_RENDER_MODE_LCD
++ && slot->face->family_name
++ && slot->face->style_name
++ && ( strcasestr(slot->face->family_name, "Courier New" )
++ && ( strcasestr(slot->face->style_name, "Regular" )
++ || strcasestr(slot->face->style_name, "Italic" ) ) ) )
++ FT_Outline_Embolden( outline, 24 );*/
++
++ if ( slot->face )
++ {
++ if ( !autohinted &&
++ use_known_settings_on_selected_fonts &&
++ mode == FT_RENDER_MODE_LCD &&
++ slot->face->family_name &&
++ slot->face->style_name &&
++ strcasestr( slot->face->family_name, "Times New Roman" ) &&
++ strcasestr( slot->face->style_name, "Italic" ) )
++ FT_Outline_EmboldenXY( outline, 12, 0 );
++
++ if ( use_known_settings_on_selected_fonts &&
++ autohinted &&
++ mode == FT_RENDER_MODE_LCD &&
++ slot->face->family_name &&
++ slot->face->style_name &&
++ strcasestr(slot->face->family_name, "FreeSerif" ) &&
++ strcasestr(slot->face->style_name, "Italic" ) )
++ FT_Outline_EmboldenXY( outline, 8, 0 );
++
++ if ( global_embolden_x_value != 0 || global_embolden_y_value != 0 )
++ FT_Outline_EmboldenXY( outline,
++ global_embolden_x_value,
++ global_embolden_y_value );
++
++ if ( ( bold_embolden_x_value != 0 || bold_embolden_y_value != 0 ) &&
++ ( slot->face->style_name &&
++ ( strcasestr(slot->face->style_name, "Bold" ) ||
++ strcasestr(slot->face->style_name, "Black" ) ||
++ ( slot->face->style_flags &&
++ slot->face->style_flags & FT_STYLE_FLAG_BOLD ) ) ) )
++ FT_Outline_EmboldenXY( outline,
++ bold_embolden_x_value,
++ bold_embolden_y_value );
++ }
++
++ FT_Outline_Copy( outline, outline_orig );
++ }
++
++ /* translate the outline to the new origin if needed */
++ if ( align_called == 0 )
++ {
++ FT_Pos enlarge_cbox = 0;
++
++ /* enlarge for grayscale rendering */
++ if ( mode == FT_RENDER_MODE_NORMAL )
++ enlarge_cbox = 64;
++
++ if ( origin )
++ {
++ FT_Outline_Translate( outline, origin->x, origin->y );
++ have_translated_origin = TRUE;
++ }
++
++ /* compute the control box, and grid fit it */
++ /*FT_Outline_Get_CBox( outline, &cbox );*/
++
++ cbox.xMin = FT_PIX_FLOOR( cbox.xMin - enlarge_cbox );
++ cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
++ cbox.xMax = FT_PIX_CEIL( cbox.xMax + enlarge_cbox );
++ cbox.yMax = FT_PIX_CEIL( cbox.yMax );
++#else
++ if ( origin )
++ {
++ FT_Outline_Translate( outline, origin->x, origin->y );
++ have_translated_origin = TRUE;
++ }
++
++ /* compute the control box, and grid fit it */
++ FT_Outline_Get_CBox( outline, &cbox );
++
++ cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
++ cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
++ cbox.xMax = FT_PIX_CEIL( cbox.xMax );
++ cbox.yMax = FT_PIX_CEIL( cbox.yMax );
++#endif
++
++ width = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
++ height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
++
++#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ width_org = width;
++ height_org = height;
++#endif
++
+ /* release old bitmap buffer */
+ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+ {
+@@ -149,34 +2677,85 @@
+ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+- if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
++ /* allocate new one */
++ pitch = width;
++ if ( hmul )
+ {
+- error = FT_THROW( Raster_Overflow );
+- goto Exit;
++ width = width * 3;
++ pitch = FT_PAD_CEIL( width, 4 );
+ }
+
+- /* allocate new one */
+- if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
+- goto Exit;
++ if ( vmul )
++ height *= 3;
+
+- slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
++ x_shift = cbox.xMin;
++ y_shift = cbox.yMin;
++ x_left = cbox.xMin >> 6;
++ y_top = cbox.yMax >> 6;
+
+- x_shift = 64 * -slot->bitmap_left;
+- y_shift = 64 * -slot->bitmap_top;
+- if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
+- y_shift += 64 * (FT_Int)bitmap->rows / 3;
+- else
+- y_shift += 64 * (FT_Int)bitmap->rows;
++#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ if ( lcd_filter_func )
++ {
++ if ( hmul )
++ {
++ x_shift -= 64 * ( lcd_extra >> 1 );
++ x_left -= lcd_extra >> 1;
++ width += 3 * lcd_extra;
++ pitch = FT_PAD_CEIL( width, 4 );
++ }
+
+- if ( origin )
++ if ( vmul )
++ {
++ y_shift -= 64 * ( lcd_extra >> 1 );
++ y_top += lcd_extra >> 1;
++ height += 3 * lcd_extra;
++ }
++ }
++#endif
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ }
++#endif
++
++
++ /* Required check is (pitch * height < FT_ULONG_MAX), */
++ /* but we care realistic cases only. Always pitch <= width. */
++ if ( width > 0x7FFF || height > 0x7FFF )
+ {
+- x_shift += origin->x;
+- y_shift += origin->y;
++ FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n",
++ width, height ));
++ error = FT_THROW( Raster_Overflow );
++ goto Exit;
+ }
+
++ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
++ bitmap->num_grays = 256;
++ bitmap->width = (unsigned int)width;
++ bitmap->rows = (unsigned int)height;
++ bitmap->pitch = pitch;
++
+ /* translate outline to render it into the bitmap */
+- if ( x_shift || y_shift )
+- FT_Outline_Translate( outline, x_shift, y_shift );
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( align_called == 0 )
++ {
++#endif
++ FT_Outline_Translate( outline, -x_shift, -y_shift );
++ have_outline_shifted = TRUE;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ }
++#endif
++ /* release old bitmap buffer */
++ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
++ {
++ FT_FREE( bitmap->buffer );
++ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
++ }
++
++ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) )
++ goto Exit;
++ else
++ have_buffer = TRUE;
++
++ slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+
+ /* set up parameters */
+ params.target = bitmap;
+@@ -223,159 +2802,240 @@
+ if ( error )
+ goto Exit;
+
+- /* finally apply filtering */
+- if ( hmul || vmul )
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM )
+ {
+- FT_Byte* lcd_weights;
+- FT_Bitmap_LcdFilterFunc lcd_filter_func;
+-
+-
+- /* Per-face LCD filtering takes priority if set up. */
+- if ( slot->face && slot->face->internal->lcd_filter_func )
++ if ( align_called == 0 && cur_width / ppem < 10 &&
++ ( alignment_strength > 0 || fitting_strength > 0 ) )
++ _lcd_stem_align ( bitmap,
++ mode,
++ slot,
++ &translate_value,
++ &scale_value,
++ alignment_strength,
++ fitting_strength,
++ &embolden_value );
++
++ if ( align_called == 0 &&
++ ( translate_value != 0 || scale_value != 1.0 ) )
+ {
+- lcd_weights = slot->face->internal->lcd_weights;
+- lcd_filter_func = slot->face->internal->lcd_filter_func;
++ align_called = 1;
++ goto RERENDER;
+ }
+- else
++
++ if ( mode == FT_RENDER_MODE_LCD )
+ {
+- lcd_weights = slot->library->lcd_weights;
+- lcd_filter_func = slot->library->lcd_filter_func;
+- }
+
+- if ( lcd_filter_func )
+- lcd_filter_func( bitmap, mode, lcd_weights );
+- }
++ if ( fringe_filter_strength > 0 /*&& autohinted*/ )
++ _ft_lcd_fringe_filter( bitmap,
++ mode,
++ fringe_filter_strength,
++ slot->library );
++
++ /*if ( autohinted)
++ _ft_lcd_stem_end_filter( bitmap, mode, 100, slot->library );*/
++
++ if ( gamma_correction_lt > 0 && gamma_correction_value != 1.0 )
++ _ft_lcd_gamma_correction_correction( bitmap,
++ mode,
++ slot,
++ gamma_correction_lt,
++ gamma_correction_value );
++
++ chromeos_cutoff = (FT_Byte)( 0.5 * 255.0 )
++ * ( chromeos_style_sharpening_strength / 100.0 );
++ chromeos_gamma_value = 1;
++
++ if ( chromeos_style_sharpening_strength > 0 )
++ _ft_lcd_chromeos_sharpen( bitmap,
++ mode,
++ chromeos_cutoff,
++ chromeos_gamma_value );
++
++ if ( ppem > 8 )
++ if ( windows_style_sharpening_strength > 0 )
++ _ft_lcd_windows_sharpen( bitmap,
++ mode,
++ windows_style_sharpening_strength,
++ slot->library );
++
++ if ( autohinted &&
++ ( cur_width * 100 ) / 64
++ > autohint_horizontal_stem_darken_strength &&
++ autohint_horizontal_stem_darken_strength != 0 )
++ autohint_horizontal_stem_darken_strength = ( cur_width * 100 ) / 64;
++
++ if ( autohint_horizontal_stem_darken_strength > 100)
++ autohint_horizontal_stem_darken_strength = 100;
++
++ /* only do on autohinted fonts */
++ /* Necessary to do on some non-thin fonts, which is why it is outside */
++ /* of the below conditional */
++ if ( autohint_horizontal_stem_darken_strength > 0 && autohinted )
++ _ft_lcd_darken_x ( bitmap,
++ mode,
++ autohint_horizontal_stem_darken_strength,
++ slot->library );
++
++ /* Enhance thin fonts */
++ if ( autohinted )
++ {
++ /* if forcibly set use that, otherwise make a good estimate */
++ float contrast, brightness;
++ ftinf_get_bc( slot->face->family_name, ppem, &brightness, &contrast);
++ if ( slot->face && !_ft_bitmap_bc ( bitmap, brightness, contrast ) )
++ {
++ FT_Bool is_fixed_name = FALSE;
++
++ if ( slot->face->family_name &&
++ strcasestr(slot->face->family_name, "Mono" ) )
++ is_fixed_name = TRUE;
++
++ /* Darken vertical stems */
++ _ft_lcd_darken_y ( bitmap,
++ mode,
++ autohint_vertical_stem_darken_strength,
++ slot->library );
++
++ /* Adjust brightness / contrast automatically based on stem width */
++ if ( cur_width != 0 && cur_width < 30 )
++ cur_width = 30;
++
++ if ( cur_width >= 30 && cur_width <= 60 )
++ {
++ float ppem_factor = sliding_scale ( 5, 11, 0.0, 1.0, ppem );
++ float brightness_factor = sliding_scale ( 30, 52, -.3, 0.0,
++ cur_width );
++ float contrast_factor = sliding_scale ( 30, 52, .45, 0.0,
++ cur_width );
++ _ft_bitmap_bc ( bitmap,
++ ppem_factor * brightness_factor,
++ ppem_factor * contrast_factor );
++
++ /* Only cap variable width thin-stemmed fonts */
++ if ( !FT_IS_FIXED_WIDTH( slot->face ) && !is_fixed_name )
++ _ft_bitmap_cap ( bitmap,
++ ( cur_width * 150 ) / 64,
++ slot->library );
++ }
++ }
++ }
+
+-#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+- if ( hmul ) /* lcd */
+- {
+- FT_Byte* line;
+- FT_Byte* temp = NULL;
+- FT_UInt i, j;
++ if ( lcd_filter_func )
++ lcd_filter_func( bitmap, mode, lcd_weights );
+
+- unsigned int height = bitmap->rows;
+- unsigned int width = bitmap->width;
+- int pitch = bitmap->pitch;
++ if ( grayscale_filter_strength > 0 )
++ _ft_lcd_grayscale_filter( bitmap,
++ mode,
++ grayscale_filter_strength,
++ slot->library );
+
+- FT_Vector* sub = slot->library->lcd_geometry;
++ }
+
++ /* Global values */
++ if ( brightness_value != 0 || contrast_value != 0 )
++ _ft_bitmap_bc ( bitmap,
++ (float)brightness_value / 300.0,
++ (float)contrast_value / 300.0);
+
+- /* Render 3 separate monochrome bitmaps, shifting the outline. */
+- width /= 3;
++ FT_Outline_Done( slot->library, outline_orig );
++ }
++ else if ( mode == FT_RENDER_MODE_LCD &&
++ lcd_filter_func )
++ lcd_filter_func( bitmap, mode, lcd_weights );
++#else
++ if ( lcd_filter_func )
++ lcd_filter_func( bitmap, mode, lcd_weights );
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+- FT_Outline_Translate( outline,
+- -sub[0].x,
+- -sub[0].y );
+- error = render->raster_render( render->raster, &params );
+- if ( error )
+- goto Exit;
++#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+- bitmap->buffer += width;
+- FT_Outline_Translate( outline,
+- sub[0].x - sub[1].x,
+- sub[0].y - sub[1].y );
+- error = render->raster_render( render->raster, &params );
+- bitmap->buffer -= width;
+- if ( error )
+- goto Exit;
++ /* render outline into bitmap */
++ error = render->raster_render( render->raster, &params );
++ if ( error )
++ goto Exit;
+
+- bitmap->buffer += 2 * width;
+- FT_Outline_Translate( outline,
+- sub[1].x - sub[2].x,
+- sub[1].y - sub[2].y );
+- error = render->raster_render( render->raster, &params );
+- bitmap->buffer -= 2 * width;
+- if ( error )
+- goto Exit;
++ /* expand it horizontally */
++ if ( hmul )
++ {
++ FT_Byte* line = bitmap->buffer;
++ FT_UInt hh;
+
+- x_shift -= sub[2].x;
+- y_shift -= sub[2].y;
+
+- /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */
+- /* XXX: It is more efficient to render every third byte above. */
++ for ( hh = height_org; hh > 0; hh--, line += pitch )
++ {
++ FT_UInt xx;
++ FT_Byte* end = line + width;
+
+- if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
+- goto Exit;
+
+- for ( i = 0; i < height; i++ )
+- {
+- line = bitmap->buffer + i * (FT_ULong)pitch;
+- for ( j = 0; j < width; j++ )
++ for ( xx = width_org; xx > 0; xx-- )
+ {
+- temp[3 * j ] = line[j];
+- temp[3 * j + 1] = line[j + width];
+- temp[3 * j + 2] = line[j + width + width];
++ FT_UInt pixel = line[xx-1];
++
++
++ end[-3] = (FT_Byte)pixel;
++ end[-2] = (FT_Byte)pixel;
++ end[-1] = (FT_Byte)pixel;
++ end -= 3;
+ }
+- FT_MEM_COPY( line, temp, pitch );
+ }
+-
+- FT_FREE( temp );
+ }
+- else if ( vmul ) /* lcd_v */
++
++ /* expand it vertically */
++ if ( vmul )
+ {
+- int pitch = bitmap->pitch;
++ FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch;
++ FT_Byte* write = bitmap->buffer;
++ FT_UInt hh;
+
+- FT_Vector* sub = slot->library->lcd_geometry;
+
++ for ( hh = height_org; hh > 0; hh-- )
++ {
++ ft_memcpy( write, read, pitch );
++ write += pitch;
+
+- /* Render 3 separate monochrome bitmaps, shifting the outline. */
+- /* Notice that the subpixel geometry vectors are rotated. */
+- /* Triple the pitch to render on each third row. */
+- bitmap->pitch *= 3;
+- bitmap->rows /= 3;
++ ft_memcpy( write, read, pitch );
++ write += pitch;
+
+- FT_Outline_Translate( outline,
+- -sub[0].y,
+- sub[0].x );
+- error = render->raster_render( render->raster, &params );
+- if ( error )
+- goto Exit;
++ ft_memcpy( write, read, pitch );
++ write += pitch;
++ read += pitch;
++ }
++ }
+
+- bitmap->buffer += pitch;
+- FT_Outline_Translate( outline,
+- sub[0].y - sub[1].y,
+- sub[1].x - sub[0].x );
+- error = render->raster_render( render->raster, &params );
+- bitmap->buffer -= pitch;
+- if ( error )
+- goto Exit;
++#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+- bitmap->buffer += 2 * pitch;
+- FT_Outline_Translate( outline,
+- sub[1].y - sub[2].y,
+- sub[2].x - sub[1].x );
+- error = render->raster_render( render->raster, &params );
+- bitmap->buffer -= 2 * pitch;
+- if ( error )
+- goto Exit;
++ /*
++ * XXX: on 16bit system, we return an error for huge bitmap
++ * to prevent an overflow.
++ */
++ if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX )
++ {
++ error = FT_THROW( Invalid_Pixel_Size );
++ goto Exit;
++ }
+
+- x_shift -= sub[2].y;
+- y_shift += sub[2].x;
++ slot->format = FT_GLYPH_FORMAT_BITMAP;
++ slot->bitmap_left = (FT_Int)x_left;
++ slot->bitmap_top = (FT_Int)y_top;
+
+- bitmap->pitch /= 3;
+- bitmap->rows *= 3;
+- }
+- else /* grayscale */
+- error = render->raster_render( render->raster, &params );
++ /* everything is fine; don't deallocate buffer */
++ have_buffer = FALSE;
+
+-#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
++ error = FT_Err_Ok;
+
+ Exit:
+- if ( !error )
+- {
+- /* everything is fine; the glyph is now officially a bitmap */
+- slot->format = FT_GLYPH_FORMAT_BITMAP;
+- }
+- else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
++ if ( have_outline_shifted )
++ FT_Outline_Translate( outline, x_shift, y_shift );
++ if ( have_translated_origin )
++ FT_Outline_Translate( outline, -origin->x, -origin->y );
++ if ( have_buffer )
+ {
+ FT_FREE( bitmap->buffer );
+ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+- if ( x_shift || y_shift )
+- FT_Outline_Translate( outline, -x_shift, -y_shift );
+-
+ return error;
+ }
+
+@@ -402,8 +3062,14 @@
+ FT_Render_Mode mode,
+ const FT_Vector* origin )
+ {
+- return ft_smooth_render_generic( render, slot, mode, origin,
+- FT_RENDER_MODE_LCD );
++ FT_Error error;
++
++ error = ft_smooth_render_generic( render, slot, mode, origin,
++ FT_RENDER_MODE_LCD );
++ if ( !error )
++ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
++
++ return error;
+ }
+
+
+@@ -414,8 +3080,14 @@
+ FT_Render_Mode mode,
+ const FT_Vector* origin )
+ {
+- return ft_smooth_render_generic( render, slot, mode, origin,
+- FT_RENDER_MODE_LCD_V );
++ FT_Error error;
++
++ error = ft_smooth_render_generic( render, slot, mode, origin,
++ FT_RENDER_MODE_LCD_V );
++ if ( !error )
++ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
++
++ return error;
+ }
+
+
+@@ -442,7 +3114,7 @@
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */
+
+- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
+ )
+
+
+@@ -469,7 +3141,7 @@
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */
+
+- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
+ )
+
+
+@@ -496,7 +3168,7 @@
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */
+
+- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */
+ )
+
+
+diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
+index 403f3753c..8a6775fc1 100644
+--- a/src/truetype/ttinterp.c
++++ b/src/truetype/ttinterp.c
+@@ -5850,6 +5850,7 @@
+
+ if ( exc->ignore_x_mode &&
+ exc->GS.freeVector.x != 0 &&
++ exc->GS.freeVector.y == 0 &&
+ !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ control_value_cutin = 0;
+ }
diff --git a/0004-Enable-long-PCF-family-names.patch b/0004-Enable-long-PCF-family-names.patch
new file mode 100644
index 000000000000..5e812300cc7e
--- /dev/null
+++ b/0004-Enable-long-PCF-family-names.patch
@@ -0,0 +1,27 @@
+From a7c04e60d28a0ad0420bb7a1943479a08a923d07 Mon Sep 17 00:00:00 2001
+Message-Id: <a7c04e60d28a0ad0420bb7a1943479a08a923d07.1552648361.git.jan.steffens@gmail.com>
+In-Reply-To: <b609203df7333beea20dbfd604262a9486f01497.1552648361.git.jan.steffens@gmail.com>
+References: <b609203df7333beea20dbfd604262a9486f01497.1552648361.git.jan.steffens@gmail.com>
+From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
+Date: Sun, 14 May 2017 18:09:31 +0200
+Subject: [PATCH 3/4] Enable long PCF family names
+
+---
+ include/freetype/config/ftoption.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
+index 1d4469a99..4ff4e7821 100644
+--- a/include/freetype/config/ftoption.h
++++ b/include/freetype/config/ftoption.h
+@@ -847,7 +847,7 @@ FT_BEGIN_HEADER
+ * If this option is activated, it can be controlled with the
+ * `no-long-family-names` property of the 'pcf' driver module.
+ */
+-/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
++#define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
+
+
+ /*************************************************************************/
+--
+2.21.0
diff --git a/0005-freetype-2.5.2-more-demos.patch b/0005-freetype-2.5.2-more-demos.patch
new file mode 100644
index 000000000000..e737cb7dafe7
--- /dev/null
+++ b/0005-freetype-2.5.2-more-demos.patch
@@ -0,0 +1,17 @@
+--- ft2demos-2.5.2/Makefile
++++ ft2demos-2.5.2/Makefile
+@@ -296,10 +296,10 @@ else
+ # The following programs are not compiled automatically; either comment
+ # out the affected line or use the program name as a Makefile target.
+ #
+- # EXES += ftchkwd
+- # EXES += ftmemchk
+- # EXES += ftpatchk
+- # EXES += fttimer
++ EXES += ftchkwd
++ EXES += ftmemchk
++ EXES += ftpatchk
++ EXES += fttimer
+ # EXES += testname
+
+ exes: $(EXES:%=$(BIN_DIR_2)/%$E)
diff --git a/0006-infinality-remix-tweaks.patch b/0006-infinality-remix-tweaks.patch
new file mode 100644
index 000000000000..063b2efd2ac8
--- /dev/null
+++ b/0006-infinality-remix-tweaks.patch
@@ -0,0 +1,139 @@
+diff --git a/src/base/ftinf_sh.c b/src/base/ftinf_sh.c
+index 87d2ff8bd..5a350f8f2 100644
+--- a/src/base/ftinf_sh.c
++++ b/src/base/ftinf_sh.c
+@@ -250,7 +250,8 @@ _settings_get (register const char *str, register unsigned int len)
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ #line 197 "ftinf_sh.gperf"
+ { .name="windows7",
+@@ -300,7 +301,8 @@ _settings_get (register const char *str, register unsigned int len)
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ #line 87 "ftinf_sh.gperf"
+ { .name="push",
+@@ -324,7 +326,8 @@ _settings_get (register const char *str, register unsigned int len)
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ #line 162 "ftinf_sh.gperf"
+ { .name="ultimate4",
+@@ -334,7 +337,8 @@ _settings_get (register const char *str, register unsigned int len)
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ #line 153 "ftinf_sh.gperf"
+ { .name="ultimate3",
+@@ -344,7 +348,8 @@ _settings_get (register const char *str, register unsigned int len)
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ }
+ };
+
+diff --git a/src/base/ftinf_sh.gperf b/src/base/ftinf_sh.gperf
+index 5f6e0ae62..f694fb374 100644
+--- a/src/base/ftinf_sh.gperf
++++ b/src/base/ftinf_sh.gperf
+@@ -139,7 +139,8 @@ struct ftinf_s;
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ { .name="ultimate2",
+ .filter_params={on, 6, 22, 36, 22, 6},
+@@ -148,7 +149,8 @@ struct ftinf_s;
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ { .name="ultimate3",
+ .filter_params={on, 8, 24, 36, 24, 8},
+@@ -157,7 +159,8 @@ struct ftinf_s;
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ { .name="ultimate4",
+ .filter_params={on, 10, 25, 37, 25, 10},
+@@ -166,7 +169,8 @@ struct ftinf_s;
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ { .name="ultimate5",
+ .filter_params={on, 12, 28, 42, 28, 12},
+@@ -175,7 +179,8 @@ struct ftinf_s;
+ .stem_alignment_strength=15,
+ .stem_fitting_strength=15,
+ .use_various_tweaks=true,
+- .windows_style_sharpening_strength=25
++ .windows_style_sharpening_strength=25,
++ .stem_darkening_cff=true
+ },
+ { .name="vanilla",
+ .filter_params={on, 6, 25, 38, 25, 6},
+diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
+index d8fd36c81..ef10506d0 100644
+--- a/src/base/ftobjs.c
++++ b/src/base/ftobjs.c
+@@ -938,6 +938,13 @@
+ ttface->cvt_program_size == 0 ) )
+ autohint = TRUE;
+ }
++
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( use_various_tweaks )
++ {
++ autohint = TRUE;
++ }
++#endif
+ }
+
+ if ( autohint )
+diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
+index e82c15c25..99df34a3c 100644
+--- a/src/smooth/ftsmooth.c
++++ b/src/smooth/ftsmooth.c
+@@ -42,6 +42,8 @@
+ static FT_Error
+ ft_smooth_init( FT_Renderer render )
+ {
++ FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
++
+ render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
+
+ return 0;
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..466ec8f253d5
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,106 @@
+# Maintainer: Philip Deljanov <philip dot deljanov at gmail dot com>
+# Contributor: bohoomil <bohoomil at zoho dot com>
+
+pkgbase=freetype2-infinality-remix
+pkgname=(freetype2-infinality-remix freetype2-demos-infinality-remix)
+pkgver=2.10.0
+pkgrel=1
+_patchrel=2019.03.15
+pkgdesc="TrueType font rendering library with Infinality Remix patches"
+arch=(i686 x86_64)
+license=('GPL')
+url="http://www.freetype.org/"
+
+# Adding harfbuzz for improved OpenType features auto-hinting
+# introduces a cycle dep to harfbuzz depending on freetype wanted by upstream
+makedepends=('libx11' 'libpng' 'harfbuzz')
+
+install=freetype2.install
+
+source=(https://download.savannah.gnu.org/releases/freetype/freetype-${pkgver}.tar.bz2
+ https://download.savannah.gnu.org/releases/freetype/freetype-doc-${pkgver}.tar.bz2
+ https://download-mirror.savannah.gnu.org/releases/freetype/ft2demos-${pkgver}.tar.bz2
+ 0001-Enable-table-validation-modules.patch
+ 0002-infinality-${pkgver}-${_patchrel}.patch
+ 0004-Enable-long-PCF-family-names.patch
+ 0005-freetype-2.5.2-more-demos.patch
+ 0006-infinality-remix-tweaks.patch
+ freetype2.sh
+ infinality-settings.sh
+ xft-settings.sh)
+
+sha256sums=('fccc62928c65192fff6c98847233b28eb7ce05f12d2fea3f6cc90e8b4e5fbe06'
+ '5fdc0fd118a0a82ff36054988b82ea2fc0da2302962b51d14ca2880ee4959fb2'
+ '0466f9c2cd609349b0bd1f1b7b85b1bffc52f72eb492a7195552d86e666d06ba'
+ 'ac11a24b62a6c044cc245ea9fa2a0cbd9e2e62f2371873dd33084c28a76e7176'
+ 'b2d511399924452297e4f2c039f3b85d22a5e17d115e5d865c27704887d6c519'
+ '54800d4da18611cf9232aad8b63d74a83153a51bb56dd39191678c738ffc8b53'
+ '36484db4b926ed026e7f32570573493b5a9793a129f08d54383a26d65a6af89b'
+ '94493ed2865fd32e5ef8ef3493fcb2ccaaf8be4c9e0eaa7b417fcbc47fe4314d'
+ 'f7f8e09c44f7552c883846e9a6a1efc50377c4932234e74adc4a8ff750606467'
+ '1a5c12aa96e2ee66f7316b8ccb7012520b231a2d8ee21cfe4064aa28db35a57c'
+ '4842d1461c240cd0f60a7247ee038271fdb1067107bea9024be6bdbb218d1bd4')
+
+prepare() {
+ mv freetype-${pkgver} freetype2
+ mv ft2demos-${pkgver} freetype2-demos
+
+ # Patching FreeType
+ cd freetype2
+ patch -Np1 -i ../0001-Enable-table-validation-modules.patch
+ patch -Np1 --verbose -i ../0002-infinality-${pkgver}-${_patchrel}.patch
+ patch -Np1 -i ../0004-Enable-long-PCF-family-names.patch
+ patch -Np1 --verbose -i ../0006-infinality-remix-tweaks.patch
+
+
+ # Patching FreeType Demos
+ cd ../freetype2-demos
+ patch -Np1 -i ../0005-freetype-2.5.2-more-demos.patch
+
+ # Suppress RPATH
+ sed -i '/X11_LIB:%=-R%/d' graph/x11/rules.mk
+}
+
+build() {
+ # Build FreeType
+ cd freetype2
+ ./configure --prefix=/usr --disable-static --with-harfbuzz --with-png
+ make
+
+ # Build FreeType demos
+ cd ../freetype2-demos
+ make
+}
+
+check() {
+ cd freetype2
+ make -k check
+}
+
+package_freetype2-infinality-remix() {
+ groups=('infinality-remix')
+ depends=('zlib' 'bzip2' 'sh' 'libpng' 'harfbuzz')
+ provides=("freetype2=$pkgver" 'freetype2-infinality' 'libfreetype.so')
+ conflicts=('freetype2' 'freetype2-infinality' 'freetype2-infinality-ultimate')
+
+ cd freetype2
+ make DESTDIR="${pkgdir}" install
+ # Disables changes to FREETYPE_PROPERTIES globally.
+ install -Dm644 ../freetype2.sh "${pkgdir}/etc/profile.d/freetype2.sh"
+ # Configures generic Xft hinting globally.
+ install -Dm755 ../xft-settings.sh "${pkgdir}/etc/X11/xinit/xinitrc.d/xft-settings.sh"
+ # Configures global default Infinality settings.
+ install -Dm755 ../infinality-settings.sh "${pkgdir}/etc/X11/xinit/xinitrc.d/infinality-settings.sh"
+}
+
+package_freetype2-demos-infinality-remix() {
+ pkgdesc="Freetype tools and demos"
+ depends=('freetype2' 'libx11')
+ conflicts=('freetype2-demos' 'freetype2-demos-git' 'freetype2-demos-infinality' 'freetype2-infinality-ultimate')
+
+ cd freetype2-demos
+ install -d "${pkgdir}/usr/bin"
+ for _i in bin/{f,t}t*; do
+ libtool --mode=install install $_i "${pkgdir}/usr/bin"
+ done
+}
diff --git a/freetype2.install b/freetype2.install
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/freetype2.install
diff --git a/freetype2.sh b/freetype2.sh
new file mode 100755
index 000000000000..93165d30fe7f
--- /dev/null
+++ b/freetype2.sh
@@ -0,0 +1,12 @@
+# Subpixel hinting mode can be chosen by setting the right TrueType interpreter
+# version. The available settings are:
+#
+# truetype:interpreter-version=35 # Classic mode (default in 2.6)
+# truetype:interpreter-version=38 # Infinality mode
+# truetype:interpreter-version=40 # Minimal mode (default in 2.7)
+#
+# There are more properties that can be set, separated by whitespace. Please
+# refer to the FreeType documentation for details.
+
+# Uncomment and configure below
+#export FREETYPE_PROPERTIES="truetype:interpreter-version=40"
diff --git a/infinality-settings.sh b/infinality-settings.sh
new file mode 100755
index 000000000000..2eb7937f1901
--- /dev/null
+++ b/infinality-settings.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+### freetype2-infinality-ultimate settings ###
+### rev. 0.5, for freetype2 v.2.6.3 ###
+### ###
+### Copyright (c) 2015 bohoomil ###
+### The MIT License (MIT) http://opensource.org/licenses/MIT ###
+### part of infinality-bundle http://bohoomil.com ###
+
+
+### As of version 2.6.2-1, freetype2-infinality-ultimate comes with
+### the "ultimate3" rendering style enabled internally by default.
+### It is still possible to use the optional "infinality-settings.sh"
+### script to switch between additional built-in rendering schemes and
+### create custom ones if necessary. Once modified, "infinality-settings.sh"
+### needs to be copied to "/etc/X11/xinit/xinitrc.d/".
+###
+### There are two levels of customization available to a user:
+###
+### 1. A set of 7 preconfigured styles selectable by name.
+
+### Available styles:
+### ultimate1 <> extra sharp
+### ultimate2 <> sharper & lighter ultimate
+### ultimate3 <> ultimate: well balanced (default)
+### ultimate4 <> darker & smoother
+### ultimate5 <> darkest & heaviest ("MacIsh")
+### osx <> Apple OS X
+### windowsxp <> MS Windows XP
+
+### If you want to use a style from the list, uncomment the variable below
+### and set its name as the value.
+
+
+export INFINALITY_FT="ultimate3"
+
+
+### 2. If you want to create a custom style, uncomment the variables below
+### and enter the values of your choice.
+
+
+#export INFINALITY_FT_FILTER_PARAMS="08 24 36 24 08"
+#export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH="0"
+#export INFINALITY_FT_FRINGE_FILTER_STRENGTH="25"
+#export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH="0"
+#export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH="25"
+#export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH="25"
+#export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH="0"
+#export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH="15"
+#export INFINALITY_FT_STEM_FITTING_STRENGTH="15"
+#export INFINALITY_FT_STEM_DARKENING_AUTOFIT="false"
+#export INFINALITY_FT_STEM_DARKENING_CFF="false"
+#export INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#export INFINALITY_FT_BRIGHTNESS="0"
+#export INFINALITY_FT_CONTRAST="0"
+#export INFINALITY_FT_USE_VARIOUS_TWEAKS="true"
+#export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS="false"
+#export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT="0"
+#export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE="0"
+#export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS="false"
+
+### Please refer to "infinality-settings-generic" file for detailed explanation
+### of customization options and provided examples.
+
+# vim:ft=sh:
diff --git a/xft-settings.sh b/xft-settings.sh
new file mode 100755
index 000000000000..913a8bd76182
--- /dev/null
+++ b/xft-settings.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+XFT_SETTINGS="
+Xft.antialias: 1
+Xft.autohint: 0
+Xft.dpi: 96
+Xft.hinting: 1
+Xft.hintstyle: hintslight
+Xft.lcdfilter: lcddefault
+Xft.rgba: rgb
+"
+
+echo "$XFT_SETTINGS" | xrdb -merge > /dev/null 2>&1
+
+# vim:ft=sh: