summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorCarlo Landmeter <clandmeter@gmail.com>2014-10-28 23:25:00 +0100
committerCarlo Landmeter <clandmeter@gmail.com>2014-10-28 23:25:21 +0100
commitee4aa42a0e2f97d57e8e1281a0eed3db45c5ab64 (patch)
tree4459dbba08d24128a65e00c281395470d6897f70 /testing
parent73359e369a31fbd7e24ea1cc04d8b123f9bc95af (diff)
downloadaports-ee4aa42a0e2f97d57e8e1281a0eed3db45c5ab64.tar.bz2
aports-ee4aa42a0e2f97d57e8e1281a0eed3db45c5ab64.tar.xz
testing/freetype-infinality: new aport
Diffstat (limited to 'testing')
-rw-r--r--testing/freetype-infinality/APKBUILD66
-rw-r--r--testing/freetype-infinality/freetype-2.2.1-enable-valid.patch20
-rw-r--r--testing/freetype-infinality/freetype-entire-infinality-patchset-20130514-01.patch5510
-rw-r--r--testing/freetype-infinality/infinality-settings.sh1135
4 files changed, 6731 insertions, 0 deletions
diff --git a/testing/freetype-infinality/APKBUILD b/testing/freetype-infinality/APKBUILD
new file mode 100644
index 000000000..0b031cfd5
--- /dev/null
+++ b/testing/freetype-infinality/APKBUILD
@@ -0,0 +1,66 @@
+# Contributor: Carlo Landmeter <clandmeter@gmail.com>
+# Maintainer:
+pkgname=freetype-infinality
+pkgver=2.4.12
+pkgrel=0
+pkgdesc="TrueType font rendering library with infinality patch"
+url="ttp://www.infinality.net/blog/infinality-freetype-patches/"
+arch="all"
+license="GPL"
+depends=""
+depends_dev="zlib-dev libpng-dev"
+makedepends="$depends_dev"
+install=""
+replaces="freetype"
+subpackages="$pkgname-dev"
+source="http://downloads.sourceforge.net/sourceforge/freetype/freetype-${pkgver}.tar.bz2
+ freetype-entire-infinality-patchset-20130514-01.patch
+ infinality-settings.sh
+ freetype-2.2.1-enable-valid.patch"
+
+_builddir=$srcdir/freetype-$pkgver
+
+prepare() {
+ local i
+ cd "$_builddir"
+ for i in $source; do
+ case $i in
+ *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
+ esac
+ done
+}
+
+build() {
+ cd "$_builddir"
+ ./configure \
+ --build=$CBUILD \
+ --host=$CHOST \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info \
+ --localstatedir=/var \
+ || return 1
+ make || return 1
+}
+
+package() {
+ cd "$_builddir"
+ make DESTDIR="$pkgdir" install || return 1
+ install -D "${srcdir}/infinality-settings.sh" \
+ "${pkgdir}/etc/profile.d/infinality-settings.sh" || return 1
+ rm -f "$pkgdir"/usr/lib/*.la
+}
+
+md5sums="3463102764315eb86c0d3c2e1f3ffb7d freetype-2.4.12.tar.bz2
+62ed195ffdf79c4e9089b8979ad64b7f freetype-entire-infinality-patchset-20130514-01.patch
+a952b8aee85f2f4a5a9dc872b678b97f infinality-settings.sh
+214119610444c9b02766ccee5e220680 freetype-2.2.1-enable-valid.patch"
+sha256sums="a78a17486689ab6852a9e1a759b179827ac9dfd7e2f237ddf169c73398c85381 freetype-2.4.12.tar.bz2
+dd062da4217c366dc715562e4b2aa194ffef9cee8589509e1ef1a4ef832a99cb freetype-entire-infinality-patchset-20130514-01.patch
+51d456528e60824f53e9d270b775de21dfa78bdb257f7e69d28737d5ac0e62d5 infinality-settings.sh
+54c83a91b0b2ad7edad7df00a2c26a11ca18431a8e323db9471268a139c46f7e freetype-2.2.1-enable-valid.patch"
+sha512sums="e028d603133c15f02f891b53c634b4243c541efbe8d9fcaa7b86582175e7749bc9198eddbe2fedcfe49359367ab9e9e0e29373f3a82f67599edf997866a2f501 freetype-2.4.12.tar.bz2
+816fed28ccd6ff73f186c564983aeb3342c0350d6a74ad7ccc56f5d6353d4ab940949faced212d214447db857ba360364d15035661a2654ba8a348d848c42ff7 freetype-entire-infinality-patchset-20130514-01.patch
+62b619b1161c8345932b222cf2812c555a54bfdf27d82cbba4505d6a7635555e3e7316b7b82f35e176d9404d3d27a3411023501b601eeb1d569f4ebbe41f0447 infinality-settings.sh
+de2aaa19a1eed20b026263e8865bd0da9a162b82967f1ce95e07f0ee7bee87bd109616b61b46142a443abe80ae794b8d664c788d7c53d8d4a228ab8a838d4165 freetype-2.2.1-enable-valid.patch"
diff --git a/testing/freetype-infinality/freetype-2.2.1-enable-valid.patch b/testing/freetype-infinality/freetype-2.2.1-enable-valid.patch
new file mode 100644
index 000000000..c78b6b70f
--- /dev/null
+++ b/testing/freetype-infinality/freetype-2.2.1-enable-valid.patch
@@ -0,0 +1,20 @@
+--- freetype-2.2.1/modules.cfg.orig 2006-07-07 21:01:09.000000000 -0400
++++ freetype-2.2.1/modules.cfg 2006-07-07 21:01:54.000000000 -0400
+@@ -110,7 +110,7 @@
+ 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).
+ #
+@@ -124,7 +124,7 @@
+
+ # OpenType table validation. Needs ftotval.c below.
+ #
+-# AUX_MODULES += otvalid
++AUX_MODULES += otvalid
+
+ # Auxiliary PostScript driver component to share common code.
+ #
diff --git a/testing/freetype-infinality/freetype-entire-infinality-patchset-20130514-01.patch b/testing/freetype-infinality/freetype-entire-infinality-patchset-20130514-01.patch
new file mode 100644
index 000000000..873561db4
--- /dev/null
+++ b/testing/freetype-infinality/freetype-entire-infinality-patchset-20130514-01.patch
@@ -0,0 +1,5510 @@
+After 20130513:
+
+Fix crash issue with certain fonts
+
+Fix issue with Courier New rendering
+
+Disable trace debug messages
+
+
+
+After 20130104:
+
+(ftsmooth.c) Perform additional checks in conditionals to prevent crashing.
+
+(ttsubpix.c) Remove unnecessary rules.
+
+(ttinterp.c) Enhance various functions with better default detection.
+
+(ttsubpix.c) Fix Load performance.
+
+Compatibility with Freetype 2.4.12
+
+Merge the subpixel-enable patch into the main patch
+
+
+
+
+After 20120616:
+
+Code simplification: Restore original rounding functions, and instead skip them outside when necessary.
+
+Fix Verdana/dejavu/verasans 12px 'a' spacing issue. Also make italics appearance consistent with regular.
+
+Lucida Grande Bold 'y' fixed.
+
+Substantial code formatting cleanup across all patches.
+
+Remove floating point arithmetic in subpixel patch. (Autohint patch eventually)
+
+Standardize the data types used to FT data types in subpixel patch
+
+Additional fixes with Verdana from Windows 7 SP1.
+
+
+
+After 20120615:
+
+Fix issue with Chrome and Verdana from Windows 7 SP1.
+
+
+
+
+After 20120403:
+
+Infinality autohint patches
+===========================
+Fix the forced slight hinting logic
+
+Enhance artificial emboldening at larger ppems
+
+
+Infinality subpixel patches
+===========================
+Substantial simplification of the TT rules, which helps with all the rest of the following improvements.
+
+Preparation for submission into Freetype tree.
+
+Fix Ubuntu S M N
+
+Courier fixes
+
+Make all fonts use standard (non-subpixel) TT hinting for characters '>' and '<'.
+
+Marked improvement on many non-Latin fonts, including Meiryo.
+
+Fix Oxygen rendering if usint TT hinting, and other ttfautohinted fonts
+
+Code cleanup
+
+
+Infinality Fontconfig Package
+=============================
+
+Add more fonts to the TT hinted list
+
+Fixes for font alias (thanks Yegorius)
+
+
+
+
+After 20111223:
+
+Get rid of TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS and do this by default if TT_CONFIG_OPTION_SUBPIXEL_HINTING is enabled.
+
+Update to Freetype 2.4.9
+
+Fix sdl_ttf
+
+Code cleanup
+
+Prevent crashes in OSX mode (thanks Markser)
+
+
+
+
+After 20111125:
+
+Courier New Hack for '2'.
+
+Tweak Arial 16px a bit.
+
+Various tweaks on Courier New, Times NR, Arial, Verdana and others that create a general improvement in appearance at certain ppems.
+
+Fixes on some Cyrillic glyphs
+
+Pragmata Pro and Pragmata added to patches
+
+Be a little more conservative in the way "known settings" of fonts are done.
+
+Many small improvements to the subpixel hinting patch.
+
+Fix a crasher in the Windows sharpening algorithm.
+
+Noticible improvement on spacing in Tahoma 11px, Arial 11px, and other Arial clones. Me likey.
+
+Code fixes to prevent some warnings and possible crashes. (Thanks banta)
+
+Fix Opera and Firefox crashes. slot->face->style_name and slot->face->family_name need to be checked for not NULL before using.
+
+
+
+
+After 20111117:
+
+Fix issue that prevented stem alignment on thin autohinted stems
+
+Fix regression in Arial italics
+
+Fix problem with bitmap copies in filters. Remove unnecessary processing.
+
+Added an internal capping filter that helps even out the filtering of very light/thin stems.
+
+General consistent and smoother appearance on very light/thin stems
+
+Add TT rules to make Droid fonts render more nicely if using TT hinter for them.
+
+TT fixes for Bitstream Vera Sans.
+
+Made the default style less stem-aligned. I may have been a little too gregarious in setting it to 100%. :)
+
+Fix problems with various autohinted fonts that result in ridiculously small letters.
+
+Fixed mangled Courier New glyphs. This pointed to a larger bug that is now fixed.
+
+Fix artifacts on Courier New glyphs 0 Q O k.
+
+OSX style in infinality settings should actually be UBUNTU style. Fixed. Still need to get a better OSX style going.
+
+Option to use predefined value on known good fonts (Verdana, Arial, etc.). This gives you the benefit of snapping and other enhancements when its known to work well, without creating misshapen glyphs on other fonts.
+
+Only do heavy snapping on m in known cases.
+
+Added LINUX style to infinality-settings.sh
+
+
+
+
+
+After 20110604:
+
+Features:
+
+Added a post-render, pre-lcd-filter filter that attempts to duplicate windows sharpness / graininess. Controlled by INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH.
+
+Added a fringe filter, intended mostly for autohint (but still effective for certain cases of TT hinting). This attempts to remove gray fringes that sometimes occur on horizontal stems and angled serifs and doodads (Times, Segoe '1', etc.)
+
+Added a grayscale filter.
+
+Added brightness/contrast filter.
+
+Substantial improvements in the stem alignment algorithm! Wow!
+
+Stem alignment now also happens on grayscale antialiased fonts (rgba=none).
+
+
+
+
+Fixes / Tweaks:
+
+Changes inside of local.conf, which are documented there.
+
+Removed an artificial shift of 1/8 pixel to the right on stem aligned glyphs which should result in sharper looking alignment.
+
+Added XFT_SETTINGS into infinality-settings.sh. This means it will require less configuration on the end-user side.
+
+Fixed code to not touch bold, thin, narrow or italic faces for scale or alignment (until they can be properly accounted for).
+
+Added -lm dependency to the code again. (It seems to sneak off now and then)
+
+Changed autohinter horizontal stem stem snapping from on/off to use a value between 0 and 100.
+
+Functions getenv() and system() were crashing evince in _lcd_stem_align() at odd times. A workaround has been put in place.
+
+Moved _lcd_stem_align and all other filters into ftsmooth.c, which is a better place.
+
+Use malloc() in _lcd_stem_align for allocating structs and arrays of structs instead of what I learned in C++ class 10+ years ago. Should prevent abiword from crashing with large pt sizes like 3000. (A workaround has been put in place to automatically skip alignment on any ppem > 300. This will prevent the crashes until the real solution can be figured out.)
+
+Fix some compiler warnings. Some are still present.
+
+Added "m" control to alignment algorithm. This will cause all stems to m (or other 3-pronged glyphs) to get aligned to pixels. It still needs a bit of work, as it makes the best looking glyph size change. This is because the glyph now needs to snap stems to only even or odd pixels, not single ones.
+
+Added rules to allow "compatible widths" (i.e. widths if the font were being bitmap TT hinted) on a glyph by glyph basis and tweaked certain fonts like arial, verdana, times new roman, segoe ui, and trebuchet to use them.
+
+Don't stem align anything below 9 ppem because it is not consistently good.
+
+When doing stem alignment, automatically align stems to center of pixel or start of pixel when necessary. When horizontal stems start snapping to 2 px, so should the vertical ones in order for it to look nice.
+
+A Verdana 12 hack to make it render more like Windows. This notoriously poor looking ppem now looks as good as Verdana 13 without needing fontconfig replacement.
+
+Courier New now looks good, and possibly better than Windows rendering, with TT or autohint rendering. By the way, the hinters of Courier New should either be commended or executed.
+
+Improvements in overshoot artifact and fringe correction- Freesans at large ppem looks nice now. Overshoots on letters like 6, g, s, 3, etc. will now be rounded to integer pixels.
+
+Wrap all infinality code within a macro that is set in ftoption.h: #ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET. Makes it easier to identify in the code and allows for easy compliation with or without the patches set.
+
+Variable renaming for more clarity, in code and in environment variables.
+
+Move stretching code into Freetype instead of relying on programs to handle fontconfig matrix (they SUCK at it... *cough* Chrome *cough*).
+
+Additional modifications to the TT subpixel rendering rules for corrections to Georgia, DejaVu Sans, Times New Roman, Courier New and a couple others.
+
+A general improvement in the way autohinted fonts render, particularly on ones that normally look fragile or thin. Examples include Optima, Freemono, Freeserif, Raleway, MgOpen, etc. I'm doing what Windows does, which is brightness/contrast adjustment, except you don't see rainbows.
+
+
+
+diff --git a/configure b/configure
+index 4d8a945..40eaa1b 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 backwards compatibility
+diff --git a/devel/ftoption.h b/devel/ftoption.h
+index 2b370e5..cf18bf6 100644
+--- a/devel/ftoption.h
++++ b/devel/ftoption.h
+@@ -582,6 +582,17 @@ FT_BEGIN_HEADER
+
+ /*************************************************************************/
+ /* */
++ /* 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
++
++ /*************************************************************************/
++ /* */
+ /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */
+ /* of the TrueType bytecode interpreter is used that doesn't implement */
+ /* any of the patented opcodes and algorithms. The patents related to */
+diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
+index 84f1695..3c69018 100644
+--- a/include/freetype/config/ftoption.h
++++ b/include/freetype/config/ftoption.h
+@@ -92,7 +92,7 @@ FT_BEGIN_HEADER
+ /* This is done to allow FreeType clients to run unmodified, forcing */
+ /* them to display normal gray-level anti-aliased glyphs. */
+ /* */
+-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
++#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+
+ /*************************************************************************/
+@@ -577,11 +577,22 @@ FT_BEGIN_HEADER
+ /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */
+ /* defined. */
+ /* */
+-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+
+ /*************************************************************************/
+ /* */
++ /* 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
++
++ /*************************************************************************/
++ /* */
+ /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */
+ /* of the TrueType bytecode interpreter is used that doesn't implement */
+ /* any of the patented opcodes and algorithms. The patents related to */
+diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
+index ef0157a..c75247e 100644
+--- a/src/autofit/aflatin.c
++++ b/src/autofit/aflatin.c
+@@ -23,6 +23,7 @@
+ #include "afglobal.h"
+ #include "aflatin.h"
+ #include "aferrors.h"
++#include "strings.h"
+
+
+ #ifdef AF_CONFIG_OPTION_USE_WARPER
+@@ -577,8 +578,33 @@
+ FT_Pos delta;
+ AF_LatinAxis axis;
+ FT_UInt nn;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ int checked_adjust_heights_env = 0;
++ FT_Bool adjust_heights = FALSE;
+
+
++ if ( checked_adjust_heights_env == 0 )
++ {
++ char *adjust_heights_env =
++ getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" );
++ if ( adjust_heights_env != NULL )
++ {
++ if ( strcasecmp(adjust_heights_env, "default" ) != 0 )
++ {
++ if ( strcasecmp(adjust_heights_env, "true") == 0 )
++ adjust_heights = TRUE;
++ else if ( strcasecmp(adjust_heights_env, "1") == 0 )
++ adjust_heights = TRUE;
++ else if ( strcasecmp(adjust_heights_env, "on") == 0 )
++ adjust_heights = TRUE;
++ else if ( strcasecmp(adjust_heights_env, "yes") == 0 )
++ adjust_heights = TRUE;
++ }
++ }
++ checked_adjust_heights_env = 1;
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
++
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ scale = scaler->x_scale;
+@@ -605,7 +631,7 @@
+ {
+ AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
+ AF_LatinBlue blue = NULL;
+-
++ int threshold = 40;
+
+ for ( nn = 0; nn < Axis->blue_count; nn++ )
+ {
+@@ -615,7 +641,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;
+@@ -701,7 +732,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;
+@@ -752,7 +789,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
+
+@@ -1498,7 +1540,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 )
+ {
+@@ -1659,8 +1704,31 @@
+ 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;
++ FT_UInt checked_autohint_snap_stem_height = 0;
+
+
++ if ( checked_autohint_snap_stem_height == 0 )
++ {
++ char *autohint_snap_stem_height_env =
++ getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" );
++ if ( autohint_snap_stem_height_env != NULL )
++ {
++ sscanf ( autohint_snap_stem_height_env, "%u",
++ &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;
++ }
++ checked_autohint_snap_stem_height = 1;
++ }
++
++ 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;
+@@ -1670,9 +1738,73 @@
+ 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 ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
++ 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 )
++ {
++ if ( strstr( metrics->root.scaler.face->style_name, "Regular" ) ||
++ strstr( metrics->root.scaler.face->style_name, "Book" ) ||
++ strstr( metrics->root.scaler.face->style_name, "Medium" ) ||
++ strcmp( metrics->root.scaler.face->style_name, "Italic" ) == 0 ||
++ strcmp( metrics->root.scaler.face->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 ( 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 */
+
+@@ -1732,6 +1864,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 */
+
+@@ -1739,7 +1874,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 */
+@@ -1802,6 +1940,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;
+
+@@ -1824,6 +1988,8 @@
+ (AF_Edge_Flags)base_edge->flags,
+ (AF_Edge_Flags)stem_edge->flags );
+
++/* 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 */
+
+ stem_edge->pos = base_edge->pos + fitted_width;
+
+@@ -2357,8 +2523,32 @@
+ {
+ FT_Error error;
+ int dim;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ FT_Int emboldening_strength = 0;
++ FT_Bool checked_use_various_tweaks_env = FALSE;
++ FT_Bool use_various_tweaks = FALSE;
+
+-
++ if ( !checked_use_various_tweaks_env )
++ {
++ char *use_various_tweaks_env =
++ getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
++ if ( use_various_tweaks_env != NULL )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "true") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "1") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "on") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "yes") == 0 )
++ use_various_tweaks = TRUE;
++ }
++ }
++ checked_use_various_tweaks_env = TRUE;
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ error = af_glyph_hints_reload( hints, outline );
+ if ( error )
+ goto Exit;
+@@ -2415,7 +2605,17 @@
+ }
+ }
+ af_glyph_hints_save( hints, outline );
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ {
++ /* Save this width for use in ftsmooth.c. This is a shameful hack */
++ const char* c1 = "CUR_WIDTH";
++ char c2[8];
++
+
++ snprintf( c2, 8, "%ld", metrics->axis->widths[0].cur );
++ setenv( c1, c2, 1 );
++ }
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ Exit:
+ return error;
+ }
+diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
+index 852fb32..4c2d548 100644
+--- a/src/base/ftlcdfil.c
++++ b/src/base/ftlcdfil.c
+@@ -23,6 +23,9 @@
+ #include FT_IMAGE_H
+ #include FT_INTERNAL_OBJECTS_H
+
++#include <math.h>
++#include <string.h>
++#include <strings.h>
+
+ #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+@@ -289,10 +292,53 @@
+ { 0x00, 0x55, 0x56, 0x55, 0x00 };
+ /* the values here sum up to a value larger than 256, */
+ /* providing a cheap gamma correction */
+- static const FT_Byte default_filter[5] =
++ static FT_Byte default_filter[5] =
+ { 0x10, 0x40, 0x70, 0x40, 0x10 };
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ int checked_filter_params_env = 0;
+
++ if ( checked_filter_params_env == 0 )
++ {
++ char *filter_params = getenv( "INFINALITY_FT_FILTER_PARAMS" );
++ if ( filter_params != NULL && strcmp( filter_params, "" ) != 0 )
++ {
++ float f1, f2, f3, f4, f5;
+
++ if ( strcasecmp( filter_params, "default" ) != 0 )
++ {
++ int args_assigned = 0;
++ args_assigned = sscanf ( filter_params,
++ "%f %f %f %f %f",
++ &f1, &f2, &f3, &f4, &f5 );
++
++ if ( args_assigned == 5 )
++ {
++ if ( f1 + f2 + f3 + f4 + f5 > 5 )
++ {
++ /* Assume we were given integers instead of floats */
++ /* 0 to 100 */
++ default_filter[0] = (FT_Byte) ( f1 * 2.55f + 0.5f );
++ default_filter[1] = (FT_Byte) ( f2 * 2.55f + 0.5f );
++ default_filter[2] = (FT_Byte) ( f3 * 2.55f + 0.5f );
++ default_filter[3] = (FT_Byte) ( f4 * 2.55f + 0.5f );
++ default_filter[4] = (FT_Byte) ( f5 * 2.55f + 0.5f );
++ }
++ else
++ {
++ /* Assume we were given floating point values */
++ /* 0 to 1.0 */
++ default_filter[0] = (FT_Byte) ( f1 * 255.0f + 0.5f );
++ default_filter[1] = (FT_Byte) ( f2 * 255.0f + 0.5f );
++ default_filter[2] = (FT_Byte) ( f3 * 255.0f + 0.5f );
++ default_filter[3] = (FT_Byte) ( f4 * 255.0f + 0.5f );
++ default_filter[4] = (FT_Byte) ( f5 * 255.0f + 0.5f );
++ }
++ }
++ }
++ }
++ checked_filter_params_env = 1;
++ }
++#endif
+ if ( !library )
+ return FT_THROW( Invalid_Argument );
+
+diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
+index 26118ed..d87be53 100644
+--- a/src/base/ftobjs.c
++++ b/src/base/ftobjs.c
+@@ -53,6 +53,10 @@
+
+ #define GRID_FIT_METRICS
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include <strings.h>
++#include <stdlib.h>
++#endif
+
+ FT_BASE_DEF( FT_Pointer )
+ ft_service_list_lookup( FT_ServiceDesc service_descriptors,
+@@ -524,6 +528,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,
+@@ -582,8 +605,40 @@
+ FT_Bool autohint = FALSE;
+ FT_Module hinter;
+ TT_Face ttface = (TT_Face)face;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+
++ int checked_use_various_tweaks_env = FALSE;
++ FT_Bool use_various_tweaks = FALSE;
++
++ if ( !checked_use_various_tweaks_env )
++ {
++ char *use_various_tweaks_env =
++ getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
+
++ if ( use_various_tweaks_env != NULL )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "true") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "1") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "on") == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "yes") == 0 )
++ use_various_tweaks = TRUE;
++ }
++ }
++ checked_use_various_tweaks_env = 1;
++ }
++
++ /* 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 );
+
+@@ -664,6 +719,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 */
+ /* */
+@@ -702,6 +769,10 @@
+ }
+ else
+ {
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ char* c1 = "CUR_WIDTH";
++ char* c2 = "0";
++#endif
+ error = driver->clazz->load_glyph( slot,
+ face->size,
+ glyph_index,
+@@ -709,6 +780,18 @@
+ if ( error )
+ goto Exit;
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ setenv ( c1, c2, 1 );
++
++ {
++ /* 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 */
+diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
+index 54ca5cd..bf34c9f 100644
+--- a/src/base/ftoutln.c
++++ b/src/base/ftoutln.c
+@@ -905,7 +905,34 @@
+ FT_Vector v_prev, v_first, v_next, v_cur;
+ FT_Int c, n, first;
+ FT_Int orientation;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ int checked_use_various_tweaks_env = 0;
++ FT_Bool use_various_tweaks = FALSE;
+
++ if ( checked_use_various_tweaks_env == 0 )
++ {
++ char *use_various_tweaks_env
++ = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
++ if ( use_various_tweaks_env != NULL )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "true" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "1" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "on" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "yes" ) == 0 )
++ use_various_tweaks = TRUE;
++ }
++ }
++ checked_use_various_tweaks_env = 1;
++ }
++
++ if ( use_various_tweaks )
++ ystrength = FT_PIX_FLOOR ( ystrength );
++#endif
+
+ if ( !outline )
+ return FT_THROW( Invalid_Argument );
+diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c
+index 241d37f..3d5a593 100644
+--- a/src/base/ftsynth.c
++++ b/src/base/ftsynth.c
+@@ -88,7 +88,32 @@
+ FT_Face face = slot->face;
+ FT_Error error;
+ FT_Pos xstr, ystr;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ int checked_use_various_tweaks_env = 0;
++ FT_Bool use_various_tweaks = FALSE;
+
++ if ( checked_use_various_tweaks_env == 0 )
++ {
++ char *use_various_tweaks_env
++ = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
++ if ( use_various_tweaks_env != NULL )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
++ {
++ if ( strcasecmp(use_various_tweaks_env, "true" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "1" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "on" ) == 0 )
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp(use_various_tweaks_env, "yes" ) == 0 )
++ use_various_tweaks = TRUE;
++ }
++
++ }
++ checked_use_various_tweaks_env = 1;
++ }
++#endif
+
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
+ slot->format != FT_GLYPH_FORMAT_BITMAP )
+@@ -101,6 +126,13 @@
+
+ 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
+ /* ignore error */
+ (void)FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
+ }
+@@ -141,6 +173,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;
+
+diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
+index 2735eaf..382f1f3 100644
+--- a/src/smooth/ftsmooth.c
++++ b/src/smooth/ftsmooth.c
+@@ -26,6 +26,17 @@
+
+ #include "ftsmerrs.h"
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#include <math.h>
++#include "../../include/freetype/ftbitmap.h"
++#include <strings.h>
++#include "../autofit/aflatin.h"
++#include "../../include/freetype/ftoutln.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
+@@ -70,29 +81,3017 @@
+ goto Exit;
+ }
+
+- if ( matrix )
+- FT_Outline_Transform( &slot->outline, matrix );
++ 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_MEM_ZERO( cbox, sizeof ( *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_New( &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_New( &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_New( &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_New( &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 );
++ }
++
++
++ int
++ pseudo_gamma ( int val, float value )
++ {
++ return 256 * ( 1.0 - pow( ( 1.0 - (float)val / 256.0 ), 1.0 / value ) );
++ }
++
++
++
++ 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_New(&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 ) ;
++ }
++ }
++ }
++
++
++ /* 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_New(&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;
++ }
++ }
++ }
++
++
++
++ /*************************************************************************/
++ /* */
++ /* */
++ /* */
++ /* */
++ /* */
++ /* */
++
++
++ typedef struct SA_Rule_
++ {
++ const char family[32];
++ const int ppem[5];
++
++ } SA_Rule;
++
++#define STEM_WIDTH_2_PPEM 18
++#define MAX_PPEM 100
++
++
++
++/* "Font name", {ppem where stem width becomes 1,
++ * ppem where stem width becomes 2... etc.} */
++/* 100 means auto-calculate */
++#define SNAPPING_STEM_WIDTHS_RULES_SIZE 21
++ SA_Rule SNAPPING_STEM_WIDTHS_Rules
++ [SNAPPING_STEM_WIDTHS_RULES_SIZE] =
++ {
++ { "Andale Mono", {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Arial Narrow", {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Calibri", {10, 19, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Cantarell", {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Century Gothic", {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Comfortaa", {10, 19, 22, MAX_PPEM, MAX_PPEM} },
++ { "Consolas", {10, 20, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Corbel", {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Futura", {10, 14, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Gill Sans", {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Helvetica CY", {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Inconsolata", {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Liberation Sans Narrow", {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Liberation Sans", {10, 19, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Lucida Grande", {10, 16, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Lucida Sans Unicode", {10, 16, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Luxi Sans", {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Open Sans", {10, 20, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Rokkitt", {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Segoe UI", {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
++ { "Trebuchet MS", {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
++ };
++
++
++/* "Font name", {ppem, scale_up=1|scale_down=0} */
++#define SNAPPING_STEM_SCALING_RULES_SIZE 31
++ SA_Rule SNAPPING_STEM_SCALING_Rules
++ [SNAPPING_STEM_SCALING_RULES_SIZE] =
++ {
++ { "Andale Mono", {11, 1,} },
++ { "Bitstream Vera Sans", {12, 1,} },
++ { "Calibri", {15, 1,} },
++ { "Calibri", {17, 1,} },
++ { "Calibri", {18, 1,} },
++ { "Candara", {14, 1,} },
++ { "Candara", {17, 1,} },
++ { "Canwell", {13, 0,} },
++ { "Comfortaa", {11, 0,} },
++ { "Consolas", {11, 1,} },
++ { "DejaVu Sans", {12, 1,} },
++ { "Freesans", {16, 0,} },
++ { "Freeserif", {13, 1,} },
++ { "Freeserif", {17, 1,} },
++ { "Inconsolata", {12, 1,} },
++ { "Inconsolata", {15, 1,} },
++ { "Lucida Grande", {13, 1,} },
++ { "Myriad Pro", {14, 1,} },
++ { "Myriad Pro", {17, 1,} },
++ { "Nina", {11, 0,} },
++ { "Nina", {12, 0,} },
++ { "Nina", {13, 0,} },
++ { "Optima", {17, 1,} },
++ { "Raleway", {15, 0,} },
++ { "Samba", {11, 0,} },
++ { "Times New Roman", {17, 1,} },
++ { "Trebuchet MS", {17, 0,} },
++ { "Trebuchet MS", {13, 0,} },
++ { "Trebuchet MS", {20, 1,} },
++ { "Verdana", {12, 1,} },
++ { "Verdana", {15, 1,} },
++ };
++
++
++/* "Font name", {ppem, scale_up=1|scale_down=0} */
++#define SNAPPING_M_RULES_SIZE 9
++ SA_Rule SNAPPING_M_Rules
++ [SNAPPING_M_RULES_SIZE] =
++ {
++ { "Courier New", {13, 1,} },
++ { "Courier New", {14, 1,} },
++ { "Courier", {13, 1,} },
++ { "Courier", {14, 1,} },
++ { "Droid Sans Mono", {12, 0,} },
++ { "Bitstream Vera Sans", {12, 0,} },
++ { "DejaVu Sans", {12, 0,} },
++ { "Essential PragmataPro", {13, 0,} },
++ { "Essential PragmataPro", {14, 0,} },
++ };
++
++
++/* "Font name", {ppem, ppem} */
++#define SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE 1
++ SA_Rule SNAPPING_SYNTHESIZE_STEMS_Rules
++ [SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE] =
++ {
++ { "---", {13, 13,} },
++ };
++
++
++/* "Font name", {ppem, ppem} */
++#define SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE 1
++ SA_Rule SNAPPING_NO_BEARING_CORRECTION_Rules
++ [SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE] =
++ {
++ { "Times New Roman", {0, 100,} },
++ };
++
++
++/* "Font name", {ppem, ppem} */
++#define SNAPPING_EDGE_DETECTION_RULES_SIZE 8
++ SA_Rule SNAPPING_EDGE_DETECTION_Rules
++ [SNAPPING_EDGE_DETECTION_RULES_SIZE] =
++ {
++ { "Tahoma", {11, 11,} },
++ { "Courier New", {10, 12,} },
++ { "Arial", {11, 11,} },
++ { "Arial", {13, 13,} },
++ { "Liberation Sans", {11, 11,} },
++ { "FreeSans", {11, 11,} },
++ { "FreeSans", {13, 13,} },
++ { "Palatino Linotype", {0, 100,} },
++ };
++
++/* "Font name", {ppem, translate_value} */
++#define SNAPPING_STEM_TRANSLATING_RULES_SIZE 6
++ SA_Rule SNAPPING_STEM_TRANSLATING_Rules
++ [SNAPPING_STEM_TRANSLATING_RULES_SIZE] =
++ {
++ { "Arial", {11, 32,} },
++ { "Arial Unicode MS", {11, 32,} },
++ { "FreeSans", {11, 32,} },
++ { "Arimo", {11, 32,} },
++ { "Liberation Sans", {11, 32,} },
++ { "Tahoma", {11, 32,} },
++ };
++
++/* "Font name", {ppem, translate_value} */
++#define SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE 74
++ SA_Rule SNAPPING_STEM_TRANSLATING_ONLY_Rules
++ [SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE] =
++ {
++ { "Arial Unicode MS", {10, 16,} },
++ { "Arial Unicode MS", {8, 32,} },
++ { "Arial Unicode MS", {9, 32,} },
++ { "Arial", {10, 16,} },
++ { "Arial", {8, 32,} },
++ { "Arial", {9, 32,} },
++ { "Arial", {16, -24,} },
++ { "Arimo", {10, 8,} },
++ { "Arimo", {8, 32,} },
++ { "Arimo", {9, 32,} },
++ { "Bitstream Vera Sans", {8, 16,} },
++ { "Calibri", {10, 16,} },
++ { "Calibri", {15, 0,} },
++ { "Candara", {10, 16,} },
++ { "Cantarell", {11, 0} },
++ { "Cantarell", {12, 0} },
++ { "Consolas", {8, 32,} },
++ { "Consolas", {9, 32,} },
++ { "Corbel", {10, 16,} },
++ { "Courier", {13, 16,} },
++ { "Courier", {15, 0,} },
++ { "Dejavu Sans Mono", {7, 16,} },
++ { "Dejavu Sans Mono", {8, 32,} },
++ { "Dejavu Sans Mono", {9, 16,} },
++ { "Dejavu Sans", {8, 16,} },
++ { "Dejavu Sans", {15, -20,} },
++ { "Droid Sans", {8, 16,} },
++ { "Droid Sans", {9, 16,} },
++ { "Freesans", {10, 16,} },
++ { "Freesans", {9, 8,} },
++ { "Georgia", {13, 16,} },
++ { "Georgia", {14, 16,} },
++ { "Georgia", {15, 0,} },
++ { "Inconsolata", {10, 24,} },
++ { "Inconsolata", {9, 32,} },
++ { "Liberation Sans", {10, 8,} },
++ { "Liberation Sans", {8, 32,} },
++ { "Liberation Sans", {9, 32,} },
++ { "Lucida Grande", {13, 24,} },
++ { "Lucida Grande", {14, 24,} },
++ { "Lucida Grande", {8, 16,} },
++ { "Lucida Grande", {9, 16,} },
++ { "Lucida Sans Unicode", {13, 24,} },
++ { "Lucida Sans Unicode", {14, 24,} },
++ { "Lucida Sans Unicode", {8, 16,} },
++ { "Lucida Sans Unicode", {9, 16,} },
++ { "Microsoft Sans Serif", {10, 16,} },
++ { "Microsoft Sans Serif", {8, 32,} },
++ { "Microsoft Sans Serif", {9, 32,} },
++ { "Myriad Pro", {10, 16,} },
++ { "Myriad Pro", {11, 0,} },
++ { "Myriad Pro", {9, 16,} },
++ { "Open Sans", {10, 16,} },
++ { "Open Sans", {9, 16,} },
++ { "Optima", {10, 0} },
++ { "Optima", {11, 0} },
++ { "Optima", {12, 0} },
++ { "Segoe UI", {10, 0,} },
++ { "Segoe UI", {7, 32,} },
++ { "Segoe UI", {8, 16,} },
++ { "Segoe UI", {9, 24,} },
++ { "Tahoma", {7, 32,} },
++ { "Tahoma", {8, 32,} },
++ { "Tahoma", {9, 32,} },
++ { "Times New Roman", {17, 8,} },
++ { "Trebuchet MS", {10, 16,} },
++ { "Trebuchet MS", {11, 0,} },
++ { "Trebuchet MS", {8, 32,} },
++ { "Trebuchet MS", {9, 32,} },
++ { "Verdana", {8, 16,} },
++ { "Verdana", {15, 16,} },
++ { "Verdana", {14, 32,} },
++ { "Verdana", {18, 32,} },
++ { "Verdana", {19, 24,} },
++ };
++
++
++/* "Font name", {start ppem, end ppem} */
++#define ALWAYS_USE_100_RULES_SIZE 46
++ SA_Rule ALWAYS_USE_100_Rules
++ [ALWAYS_USE_100_RULES_SIZE] =
++ {
++ { "Andale Mono", {0, MAX_PPEM,} },
++ { "Arial Unicode MS", {0, MAX_PPEM,} },
++ { "Arial", {0, MAX_PPEM,} },
++ { "Arimo", {0, MAX_PPEM,} },
++ { "Bitstream Vera Sans Mono", {0, MAX_PPEM,} },
++ { "Bitstream Vera Sans", {10, 14,} },
++ { "Bitstream Vera Sans", {16, 17,} },
++ { "Calibri", {23, MAX_PPEM,} },
++ { "Consolas", {0, MAX_PPEM,} },
++ { "Courier New", {12, 12,} },
++ { "Courier", {0, MAX_PPEM,} },
++ { "Cousine", {0, MAX_PPEM,} },
++ { "DejaVu Sans Mono", {0, MAX_PPEM,} },
++ { "DejaVu Sans", {10, 14,} },
++ { "DejaVu Sans", {16, 17,} },
++ { "Droid Sans", {12, 12,} },
++ { "Droid Sans", {15, 15,} },
++ { "FreeMono", {0, MAX_PPEM,} },
++ { "FreeSans", {0, MAX_PPEM,} },
++ { "Liberation Mono", {0, MAX_PPEM,} },
++ { "Lucida Console", {0, MAX_PPEM,} },
++ { "Luxi Sans", {13, 13,} },
++ { "Microsoft Sans Serif", {0, MAX_PPEM,} },
++ { "Monaco", {0, MAX_PPEM,} },
++ { "Segoe UI", {11, 12,} },
++ { "Segoe UI", {14, 14,} },
++ { "Tahoma", {11, 11,} },
++ { "Tahoma", {14, MAX_PPEM,} },
++ { "Times New Roman", {14, 14,} },
++ { "Times New Roman", {16, 16,} },
++ { "Trebuchet MS", {13, 13,} },
++ { "Ubuntu", {12, 13,} },
++ { "Ubuntu", {15, 15,} },
++ { "Verdana", {0, 14,} },
++ { "Verdana", {16, MAX_PPEM,} },
++ { "Pragmata", {0, MAX_PPEM,} },
++ { "Essential PragmataPro", {0, MAX_PPEM,} },
++ };
++
++
++
++
++#define AUTOHINT_BRIGHTNESS_RULES_SIZE 3
++ SA_Rule BRIGHTNESS_Rules
++ [AUTOHINT_BRIGHTNESS_RULES_SIZE] =
++ {
++ { "Baskerville", {0, -20,} },
++ { "Garamond", {0, -20,} },
++ { "Optima", {0, -20,} },
++ };
++
++#define AUTOHINT_CONTRAST_RULES_SIZE 3
++ SA_Rule CONTRAST_Rules
++ [AUTOHINT_CONTRAST_RULES_SIZE] =
++ {
++ { "Baskerville", {0, 25,} },
++ { "Garamond", {0, 25,} },
++ { "Optima", {0, 25,} },
++ };
++
++#if 0
++#define STEM_SPACING_RULES_SIZE 3
++ SA_Rule STEM_SPACING_Rules
++ [STEM_SPACING_RULES_SIZE] =
++ {
++ { "Tahoma", {10, 12, 18, 18, 30} },
++ { "Arial", {10, 11, 23, 25, 30} },
++ { "Freesans", {10, 12, 18, 18, 30} },
++ };
++
++#define STEM_START_RULES_SIZE 3
++ SA_Rule STEM_START_Rules
++ [STEM_START_RULES_SIZE] =
++ {
++ { "Tahoma", {14, 17, 30, 100, 100} },
++ { "Arial", {11, 18, 23, 30, 30} },
++ { "Freesans", {10, 18, 18, 25, 30} },
++ };
++#endif
++
++ typedef struct Stem_Data_
++ {
++ 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;
++ FT_Int brightness;
++ FT_Int contrast;
++ FT_Bool use_100;
++ FT_Bool synth_stems;
++ FT_Bool edge_detection;
++ FT_Bool bearing_correction;
++ FT_Int m;
++ } Stem_Data;
++
++
++ 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;
++ }
++
++
++ FT_LOCAL_DEF( void )
++ sa_fill_known_stem_values (
++ FT_String* family,
++ int ppem,
++ FT_String* style,
++ FT_UInt num_stems,
++ Stem_Data* known_stem_values )
++ {
++ FT_Int i, j;
++ if (verbose) printf("%s ", family);
++
++ i = 0;
++ while ( i < SNAPPING_STEM_WIDTHS_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_STEM_WIDTHS_Rules[i].family,
++ family ) == 0 ) )
++ {
++ j = 0;
++ known_stem_values->stem_width = 1;
++
++ while (j < 4)
++ {
++ if ( SNAPPING_STEM_WIDTHS_Rules[i].ppem[j] == MAX_PPEM )
++ {
++ known_stem_values->stem_width = -1; /* use default */
++ j = 5;
++ i = SNAPPING_STEM_WIDTHS_RULES_SIZE;
++ }
++ else if ( ppem < SNAPPING_STEM_WIDTHS_Rules[i].ppem[j] )
++ {
++ known_stem_values->stem_width = j;
++ j = 5;
++ i = SNAPPING_STEM_WIDTHS_RULES_SIZE;
++ }
++ j++;
++ }
++ }
++ i++;
++ }
++
++ i = 0;
++ while ( i < SNAPPING_STEM_SCALING_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_STEM_SCALING_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->stem_scaling = -1; /* default */
++
++ if ( ppem == SNAPPING_STEM_SCALING_Rules[i].ppem[0] )
++ {
++ known_stem_values->stem_scaling
++ = SNAPPING_STEM_SCALING_Rules[i].ppem[1];
++ i = SNAPPING_STEM_SCALING_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++ i = 0;
++ while ( i < SNAPPING_M_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_M_Rules[i].family, family ) == 0 ) )
++ {
++ known_stem_values->m = -1; /* default */
++
++ if ( ppem == SNAPPING_M_Rules[i].ppem[0] )
++ {
++ known_stem_values->m = SNAPPING_M_Rules[i].ppem[1];
++ i = SNAPPING_M_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++ i = 0;
++ while ( i < SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->stem_translating_only = -1024; /* default */
++
++ if ( ppem == SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[0] ||
++ SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[0] == 0 )
++ {
++ known_stem_values->stem_translating_only
++ = SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[1];
++ i = SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++ i = 0;
++ while ( i < SNAPPING_STEM_TRANSLATING_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_STEM_TRANSLATING_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->stem_translating = 0; /* default */
++
++ if ( ppem == SNAPPING_STEM_TRANSLATING_Rules[i].ppem[0] ||
++ SNAPPING_STEM_TRANSLATING_Rules[i].ppem[0] == 0 )
++ {
++ known_stem_values->stem_translating
++ = SNAPPING_STEM_TRANSLATING_Rules[i].ppem[1];
++ i = SNAPPING_STEM_TRANSLATING_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++ i = 0;
++ while ( i < ALWAYS_USE_100_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( ALWAYS_USE_100_Rules[i].family, family ) == 0 ) )
++ {
++ known_stem_values->use_100 = FALSE; /* default */
++
++ if ( ppem >= ALWAYS_USE_100_Rules[i].ppem[0] &&
++ ppem <= ALWAYS_USE_100_Rules[i].ppem[1] )
++ {
++ known_stem_values->use_100 = TRUE;
++ i = ALWAYS_USE_100_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++ i = 0;
++ while ( i < SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_SYNTHESIZE_STEMS_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->synth_stems = FALSE; /* default */
++
++ if ( ppem >= SNAPPING_SYNTHESIZE_STEMS_Rules[i].ppem[0] &&
++ ppem <= SNAPPING_SYNTHESIZE_STEMS_Rules[i].ppem[1] )
++ {
++ known_stem_values->synth_stems = TRUE;
++ i = SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++ i = 0;
++ while ( i < SNAPPING_EDGE_DETECTION_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_EDGE_DETECTION_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->edge_detection = FALSE; /* default */
++
++ if ( ppem >= SNAPPING_EDGE_DETECTION_Rules[i].ppem[0] &&
++ ppem <= SNAPPING_EDGE_DETECTION_Rules[i].ppem[1] )
++ {
++ known_stem_values->edge_detection = TRUE;
++ i = SNAPPING_EDGE_DETECTION_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++ i = 0;
++ while ( i < SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( SNAPPING_NO_BEARING_CORRECTION_Rules[i].family,
++ family ) == 0 ) )
++ {
++ known_stem_values->bearing_correction = TRUE; /* default */
++
++ if ( ppem >= SNAPPING_NO_BEARING_CORRECTION_Rules[i].ppem[0] &&
++ ppem <= SNAPPING_NO_BEARING_CORRECTION_Rules[i].ppem[1] )
++ {
++ known_stem_values->bearing_correction = FALSE;
++ i = SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++
++#if 0
++ i = 0;
++ while ( i < AUTOHINT_BRIGHTNESS_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( BRIGHTNESS_Rules[i].family, family ) == 0 ) )
++ {
++ known_stem_values->brightness = 0.0;
++
++ if ( ppem == BRIGHTNESS_Rules[i].ppem[0] ||
++ BRIGHTNESS_Rules[i].ppem[0] == 0 )
++ {
++ known_stem_values->brightness = BRIGHTNESS_Rules[i].ppem[1];
++ i = AUTOHINT_BRIGHTNESS_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++ i = 0;
++ while ( i < AUTOHINT_CONTRAST_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( CONTRAST_Rules[i].family, family ) == 0 ) )
++ {
++ known_stem_values->contrast = 0.0;
++
++ if ( ppem == CONTRAST_Rules[i].ppem[0] ||
++ CONTRAST_Rules[i].ppem[0] == 0 )
++ {
++ known_stem_values->contrast = CONTRAST_Rules[i].ppem[1];
++ i = AUTOHINT_CONTRAST_RULES_SIZE;
++ }
++ }
++ i++;
++ }
++
++ for ( i = 0; i <= STEM_SPACING_RULES_SIZE; i++ )
++ {
++ if ( family &&
++ ( strcasecmp( STEM_SPACING_Rules[i].family, family ) == 0 ) )
++ {
++ j = 0;
++ known_stem_values->stem_spacing = 2; /* default */
++
++ while (j < 4)
++ {
++ if ( ppem < STEM_SPACING_Rules[i].ppem[j] )
++ {
++ known_stem_values->stem_spacing = j;
++ j = 5;
++ }
++ j++;
++ }
++ }
++ }
++
++
++ for ( i = 0; i <= STEM_START_RULES_SIZE; i++ )
++ {
++ if ( family &&
++ ( strcasecmp( STEM_START_Rules[i].family, family ) == 0 ) )
++ {
++ j = 0;
++ known_stem_values->stem_start = 1; /* default */
++
++ while (j < 4)
++ {
++ if ( ppem < STEM_START_Rules[i].ppem[j] )
++ {
++ known_stem_values->stem_start = j;
++ j = 5;
++ }
++ j++;
++ }
++ }
++ }
++#endif
++ }
++
++
++ FT_LOCAL_DEF( FT_Int )
++ get_contrast ( FT_String* family,
++ int ppem )
++ {
++ FT_Int i;
++
++
++ if ( verbose )
++ printf( "%s ", family );
++
++ i = 0;
++ while ( i < AUTOHINT_CONTRAST_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( CONTRAST_Rules[i].family, family ) == 0 ) )
++ {
++ if ( ppem == CONTRAST_Rules[i].ppem[0] ||
++ CONTRAST_Rules[i].ppem[0] == 0 )
++ return CONTRAST_Rules[i].ppem[1];
++ }
++ i++;
++ }
++ return 0;
++ }
++
++
++ FT_LOCAL_DEF( FT_Int )
++ get_brightness ( FT_String* family,
++ int ppem )
++ {
++ FT_Int i;
++
++
++ if ( verbose )
++ printf("%s ", family);
++
++ i = 0;
++ while ( i < AUTOHINT_BRIGHTNESS_RULES_SIZE )
++ {
++ if ( family &&
++ ( strcasecmp( BRIGHTNESS_Rules[i].family, family ) == 0 ) )
++ {
++ if ( ppem == BRIGHTNESS_Rules[i].ppem[0] ||
++ BRIGHTNESS_Rules[i].ppem[0] == 0 )
++ return BRIGHTNESS_Rules[i].ppem[1];
++ }
++ i++;
++ }
++ return 0;
++ }
++
++
++ /* 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[width * 256];
++ 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;*/
++
++ FT_Bool has_serifs = FALSE;
++ FT_Bool autohinted = FALSE;
++
++ const FT_Int MIN_PPEM = 7;
++ /*const FT_Int MAX_PPEM = 100;*/
++ const FT_Int MAX_STEMS = 3;
++ FT_Int ppem = 0;
++
++ FT_Bool checked_use_known_settings_on_selected_fonts_env = FALSE;
++ FT_Bool use_known_settings_on_selected_fonts = FALSE;
++
++ int cur_width;
++ char *cur_width_env = getenv( "CUR_WIDTH" );
++
++
++
++ if ( cur_width_env != NULL )
++ {
++ sscanf ( cur_width_env, "%d", &cur_width );
++ if ( cur_width != 0 )
++ autohinted = TRUE;
++ }
++
++ /* reset to default */
++ *scale_value = 1.0;
++
++ if ( !checked_use_known_settings_on_selected_fonts_env )
++ {
++ char *use_known_settings_on_selected_fonts_env =
++ getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
++ if ( use_known_settings_on_selected_fonts_env != NULL )
++ {
++ if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "default" ) != 0 )
++ {
++ if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "true") == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "1") == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "on") == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "yes") == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ }
++ }
++ checked_use_known_settings_on_selected_fonts_env = TRUE;
++ }
++
++
++ /* 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;
++
++
++ /* 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 ( slot->face->family_name )
++ {
++ if ( strcasestr(slot->face->family_name, "Courier" ) ||
++ strcasestr(slot->face->family_name, "Serif" ) ||
++ strcasestr(slot->face->family_name, "Times" ) )
++ has_serifs = TRUE;
++ }
++
++ 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;
++ }
++ /* only look at top 3 for now */
++ known_stem_values
++ = (Stem_Data*) malloc ( columns_per_pixel * sizeof ( Stem_Data ) );
++ known_stem_values->stem_spacing = -1;
++ known_stem_values->stem_width = -1;
++ known_stem_values->stem_start = -1;
++ known_stem_values->stem_scaling = -1;
++ known_stem_values->stem_translating_only = -1024;
++ known_stem_values->stem_translating = 0;
++ known_stem_values->brightness = 0;
++ known_stem_values->contrast = 0;
++ known_stem_values->use_100 = FALSE;
++ known_stem_values->m = -1;
++ known_stem_values->synth_stems = FALSE;
++ known_stem_values->bearing_correction = TRUE;
++
++ if ( use_known_settings_on_selected_fonts )
++ {
++ sa_fill_known_stem_values ( slot->face->family_name,
++ ppem, slot->face->style_name,
++ valid_stems, known_stem_values );
++ if ( verbose )
++ printf ( "width:%d,spacing:%d,start:%d,scaling:%d,translate:%d ",
++ known_stem_values->stem_width,
++ known_stem_values->stem_spacing,
++ known_stem_values->stem_start,
++ known_stem_values->stem_scaling,
++ known_stem_values->stem_translating_only );
++ }
++
++ /* translate value may be set for < 10 */
++ if ( use_known_settings_on_selected_fonts &&
++ known_stem_values->stem_translating_only > -1024 )
++ {
++ *translate_value = known_stem_values->stem_translating_only;
++ return;
++ }
++
++ if ( use_known_settings_on_selected_fonts &&
++ known_stem_values->bearing_correction == FALSE )
++ strategy_bearing_correction = 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;
++
++ if ( ppem < 9 )
++ return;
++ if ( ppem > 20 )
++ strategy_use_m_control = TRUE;
++
++ /* Allocate */
++ segments
++ = (Stem_Segment*) malloc( (1) * sizeof ( Stem_Segment ) );
++ leftmost_segment
++ = (Stem_Segment*) malloc( sizeof ( Stem_Segment ) );
++ leftmost_segment_not_extrema
++ = (Stem_Segment*) malloc( sizeof ( Stem_Segment ) );
++ rightmost_segment
++ = (Stem_Segment*) malloc( sizeof ( Stem_Segment ) );
++ rightmost_segment_not_extrema
++ = (Stem_Segment*) malloc( sizeof ( Stem_Segment ) );
++
++ stems = (Stem*) malloc ( MAX_STEMS * sizeof ( Stem ) );
++ possible_stems = (Stem*) malloc ( MAX_STEMS * sizeof ( Stem ) );
++ leftmost_stem = (Stem*) malloc ( sizeof (Stem));
++ rightmost_stem = (Stem*) malloc ( sizeof(Stem));
++ centers = (Stem_Center*) malloc ( (1) * sizeof ( Stem_Center ) );
++
++ if ( verbose )
++ printf("\n");
++
++ /* Initialize */
++ for ( xx = 0; xx < width * 256; xx += 1 )
++ stem_centers[xx] = 0;
++
++ for ( xx = 0; xx < num_segments; xx += 1 )
++ {
++ segments[xx].x1 = 0;
++ segments[xx].x2 = 0;
++ segments[xx].y = 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 */
++ segments = (Stem_Segment*) realloc
++ ( segments, ( num_segments + 1 ) * 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 */
++ centers = (Stem_Center*) realloc
++ ( centers, ( num_centers + 1 ) * 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 best_height = 0, 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 large_gap_found = FALSE, no_gap_found = FALSE;
++ FT_Bool large_gap_found_ledge = FALSE, no_gap_found_ledge = FALSE;
++ FT_Bool large_gap_found_redge = FALSE, 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;
++
++ large_gap_found = large_gap_found_ledge = large_gap_found_redge = FALSE;
++ 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 )
++ large_gap_found = TRUE;
++
++ /* 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 )
++ large_gap_found_ledge = TRUE;
++
++ /* 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 )
++ large_gap_found_redge = TRUE;
++
++ /* 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;
++
++ best_height = 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;
++ best_height = stem_matches;
++ 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;
++ best_height = stem_matches_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;
++ best_height = stem_matches_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 )
++ if ( 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 );
++ }
++
++ 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;
++ }
++
++ /* 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;
++ }
++
++ }
++ 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;
++ }
++ }
++
++ if ( strategy_use_strengths )
++ {
++ FT_Int strength_cutoff = center_offset;
++
++
++ delta2 = new_distance - stem_distance;
++
++ if ( abs ( delta2 ) > strength_cutoff )
++ strength_cutoff = delta2;
++
++ 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;
++ }
++
++ *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;
++
++ 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 ( 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;
++ }
++
++ Exit:
++
++#define transformed_point( point ) point * *scale_value + *translate_value * 12
++
++ 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;
++ }
+
+- if ( delta )
+- FT_Outline_Translate( &slot->outline, delta->x, delta->y );
++ STVALUES
+
+- Exit:
+- return error;
++ free ( segments );
++ free ( leftmost_segment );
++ free ( rightmost_segment );
++ free ( known_stem_values );
++ free ( stems );
++ free ( possible_stems );
++ free ( leftmost_stem );
++ free ( rightmost_stem );
++ free ( centers );
+ }
+
+
+- /* 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_MEM_ZERO( cbox, sizeof ( *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
+@@ -104,8 +3103,9 @@
+ {
+ FT_Error error;
+ FT_Outline* outline = NULL;
++ FT_Outline* outline_orig = NULL;
+ FT_BBox cbox;
+- FT_Pos width, height, pitch;
++ FT_Pos width, height, pitch, ppem;
+ #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ FT_Pos height_org, width_org;
+ #endif
+@@ -121,6 +3121,483 @@
+ 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 checked_chromeos_style_sharpening_strength = 0;
++ int alignment_strength = 0;
++ int fitting_strength = 0;
++ FT_UInt checked_alignment_strength = 0;
++ FT_UInt checked_fitting_strength = 0;
++ FT_UInt checked_fringe_filter_strength = 0;
++ int fringe_filter_strength = 0;
++ FT_UInt checked_grayscale_filter_strength = 0;
++ int grayscale_filter_strength = 0;
++
++ FT_UInt checked_autohint_horizontal_stem_darken_strength = 0;
++ int autohint_horizontal_stem_darken_strength = 0;
++
++ FT_UInt checked_autohint_vertical_stem_darken_strength = 0;
++ int autohint_vertical_stem_darken_strength = 0;
++
++ int windows_style_sharpening_strength = 0;
++ FT_UInt checked_windows_style_sharpening_strength = 0;
++ float gamma_correction_value = 1;
++ float gamma_correction_lt = 0;
++ FT_UInt checked_gamma_correction_value = 0;
++
++ FT_Int brightness_value = 0.0;
++ FT_UInt checked_brightness_value = 0;
++
++ FT_Int contrast_value = 0.0;
++ FT_UInt checked_contrast_value = 0;
++
++ FT_Int snapping_sliding_scale_value = 0;
++ FT_UInt checked_snapping_sliding_scale_value = 0;
++
++ FT_Int global_embolden_x_value = 0;
++ FT_UInt checked_global_embolden_x_value = 0;
++
++ FT_Int global_embolden_y_value = 0;
++ FT_UInt checked_global_embolden_y_value = 0;
++
++ FT_Int bold_embolden_x_value = 0;
++ FT_UInt checked_bold_embolden_x_value = 0;
++
++ FT_Int bold_embolden_y_value = 0;
++ FT_UInt checked_bold_embolden_y_value = 0;
++
++ FT_Byte chromeos_cutoff;
++ double chromeos_gamma_value;
++
++ float embolden_value = 0.0;
++ FT_Bool autohinted = FALSE;
++
++ FT_UInt autohint_minimum_stem_height = 0;
++ FT_UInt checked_autohint_minimum_stem_height = 0;
++
++ int checked_use_various_tweaks_env = 0;
++ FT_Bool use_various_tweaks = FALSE;
++
++ int cur_width;
++ char *cur_width_env = getenv( "CUR_WIDTH" );
++
++ const FT_Int MIN_PPEM = 1;
++ /*const FT_Int MAX_PPEM = 100; */
++
++ int checked_use_known_settings_on_selected_fonts_env = 0;
++ FT_Bool use_known_settings_on_selected_fonts = FALSE;
++
++ 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_env != NULL )
++ {
++ sscanf ( cur_width_env, "%d", &cur_width );
++
++ if ( cur_width != 0 )
++ autohinted = TRUE;
++ }
++
++ if ( checked_use_known_settings_on_selected_fonts_env == 0 )
++ {
++ char *use_known_settings_on_selected_fonts_env =
++ getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
++ if ( use_known_settings_on_selected_fonts_env != NULL )
++ {
++ if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "default" ) != 0 )
++ {
++ if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "true" ) == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "1" ) == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "on" ) == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ else if ( strcasecmp( use_known_settings_on_selected_fonts_env,
++ "yes" ) == 0 )
++ use_known_settings_on_selected_fonts = TRUE;
++ }
++ }
++ checked_use_known_settings_on_selected_fonts_env = 1;
++ }
++
++ if ( checked_use_various_tweaks_env == 0 )
++ {
++ char *use_various_tweaks_env
++ = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
++
++ if ( use_various_tweaks_env != NULL )
++ {
++ if ( strcasecmp( use_various_tweaks_env, "default" ) != 0 )
++ {
++ if ( strcasecmp( use_various_tweaks_env, "true") == 0)
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp( use_various_tweaks_env, "1") == 0)
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp( use_various_tweaks_env, "on") == 0)
++ use_various_tweaks = TRUE;
++ else if ( strcasecmp( use_various_tweaks_env, "yes") == 0)
++ use_various_tweaks = TRUE;
++ }
++ }
++ checked_use_various_tweaks_env = 1;
++ }
++
++ if ( checked_autohint_minimum_stem_height == 0 )
++ {
++ char *autohint_minimum_stem_height_env =
++ getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" );
++
++ if ( autohint_minimum_stem_height_env != NULL )
++ {
++ sscanf ( autohint_minimum_stem_height_env, "%u",
++ &autohint_minimum_stem_height );
++
++ if ( autohint_minimum_stem_height > 100 )
++ autohint_minimum_stem_height = 100;
++ else if ( autohint_minimum_stem_height < 0 )
++ autohint_minimum_stem_height = 0;
++ }
++ checked_autohint_minimum_stem_height = 1;
++ }
++
++ if ( checked_snapping_sliding_scale_value == 0 )
++ {
++ char *snapping_sliding_scale_env =
++ getenv ( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" );
++
++ if ( snapping_sliding_scale_env != NULL )
++ {
++ sscanf ( snapping_sliding_scale_env, "%d",
++ &snapping_sliding_scale_value );
++
++ if ( snapping_sliding_scale_value > MAX_PPEM )
++ snapping_sliding_scale_value = 0;
++ else if ( snapping_sliding_scale_value < 0 )
++ snapping_sliding_scale_value = 0;
++
++ if (snapping_sliding_scale_value < 11 &&
++ snapping_sliding_scale_value > 0 )
++ snapping_sliding_scale_value = 11;
++ }
++ checked_snapping_sliding_scale_value = 1;
++ }
++
++ if ( checked_alignment_strength == 0)
++ {
++ char *alignment_strength_env =
++ getenv ( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" );
++
++ if ( alignment_strength_env != NULL )
++ {
++ sscanf ( alignment_strength_env, "%d", &alignment_strength );
++
++ if ( alignment_strength > 100 )
++ alignment_strength = 100;
++ else if ( alignment_strength < 0 )
++ alignment_strength = 0;
++ }
++
++ if ( alignment_strength > 100 )
++ alignment_strength = 100;
++ checked_alignment_strength = 1;
++
++ if ( snapping_sliding_scale_value != 0 )
++ alignment_strength = sliding_scale
++ ( 10, snapping_sliding_scale_value, alignment_strength, 100, ppem );
++ }
++
++ if ( checked_fitting_strength == 0 )
++ {
++ char *fitting_strength_env =
++ getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
++
++ if ( fitting_strength_env != NULL )
++ {
++ sscanf ( fitting_strength_env, "%d", &fitting_strength );
++
++ if ( fitting_strength > 100 )
++ fitting_strength = 100;
++ else if ( fitting_strength < 0 )
++ fitting_strength = 0;
++ }
++
++ if ( fitting_strength > 100 )
++ fitting_strength = 100;
++
++ checked_fitting_strength = 1;
++
++ if ( snapping_sliding_scale_value != 0 )
++ fitting_strength = sliding_scale
++ ( 10, snapping_sliding_scale_value, fitting_strength, 100, ppem );
++ }
++
++ if ( checked_chromeos_style_sharpening_strength == 0 )
++ {
++ char *chromeos_style_sharpening_strength_env =
++ getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" );
++ if ( chromeos_style_sharpening_strength_env != NULL )
++ {
++ sscanf ( chromeos_style_sharpening_strength_env, "%d",
++ &chromeos_style_sharpening_strength );
++
++ if ( chromeos_style_sharpening_strength > 100 )
++ chromeos_style_sharpening_strength = 100;
++ else if ( chromeos_style_sharpening_strength < 0 )
++ chromeos_style_sharpening_strength = 0;
++ }
++
++ if ( ppem > 10 )
++ chromeos_style_sharpening_strength =
++ ( chromeos_style_sharpening_strength * ppem ) / 10;
++
++ if ( chromeos_style_sharpening_strength > 100 )
++ chromeos_style_sharpening_strength = 100;
++ checked_chromeos_style_sharpening_strength = 1;
++ }
++
++
++ if ( checked_brightness_value == 0)
++ {
++ char *brightness_env = getenv( "INFINALITY_FT_BRIGHTNESS" );
++ if ( brightness_env != NULL )
++ {
++ sscanf ( brightness_env, "%d", &brightness_value );
++ if (brightness_value > 100 )
++ brightness_value = 100;
++ else if (brightness_value < -100 )
++ brightness_value = 0;
++ }
++ checked_brightness_value = 1;
++ }
++
++ if ( checked_contrast_value == 0)
++ {
++ char *contrast_env = getenv( "INFINALITY_FT_CONTRAST" );
++ if ( contrast_env != NULL )
++ {
++ sscanf ( contrast_env, "%d", &contrast_value );
++ if (contrast_value > 100 )
++ contrast_value = 100;
++ else if (contrast_value < -100 )
++ contrast_value = 100;
++ }
++ checked_contrast_value = 1;
++ }
++
++ if ( checked_windows_style_sharpening_strength == 0)
++ {
++ char *windows_style_sharpening_strength_env =
++ getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" );
++
++ if ( windows_style_sharpening_strength_env != NULL )
++ {
++ sscanf ( windows_style_sharpening_strength_env, "%d",
++ &windows_style_sharpening_strength );
++
++ if ( windows_style_sharpening_strength > 100 )
++ windows_style_sharpening_strength = 100;
++ else if ( windows_style_sharpening_strength < 0 )
++ windows_style_sharpening_strength = 0;
++ }
++ /* 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;
++ checked_windows_style_sharpening_strength = 1;
++ }
++
++ if ( checked_gamma_correction_value == 0 )
++ {
++ char *gamma_correction_value_env =
++ getenv( "INFINALITY_FT_GAMMA_CORRECTION" );
++
++ if ( gamma_correction_value_env != NULL )
++ {
++ float f1, f2;
++
++ if ( strcasecmp( gamma_correction_value_env, "default" ) != 0 )
++ {
++ sscanf ( gamma_correction_value_env, "%f %f", &f1, &f2 );
++ gamma_correction_lt = f1;
++ gamma_correction_value = f2 / 100.0;
++ }
++ if ( gamma_correction_value < .01 ) gamma_correction_value = 1.0;
++ }
++ checked_gamma_correction_value = 1;
++ }
++
++ /* 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 ( checked_fringe_filter_strength == 0 )
++ {
++ char *fringe_filter_strength_env =
++ getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" );
++ if ( fringe_filter_strength_env != NULL )
++ {
++ sscanf ( fringe_filter_strength_env, "%d", &fringe_filter_strength );
++
++ if ( fringe_filter_strength > 100 )
++ fringe_filter_strength = 100;
++ else if ( fringe_filter_strength < 0 )
++ fringe_filter_strength = 0;
++ }
++ checked_fringe_filter_strength = 1;
++ }
++
++
++ if ( checked_grayscale_filter_strength == 0)
++ {
++ char *grayscale_filter_strength_env =
++ getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" );
++ if ( grayscale_filter_strength_env != NULL )
++ {
++ sscanf ( grayscale_filter_strength_env, "%d",
++ &grayscale_filter_strength );
++ if ( grayscale_filter_strength > 100 ) grayscale_filter_strength = 100;
++ else if (grayscale_filter_strength < 0 ) grayscale_filter_strength = 0;
++ }
++ checked_grayscale_filter_strength = 1;
++ }
++
++
++ if ( checked_autohint_horizontal_stem_darken_strength == 0)
++ {
++ char *autohint_horizontal_stem_darken_strength_env =
++ getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" );
++ if ( autohint_horizontal_stem_darken_strength_env != NULL )
++ {
++ sscanf ( autohint_horizontal_stem_darken_strength_env, "%d",
++ &autohint_horizontal_stem_darken_strength );
++
++ if ( autohint_horizontal_stem_darken_strength > 100 )
++ autohint_horizontal_stem_darken_strength = 100;
++ else if ( autohint_horizontal_stem_darken_strength < 0 )
++ autohint_horizontal_stem_darken_strength = 0;
++ }
++ checked_autohint_horizontal_stem_darken_strength = 1;
++ }
++
++ if ( checked_autohint_vertical_stem_darken_strength == 0)
++ {
++ char *autohint_vertical_stem_darken_strength_env =
++ getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" );
++ if ( autohint_vertical_stem_darken_strength_env != NULL )
++ {
++ sscanf ( autohint_vertical_stem_darken_strength_env, "%d",
++ &autohint_vertical_stem_darken_strength );
++
++ if ( autohint_vertical_stem_darken_strength > 100 )
++ autohint_vertical_stem_darken_strength = 100;
++ else if ( autohint_horizontal_stem_darken_strength < 0 )
++ autohint_vertical_stem_darken_strength = 0;
++ }
++ checked_autohint_vertical_stem_darken_strength = 1;
++ }
++
++ if ( checked_global_embolden_x_value == 0)
++ {
++ char *global_embolden_x_env =
++ getenv ( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" );
++ if ( global_embolden_x_env != NULL )
++ {
++ sscanf ( global_embolden_x_env, "%d", &global_embolden_x_value );
++
++ if ( global_embolden_x_value > 128 )
++ global_embolden_x_value = 128;
++ else if ( global_embolden_x_value < -128 )
++ global_embolden_x_value = -128;
++ }
++ checked_global_embolden_x_value = 1;
++ }
++
++ if ( checked_global_embolden_y_value == 0)
++ {
++ char *global_embolden_y_env =
++ getenv ( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" );
++ if ( global_embolden_y_env != NULL )
++ {
++ sscanf ( global_embolden_y_env, "%d", &global_embolden_y_value );
++ if ( global_embolden_y_value > 128 )
++ global_embolden_y_value = 128;
++ else if ( global_embolden_y_value < -128 )
++ global_embolden_y_value = -128;
++ }
++ checked_global_embolden_y_value = 1;
++ }
++
++
++ if ( checked_bold_embolden_x_value == 0)
++ {
++ char *bold_embolden_x_env =
++ getenv ( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" );
++
++ if ( bold_embolden_x_env != NULL )
++ {
++ sscanf ( bold_embolden_x_env, "%d", &bold_embolden_x_value );
++ if (bold_embolden_x_value > 128 )
++ bold_embolden_x_value = 128;
++ else if (bold_embolden_x_value < -128 )
++ bold_embolden_x_value = -128;
++ }
++ checked_bold_embolden_x_value = 1;
++ }
++
++ if ( checked_bold_embolden_y_value == 0)
++ {
++ char *bold_embolden_y_env = getenv ( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" );
++
++ if ( bold_embolden_y_env != NULL )
++ {
++ sscanf ( bold_embolden_y_env, "%d", &bold_embolden_y_value );
++ if (bold_embolden_y_value > 128 )
++ bold_embolden_y_value = 128;
++ else if (bold_embolden_y_value < -128 )
++ bold_embolden_y_value = -128;
++ }
++ checked_bold_embolden_y_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
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+@@ -136,9 +3613,105 @@
+ 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 );
+@@ -152,6 +3725,7 @@
+ cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
+ cbox.xMax = FT_PIX_CEIL( cbox.xMax );
+ cbox.yMax = FT_PIX_CEIL( cbox.yMax );
++#endif
+
+ if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
+ {
+@@ -228,6 +3802,9 @@
+ y_top += extra >> 1;
+ }
+ }
++#endif
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ }
+
+ #endif
+
+@@ -252,6 +3829,9 @@
+ bitmap->pitch = pitch;
+
+ /* translate outline to render it into the bitmap */
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( align_called == 0 )
++#endif
+ FT_Outline_Translate( outline, -x_shift, -y_shift );
+ have_outline_shifted = TRUE;
+
+@@ -307,9 +3887,153 @@
+ if ( error )
+ goto Exit;
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM )
++ {
++ 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 ) )
++ {
++ align_called = 1;
++ goto RERENDER;
++ }
++
++ if ( mode == FT_RENDER_MODE_LCD )
++ {
++
++ 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 */
++ if ( slot->face && !_ft_bitmap_bc ( bitmap,
++ (float)get_brightness( slot->face->family_name, ppem ) / 300.0,
++ (float)get_contrast( slot->face->family_name, ppem ) / 300.0 ) )
++ {
++ 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 );
++ }
++ }
++ }
++
++
++ if ( slot->library->lcd_filter_func )
++ slot->library->lcd_filter_func( bitmap, mode, slot->library );
++
++ if ( grayscale_filter_strength > 0 )
++ _ft_lcd_grayscale_filter( bitmap,
++ mode,
++ grayscale_filter_strength,
++ slot->library );
++
++ }
++
++ /* Global values */
++ if ( brightness_value != 0 || contrast_value != 0 )
++ _ft_bitmap_bc ( bitmap,
++ (float)brightness_value / 300.0,
++ (float)contrast_value / 300.0);
++
++ FT_Outline_Done( slot->library, outline_orig );
++ }
++ else if ( mode == FT_RENDER_MODE_LCD &&
++ slot->library->lcd_filter_func )
++ slot->library->lcd_filter_func( bitmap, mode, slot->library );
++#else
+ if ( slot->library->lcd_filter_func )
+ slot->library->lcd_filter_func( bitmap, mode, slot->library );
+
++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+ #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+ /* render outline into bitmap */
+diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
+index 872894d..44e4274 100644
+--- a/src/truetype/ttinterp.c
++++ b/src/truetype/ttinterp.c
+@@ -1842,8 +1842,7 @@
+ FT_UNUSED_EXEC;
+
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( !CUR.ignore_x_mode ||
+- ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVEX ) )
++ if ( !CUR.ignore_x_mode )
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ zone->cur[point].x += distance;
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
+@@ -4464,7 +4463,7 @@
+
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* arguments to opcodes are skipped by `SKIP_Code' */
+- FT_Byte opcode_pattern[7][12] = {
++ FT_Byte opcode_pattern[9][12] = {
+ /* #0 inline delta function 1 */
+ {
+ 0x4B, /* PPEM */
+@@ -4542,10 +4541,23 @@
+ 0x43, /* RS */
+ 0x58 /* IF */
+ },
++ /* #7 TypeMan Talk DiagEndCtrl function */
++ {
++ 0x01, /* SVTCA_x */
++ 0x20, /* DUP */
++ 0xB0, /* PUSHB_1 */
++ /* 3 */
++ 0x25, /* CINDEX */
++ },
++ /* #8 TypeMan Talk Align */
++ {
++ 0x06, /* SPVTL */
++ 0x7D, /* RDTG */
++ },
+ };
+- FT_UShort opcode_patterns = 7;
+- FT_UShort opcode_pointer[7] = { 0, 0, 0, 0, 0, 0, 0 };
+- FT_UShort opcode_size[7] = { 12, 8, 8, 6, 7, 4, 5 };
++ FT_UShort opcode_patterns = 9;
++ FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
++ FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
+ FT_UShort i;
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+@@ -4684,6 +4696,17 @@
+ CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
+ }
+ break;
++
++ case 7:
++ rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
++ CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
++ break;
++
++ case 8:
++ /*rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
++ CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;*/
++ break;
++
+ }
+ opcode_pointer[i] = 0;
+ }
+@@ -4729,6 +4752,10 @@
+ FT_UNUSED_ARG;
+
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ CUR.sph_in_func_flags = 0x0000;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
+ {
+ CUR.error = FT_THROW( ENDF_In_Exec_Stream );
+@@ -4814,7 +4841,13 @@
+ goto Fail;
+
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- CUR.sph_in_func_flags &= def->sph_fdef_flags;
++ if ( CUR.ignore_x_mode &&
++ ( ( CUR.iup_called &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
++ ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) )
++ goto Fail;
++ else
++ CUR.sph_in_func_flags = def->sph_fdef_flags;
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ /* check the call stack */
+@@ -4839,10 +4872,6 @@
+
+ CUR.step_ins = FALSE;
+
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- CUR.sph_in_func_flags &= !def->sph_fdef_flags;
+-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+-
+ return;
+
+ Fail:
+@@ -4900,7 +4929,11 @@
+ goto Fail;
+
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- CUR.sph_in_func_flags &= def->sph_fdef_flags;
++ if ( CUR.ignore_x_mode &&
++ ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
++ goto Fail;
++ else
++ CUR.sph_in_func_flags = def->sph_fdef_flags;
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ /* check stack */
+@@ -4927,10 +4960,6 @@
+ CUR.step_ins = FALSE;
+ }
+
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- CUR.sph_in_func_flags &= !def->sph_fdef_flags;
+-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+-
+ return;
+
+ Fail:
+@@ -5779,9 +5808,7 @@
+ if ( CUR.GS.freeVector.x != 0 )
+ {
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( !CUR.ignore_x_mode ||
+- ( CUR.ignore_x_mode &&
+- ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_MOVE_ZP2 ) ) )
++ if ( !CUR.ignore_x_mode )
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ CUR.zp2.cur[point].x += dx;
+ if ( touch )
+@@ -6030,14 +6057,17 @@
+ else
+ B1 = CUR.zp2.cur[point].x;
+
+- if ( CUR.GS.freeVector.y != 0 &&
+- ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_INLINE_DELTAS ) )
+- goto Skip;
+-
+ if ( !CUR.face->sph_compatibility_mode &&
+ CUR.GS.freeVector.y != 0 )
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
++ else if ( CUR.sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
++ {
++ MOVE_Zp2_Point( point, dx, dy, TRUE );
++ /* don't allow reversals */
++ goto Skip;
++ }
++
+ else if ( CUR.face->sph_compatibility_mode )
+ {
+ if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
+@@ -6046,6 +6076,12 @@
+ dy = FT_PIX_ROUND( B1 + dy ) - B1;
+ }
+
++ /* skip post-iup deltas */
++ if ( CUR.iup_called &&
++ ( ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
++ ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
++ goto Skip;
++
+ if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
+ ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ||
+ ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
+@@ -6223,6 +6259,7 @@
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
++ CUR.GS.freeVector.y == 0 &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ control_value_cutin = 0;
+ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+@@ -6489,11 +6526,6 @@
+ cvt_dist = 0;
+ else
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( CUR.ignore_x_mode &&
+- ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) )
+- cvt_dist = 0;
+-#endif
+
+ /* single width test */
+
+@@ -6642,12 +6674,6 @@
+ ( B2 & 63 ) != 0 &&
+ ( B1 & 63 ) != 0 )
+ reverse_move = TRUE;
+-
+- if ( ( CUR.sph_tweak_flags &
+- SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) &&
+- !reverse_move &&
+- FT_ABS( B1 - B2 ) >= 64 )
+- reverse_move = TRUE;
+ }
+
+ if ( reverse_move )
+@@ -7214,7 +7240,7 @@
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( CUR.ignore_x_mode )
+ {
+- CUR.iup_called = 1;
++ CUR.iup_called = TRUE;
+ if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
+ return;
+ }
+@@ -7291,7 +7317,13 @@
+ FT_Long B;
+ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_UShort B1, B2;
+-#endif
++
++
++ if ( CUR.ignore_x_mode &&
++ CUR.iup_called &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
++ goto Fail;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+ #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
+@@ -7388,7 +7420,7 @@
+ #if 0
+ /* Standard Subpixel Hinting: Allow y move. */
+ /* This messes up dejavu and may not be needed... */
+- if ( !CUR.face->sph_compatibility_mode &&
++ if ( !CUR.face->sph_compatibility_mode &&
+ CUR.GS.freeVector.y != 0 )
+ CUR_Func_move( &CUR.zp0, A, B );
+ else
+@@ -7419,14 +7451,14 @@
+ ( B1 & 63 ) == 0 &&
+ ( B2 & 63 ) != 0 ) ||
+ ( ( CUR.sph_tweak_flags &
+- SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
++ SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
+ ( B1 & 63 ) != 0 &&
+ ( B2 & 63 ) != 0 ) ) )
+ CUR_Func_move( &CUR.zp0, A, -B );
+ }
+ #else
+ CUR_Func_move( &CUR.zp0, A, B );
+-#endif /* *TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ }
+ }
+ else
+@@ -8031,6 +8063,19 @@
+ TT_RunIns( TT_ExecContext exc )
+ {
+ FT_Long ins_counter = 0; /* executed instructions counter */
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Byte opcode_pattern[1][2] = {
++ /* #8 TypeMan Talk Align */
++ {
++ 0x06, /* SPVTL */
++ 0x7D, /* RDTG */
++ },
++ };
++ FT_UShort opcode_patterns = 1;
++ FT_UShort opcode_pointer[1] = { 0 };
++ FT_UShort opcode_size[1] = { 1 };
++ FT_UShort i;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+ #ifdef TT_CONFIG_OPTION_STATIC_RASTER
+@@ -8116,6 +8161,34 @@
+ CUR.step_ins = TRUE;
+ CUR.error = FT_Err_Ok;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ for ( i = 0; i < opcode_patterns; i++ )
++ {
++ if ( opcode_pointer[i] < opcode_size[i] &&
++ CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
++ {
++ opcode_pointer[i] += 1;
++
++ if ( opcode_pointer[i] == opcode_size[i] )
++ {
++ FT_TRACE7(( "sph: opcode ptrn: %d, %s %s\n",
++ i,
++ CUR.face->root.family_name,
++ CUR.face->root.style_name ));
++
++ switch ( i )
++ {
++ case 0:
++ break;
++ }
++ opcode_pointer[i] = 0;
++ }
++ }
++ else
++ opcode_pointer[i] = 0;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+ {
+@@ -8312,13 +8385,7 @@
+ break;
+
+ case 0x2B: /* CALL */
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( !CUR.ignore_x_mode ||
+- !CUR.iup_called ||
+- ( CUR.iup_called &&
+- !( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) )
+-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+- Ins_CALL( EXEC_ARG_ args );
++ Ins_CALL( EXEC_ARG_ args );
+ break;
+
+ case 0x2C: /* FDEF */
+@@ -8336,11 +8403,7 @@
+
+ case 0x30: /* IUP */
+ case 0x31: /* IUP */
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( CUR.ignore_x_mode )
+- CUR.iup_called = TRUE;
+-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+- Ins_IUP( EXEC_ARG_ args );
++ Ins_IUP( EXEC_ARG_ args );
+ break;
+
+ case 0x32: /* SHP */
+@@ -8499,13 +8562,7 @@
+ break;
+
+ case 0x5D: /* DELTAP1 */
+-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+- if ( !CUR.ignore_x_mode ||
+- !CUR.iup_called ||
+- ( CUR.iup_called &&
+- !( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) )
+-#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+- Ins_DELTAP( EXEC_ARG_ args );
++ Ins_DELTAP( EXEC_ARG_ args );
+ break;
+
+ case 0x5E: /* SDB */
+diff --git a/src/truetype/ttsubpix.c b/src/truetype/ttsubpix.c
+index 27e9b15..5267233 100644
+--- a/src/truetype/ttsubpix.c
++++ b/src/truetype/ttsubpix.c
+@@ -286,25 +286,14 @@
+
+
+ /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */
+-#define PIXEL_HINTING_RULES_SIZE 1
++#define PIXEL_HINTING_RULES_SIZE 2
+
+ const SPH_TweakRule PIXEL_HINTING_Rules
+ [PIXEL_HINTING_RULES_SIZE] =
+ {
+ /* these characters are almost always safe */
+- { "-", 0, "", 0 },
+- };
+-
+-
+- /* According to Greg Hitchcock and the MS whitepaper, this should work */
+- /* on all legacy MS fonts, but creates artifacts with some. Only using */
+- /* where absolutely necessary. */
+-#define SKIP_INLINE_DELTAS_RULES_SIZE 1
+-
+- const SPH_TweakRule SKIP_INLINE_DELTAS_Rules
+- [SKIP_INLINE_DELTAS_RULES_SIZE] =
+- {
+- { "-", 0, "", 0 },
++ { "Courier New", 12, "Italic", 'z' },
++ { "Courier New", 11, "Italic", 'z' },
+ };
+
+
+@@ -320,42 +309,41 @@
+
+ /* Skip Y moves that start with a point that is not on a Y pixel */
+ /* boundary and don't move that point to a Y pixel boundary. */
+-#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 9
++#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 5
+
+ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules
+ [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
+ {
+ /* fix vwxyz thinness*/
+- { "Consolas", 0, "Regular", 0 },
+- /* fix tiny gap at top of m */
+- { "Arial", 0, "Regular", 'm' },
++ { "Consolas", 0, "", 0 }, { "-", 0, "N", 0 },
+ /* Fix thin middle stems */
+- { "Core MS Legacy Fonts", 0, "Regular/Bold Class", 'N' },
+- { "Lucida Grande", 0, "", 'N' },
+- { "Lucida Grande", 0, "Bold", 'y' },
++ { "-Core MS Legacy Fonts", 0, "Regular/Bold Class", 0 },
+ /* Cyrillic small letter I */
+- { "Legacy Sans Fonts", 0, "", 0x438 },
+- { "Verdana Clones", 0, "",'N' },
+- /* Fix misshapen x */
+- { "Verdana", 0, "Bold", 'x' },
+- /* Fix misshapen s */
+- { "Tahoma", 0, "", 's' },
++ { "Legacy Sans Fonts", 0, "", 0 },
++ /* Fix artifacts with some Regular & Bold */
++ { "Verdana Clones", 0, "", 0 },
+ };
+
+
+-#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 7
++#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
+
+ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
+ [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
+ {
+- { "Tahoma", 0, "", 'N' },
+- { "Comic Sans MS", 0, "", 'N' },
+- { "Verdana", 0, "Regular/Bold Class", 'N' },
+- { "Verdana", 11, "Bold", 'x' },
+- /* Cyrillic small letter I */
+- { "Arial", 0, "", 0x438 },
+- { "Arial", 11, "Bold", 'N' },
+- { "Trebuchet MS", 0, "Bold", 0 },
++ { "-", 0, "", 0 },
++ };
++
++
++ /* Skip Y moves that start with a point that is not on a Y pixel */
++ /* boundary and don't move that point to a Y pixel boundary. */
++#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2
++
++ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules
++ [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] =
++ {
++ /* Maintain thickness of diagonal in 'N' */
++ { "Times New Roman", 0, "Regular/Bold Class", 'N' },
++ { "Georgia", 0, "Regular/Bold Class", 'N' },
+ };
+
+
+@@ -399,16 +387,6 @@
+ };
+
+
+- /* Allow a Direct_Move_X along X freedom vector if matched. */
+-#define ALLOW_X_DMOVEX_RULES_SIZE 1
+-
+- const SPH_TweakRule ALLOW_X_DMOVEX_Rules
+- [ALLOW_X_DMOVEX_RULES_SIZE] =
+- {
+- { "-", 0, "Regular", 0 },
+- };
+-
+-
+ /* Allow a Direct_Move along X freedom vector if matched. */
+ #define ALLOW_X_DMOVE_RULES_SIZE 1
+
+@@ -420,17 +398,6 @@
+ };
+
+
+- /* Allow a ZP2 move along freedom vector if matched; */
+- /* This is called from SHP, SHPIX, SHC, SHZ. */
+-#define ALLOW_X_MOVE_ZP2_RULES_SIZE 1
+-
+- const SPH_TweakRule ALLOW_X_MOVE_ZP2_Rules
+- [ALLOW_X_MOVE_ZP2_RULES_SIZE] =
+- {
+- { "-", 0, "", 0 },
+- };
+-
+-
+ /* Return MS rasterizer version 35 if matched. */
+ #define RASTERIZER_35_RULES_SIZE 8
+
+@@ -455,7 +422,8 @@
+ const SPH_TweakRule NORMAL_ROUND_Rules
+ [NORMAL_ROUND_RULES_SIZE] =
+ {
+- /* Fix serif thickness */
++ /* Fix serif thickness for certain ppems */
++ /* Can probably be generalized somehow */
+ { "Courier New", 0, "", 0 },
+ };
+
+@@ -481,7 +449,7 @@
+
+
+ /* Skip DELTAP instructions if matched. */
+-#define ALWAYS_SKIP_DELTAP_RULES_SIZE 15
++#define ALWAYS_SKIP_DELTAP_RULES_SIZE 18
+
+ const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
+ [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
+@@ -491,7 +459,11 @@
+ { "Trebuchet MS", 14, "Regular", 'e' },
+ { "Trebuchet MS", 13, "Regular", 'e' },
+ { "Trebuchet MS", 15, "Regular", 'e' },
++ { "Trebuchet MS", 0, "Italic", 'v' },
++ { "Trebuchet MS", 0, "Italic", 'w' },
++ { "Trebuchet MS", 0, "Regular", 'Y' },
+ { "Arial", 11, "Regular", 's' },
++ /* prevent problems with '3' and others */
+ { "Verdana", 10, "Regular", 0 },
+ { "Verdana", 9, "Regular", 0 },
+ /* Cyrillic small letter short I */
+@@ -508,57 +480,23 @@
+
+
+ /* Always do DELTAP instructions if matched. */
+-#define ALWAYS_DO_DELTAP_RULES_SIZE 2
++#define ALWAYS_DO_DELTAP_RULES_SIZE 1
+
+ const SPH_TweakRule ALWAYS_DO_DELTAP_Rules
+ [ALWAYS_DO_DELTAP_RULES_SIZE] =
+ {
+- { "Verdana Clones", 17, "Regular Class", 'K' },
+- { "Verdana Clones", 17, "Regular Class", 'k' },
+- };
+-
+-
+- /* Do an extra RTG instruction in DELTAP if matched. */
+-#define DELTAP_RTG_RULES_SIZE 1
+-
+- static const SPH_TweakRule DELTAP_RTG_Rules
+- [DELTAP_RTG_RULES_SIZE] =
+- {
+- { "-", 0, "", 0 },
+- };
+-
+-
+- /* Force CVT distance to zero in MIRP. */
+-#define MIRP_CVT_ZERO_RULES_SIZE 1
+-
+- static const SPH_TweakRule MIRP_CVT_ZERO_Rules
+- [MIRP_CVT_ZERO_RULES_SIZE] =
+- {
+- { "-", 0, "", 0 },
+- };
+-
+-
+- /* Skip moves that meet or exceed 1 pixel. */
+-#define DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE 1
+-
+- static const SPH_TweakRule DELTAP_SKIP_EXAGGERATED_VALUES_Rules
+- [DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE] =
+- {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Don't allow ALIGNRP after IUP. */
+-#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 4
++#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1
+
+ static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules
+ [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] =
+ {
+ /* Prevent creation of dents in outline */
+- { "Courier New", 0, "Bold", 'C' },
+- { "Courier New", 0, "Bold", 'D' },
+- { "Courier New", 0, "Bold", 'Q' },
+- { "Courier New", 0, "Bold", '0' },
++ { "-", 0, "", 0 },
+ };
+
+
+@@ -573,16 +511,13 @@
+
+
+ /* Don't allow CALL after IUP. */
+-#define NO_CALL_AFTER_IUP_RULES_SIZE 4
++#define NO_CALL_AFTER_IUP_RULES_SIZE 1
+
+ static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules
+ [NO_CALL_AFTER_IUP_RULES_SIZE] =
+ {
+ /* Prevent creation of dents in outline */
+- { "Courier New", 0, "Bold", 'O' },
+- { "Courier New", 0, "Bold", 'Q' },
+- { "Courier New", 0, "Bold", 'k' },
+- { "Courier New", 0, "Bold Italic", 'M' },
++ { "-", 0, "", 0 },
+ };
+
+
+@@ -605,29 +540,16 @@
+
+
+ /* Embolden these glyphs slightly. */
+-#define EMBOLDEN_RULES_SIZE 5
++#define EMBOLDEN_RULES_SIZE 2
+
+ static const SPH_TweakRule EMBOLDEN_Rules
+ [EMBOLDEN_RULES_SIZE] =
+ {
+- { "Courier New", 12, "Italic", 'z' },
+- { "Courier New", 11, "Italic", 'z' },
+- { "Courier New", 10, "Italic", 'z' },
+ { "Courier New", 0, "Regular", 0 },
+ { "Courier New", 0, "Italic", 0 },
+ };
+
+
+- /* Do an extra RDTG instruction in DELTAP if matched. */
+-#define DELTAP_RDTG_RULES_SIZE 1
+-
+- static const SPH_TweakRule DELTAP_RDTG_Rules
+- [DELTAP_RDTG_RULES_SIZE] =
+- {
+- { "-", 0, "", 0 },
+- };
+-
+-
+ /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */
+ /* similar to Windows XP. */
+ #define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
+@@ -998,12 +920,9 @@
+ }
+
+ TWEAK_RULES( ALLOW_X_DMOVE );
+- TWEAK_RULES( ALLOW_X_DMOVEX );
+- TWEAK_RULES( ALLOW_X_MOVE_ZP2 );
+ TWEAK_RULES( ALWAYS_DO_DELTAP );
+ TWEAK_RULES( ALWAYS_SKIP_DELTAP );
+ TWEAK_RULES( DEEMBOLDEN );
+- TWEAK_RULES( DELTAP_SKIP_EXAGGERATED_VALUES );
+ TWEAK_RULES( DO_SHPIX );
+ TWEAK_RULES( EMBOLDEN );
+ TWEAK_RULES( MIAP_HACK );
+@@ -1012,13 +931,13 @@
+ TWEAK_RULES( NO_CALL_AFTER_IUP );
+ TWEAK_RULES( NO_DELTAP_AFTER_IUP );
+ TWEAK_RULES( RASTERIZER_35 );
+- TWEAK_RULES( SKIP_INLINE_DELTAS );
+ TWEAK_RULES( SKIP_IUP );
+- TWEAK_RULES( MIRP_CVT_ZERO );
+
+ TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES );
+ TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES );
+
++ TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP );
++
+ TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES );
+ TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
+
+diff --git a/src/truetype/ttsubpix.h b/src/truetype/ttsubpix.h
+index 5e5d8e6..8a54fc7 100644
+--- a/src/truetype/ttsubpix.h
++++ b/src/truetype/ttsubpix.h
+@@ -34,14 +34,15 @@ FT_BEGIN_HEADER
+ /* ID flags to identify special functions at FDEF and runtime. */
+ /* */
+ /* */
+-#define SPH_FDEF_INLINE_DELTA_1 0x0000001
+-#define SPH_FDEF_INLINE_DELTA_2 0x0000002
+-#define SPH_FDEF_DIAGONAL_STROKE 0x0000004
+-#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008
+-#define SPH_FDEF_TTFAUTOHINT_1 0x0000010
+-#define SPH_FDEF_SPACING_1 0x0000020
+-#define SPH_FDEF_SPACING_2 0x0000040
+-#define SPH_FDEF_TYPEMAN_STROKES 0x0000080
++#define SPH_FDEF_INLINE_DELTA_1 0x0000001
++#define SPH_FDEF_INLINE_DELTA_2 0x0000002
++#define SPH_FDEF_DIAGONAL_STROKE 0x0000004
++#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008
++#define SPH_FDEF_TTFAUTOHINT_1 0x0000010
++#define SPH_FDEF_SPACING_1 0x0000020
++#define SPH_FDEF_SPACING_2 0x0000040
++#define SPH_FDEF_TYPEMAN_STROKES 0x0000080
++#define SPH_FDEF_TYPEMAN_DIAGENDCTRL 0x0000100
+
+
+ /*************************************************************************/
+@@ -50,29 +51,25 @@ FT_BEGIN_HEADER
+ /* */
+ /* */
+ #define SPH_TWEAK_ALLOW_X_DMOVE 0x0000001
+-#define SPH_TWEAK_ALLOW_X_DMOVEX 0x0000002
+-#define SPH_TWEAK_ALLOW_X_MOVE_ZP2 0x0000004
+-#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000008
+-#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000010
+-#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000020
+-#define SPH_TWEAK_DEEMBOLDEN 0x0000040
+-#define SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES 0x0000080
+-#define SPH_TWEAK_DO_SHPIX 0x0000100
+-#define SPH_TWEAK_EMBOLDEN 0x0000200
+-#define SPH_TWEAK_MIAP_HACK 0x0000400
+-#define SPH_TWEAK_NORMAL_ROUND 0x0000800
+-#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0001000
+-#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0002000
+-#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0004000
+-#define SPH_TWEAK_PIXEL_HINTING 0x0008000
+-#define SPH_TWEAK_RASTERIZER_35 0x0010000
+-#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0020000
+-#define SPH_TWEAK_SKIP_INLINE_DELTAS 0x0040000
+-#define SPH_TWEAK_SKIP_IUP 0x0080000
+-#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0100000
+-#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0200000
+-#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0400000
+-#define SPH_TWEAK_MIRP_CVT_ZERO 0x0800000
++#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000002
++#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000004
++#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000008
++#define SPH_TWEAK_DEEMBOLDEN 0x0000010
++#define SPH_TWEAK_DO_SHPIX 0x0000020
++#define SPH_TWEAK_EMBOLDEN 0x0000040
++#define SPH_TWEAK_MIAP_HACK 0x0000080
++#define SPH_TWEAK_NORMAL_ROUND 0x0000100
++#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0000200
++#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0000400
++#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0000800
++#define SPH_TWEAK_PIXEL_HINTING 0x0001000
++#define SPH_TWEAK_RASTERIZER_35 0x0002000
++#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0004000
++#define SPH_TWEAK_SKIP_IUP 0x0008000
++#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0010000
++#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0020000
++#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0040000
++#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP 0x0080000
+
+
+ FT_LOCAL( FT_Bool )
diff --git a/testing/freetype-infinality/infinality-settings.sh b/testing/freetype-infinality/infinality-settings.sh
new file mode 100644
index 000000000..f428320e2
--- /dev/null
+++ b/testing/freetype-infinality/infinality-settings.sh
@@ -0,0 +1,1135 @@
+##################################################################
+### INFINALITY ENVIRONMENT VARIABLES FOR EXTRA RUN-TIME OPTIONS ##
+##################################################################
+#
+# These environment variables require that their respective patches
+# from http://www.infinality.net have been applied to the Freetype
+# installation you are using. They will do abolutely
+# nothing otherwise!
+#
+
+# This file should be copied to /etc/profile.d/ for system-wide
+# effects and/or included in ~/.bashrc or ~/.bash_profile for per-user
+# effects:
+#
+# . ~/path/to/this/file/infinality-settings.sh
+#
+# Of course, the per-user settings will override the system-wide
+# settings. Default values indicated below will be used when the
+# environment variables below are not defined.
+#
+# When I say "Default:" below, I'm referring to the default if no
+# environment variables are set. Generally this ends up being
+# whatever Freetype's default is set to.
+#
+
+
+##################################################################
+# EXAMPLES
+#
+# Please see 3/4 down in this file for examples of different settings.
+#
+
+
+
+
+
+
+#################################################################
+################## EXPLANATION OF SETTINGS ######################
+#################################################################
+
+
+
+##################################################################
+# SET_XFT_SETTINGS
+#
+# Should the below Xft settings be set globally by this script? (true/false)
+
+SET_XFT_SETTINGS=true
+
+# XFT settings are like a red-headed stepchild that should be beaten severely.
+# These only affect legacy programs, and *parts* of some modern programs like
+# google-chrome. We only deal with these settings because we have to, otherwise
+# crap will slip by. I recommend using hintslight and autohint as the defaults
+# normally in /etc/fonts/. The reason hintfull and autohint:0 is needed here
+# because otherwise some programs will occassionally request slight hinting for
+# a truetype font. When a program does this, Freetype automatically uses the
+# autohinter, when you may actually want it to be rendered with the TT hinter,
+# (if specified in /etc/fonts/). So setting this to hintfull guarantees that the
+# TT font will be rendered with the TT hinter (assuming it is specified in
+# /etc/fonts/ to be rendered that way.) For TT fonts that you want
+# rendered with autohint, specifiying that in the /etc/fonts/
+# should be enough. But you might think that by setting this to hintfull
+# that it's going to use Freetype's full autohinting (which we *completely*
+# avoid) for fonts you want autohinted. This is where
+# INFINALITY_FT_AUTOFIT_FORCE_SLIGHT_HINTING comes in. It tells freetype to
+# use slight hinting on fonts set for autohinting, even if the program requests
+# full autohinting. Freetype's full hinting only looks OK under certain
+# circumstances. The goal of infinality is to make infinality hinting look
+# good all the time.
+
+XFT_SETTINGS="
+Xft.antialias: 1
+Xft.autohint: 0
+Xft.dpi: 96
+Xft.hinting: 1
+Xft.hintstyle: hintfull
+Xft.lcdfilter: lcddefault
+Xft.rgba: rgb
+"
+
+if [ "$SET_XFT_SETTINGS" = "true" ]; then
+ echo "$XFT_SETTINGS" | xrdb -merge > /dev/null 2>&1
+fi
+
+
+
+##################################################################
+# INFINALITY_FT_FILTER_PARAMS
+#
+# This is a modified version of the patch here:
+# http://levelsofdetail.kendeeter.com/2008/12/dynamic_fir_filter_patch.html
+#
+# Allows you to adjust the FIR filter at runtime instead of at
+# compile time. The idea is to have values add up to 100, and be
+# symmetrical around the middle value. If the values add up to
+# more than 100, the glyphs will appear darker. If less than 100,
+# lighter. I recommend using this method to make glyphs darker
+# or lighter globally as opposed to using the gamma option (see note in
+# the gamma option).
+#
+# Here are some samples of various filter parameters:
+#
+# (this has been changed to use integers between 0 and 100 to
+# avoid problems with regional differences like comma for decimal point)
+#
+#
+# Strong Extra Smooth "15 20 30 20 15" (extra smooth, natural weight)
+# Extra Smooth "20 20 30 20 20" (extra smooth, extra weight)
+# Smooth "15 20 32 20 15" (smooth, natural weight)
+# Stronger Gibson "11 22 38 22 11" (smooth, extra weight)
+# Gibson "11 22 33 22 11" (smooth, natural weight)
+# Freetype Light "00 33 34 33 00" (sharp, natural weight) # freetype's "light" LCD filter
+# Freetype Default "06 25 44 25 06" (sharp, extra weight) # freetype's default
+# Extra Sharp "00 35 35 35 00" (extra sharp, extra weight) # freetype's "light" LCD filter on acid
+#
+#
+# Windows uses something more sharp, maybe along the lines of Freetype's default
+#
+# Default if no ENV_VARS present: [Freetype's default]
+# Recommended: "11 22 38 22 11" (too dark / smooth for some)
+#
+# Example 1: export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+
+
+
+##################################################################
+# INFINALITY_FT_STEM_ALIGNMENT_STRENGTH
+#
+# This performs analysis on each glyph and determines an amount
+# to shift the glyph, left or right, so that it aligns better to
+# pixel boundaries.
+#
+# This results in subtley cleaner looking stems, at the expense of
+# proper distances between glyphs. This is only active for sizes
+# 10 px or greater and does not apply to bold or italic fonts.
+#
+# There are also exceptions on a small number of fonts that I've
+# not been able to render nicely with alignment enabled. In those
+# cases, a forced translation is applied instead.
+#
+# Possible values:
+# 0 through 100 - think of as percentage of strength
+#
+# 0 corresponds to no shifting whatsoever. In other words, OFF.
+#
+# 100 corresponds to a full move to a snap zone defined by
+# the snapping algorithm, be it left or right. This
+# is the full amount any glyph could be moved in order to make it
+# align to the pixel.
+#
+# Values inbetween act as caps. If the algorithm determines that it
+# wants to move the glyph .33 of a pixel to the left, but the value
+# is set to 50 (i.e. 50%), then the maximum move that would be allowed
+# is 50% of half a pixel, in other words .25. So instead of .33 the
+# glyph is moved .25 of a pixel.
+#
+# For a subtle effect that doesn't dramatically affect the glyph, use
+# 25 for this and 25 for INFINALITY_FT_STEM_FITTING_STRENGTH
+#
+# Default if no ENV_VARS present: 0
+# Recommended if you want to use it: 100
+
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+
+
+
+##################################################################
+# INFINALITY_FT_STEM_FITTING_STRENGTH
+#
+# This performs analysis on each glyph and determines an amount
+# to horizontally scale the glyph, so that stems align better to
+# pixel boundaries. An emboldening (or anti-emboldening) is
+# performed afterward to account for stem width exaggeration.
+#
+# This results in subtley cleaner looking fonts, at the expense of
+# proper distances between glyphs and slightly misshapen glyphs.
+# This is only active for sizes 10 px or greater and does not
+# apply to bold or italic fonts.
+#
+# There are also exceptions on a small number of fonts that I've
+# not been able to render nicely with fitting enabled. In those
+# cases, a forced translation is applied instead.
+#
+#
+# Possible values:
+# 0 through 100 - think of as percentage of strength
+#
+# 0 corresponds to no stretching whatsoever. In other words, OFF.
+#
+# 100 corresponds to a full pixel stretch, be outward or inward. This
+# is the full amount any glyph could be stretched in order to make it
+# align to a pixel boundary. Which direction is chosen is part
+# of the art of what I'm trying to do in the code. ;)
+#
+#
+# Values inbetween act as caps. If the algorithm determines that it
+# wants to stretch the glyph .75 of a pixel outward, but the value
+# is set to 50 (i.e. 50%), then the maximum move that would be allowed
+# is 50% of a pixel, in other words .50. So instead of .75 the
+# glyph is stretched .50 of a pixel.
+#
+# For a subtle effect that doesn't dramatically affect the glyph, use
+# 25 for this and 25 for INFINALITY_FT_STEM_FITTING_STRENGTH
+#
+# Default if no ENV_VARS present: 0
+# Recommended if you want to use it: 100
+
+export INFINALITY_FT_STEM_FITTING_STRENGTH=25
+
+
+
+##################################################################
+# INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE
+#
+# This allows you to set a ppem at which alignment and fitting
+# will reach 100%. As glyphs become larger, more dramatic
+# snapping will not affect the glyph shape as much, so it makes
+# sense to allow this.
+#
+# For fonts that are 10 ppem, the values set above for
+# INFINALITY_FT_STEM_ALIGNMENT_STRENGTH and
+# INFINALITY_FT_STEM_FITTING_STRENGTH will be used. As the ppem
+# gradually becomes larger, so will the strength settings, and
+# they will reach 100% at the ppem you specify here.
+#
+# This is a simple linear scale.
+#
+# Possible values:
+# 0 means to not use this feature
+#
+# 11 and up will set the 100% level to that ppem value
+#
+# Anything else is officially undefined, but I still bound it internally.
+#
+# Default if no ENV_VARS present: 0
+
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=40
+
+
+
+##################################################################
+# INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS
+#
+# This applies largely to certain MS fonts, but some others as well.
+# it will apply known good settings on a font-by-font basis, regardless
+# of the other settings above or below.
+#
+# - Use known values for selected fonts & ppems that are known to look
+# ok with 100:
+#
+# INFINALITY_FT_STEM_ALIGNMENT_STRENGTH
+# INFINALITY_FT_STEM_FITTING_STRENGTH
+#
+# - Use various internal tweaks like compatible widths and other
+# font-specific hacks.
+# - Use gamma, brightness or contrast adjustments automatically
+# on certain fonts. Global settings will still apply afterwards.
+# - Enable various forced settings on selective fonts during
+# rasterization and stem_alignment.
+#
+# If set to TRUE, this will use 100 regardless of the values you have
+# specified above. It will not affect fonts that are not in this
+# small list.
+#
+# Possible values:
+# FALSE means to not use this feature
+#
+# TRUE will enable this feature
+#
+# Default if no ENV_VARS present: FALSE
+# Recommended: TRUE
+#
+
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+##################################################################
+# INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH
+#
+# This enables an algorithm found in ChromeOS for sharpening the
+# appearance of glyphs. It is based off this patch:
+#
+# http://codereview.chromium.org/3298011/diff/9001/media-libs/freetype/files/freetype-2.3.11-lcd-sharpen.patches
+#
+# It gives glyphs a more "grainy" look through some gamma
+# correction. It does tend to thin out vertical stems, which
+# may be a feature or a bug depending on your taste ;)
+#
+#
+# Possible values:
+# 0 through 100 - think of as percentage of strength
+#
+# 0 corresponds to no sharpening whatsoever. In other words, OFF.
+#
+# 25 is good for a subtle effect.
+#
+# 50 corresponds to the default ChromeOS value.
+#
+# 100 corresponds to maximum sharpening. This usually results in
+# something undesirable looking.
+#
+#
+# As you increase this amount, it is good to decrease the gamma (2nd value)
+# of INFINALITY_FT_PSEUDO_GAMMA, and possibly increase
+# INFINALITY_FT_STEM_FITTING_STRENGTH and
+# INFINALITY_FT_STEM_ALIGNMENT_STRENGTH, as it seems like the algorithm
+# lightens stems that aren't fully on-pixel.
+#
+# Default if no ENV_VARS present: 0
+# Recommended: If you're going to use this filter - 50
+
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+
+
+
+##################################################################
+# INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH
+#
+# This enables an algorithm developed with the intention to sharpen
+# fonts to look similarly to Windows.
+#
+# It gives glyphs a more "grainy" look, like the ChromeOS filter
+# except it does so more selectively. This prevents the thinning
+# of vertical stems that is noticible when a blanket gamma filter
+# like the ChromeOS filter is applied.
+#
+# I also get a "cleaner" impression from the fonts with this Windows
+# style filter. This filter was done by 100% experimentation,
+# and there things that could probably be improved.
+#
+# Some may argue that I shouldn't be trying to take the shortcomings
+# of the MS approach and bring them here. I disagree, as part
+# of freedom is having the right to make your fonts look as
+# shitty as you'd like.
+#
+# Using this filter does somewhat lessen the need to use stem
+# fitting and stem alignment, as glyphs appear sharper.
+#
+# This setting can be used at the same time as the previous chromeOS
+# sharpening, and happens after it in the code.
+#
+#
+# Possible values:
+# 0 through 100 - think of as percentage of strength
+#
+# 0 corresponds to no sharpening whatsoever. In other words, OFF.
+#
+# 10-25 is good for a subtle effect while not completely decimating glyphs.
+#
+# 50-75 corresponds to probably something in the range that Windows uses.
+#
+# 100 corresponds to maximum sharpening.
+#
+#
+# Using a high value for this variable along with enabling the
+# fringe filter (below) almost eliminates the need
+# for INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT to be set to 100,
+# and can instead be set at 0. (Setting
+# INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT to 0 prevents missing
+# stems in the middle of s. The drawback is that many fonts just look
+# way too sharp and grainy at this setting. Your call.)
+#
+# Default if no ENV_VARS present: 0
+# Recommended if you want to use this filter: 65
+
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=10
+
+
+
+##################################################################
+# INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT
+#
+# When using autohinting, horizontal stems you'd find in E, f, T, -,
+# etc. are normally not snapped to full integer pixel heights, meaning
+# that you will get a semi-dark fringe on these stems, above or
+# below the black line of pixels:
+#
+# ##########
+# ##
+# ##-------
+# #########
+# ##
+# ##--------
+# ##########
+#
+# (- represents the semi-dark pixels)
+#
+# Setting this to 100 will force integer pixel heights. Setting it to
+# zero will do what Freetype does by default. Anything inbetween will
+# act as a weighted average of the two.
+#
+# This is disabled when the standard width is found (via voodoo) to be
+# less than 1 pixel, in order to prevent the vanishing stem issues on
+# letters with diagonal stems like a and s.
+#
+# Under most circumstances, this should be set at 100. If you choose to
+# not set it to 100, you may want to set INFINALITY_FT_FRINGE_FILTER_STRENGTH
+# to a non-zero value in order to reduce fringing.
+#
+#
+# Possible values:
+# 0 - default Freetype value
+# 100 - a full pixel
+#
+#
+# Default if no ENV_VARS present: 0
+# Recommended: 100
+
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+
+
+
+##################################################################
+# INFINALITY_FT_USE_VARIOUS_TWEAKS
+#
+# - Force autohint when no TT instructions present.
+# - Artificially embolden horizontally only.
+# - When artificially emboldening, maintain the glyph width.
+# - Embolden light and thin-stemmed glyphs automatically.
+# - Don't sharpen italics.
+#
+# Some fonts look bad when stem aligned at certain ppems, no matter
+# what. I've put exceptions in to deal with these, included in
+# these tweaks. Georgia and Lucida Grande are examples.
+#
+#
+# Possible values:
+# true - enable tweaks
+# false - do not enable tweaks (do Freetype default)
+#
+#
+# Default if no ENV_VARS present: false
+# Recommended: true
+
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+
+
+
+##################################################################
+# INFINALITY_FT_GAMMA_CORRECTION
+#
+# This does a weighted gamma correction at the LCD filter phase
+# PRIOR to the LCD filter. Unfortunately it does not however
+# take into account the color on which the glyph is being rendered
+# (or for that matter the color of the glyph),
+# which would need to happen in X rendering. It is actually
+# using the gamma function in calculations though.
+#
+# The first value indicates a px value, the second indicates a
+# "gamma" value. All sizes less than the px value will be corrected
+# on a weighted scale based on the second value.
+#
+# The gamma value is commonly between 0.0 and 3.0. Due to localization
+# issues, the gamma value should be specified as it's actual value
+# multiplied by 100. So a gamma of 1.3 would be 130. In practice,
+# I'd stay between 40 and 250.
+#
+#
+# Values 1 through 100 will darken the glyph
+# Values greater than 100 will lighten the glyph
+#
+#
+# Example 1: Darken glyphs that are less than 10 px. With some fonts
+# even 5 or 6px is readable!
+# export INFINALITY_FT_GAMMA_CORRECTION="10 60"
+#
+# Example 2: Lighten all glyphs (below 100px)
+# export INFINALITY_FT_GAMMA_CORRECTION="100 150"
+#
+# Example 3: Do nothing
+# export INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#
+# Default: [No gamma correction]
+
+export INFINALITY_FT_GAMMA_CORRECTION="0 100"
+
+
+
+##################################################################
+# INFINALITY_FT_BRIGHTNESS
+#
+# This filter adjusts brightness, using the standard algorithm
+# for brightness. It is applied AFTER the LCD filtering.
+#
+# For a Windows XP look, set brightness to something and contrast to 50
+# This will also tend to increase its sharpness.
+# These values are relative and don't really mean anything
+# however they are satisfactory for a range of appearances.
+# Another tip is to use a gamma setting of "1000 110" or something
+# over 100 to lighten things before processing.
+#
+# Default if no ENV_VARS present: 0
+# Dark XP Experience: -25
+# Light XP Experience: 40
+#
+# Example: export INFINALITY_FT_BRIGHTNESS="-20"
+
+export INFINALITY_FT_BRIGHTNESS="0"
+
+
+
+##################################################################
+# INFINALITY_FT_CONTRAST
+#
+# This filter adjusts contrast, using the standard algorithm
+# for contrast. It is applied AFTER the LCD filtering.
+#
+# For a Windows XP look, set brightness to -25 and contrast to 50
+# This will also tend to increase its sharpness.
+# These values are relative and don't really mean anything
+# however they are satisfactory for a range of appearances.
+# Another tip is to use a gamma setting of "1000 110" or something
+# over 100 to lighten things before processing.
+#
+# Default if no ENV_VARS present: 0
+# Dark or Light XP Experience: 50
+#
+# Example: export INFINALITY_FT_CONTRAST="50"
+
+export INFINALITY_FT_CONTRAST="0"
+
+
+
+##################################################################
+# INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH
+#
+# This filter adjusts subpixel-rendered glyphs toward grayscale.
+# Sometimes this is useful in getting a rendering more like
+# OSX.
+#
+# Range: Integers 0 through 100
+# 0 represents no filtering
+# 50 represents halfway between subpixel and grayscale
+# 100 represents completely grayscale
+#
+# Default if no ENV_VARS present: 0
+# Recommended, if you want to use it: 30
+#
+# Example: export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH="33"
+
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH="0"
+
+
+
+##################################################################
+# INFINALITY_FT_FRINGE_FILTER_STRENGTH
+#
+# This filter tries to remove the horizontal fringing that is found on
+# default autohinted glyphs (similar to OSX-rendered glyphs).
+# For example, an E may be rendered so that the middle horizontal
+# stem is 100% black, but also has a horizonal row of pixels above
+# it that is at 50% intensity. This makes the glyph look dirty,
+# however it is technically accurate.
+#
+# This would be useful in cases where you have
+# INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT set to something less than 100
+# but also can affect glyphs at 100, to some degree.
+#
+# Unless fonts are showing fringes in a way that annoys you, I recommend
+# keeping it disabled, as it can slightly interfere with smooth appearance
+# sometimes.
+#
+#
+# Range: Integers 0 through 100
+# 0 represents no filtering
+# 50 represents a 50% reduction of detected fringes
+# 100 represents completely removing detected fringes
+#
+#
+# Default if no ENV_VARS present: 0
+# Recommended, if you want to use it: 100
+#
+# Example: export INFINALITY_FT_FRINGE_FILTER_STRENGTH="100"
+
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH="0"
+
+
+
+##################################################################
+# INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH
+#
+# This post-filter darkens horizontal stems that autohint renders as semi-dark.
+# Freetype will by default not force stems to render to pixel boundaries
+# because it results in "vanishing stems". This happens on things like
+# s S a and other glyphs with center diagonal stems.
+#
+# If you have INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT set to 100,
+# you're telling it to force pixel boundaries, which can result in the
+# vanishing stems. To get around this problem, I internally override the
+# INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT setting if the stem width
+# is less than a full pixel, regardless. This causes semi-dark stems, but
+# at least there are stems there.
+#
+# This filter is intended to darken those semi-dark stems. I highly
+# recommend using this, but setting to a low value like 10, because
+# it is particularly sensitive right now, and can make thin fonts
+# look weird otherwise.
+#
+#
+# Range: Integers 0 through 100
+# 0 represents no darkening
+# 50 represents a 50% increase toward 1 pixel in height
+# 100 represents a full pixel of height
+#
+#
+# Default if no ENV_VARS present: 0
+# Recommended, if you want to use it: 10
+#
+# Example: export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH="10"
+
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH="10"
+
+
+
+##################################################################
+# INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH
+#
+# This post-filter darkens vertical stems less than 1 pixel that autohint
+# renders as semi-dark. This applies mostly to thin fonts like
+# Courier New, Raleway, and fonts with the word "Light" in the title or
+# style. Although what autohint is doing is technically correct, it
+# results in a bad looking rendering because it's too light, at small
+# ppems. This filter tries to correct that.
+#
+# There is an aspect of this that is automatic, so it's safer to use
+# larger values for this than the above horizontal ENV_VAR. However
+# setting this higher has more impact on thinner fonts. So, I still
+# recommend lower values.
+#
+#
+# Range: Integers 0 through 100
+# 0 represents no darkening
+# 50 represents a 50% increase (from current strength) toward 1 pixel
+# 100 represents a full pixel of width
+#
+#
+# Default if no ENV_VARS present: 0
+# Recommended, if you want to use it: 25
+#
+# Example: export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH="25"
+
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH="25"
+
+
+
+##################################################################
+# INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS
+#
+# This will slightly stretch some glyphs vertically between 9px
+# and 14px (inclusive). Some people may find this more
+# aesthetically pleasing. This only applies to fonts that are
+# using autohint. I used to recommend this to be set true, but
+# it does mess with some (less popular) glyphs in a nasty way.
+#
+# The goal here is to increase the height of some fonts by 1 px
+# but leave the x-height where it is. Arial is a good example
+# of this working properly. Compare the heights of Arial, Times
+# and Freesans with this on, vs. TT hinted versions of Arial and
+# Times.
+#
+#
+# Possible values:
+# true - enable height adjustment
+# false - do not enable height adjustment
+#
+#
+# Default: false
+
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+
+
+# Experimental emboldening values for OSX mode
+export INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=0
+export INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE=0
+export INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE=0 # This one seems to crash at anything other than 0
+export INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE=0
+
+#################################################################
+########################### EXAMPLES ############################
+#################################################################
+#
+# Set the USE_STYLE variable below to try each example.
+# Make sure to set your style in /etc/fonts/infinality.conf too.
+#
+# Possible options:
+#
+# DEFAULT - Use above settings. A compromise that should please most people.
+# OSX - Simulate OSX rendering
+# IPAD - Simulate iPad rendering
+# UBUNTU - Simulate Ubuntu rendering
+# LINUX - Generic "Linux" style - no snapping or certain other tweaks
+# WINDOWS - Simulate Windows rendering
+# WINDOWS7 - Simulate Windows rendering with normal glyphs
+# WINDOWS7LIGHT- Simulate Windows 7 rendering with lighter glyphs
+# WINDOWS - Simulate Windows rendering
+# VANILLA - Just subpixel hinting
+# CUSTOM - Your own choice. See below
+# ----- Infinality styles -----
+# CLASSIC - Infinality rendering circa 2010. No snapping.
+# NUDGE - CLASSIC with lightly stem snapping and tweaks
+# PUSH - CLASSIC with medium stem snapping and tweaks
+# SHOVE - Full stem snapping and tweaks without sharpening
+# SHARPENED - Full stem snapping, tweaks, and Windows-style sharpening
+# INFINALITY - Settings I use
+# DISABLED - Act as though running without the extra infinality enhancements (just subpixel hinting).
+
+USE_STYLE="DEFAULT"
+
+
+
+### WARNING - NEEDS WORK - ALSO LIABLE TO CRASH APPLICATIONS ###
+################# OSX STYLE #################
+if [ "$USE_STYLE" = "OSX" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="03 32 38 32 03"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=25
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="1000 80"
+export INFINALITY_FT_BRIGHTNESS="10"
+export INFINALITY_FT_CONTRAST="20"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+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
+export INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=0
+export INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE=8
+export INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE=0
+export INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE=0
+
+fi
+
+
+
+################# IPAD STYLE #################
+if [ "$USE_STYLE" = "IPAD" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="00 00 100 00 00"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=100
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="1000 80"
+export INFINALITY_FT_BRIGHTNESS="0"
+export INFINALITY_FT_CONTRAST="0"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+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
+export INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=0
+export INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE=0
+export INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE=0
+export INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE=0
+
+fi
+
+
+
+################# UBUNTU STYLE #################
+if [ "$USE_STYLE" = "UBUNTU" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="1000 80"
+export INFINALITY_FT_BRIGHTNESS="-10"
+export INFINALITY_FT_CONTRAST="15"
+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
+
+fi
+
+
+
+################# LINUX STYLE #################
+if [ "$USE_STYLE" = "LINUX" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+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=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+fi
+
+
+################# WINDOWS XP STYLE LIGHT #################
+if [ "$USE_STYLE" = "WINDOWSXPLIGHT" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+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_GAMMA_CORRECTION="1000 120"
+export INFINALITY_FT_BRIGHTNESS="20"
+export INFINALITY_FT_CONTRAST="30"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# WINDOWS 7 STYLE LIGHT #################
+if [ "$USE_STYLE" = "WINDOWS7LIGHT" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="20 25 38 25 05"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=100
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="1000 160"
+export INFINALITY_FT_BRIGHTNESS="0"
+export INFINALITY_FT_CONTRAST="20"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# WINDOWS XP STYLE #################
+if [ "$USE_STYLE" = "WINDOWSXP" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+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_GAMMA_CORRECTION="1000 120"
+export INFINALITY_FT_BRIGHTNESS="10"
+export INFINALITY_FT_CONTRAST="20"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# WINDOWS 7 STYLE #################
+if [ "$USE_STYLE" = "WINDOWS7" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="20 25 42 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="1000 120"
+export INFINALITY_FT_BRIGHTNESS="10"
+export INFINALITY_FT_CONTRAST="20"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+############### VANILLA STYLE ##############
+if [ "$USE_STYLE" = "VANILLA" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="06 25 38 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+export INFINALITY_FT_GAMMA_CORRECTION="0 100"
+export INFINALITY_FT_BRIGHTNESS="0"
+export INFINALITY_FT_CONTRAST="0"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+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
+
+fi
+
+
+############### CLASSIC INFINALITY STYLE ##############
+if [ "$USE_STYLE" = "CLASSIC" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="06 25 38 25 06"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=0
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+export INFINALITY_FT_STEM_FITTING_STRENGTH=0
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+fi
+
+
+################# NUDGE STYLE #################
+if [ "$USE_STYLE" = "NUDGE" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+export INFINALITY_FT_STEM_FITTING_STRENGTH=15
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+fi
+
+
+################# PUSH STYLE #################
+if [ "$USE_STYLE" = "PUSH" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=75
+export INFINALITY_FT_STEM_FITTING_STRENGTH=50
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# INFINALITY STYLE #################
+if [ "$USE_STYLE" = "INFINALITY" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=5
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+export INFINALITY_FT_STEM_FITTING_STRENGTH=25
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=40
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# SHOVE STYLE #################
+if [ "$USE_STYLE" = "SHOVE" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=100
+export INFINALITY_FT_STEM_FITTING_STRENGTH=100
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# SHARPENED INFINALITY STYLE #################
+if [ "$USE_STYLE" = "SHARPENED" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+export INFINALITY_FT_STEM_FITTING_STRENGTH=25
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=40
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+
+################# DISABLED STYLE #################
+if [ "$USE_STYLE" = "DISABLED" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS=
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=
+export INFINALITY_FT_STEM_FITTING_STRENGTH=
+export INFINALITY_FT_GAMMA_CORRECTION="0 100"
+export INFINALITY_FT_BRIGHTNESS="0"
+export INFINALITY_FT_CONTRAST="0"
+export INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+fi
+
+
+################# CUSTOM STYLE #################
+if [ "$USE_STYLE" = "CUSTOM" ]; then
+
+export INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=100
+export INFINALITY_FT_STEM_FITTING_STRENGTH=100
+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=true
+export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+fi
+
+