summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen de Groot <yngwin@gmail.com>2012-07-23 18:50:58 +0800
committerBen de Groot <yngwin@gmail.com>2012-07-23 18:50:58 +0800
commit7f54602764865c6bebda162b10a5b3cd49ec3f8b (patch)
tree1b3de380546f2e503f77c3a0774c864bdb6514d5 /media-libs
parentmedia-sound/coquillo has been moved to official tree (diff)
downloadbetagarden-7f54602764865c6bebda162b10a5b3cd49ec3f8b.tar.gz
betagarden-7f54602764865c6bebda162b10a5b3cd49ec3f8b.tar.bz2
betagarden-7f54602764865c6bebda162b10a5b3cd49ec3f8b.zip
Add infinality font patches and eselect module
Diffstat (limited to 'media-libs')
-rw-r--r--media-libs/fontconfig-infinality/Manifest4
-rw-r--r--media-libs/fontconfig-infinality/files/Xresources32
-rw-r--r--media-libs/fontconfig-infinality/files/infinality-settings.sh1014
-rw-r--r--media-libs/fontconfig-infinality/fontconfig-infinality-20120619.ebuild48
-rw-r--r--media-libs/freetype/Manifest9
-rw-r--r--media-libs/freetype/files/freetype-2.3.2-enable-valid.patch22
-rw-r--r--media-libs/freetype/files/freetype-2.4.9-type1-incremental.patch101
-rw-r--r--media-libs/freetype/files/freetype-add-subpixel-hinting-infinality.patch2927
-rw-r--r--media-libs/freetype/files/freetype-enable-subpixel-hinting-infinality.patch21
-rw-r--r--media-libs/freetype/files/freetype-entire-infinality-patchset.patch4630
-rw-r--r--media-libs/freetype/freetype-2.4.10-r1.ebuild142
11 files changed, 8950 insertions, 0 deletions
diff --git a/media-libs/fontconfig-infinality/Manifest b/media-libs/fontconfig-infinality/Manifest
new file mode 100644
index 0000000..5ed534e
--- /dev/null
+++ b/media-libs/fontconfig-infinality/Manifest
@@ -0,0 +1,4 @@
+AUX Xresources 1814 SHA256 edbc78ddf590ab9bdf19e6f34fedf6ecdc54c29da67c0d14f25c74e7ae8207a4 SHA512 0647e3a2ed6f68c8d1266de52288bac2fca9320aef1573e74f30bff0e0176c6a63c8c71d3d4aae764b5bf57fe3ca8f3f2906e1c51d8cb26c855bb9858490f3b0 WHIRLPOOL f41770a99158482b25d332a6fdb2d64d31d94c4ec95423e462ef44aecc54fa19391c31061d79305c6194bda83b23a59b019e29a507a7f0c9563decc7a07b17c1
+AUX infinality-settings.sh 36878 SHA256 e6d53cf67e52fb22eadc03a82212eef63cd68a63ec9b50fc82df5fd2c646778f SHA512 34f84579c4a536987a2420078bafd3bf22b4cc5ff73e3e2fa6a9cd008c088b8a80d1b05fe602c96a1c14a1b5143b6446394c3f16b004084c45a2b97ac993ec3b WHIRLPOOL 5a746700b9c979c9598d29a04b8c8688f95b2ced5fb40d72809e15e4ab1166a37ab14b9db6580bc9f8cf73335732b800d7f64d39946f74feac47d9d2241c5e42
+DIST fontconfig-infinality-20120619.tar.xz 18956 SHA256 56563ea3200fa9c9b0a269260115e93bb4a635cef073655bef8dbe541031cac6 SHA512 2b20dd6c459572d8864459c32b9a50cfa3757df9fbdab75528772be81dbe7de31d2e997c4047083270769ee80d5e110ca43a9bddaf8c771f70e4181cab7cfb56 WHIRLPOOL 9fb51dbd24e118b276a0e7688a5d8d1f3db4952a399ef076db62531bb13f48c5b7484f3664c0d8de6fc809ad37b76275a95124bea366d3a6bd4e847b5f354d2e
+EBUILD fontconfig-infinality-20120619.ebuild 1069 SHA256 fd94327bd90cd6784df382a6787bdb431ff0c8e0783b0f7605ca60a5432c763e SHA512 44063190774180269d188e206e7f867b58ce0da6f9ae44f3de0d99cbc6bbdcb357890d6903484c12f69a4d5026768dfda99ea2326d61ff1b04dc87b34fbe175c WHIRLPOOL 8a239915ffce17832f1efbfe743a09fadff537a380a4ed63771747740a6f74d4ca8cf9bfff6e50d1a04509b92e6650f475bb85ef1ade43461d53dd7f7c33fe46
diff --git a/media-libs/fontconfig-infinality/files/Xresources b/media-libs/fontconfig-infinality/files/Xresources
new file mode 100644
index 0000000..d34e001
--- /dev/null
+++ b/media-libs/fontconfig-infinality/files/Xresources
@@ -0,0 +1,32 @@
+#################################################################
+################## EXPLANATION OF SETTINGS ######################
+#################################################################
+
+# 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 local.conf. 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 local.conf). So setting this to hintfull guarantees that the
+# TT font will be rendered with the TT hinter (assuming it is specified in
+# /etc/fonts/local.conf to be rendered that way.) For TT fonts that you want
+# rendered with autohint, specifiying that in the /etc/fonts/local.conf
+# 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.antialias: 1
+Xft.autohint: 0
+Xft.dpi: 96
+Xft.hinting: 1
+Xft.hintstyle: hintfull
+Xft.lcdfilter: lcddefault
+Xft.rgba: rgb
diff --git a/media-libs/fontconfig-infinality/files/infinality-settings.sh b/media-libs/fontconfig-infinality/files/infinality-settings.sh
new file mode 100644
index 0000000..6d0a858
--- /dev/null
+++ b/media-libs/fontconfig-infinality/files/infinality-settings.sh
@@ -0,0 +1,1014 @@
+##################################################################
+### 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!
+#
+# 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 ######################
+#################################################################
+
+
+
+##################################################################
+# 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"
+#
+
+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
+
+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
+
+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
+
+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
+#
+
+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
+
+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
+
+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
+
+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
+
+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]
+
+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"
+
+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"
+
+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"
+
+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"
+
+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"
+
+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"
+
+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
+
+INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+
+
+# Experimental emboldening values for OSX mode
+INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=0
+INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE=0
+INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE=0
+INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE=0
+
+#################################################################
+########################### EXAMPLES ############################
+#################################################################
+#
+# Make sure to set your style in /etc/fonts/local.conf too.
+#
+# Possible options:
+#
+# DEFAULT - Use above settings. A compromise that should please most people.
+# OSX - Simulate OSX 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).
+
+### NEEDS WORK ###
+################# OSX STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="03 32 38 32 03"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=25
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="1000 80"
+#INFINALITY_FT_BRIGHTNESS="10"
+#INFINALITY_FT_CONTRAST="20"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=0
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+#INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=0
+#INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE=8
+#INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE=16
+#INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE=0
+
+
+
+
+################# UBUNTU STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="1000 80"
+#INFINALITY_FT_BRIGHTNESS="-10"
+#INFINALITY_FT_CONTRAST="15"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=0
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+
+################# LINUX STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+################# WINDOWS XP STYLE LIGHT #################
+
+#INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=15
+#INFINALITY_FT_STEM_FITTING_STRENGTH=15
+#INFINALITY_FT_GAMMA_CORRECTION="1000 120"
+#INFINALITY_FT_BRIGHTNESS="20"
+#INFINALITY_FT_CONTRAST="30"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# WINDOWS 7 STYLE LIGHT #################
+
+#INFINALITY_FT_FILTER_PARAMS="20 25 38 25 05"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=100
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="1000 160"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="20"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# WINDOWS XP STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="06 25 44 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=15
+#INFINALITY_FT_STEM_FITTING_STRENGTH=15
+#INFINALITY_FT_GAMMA_CORRECTION="1000 120"
+#INFINALITY_FT_BRIGHTNESS="10"
+#INFINALITY_FT_CONTRAST="20"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# WINDOWS 7 STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="20 25 42 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=100
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="1000 120"
+#INFINALITY_FT_BRIGHTNESS="10"
+#INFINALITY_FT_CONTRAST="20"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+############### VANILLA STYLE ##############
+
+#INFINALITY_FT_FILTER_PARAMS="06 25 38 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=0
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=0
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+############### CLASSIC INFINALITY STYLE ##############
+
+#INFINALITY_FT_FILTER_PARAMS="06 25 38 25 06"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=0
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=0
+#INFINALITY_FT_STEM_FITTING_STRENGTH=0
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+################# NUDGE STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+#INFINALITY_FT_STEM_FITTING_STRENGTH=15
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+################# PUSH STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=75
+#INFINALITY_FT_STEM_FITTING_STRENGTH=50
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=30
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# INFINALITY STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=5
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+#INFINALITY_FT_STEM_FITTING_STRENGTH=25
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=40
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# SHOVE STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=100
+#INFINALITY_FT_STEM_FITTING_STRENGTH=100
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# SHARPENED INFINALITY STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=65
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=25
+#INFINALITY_FT_STEM_FITTING_STRENGTH=25
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=40
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true
+
+
+
+################# DISABLED STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS=
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=
+#INFINALITY_FT_STEM_FITTING_STRENGTH=
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=false
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=false
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
+
+
+
+################# CUSTOM STYLE #################
+
+#INFINALITY_FT_FILTER_PARAMS="11 22 38 22 11"
+#INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
+#INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
+#INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10
+#INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25
+#INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0
+#INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=100
+#INFINALITY_FT_STEM_FITTING_STRENGTH=100
+#INFINALITY_FT_GAMMA_CORRECTION="0 100"
+#INFINALITY_FT_BRIGHTNESS="0"
+#INFINALITY_FT_CONTRAST="0"
+#INFINALITY_FT_USE_VARIOUS_TWEAKS=true
+#INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
+#INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
+#INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0
+#INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=true \ No newline at end of file
diff --git a/media-libs/fontconfig-infinality/fontconfig-infinality-20120619.ebuild b/media-libs/fontconfig-infinality/fontconfig-infinality-20120619.ebuild
new file mode 100644
index 0000000..8d4d6e4
--- /dev/null
+++ b/media-libs/fontconfig-infinality/fontconfig-infinality-20120619.ebuild
@@ -0,0 +1,48 @@
+# Copyright 1999-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI="4"
+
+DESCRIPTION="Configuration to be used in conjunction with the freetype-infinality subpixel hinting"
+HOMEPAGE="http://www.infinality.net/blog/infinality-freetype-patches/"
+SRC_URI="http://dev.gentoo.org/~yngwin/distfiles/${P}.tar.xz"
+
+LICENSE="MIT"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE=""
+
+DEPEND=""
+RDEPEND="app-admin/eselect-fontconfig
+ app-admin/eselect-infinality
+ media-libs/freetype:2[lcdfilter]
+ >=x11-libs/libXft-2.3.0"
+
+src_configure() {
+ :
+}
+
+src_compile() {
+ :
+}
+
+src_install() {
+ dodoc infinality/{CHANGELOG,CHANGELOG.pre_git,README}
+
+ insinto /etc/fonts/conf.avail
+ doins conf.avail/52-infinality.conf
+
+ insinto /etc/fonts/infinality
+ doins -r infinality/{conf.src,styles.conf.avail,infinality.conf}
+
+ insinto /etc/X11/
+ doins "${FILESDIR}"/Xresources
+
+ newenvd "${FILESDIR}"/infinality-settings.sh 99lcdfilter
+}
+
+pkg_postinst() {
+ elog "Use eselect fontconfig enable 52-infinality.conf"
+ elog "to enable the configuration"
+}
diff --git a/media-libs/freetype/Manifest b/media-libs/freetype/Manifest
new file mode 100644
index 0000000..164bf46
--- /dev/null
+++ b/media-libs/freetype/Manifest
@@ -0,0 +1,9 @@
+AUX freetype-2.3.2-enable-valid.patch 624 SHA256 3c26cd8b92510490b4bdbdd12b078e33a4f8607eaee64a800c3ea23097d5d43b SHA512 4dd637fa77b3386cc20fff3e68c64411fdc85a09b5bd61a75647aeff294e037c22cf0b788dae1e90f4cb12b1cb2775d0ac658c82eb998603b070af5f8242cff6 WHIRLPOOL 2c25610f0ecde1d5517c780d6db96abd00bbf04fda9343a3cb1ccaddf6b3263bfb6806d198db110566df1cfd765e1c734f6e303ab81a50e60ce7697ce506162e
+AUX freetype-2.4.9-type1-incremental.patch 3213 SHA256 a41b8a606ab53ff84d96e6390514ed3ee3cba28d35f822c504169771525ef012 SHA512 ca877af277d8e95240020907ef874facf09b35f23c70218bd59285a9285a2c7bca72cad42a89e71648cd6fb0d44a6eb8c3ff76068bf0484c77126d7301621ad4 WHIRLPOOL 24bdfc8af7cfa021ae2e78920cb9c841d0fe830d79ad24088c25ce27e3d01160418b210b8dd82cc916be32f3e8971d8901793e430604a3ab576eda9816b96b32
+AUX freetype-add-subpixel-hinting-infinality.patch 118843 SHA256 4b7e1a9d9784ea57e9607d85c2a7dd5c16fc2bfc31a91498bae11653d4bfd5b2 SHA512 bcc0e933cd9604eaf9b4ac57f7d49db6517005f70a3d35cb5973de6d68364f53515a2150d126e12f0f79030357d451de304db77274a87d39ddbb54cf55e4ef11 WHIRLPOOL 80ff2a8b134edaef121940e2e017bdff8d7050e0ee13acf94ea12d162a04c981d0a468c6e9e6361a89d516e804d33eb9b6e46b2a9903bfe672df598cb3a4e025
+AUX freetype-enable-subpixel-hinting-infinality.patch 1226 SHA256 fc555a25c517e8fd0233e442ef25412150225ef4e800e7cd53494755b0086626 SHA512 1c87195a8b1b16805c98251e1379b96e3497064a4ef12935a579467c8f02c09913fcd422672132ee8a1d3e90ebc350057f988eb93be412515ca4a81c83f93b63 WHIRLPOOL 8465d448bf4df673d0123b5449b393ea4210e28c5ba522d731ea62edfab1acc1f2724e930e781d90bfdbcc2deefc1fac81a06a5f3720ecdc215e941b32d1732a
+AUX freetype-entire-infinality-patchset.patch 172999 SHA256 f135d1c3a6e6ef348e78066bf83e0e4744cd86127dc541ae0246de191c1074bf SHA512 82d851c61aab8bbc90a29903c782db482e4fd8a4bb3f52b22877a83eda89da03c93019f1912e983130e2525803ec1723554a3e33d34d8ea8b9762c7a5d487a04 WHIRLPOOL 83310aed6d2dc1b192dcce80e9e47c93d2748e43caf86b375f18afda5a63220bd36c7653dd52939e6baf73e44a8fac95dea23cadc1c98d8b19b5e1f8818f9e32
+DIST freetype-2.4.10.tar.bz2 1508927 SHA256 0c8e242c33c45928de560d7d595db06feb41d1b22167e37260ceabe72f9e992f SHA512 41547dba00a949792b44f42a8b5a69fb6dd4c6f3d454221a0b20ac6eaedd938465922197ccdd49bdff4c03e85ab4d38a77d3c48a597e3c69790ebeba359a0107 WHIRLPOOL 455efafdc97677bec9ee234d3aedde0945123587a788e483bfeb9c1a1d00a121e2921632145678d439fbd497c96191b053143247fb31ed039ad5984d0be47eef
+DIST freetype-doc-2.4.10.tar.bz2 106697 SHA256 b83b46fd02d00c256eea12bddf598454f95858dbeaa853b76dac5974f0321fd8 SHA512 feabab8f8589bce736b4aeb92513c3830cd0e95682f22e0c113c28a5c23c9732e5f6b7c309c5154570adfb87278b3bdfb8c9b34be309c383e63690745ae16e11 WHIRLPOOL 2f6ae792acd8435b7dec4359bc0a611a0bfffd26e46bf52d86be6f3f2ea113424267edcffaec833a9b96da0b462cd8328bef951708db18b4b8e54e3658d61352
+DIST ft2demos-2.4.10.tar.bz2 163949 SHA256 3fb7e97f35c0f59ecd967577a3e77fbcca10d84c00129a74e5da45bf3625cc45 SHA512 18fabb65776cc6fad164eff07413e41ea1887f38035bc3fe81f9c525160f718bd568592d81e259c49616ad167daefa591e6614f9049f51723716465a4dac8769 WHIRLPOOL 7bb4ce7fedf4176ff372c60d4ae5c9e84fcca28fd77ab5ae0a26248d0d45acd764c860e926d5dfca4053431ccbb60858c60f76b414b863b20d77e89f32e357e4
+EBUILD freetype-2.4.10-r1.ebuild 3630 SHA256 99168b729c21845b8a3a287df3f6ed8c431b8e40dc52f1fc839783904a68052e SHA512 2daf0b85762104d9e55958dc175d5d4c29f33737dc85d7dff208a1bf7a0dce9ec29941943f67c0f309a392eff66a422f1717de0cfc0223d35dbdf25c4bee6431 WHIRLPOOL c52b21a77ddcfff842b8fac979e7b40efc49478f67dc59fd708afb17935dcc7b9504f701993db7b2ae1e496fb8a95c618355ddcb0744df7816af177939046646
diff --git a/media-libs/freetype/files/freetype-2.3.2-enable-valid.patch b/media-libs/freetype/files/freetype-2.3.2-enable-valid.patch
new file mode 100644
index 0000000..44f3bf6
--- /dev/null
+++ b/media-libs/freetype/files/freetype-2.3.2-enable-valid.patch
@@ -0,0 +1,22 @@
+Enables gxvalid and otvalid modules for use with ftvalid.
+
+--- 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/media-libs/freetype/files/freetype-2.4.9-type1-incremental.patch b/media-libs/freetype/files/freetype-2.4.9-type1-incremental.patch
new file mode 100644
index 0000000..a08c44d
--- /dev/null
+++ b/media-libs/freetype/files/freetype-2.4.9-type1-incremental.patch
@@ -0,0 +1,101 @@
+--- a/src/type1/t1load.c
++++ b/src/type1/t1load.c
+@@ -71,6 +71,13 @@
+ #include "t1errors.h"
+
+
++#ifdef FT_CONFIG_OPTION_INCREMENTAL
++#define IS_INCREMENTAL ( face->root.internal->incremental_interface != 0 )
++#else
++#define IS_INCREMENTAL 0
++#endif
++
++
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+@@ -1030,7 +1037,8 @@
+ static int
+ read_binary_data( T1_Parser parser,
+ FT_Long* size,
+- FT_Byte** base )
++ FT_Byte** base,
++ FT_Bool incremental )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+@@ -1065,8 +1073,12 @@
+ }
+ }
+
+- FT_ERROR(( "read_binary_data: invalid size field\n" ));
+- parser->root.error = T1_Err_Invalid_File_Format;
++ if( !incremental )
++ {
++ FT_ERROR(( "read_binary_data: invalid size field\n" ));
++ parser->root.error = T1_Err_Invalid_File_Format;
++ }
++
+ return 0;
+ }
+
+@@ -1387,16 +1399,17 @@
+ FT_Byte* base;
+
+
+- /* If the next token isn't `dup' we are done. */
+- if ( parser->root.cursor + 4 < parser->root.limit &&
+- ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
++ /* If we are out of data, or if the next token isn't `dup', */
++ /* we are done. */
++ if ( parser->root.cursor + 4 >= parser->root.limit ||
++ ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
+ break;
+
+ T1_Skip_PS_Token( parser ); /* `dup' */
+
+ idx = T1_ToInt( parser );
+
+- if ( !read_binary_data( parser, &size, &base ) )
++ if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
+ return;
+
+ /* The binary string is followed by one token, e.g. `NP' */
+@@ -1582,7 +1595,7 @@
+ cur++; /* skip `/' */
+ len = parser->root.cursor - cur;
+
+- if ( !read_binary_data( parser, &size, &base ) )
++ if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
+ return;
+
+ /* for some non-standard fonts like `Optima' which provides */
+@@ -1871,7 +1884,7 @@
+
+
+ parser->root.cursor = start_binary;
+- if ( !read_binary_data( parser, &s, &b ) )
++ if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
+ return T1_Err_Invalid_File_Format;
+ have_integer = 0;
+ }
+@@ -1884,7 +1897,7 @@
+
+
+ parser->root.cursor = start_binary;
+- if ( !read_binary_data( parser, &s, &b ) )
++ if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
+ return T1_Err_Invalid_File_Format;
+ have_integer = 0;
+ }
+@@ -2160,9 +2173,7 @@
+ type1->subrs_len = loader.subrs.lengths;
+ }
+
+-#ifdef FT_CONFIG_OPTION_INCREMENTAL
+- if ( !face->root.internal->incremental_interface )
+-#endif
++ if ( !IS_INCREMENTAL )
+ if ( !loader.charstrings.init )
+ {
+ FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
diff --git a/media-libs/freetype/files/freetype-add-subpixel-hinting-infinality.patch b/media-libs/freetype/files/freetype-add-subpixel-hinting-infinality.patch
new file mode 100644
index 0000000..8bb026b
--- /dev/null
+++ b/media-libs/freetype/files/freetype-add-subpixel-hinting-infinality.patch
@@ -0,0 +1,2927 @@
+diff -Nur freetype-orig/devel/ftoption.h freetype-subpixel/devel/ftoption.h
+--- freetype-orig/devel/ftoption.h 2012-06-14 00:35:57.000000000 -0500
++++ freetype-subpixel/devel/ftoption.h 2012-06-15 07:31:12.119986648 -0500
+@@ -560,6 +560,28 @@
+
+ /*************************************************************************/
+ /* */
++ /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */
++ /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */
++ /* replaces the native TrueType hinting mechanism when anything but */
++ /* FT_RENDER_MODE_MONO is requested. */
++ /* */
++ /* Enabling this causes the TrueType driver to ignore instructions under */
++ /* certain conditions. This is done in accordance with the guide here, */
++ /* with some minor differences: */
++ /* */
++ /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */
++ /* */
++ /* By undefining this, you only compile the code necessary to hint */
++ /* TrueType glyphs with native TT hinting. */
++ /* */
++ /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */
++ /* defined. */
++ /* */
++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
++
++ /*************************************************************************/
++ /* */
+ /* 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 -Nur freetype-orig/include/freetype/config/ftoption.h freetype-subpixel/include/freetype/config/ftoption.h
+--- freetype-orig/include/freetype/config/ftoption.h 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/include/freetype/config/ftoption.h 2012-06-15 07:31:12.146985731 -0500
+@@ -560,6 +560,28 @@
+
+ /*************************************************************************/
+ /* */
++ /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */
++ /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */
++ /* replaces the native TrueType hinting mechanism when anything but */
++ /* FT_RENDER_MODE_MONO is requested. */
++ /* */
++ /* Enabling this causes the TrueType driver to ignore instructions under */
++ /* certain conditions. This is done in accordance with the guide here, */
++ /* with some minor differences: */
++ /* */
++ /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */
++ /* */
++ /* By undefining this, you only compile the code necessary to hint */
++ /* TrueType glyphs with native TT hinting. */
++ /* */
++ /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */
++ /* defined. */
++ /* */
++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
++
++ /*************************************************************************/
++ /* */
+ /* 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 -Nur freetype-orig/include/freetype/internal/ftobjs.h freetype-subpixel/include/freetype/internal/ftobjs.h
+--- freetype-orig/include/freetype/internal/ftobjs.h 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/include/freetype/internal/ftobjs.h 2012-06-15 07:31:12.147985698 -0500
+@@ -81,6 +81,14 @@
+ #define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 )
+ #define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 )
+
++ /*
++ * These are used in ttinterp.c for subpixel hinting with an
++ * adjustable grids-per-pixel value.
++ */
++#define FT_PIX_FLOOR_GRID( x, n ) ( (x) & ~( 64 / (n) - 1 ) )
++#define FT_PIX_ROUND_GRID( x, n ) FT_PIX_FLOOR_GRID( (x) + 32 / (n), (n) )
++#define FT_PIX_CEIL_GRID( x, n ) FT_PIX_FLOOR_GRID( (x) + 63 / (n), (n) )
++
+
+ /*
+ * Return the highest power of 2 that is <= value; this correspond to
+diff -Nur freetype-orig/src/truetype/rules.mk freetype-subpixel/src/truetype/rules.mk
+--- freetype-orig/src/truetype/rules.mk 2011-01-03 00:06:51.000000000 -0600
++++ freetype-subpixel/src/truetype/rules.mk 2012-06-15 07:31:12.148985665 -0500
+@@ -31,7 +31,8 @@
+ $(TT_DIR)/ttinterp.c \
+ $(TT_DIR)/ttobjs.c \
+ $(TT_DIR)/ttpic.c \
+- $(TT_DIR)/ttpload.c
++ $(TT_DIR)/ttpload.c \
++ $(TT_DIR)/ttsubpix.c
+
+ # TrueType driver headers
+ #
+diff -Nur freetype-orig/src/truetype/truetype.c freetype-subpixel/src/truetype/truetype.c
+--- freetype-orig/src/truetype/truetype.c 2009-07-03 08:28:24.000000000 -0500
++++ freetype-subpixel/src/truetype/truetype.c 2012-06-15 07:31:12.149985631 -0500
+@@ -27,6 +27,7 @@
+
+ #ifdef TT_USE_BYTECODE_INTERPRETER
+ #include "ttinterp.c"
++#include "ttsubpix.c"
+ #endif
+
+ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+diff -Nur freetype-orig/src/truetype/ttgload.c freetype-subpixel/src/truetype/ttgload.c
+--- freetype-orig/src/truetype/ttgload.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/src/truetype/ttgload.c 2012-06-15 07:31:12.151985563 -0500
+@@ -32,6 +32,7 @@
+ #endif
+
+ #include "tterrors.h"
++#include "ttsubpix.h"
+
+
+ /*************************************************************************/
+@@ -149,6 +150,15 @@
+ loader->top_bearing = top_bearing;
+ loader->vadvance = advance_height;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( loader->exec )
++ loader->exec->sph_tweak_flags = 0;
++
++ /* this may not be the right place for this, but it works */
++ if ( loader->exec && loader->exec->ignore_x_mode )
++ sph_set_tweaks( loader, glyph_index );
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ if ( !loader->linear_def )
+ {
+ loader->linear_def = 1;
+@@ -813,6 +823,13 @@
+ loader->pp4 = zone->cur[zone->n_points - 1];
+ }
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
++ FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
++
++ else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
++ FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
++#endif
+ return TT_Err_Ok;
+ }
+
+@@ -835,6 +852,13 @@
+ FT_Outline* outline;
+ FT_Int n_points;
+
++ TT_Face face = (TT_Face)loader->face;
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_String* family = face->root.family_name;
++ int ppem = loader->size->metrics.x_ppem;
++ FT_String* style = face->root.style_name;
++ float x_scale_factor = 1.0;
++#endif
+
+ outline = &gloader->current.outline;
+ n_points = outline->n_points;
+@@ -889,6 +913,26 @@
+ loader->zone.n_points + 4 );
+ }
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /* scale, but only if enabled and only if TT hinting is being used */
++ if ( IS_HINTED( loader->load_flags ) )
++ x_scale_factor = scale_test_tweak( face, family, ppem, style,
++ loader->glyph_index, X_SCALING_Rules,
++ X_SCALING_RULES_SIZE );
++ /* scale the glyph */
++ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
++ x_scale_factor != 1.0 )
++ {
++ FT_Vector* vec = outline->points;
++ FT_Vector* limit = outline->points + n_points;
++ FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale * x_scale_factor;
++ FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale;
++
++ /* compensate for any scaling by de/emboldening */
++ if ( x_scale_factor != 1.0 && ppem > 11 )
++ FT_Outline_EmboldenXY( outline,
++ (FT_Int) ( 16.0 * (float)ppem * ( 1.0 - x_scale_factor) ), 0 );
++#else
+ /* scale the glyph */
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+@@ -896,7 +940,7 @@
+ FT_Vector* limit = outline->points + n_points;
+ FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale;
+ FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+-
++#endif
+
+ for ( ; vec < limit; vec++ )
+ {
+@@ -1648,12 +1692,26 @@
+ {
+ FT_Byte* widthp;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Bool ignore_x_mode;
++
++
++ ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) !=
++ FT_RENDER_MODE_MONO );
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ widthp = tt_face_get_device_metrics( face,
+ size->root.metrics.x_ppem,
+ glyph_index );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( widthp &&
++ ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
++ !ignore_x_mode ||
++ SPH_OPTION_BITMAP_WIDTHS ) )
++#else
+ if ( widthp )
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ glyph->metrics.horiAdvance = *widthp << 6;
+ }
+
+@@ -1848,6 +1906,15 @@
+ {
+ TT_ExecContext exec;
+ FT_Bool grayscale;
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Bool subpixel_hinting;
++ FT_Bool grayscale_hinting;
++#if 0
++ FT_Bool compatible_widths;
++ FT_Bool symmetrical_smoothing;
++ FT_Bool bgr;
++#endif
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+ if ( !size->cvt_ready )
+@@ -1865,11 +1932,88 @@
+ if ( !exec )
+ return TT_Err_Could_Not_Find_Context;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++ subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags )
++ != FT_RENDER_MODE_MONO ) &&
++ SPH_OPTION_SET_SUBPIXEL );
++
++ if ( subpixel_hinting )
++ grayscale = grayscale_hinting = FALSE;
++
++ else if ( SPH_OPTION_SET_GRAYSCALE )
++ {
++ grayscale = grayscale_hinting = TRUE;
++ subpixel_hinting = FALSE;
++ }
++
++ if ( FT_IS_TRICKY( glyph->face ) )
++ {
++ subpixel_hinting = grayscale_hinting = FALSE;
++ }
++
++ exec->ignore_x_mode = subpixel_hinting || grayscale_hinting;
++ exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
++ if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
++ exec->rasterizer_version = 35;
++
++#if 1
++ exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
++ exec->symmetrical_smoothing = FALSE;
++ exec->bgr = FALSE;
++#else /* 0 */
++ exec->compatible_widths =
++ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
++ TT_LOAD_COMPATIBLE_WIDTHS );
++ exec->symmetrical_smoothing =
++ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
++ TT_LOAD_SYMMETRICAL_SMOOTHING );
++ exec->bgr =
++ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
++ TT_LOAD_BGR );
++#endif /* 0 */
++
++#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ grayscale =
+ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO );
+
++#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ TT_Load_Context( exec, face, size );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++ /* a change from mono to subpixel rendering (and vice versa) */
++ /* requires a re-execution of the CVT program */
++ if ( subpixel_hinting != exec->subpixel_hinting )
++ {
++ FT_UInt i;
++
++
++ exec->subpixel_hinting = subpixel_hinting;
++
++ for ( i = 0; i < size->cvt_size; i++ )
++ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
++ tt_size_run_prep( size, pedantic );
++ }
++
++ /* a change from mono to grayscale rendering (and vice versa) */
++ /* requires a re-execution of the CVT program */
++ if ( grayscale != exec->grayscale_hinting )
++ {
++ FT_UInt i;
++
++
++ exec->grayscale_hinting = grayscale_hinting;
++
++ for ( i = 0; i < size->cvt_size; i++ )
++ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
++ tt_size_run_prep( size, pedantic );
++ }
++
++#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* a change from mono to grayscale rendering (and vice versa) */
+ /* requires a re-execution of the CVT program */
+ if ( grayscale != exec->grayscale )
+@@ -1887,6 +2031,8 @@
+ tt_size_run_prep( size, pedantic );
+ }
+
++#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* see whether the cvt program has disabled hinting */
+ if ( exec->GS.instruct_control & 1 )
+ load_flags |= FT_LOAD_NO_HINTING;
+diff -Nur freetype-orig/src/truetype/ttinterp.c freetype-subpixel/src/truetype/ttinterp.c
+--- freetype-orig/src/truetype/ttinterp.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/src/truetype/ttinterp.c 2012-06-16 10:31:47.161209856 -0500
+@@ -27,13 +27,16 @@
+ #include FT_SYSTEM_H
+
+ #include "ttinterp.h"
+-
+ #include "tterrors.h"
++#include "ttsubpix.h"
+
+
+ #ifdef TT_USE_BYTECODE_INTERPRETER
+
+
++#define xxxSPH_DEBUG
++#define xxxSPH_DEBUG_MORE_VERBOSE
++
+ #define TT_MULFIX FT_MulFix
+ #define TT_MULDIV FT_MulDiv
+ #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
+@@ -153,11 +156,11 @@
+ #define NORMalize( x, y, v ) \
+ Normalize( EXEC_ARG_ x, y, v )
+
+-#define SET_SuperRound( scale, flags ) \
+- SetSuperRound( EXEC_ARG_ scale, flags )
++#define SET_SuperRound( scale, flags, res ) \
++ SetSuperRound( EXEC_ARG_ scale, flags, res )
+
+-#define ROUND_None( d, c ) \
+- Round_None( EXEC_ARG_ d, c )
++#define ROUND_None( d, c, e ) \
++ Round_None( EXEC_ARG_ d, c, e )
+
+ #define INS_Goto_CodeRange( range, ip ) \
+ Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
+@@ -168,8 +171,8 @@
+ #define CUR_Func_move_orig( z, p, d ) \
+ CUR.func_move_orig( EXEC_ARG_ z, p, d )
+
+-#define CUR_Func_round( d, c ) \
+- CUR.func_round( EXEC_ARG_ d, c )
++#define CUR_Func_round( d, c, e ) \
++ CUR.func_round( EXEC_ARG_ d, c, e )
+
+ #define CUR_Func_read_cvt( index ) \
+ CUR.func_read_cvt( EXEC_ARG_ index )
+@@ -1850,6 +1853,10 @@
+
+ if ( v != 0 )
+ {
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( !CUR.ignore_x_mode ||
++ ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) )
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ zone->cur[point].x += TT_MULDIV( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+@@ -1932,6 +1939,10 @@
+ {
+ FT_UNUSED_EXEC;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( !CUR.ignore_x_mode ||
++ ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVEX ) )
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ zone->cur[point].x += distance;
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
+ }
+@@ -1994,6 +2005,8 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* The compensated distance. */
+ /* */
+@@ -2005,11 +2018,13 @@
+ /* */
+ static FT_F26Dot6
+ Round_None( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
++ FT_UNUSED( resolution );
+
+
+ if ( distance >= 0 )
+@@ -2024,6 +2039,7 @@
+ if ( val > 0 )
+ val = 0;
+ }
++
+ return val;
+ }
+
+@@ -2041,12 +2057,15 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+@@ -2055,15 +2074,15 @@
+
+ if ( distance >= 0 )
+ {
+- val = distance + compensation + 32;
++ val = distance + compensation + 32 / resolution;
+ if ( distance && val > 0 )
+- val &= ~63;
++ val &= ~( 64 / resolution - 1 );
+ else
+ val = 0;
+ }
+ else
+ {
+- val = -FT_PIX_ROUND( compensation - distance );
++ val = -FT_PIX_ROUND_GRID( compensation - distance, resolution );
+ if ( val > 0 )
+ val = 0;
+ }
+@@ -2085,12 +2104,15 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+@@ -2099,13 +2121,15 @@
+
+ if ( distance >= 0 )
+ {
+- val = FT_PIX_FLOOR( distance + compensation ) + 32;
++ val = FT_PIX_FLOOR_GRID( distance + compensation, resolution ) +
++ 32 / resolution;
+ if ( distance && val < 0 )
+ val = 0;
+ }
+ else
+ {
+- val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
++ val = -( FT_PIX_FLOOR_GRID( compensation - distance, resolution ) +
++ 32 / resolution );
+ if ( val > 0 )
+ val = 0;
+ }
+@@ -2127,12 +2151,15 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+@@ -2143,13 +2170,13 @@
+ {
+ val = distance + compensation;
+ if ( distance && val > 0 )
+- val &= ~63;
++ val &= ~( 64 / resolution - 1 );
+ else
+ val = 0;
+ }
+ else
+ {
+- val = -( ( compensation - distance ) & -64 );
++ val = -( ( compensation - distance ) & -( 64 / resolution ) );
+ if ( val > 0 )
+ val = 0;
+ }
+@@ -2171,12 +2198,15 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+@@ -2185,15 +2215,15 @@
+
+ if ( distance >= 0 )
+ {
+- val = distance + compensation + 63;
++ val = distance + compensation + ( 64 / resolution - 1 );
+ if ( distance && val > 0 )
+- val &= ~63;
++ val &= ~( 64 / resolution - 1 );
+ else
+ val = 0;
+ }
+ else
+ {
+- val = - FT_PIX_CEIL( compensation - distance );
++ val = -FT_PIX_CEIL_GRID( compensation - distance, resolution );
+ if ( val > 0 )
+ val = 0;
+ }
+@@ -2215,12 +2245,15 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
+@@ -2229,15 +2262,15 @@
+
+ if ( distance >= 0 )
+ {
+- val = distance + compensation + 16;
++ val = distance + compensation + 16 / resolution;
+ if ( distance && val > 0 )
+- val &= ~31;
++ val &= ~( 32 / resolution - 1 );
+ else
+ val = 0;
+ }
+ else
+ {
+- val = -FT_PAD_ROUND( compensation - distance, 32 );
++ val = -FT_PAD_ROUND( compensation - distance, 32 / resolution );
+ if ( val > 0 )
+ val = 0;
+ }
+@@ -2259,6 +2292,8 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+@@ -2270,10 +2305,13 @@
+ /* */
+ static FT_F26Dot6
+ Round_Super( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
++ FT_UNUSED( resolution );
++
+
+ if ( distance >= 0 )
+ {
+@@ -2309,6 +2347,8 @@
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
++ /* resolution :: The number of grid lines per pixel. */
++ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+@@ -2318,10 +2358,13 @@
+ /* */
+ static FT_F26Dot6
+ Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation )
++ FT_F26Dot6 compensation,
++ FT_Int resolution )
+ {
+ FT_F26Dot6 val;
+
++ FT_UNUSED( resolution );
++
+
+ if ( distance >= 0 )
+ {
+@@ -2404,13 +2447,19 @@
+ /* Sets Super Round parameters. */
+ /* */
+ /* <Input> */
+- /* GridPeriod :: Grid period */
+- /* selector :: SROUND opcode */
++ /* GridPeriod :: The grid period. */
++ /* */
++ /* selector :: The SROUND opcode. */
++ /* */
++ /* resolution :: The number of grid lines per pixel. */
+ /* */
+ static void
+ SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
+- FT_Long selector )
++ FT_Long selector,
++ FT_Int resolution )
+ {
++ FT_UNUSED( resolution );
++
+ switch ( (FT_Int)( selector & 0xC0 ) )
+ {
+ case 0:
+@@ -3080,13 +3129,13 @@
+
+
+ #define DO_SROUND \
+- SET_SuperRound( 0x4000, args[0] ); \
++ SET_SuperRound( 0x4000, args[0], 1 ); \
+ CUR.GS.round_state = TT_Round_Super; \
+ CUR.func_round = (TT_Round_Func)Round_Super;
+
+
+ #define DO_S45ROUND \
+- SET_SuperRound( 0x2D41, args[0] ); \
++ SET_SuperRound( 0x2D41, args[0], 1 ); \
+ CUR.GS.round_state = TT_Round_Super_45; \
+ CUR.func_round = (TT_Round_Func)Round_Super_45;
+
+@@ -3257,12 +3306,12 @@
+ args[0] = ( args[0] != args[1] );
+
+
+-#define DO_ODD \
+- args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
++#define DO_ODD \
++ args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 64 );
+
+
+-#define DO_EVEN \
+- args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
++#define DO_EVEN \
++ args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 0 );
+
+
+ #define DO_AND \
+@@ -3311,6 +3360,34 @@
+ #define DO_CEILING \
+ args[0] = FT_PIX_CEIL( args[0] );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++#define DO_RS \
++ { \
++ FT_ULong I = (FT_ULong)args[0]; \
++ \
++ \
++ if ( BOUNDSL( I, CUR.storeSize ) ) \
++ { \
++ if ( CUR.pedantic_hinting ) \
++ ARRAY_BOUND_ERROR; \
++ else \
++ args[0] = 0; \
++ } \
++ else \
++ { \
++ /* subpixel hinting - avoid Typeman Dstroke and */ \
++ /* IStroke and Vacuform rounds */ \
++ \
++ if ( CUR.compatibility_mode && \
++ ( I == 24 || I == 22 || I == 8 ) ) \
++ args[0] = 0; \
++ else \
++ args[0] = CUR.storage[I]; \
++ } \
++ }
++
++#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ #define DO_RS \
+ { \
+@@ -3330,6 +3407,8 @@
+ args[0] = CUR.storage[I]; \
+ }
+
++#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+
+ #define DO_WS \
+ { \
+@@ -3405,15 +3484,17 @@
+ CUR.error = TT_Err_Debug_OpCode;
+
+
+-#define DO_ROUND \
+- args[0] = CUR_Func_round( \
+- args[0], \
+- CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
++#define DO_ROUND \
++ args[0] = CUR_Func_round( \
++ args[0], \
++ CUR.tt_metrics.compensations[CUR.opcode - 0x68], \
++ 1 );
+
+
+-#define DO_NROUND \
+- args[0] = ROUND_None( args[0], \
+- CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
++#define DO_NROUND \
++ args[0] = ROUND_None( args[0], \
++ CUR.tt_metrics.compensations[CUR.opcode - 0x6C], \
++ 1 );
+
+
+ #define DO_MAX \
+@@ -4587,6 +4668,24 @@
+ TT_DefRecord* rec;
+ TT_DefRecord* limit;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++#if 0
++ int opcode_pattern[4][12] = {
++ /* VacuFormRound function */
++ {0x45,0x23,0x46,0x60,0x20},
++ /* inline delta function 1 */
++ {0x4B,0x53,0x23,0x4B,0x51,0x5A,0x58,0x38,0x1B,0x21,0x21,0x59},
++ /* inline delta function 2 */
++ {0x4B,0x54,0x58,0x38,0x1B,0x5A,0x21,0x21,0x59},
++ /* diagonal stroke function */
++ {0x20,0x20,0x40,0x60,0x47,0x40,0x23,0x42},
++ };
++ int opcode_patterns = 4;
++ int i;
++ int opcode_pointer[4] = {0,0,0,0};
++#endif
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+
+ /* some font programs are broken enough to redefine functions! */
+ /* We will then parse the current table. */
+@@ -4620,10 +4719,11 @@
+ return;
+ }
+
+- rec->range = CUR.curRange;
+- rec->opc = (FT_UInt16)n;
+- rec->start = CUR.IP + 1;
+- rec->active = TRUE;
++ rec->range = CUR.curRange;
++ rec->opc = (FT_UInt16)n;
++ rec->start = CUR.IP + 1;
++ rec->active = TRUE;
++ rec->inline_delta = FALSE;
+
+ if ( n > CUR.maxFunc )
+ CUR.maxFunc = (FT_UInt16)n;
+@@ -4633,6 +4733,78 @@
+
+ while ( SKIP_Code() == SUCCESS )
+ {
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++#if 0
++#ifdef SPH_DEBUG_MORE_VERBOSE
++ printf ("Opcode: %d ", CUR.opcode);
++#endif
++
++ for ( i = 0; i < opcode_patterns; i++ )
++ {
++ if ( CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
++ {
++#ifdef SPH_DEBUG_MORE_VERBOSE
++ printf( "function %d, opcode ptrn: %d"
++ " op# %d: %d FOUND \n",
++ n, i, opcode_pointer[i], CUR.opcode );
++#endif
++ opcode_pointer[i] += 1;
++
++ if ( i == 0 && opcode_pointer[0] == 5 )
++ {
++
++ CUR.inline_delta_funcs[CUR.num_delta_funcs] = n;
++ CUR.num_delta_funcs++;
++#ifdef SPH_DEBUG
++ printf( "Vacuform Round FUNCTION %d detected\n", n);
++#endif
++ /*rec->active = FALSE;*/
++ opcode_pointer[i] = 0;
++ }
++
++ if ( i == 1 && opcode_pointer[1] == 12 )
++ {
++ CUR.inline_delta_funcs[CUR.num_delta_funcs] = n;
++ CUR.num_delta_funcs++;
++#ifdef SPH_DEBUG
++ printf( "inline delta FUNCTION1 %d detected\n",
++ n, CUR.num_delta_funcs);
++#endif
++ rec->inline_delta = TRUE;
++ opcode_pointer[i] = 0;
++ }
++
++ if ( i == 2 && opcode_pointer[1] == 9 )
++ {
++ CUR.inline_delta_funcs[CUR.num_delta_funcs] = n;
++ CUR.num_delta_funcs++;
++ rec->inline_delta = TRUE;
++#ifdef SPH_DEBUG
++ printf( "inline delta2 FUNCTION2 %d detected\n",
++ n, CUR.num_delta_funcs);
++#endif
++ opcode_pointer[i] = 0;
++ }
++
++ if ( i == 4 && opcode_pointer[1] == 8 )
++ {
++ CUR.inline_delta_funcs[CUR.num_delta_funcs] = n;
++ CUR.num_delta_funcs++;
++ /*rec->active = FALSE;*/
++#ifdef SPH_DEBUG
++ printf( "diagonal stroke function %d detected\n",
++ n, CUR.num_delta_funcs);
++#endif
++ opcode_pointer[i] = 0;
++ }
++ }
++
++ else
++ opcode_pointer[i] = 0;
++ }
++#endif
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ switch ( CUR.opcode )
+ {
+ case 0x89: /* IDEF */
+@@ -4676,6 +4848,15 @@
+
+ CUR.step_ins = FALSE;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /*
++ * CUR.ignore_x_mode may be turned off prior to function calls. This
++ * ensures it is turned back on.
++ */
++ CUR.ignore_x_mode = ( CUR.subpixel_hinting || CUR.grayscale_hinting )
++ && !( CUR.sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING );
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ if ( pRec->Cur_Count > 0 )
+ {
+ CUR.callTop++;
+@@ -4709,6 +4890,10 @@
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Bool oldF;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+
+ /* first of all, check the index */
+
+@@ -4746,6 +4931,20 @@
+ if ( !def->active )
+ goto Fail;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /* This is test code used to detect inline delta functions */
++ oldF = def->inline_delta;
++ if ( CUR.ignore_x_mode )
++ {
++ if ( def->inline_delta )
++ CUR.in_delta_function = TRUE;
++ }
++
++#ifdef SPH_DEBUG
++ printf("Entering function %d\n", F);
++#endif
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* check the call stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+@@ -4767,6 +4966,13 @@
+ def->start );
+
+ CUR.step_ins = FALSE;
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ CUR.in_delta_function = oldF;
++
++#ifdef SPH_DEBUG
++ printf("Leaving function %d\n", F);
++#endif
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ return;
+
+ Fail:
+@@ -4787,6 +4993,10 @@
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Bool oldF;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+
+ /* first of all, check the index */
+ F = args[1];
+@@ -4823,6 +5033,15 @@
+ if ( !def->active )
+ goto Fail;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ oldF = def->inline_delta;
++ if ( CUR.ignore_x_mode )
++ {
++ if ( def->inline_delta )
++ CUR.in_delta_function = TRUE;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* check stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+@@ -4846,6 +5065,11 @@
+
+ CUR.step_ins = FALSE;
+ }
++
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ CUR.in_delta_function = oldF;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ return;
+
+ Fail:
+@@ -5195,6 +5419,12 @@
+ }
+ }
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
++ if ( CUR.ignore_x_mode && FT_ABS( D ) == 64 )
++ D += 1;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ args[0] = D;
+ }
+
+@@ -5691,7 +5921,12 @@
+
+ if ( CUR.GS.freeVector.x != 0 )
+ {
+- CUR.zp2.cur[point].x += dx;
++#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 ) ) )
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++ CUR.zp2.cur[point].x += dx;
+ if ( touch )
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
+ }
+@@ -5872,6 +6107,9 @@
+ {
+ FT_F26Dot6 dx, dy;
+ FT_UShort point;
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Int B1, B2;
++#endif
+
+
+ if ( CUR.top < CUR.GS.loop + 1 )
+@@ -5917,7 +6155,77 @@
+ }
+ }
+ else
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ {
++ /* If not using ignore_x_mode rendering, allow ZP2 move. */
++ /* If inline deltas aren't allowed, skip ZP2 move. */
++ /* If using ignore_x_mode rendering, allow ZP2 point move if: */
++ /* - freedom vector is y and compatibility_mode is off */
++ /* - the glyph is composite and the move is in the Y direction */
++ /* - the glyph is specifically set to allow SHPIX moves */
++ /* - the move is on a previously Y-touched point */
++
++ if ( CUR.ignore_x_mode )
++ {
++ /* save point for later comparison */
++ if ( CUR.GS.freeVector.y != 0 )
++ B1 = CUR.zp2.cur[point].y;
++ 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.ignore_x_mode &&
++ !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
++ MOVE_Zp2_Point( point, dx, dy, TRUE );
++
++ else if ( CUR.ignore_x_mode && CUR.compatibility_mode )
++ {
++ if ( CUR.ignore_x_mode &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
++ {
++ dx = FT_PIX_ROUND ( B1 + dx ) - B1;
++ dy = FT_PIX_ROUND ( B1 + dy ) - B1;
++ }
++
++ 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 ) ||
++ ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) )
++ )
++ MOVE_Zp2_Point( point, dx, dy, TRUE );
++ }
++
++ /* save new point */
++ if ( CUR.GS.freeVector.y != 0 )
++ B2 = CUR.zp2.cur[point].y;
++ else B2 = CUR.zp2.cur[point].x;
++
++ /* reverse any disallowed moves */
++ if ( ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
++ CUR.GS.freeVector.y != 0 &&
++ B1 % 64 != 0 &&
++ B2 % 64 != 0 && B1 != B2 ) ||
++ ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
++ CUR.GS.freeVector.y != 0 &&
++ B1 % 64 == 0 &&
++ B2 % 64 != 0 && B1 != B2 ) )
++ {
++#ifdef SPH_DEBUG
++ printf( "Reversing ZP2 move\n" );
++#endif
++ MOVE_Zp2_Point( point, -dx, -dy, TRUE );
++ }
++ }
++ else
++ MOVE_Zp2_Point( point, dx, dy, TRUE );
++ }
++ Skip:
++#else
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ CUR.GS.loop--;
+ }
+@@ -5939,7 +6247,18 @@
+ {
+ FT_UShort point;
+ FT_F26Dot6 distance;
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Int gridlines_per_pixel = 1;
++
+
++ if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.x != 0 )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_X;
++ else if ( CUR.GS.freeVector.y != 0 )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_Y;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ point = (FT_UShort)args[0];
+
+@@ -5963,6 +6282,15 @@
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /* subpixel hinting - make MSIRP respect CVT cut-in; */
++ if ( CUR.ignore_x_mode &&
++ CUR.GS.freeVector.x != 0 &&
++ FT_ABS( distance - args[1] ) >=
++ CUR.GS.control_value_cutin / gridlines_per_pixel )
++ distance = args[1];
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ CUR_Func_move( &CUR.zp1, point, args[1] - distance );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+@@ -5985,7 +6313,21 @@
+ FT_UShort point;
+ FT_F26Dot6 cur_dist,
+ distance;
++ FT_Int gridlines_per_pixel = 1;
++
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.x != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_X;
++
++ else if ( CUR.GS.freeVector.y != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_Y;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ point = (FT_UShort)args[0];
+
+@@ -6000,7 +6342,8 @@
+ {
+ cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
+ distance = CUR_Func_round( cur_dist,
+- CUR.tt_metrics.compensations[0] ) - cur_dist;
++ CUR.tt_metrics.compensations[0],
++ gridlines_per_pixel ) - cur_dist;
+ }
+ else
+ distance = 0;
+@@ -6025,8 +6368,22 @@
+ FT_UShort point;
+ FT_F26Dot6 distance,
+ org_dist;
++ FT_Int gridlines_per_pixel = 1;
+
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.x != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_X;
++
++ else if ( CUR.GS.freeVector.y != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_Y;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ cvtEntry = (FT_ULong)args[1];
+ point = (FT_UShort)args[0];
+
+@@ -6062,21 +6419,34 @@
+
+ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
+ {
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /* only adjust legacy fonts x otherwise breaks Calibri italic */
++ if ( CUR.compatibility_mode )
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
+ CUR.GS.freeVector.x );
+ CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
+ CUR.GS.freeVector.y ),
+ CUR.zp0.cur[point] = CUR.zp0.org[point];
+ }
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( distance > 0 &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
++ CUR.GS.freeVector.y != 0 )
++ distance = 0 ;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
+
+ if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
+ {
+- if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
++ if ( FT_ABS( distance - org_dist ) >
++ CUR.GS.control_value_cutin / gridlines_per_pixel )
+ distance = org_dist;
+
+- distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
++ distance = CUR_Func_round( distance,
++ CUR.tt_metrics.compensations[0],
++ gridlines_per_pixel );
+ }
+
+ CUR_Func_move( &CUR.zp0, point, distance - org_dist );
+@@ -6098,6 +6468,24 @@
+ {
+ FT_UShort point;
+ FT_F26Dot6 org_dist, distance;
++ FT_Int minimum_distance_factor = 64;
++ FT_Int gridlines_per_pixel = 1;
++
++
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.x != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ {
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_X;
++ minimum_distance_factor = 64 - gridlines_per_pixel / 3;
++ }
++ else if ( CUR.GS.freeVector.y != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_Y;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+ point = (FT_UShort)args[0];
+@@ -6163,11 +6551,13 @@
+ if ( ( CUR.opcode & 4 ) != 0 )
+ distance = CUR_Func_round(
+ org_dist,
+- CUR.tt_metrics.compensations[CUR.opcode & 3] );
++ CUR.tt_metrics.compensations[CUR.opcode & 3],
++ gridlines_per_pixel );
+ else
+ distance = ROUND_None(
+ org_dist,
+- CUR.tt_metrics.compensations[CUR.opcode & 3] );
++ CUR.tt_metrics.compensations[CUR.opcode & 3],
++ gridlines_per_pixel );
+
+ /* minimum distance flag */
+
+@@ -6175,13 +6565,17 @@
+ {
+ if ( org_dist >= 0 )
+ {
+- if ( distance < CUR.GS.minimum_distance )
+- distance = CUR.GS.minimum_distance;
++ if ( distance < FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 ) )
++ distance = FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 );
+ }
+ else
+ {
+- if ( distance > -CUR.GS.minimum_distance )
+- distance = -CUR.GS.minimum_distance;
++ if ( distance > -FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 ) )
++ distance = -FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 );
+ }
+ }
+
+@@ -6218,10 +6612,37 @@
+ cur_dist,
+ org_dist;
+
++ FT_Int minimum_distance_factor = 64;
++ FT_Int gridlines_per_pixel = 1;
++
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_Int B1;
++ FT_Int B2;
++ FT_Bool reverse_move = FALSE;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ point = (FT_UShort)args[0];
+ cvtEntry = (FT_ULong)( args[1] + 1 );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.x != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ {
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_X;
++ /* high value emboldens glyphs at lower ppems (< 14); */
++ /* Courier looks better with 52 -- */
++ /* MS ClearType Rasterizer supposedly uses 32 */
++ minimum_distance_factor = 64 - gridlines_per_pixel / 3;
++ }
++
++ else if ( CUR.GS.freeVector.y != 0 &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
++ gridlines_per_pixel = SPH_OPTION_GRIDLINES_PER_PIXEL_Y;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+@@ -6237,6 +6658,10 @@
+ cvt_dist = 0;
+ else
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO )
++ cvt_dist = 0;
++#endif
+
+ /* single width test */
+
+@@ -6274,8 +6699,15 @@
+ if ( ( org_dist ^ cvt_dist ) < 0 )
+ cvt_dist = -cvt_dist;
+ }
+-
+- /* control value cutin and round */
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.GS.freeVector.y != 0 &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
++ {
++ if ( cur_dist < -64 ) cvt_dist -= 16;
++ else if ( cur_dist > 64 && cur_dist < 84) cvt_dist += 32;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++ /* control value cut-in and round */
+
+ if ( ( CUR.opcode & 4 ) != 0 )
+ {
+@@ -6296,18 +6728,21 @@
+ /* `ttinst2.doc', version 1.66, is thus incorrect since */
+ /* it implies `>=' instead of `>'. */
+
+- if ( FT_ABS( cvt_dist - org_dist ) > CUR.GS.control_value_cutin )
++ if ( FT_ABS( cvt_dist - org_dist ) >
++ CUR.GS.control_value_cutin / gridlines_per_pixel )
+ cvt_dist = org_dist;
+ }
+
+ distance = CUR_Func_round(
+ cvt_dist,
+- CUR.tt_metrics.compensations[CUR.opcode & 3] );
++ CUR.tt_metrics.compensations[CUR.opcode & 3],
++ gridlines_per_pixel );
+ }
+ else
+ distance = ROUND_None(
+ cvt_dist,
+- CUR.tt_metrics.compensations[CUR.opcode & 3] );
++ CUR.tt_metrics.compensations[CUR.opcode & 3],
++ gridlines_per_pixel );
+
+ /* minimum distance test */
+
+@@ -6315,18 +6750,63 @@
+ {
+ if ( org_dist >= 0 )
+ {
+- if ( distance < CUR.GS.minimum_distance )
+- distance = CUR.GS.minimum_distance;
++ if ( distance < FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 ) )
++ distance = FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 );
+ }
+ else
+ {
+- if ( distance > -CUR.GS.minimum_distance )
+- distance = -CUR.GS.minimum_distance;
++ if ( distance > -FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 ) )
++ distance = -FT_MulDiv( minimum_distance_factor,
++ CUR.GS.minimum_distance, 64 );
+ }
+ }
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ B1 = CUR.zp1.cur[point].y;
++
++ /* Round moves if necessary */
++ if ( CUR.ignore_x_mode &&
++ CUR.GS.freeVector.y != 0 &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
++ distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
++
++ if ( CUR.GS.freeVector.y != 0 &&
++ ( CUR.opcode & 16 ) == 0 &&
++ ( CUR.opcode & 8 ) == 0 &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
++ distance +=64;
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ B2 = CUR.zp1.cur[point].y;
++
++ /* Reverse move if necessary */
++ if ( CUR.ignore_x_mode )
++ {
++ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
++ CUR.GS.freeVector.y != 0 && B1 % 64 == 0 && B2 % 64 != 0 )
++ reverse_move = TRUE;
++
++ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
++ CUR.GS.freeVector.y != 0 && B2 % 64 != 0 && B1 % 64 != 0 )
++ reverse_move = TRUE;
++
++ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) &&
++ !reverse_move &&
++ abs ( B1 - B2 ) >= 64 )
++ reverse_move = TRUE;
++ }
++
++ if ( reverse_move )
++ CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
++
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ Fail:
+ CUR.GS.rp1 = CUR.GS.rp0;
+
+@@ -6350,8 +6830,14 @@
+ FT_F26Dot6 distance;
+
+ FT_UNUSED_ARG;
+-
+-
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode && CUR.iup_called &&
++ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
++ {
++ CUR.error = TT_Err_Invalid_Reference;
++ goto Fail;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ if ( CUR.top < CUR.GS.loop ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+@@ -6846,6 +7332,15 @@
+ contour = 0;
+ point = 0;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ CUR.iup_called = 1;
++ if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
++ return;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ do
+ {
+ end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
+@@ -6915,7 +7410,9 @@
+ FT_UShort A;
+ FT_ULong C;
+ FT_Long B;
+-
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ FT_UShort B1, B2;
++#endif
+
+ #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
+ /* Delta hinting is covered by US Patent 5159668. */
+@@ -6988,7 +7485,67 @@
+ B++;
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /*
++ * Allow delta move if
++ *
++ * - not using ignore_x_mode rendering
++ * - glyph is specifically set to allow it
++ * - glyph is composite and freedom vector is not subpixel vector
++ */
++ if ( !CUR.ignore_x_mode ||
++ ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
++ ( CUR.is_composite && CUR.GS.freeVector.y != 0 ))
++ CUR_Func_move( &CUR.zp0, A, B );
++
++ /* Otherwise apply subpixel hinting and compatibility mode rules */
++ else if ( CUR.ignore_x_mode )
++ {
++ if ( CUR.GS.freeVector.y != 0 )
++ B1 = CUR.zp0.cur[A].y;
++ else
++ B1 = CUR.zp0.cur[A].x;
++
++ /* Standard Subpixel Hinting: Allow y move */
++ if ( !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
++ CUR_Func_move( &CUR.zp0, A, B );
++
++ /* Compatibility Mode: Allow x or y move if point touched in
++ Y direction */
++ else if ( CUR.compatibility_mode &&
++ !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ))
++ {
++ /* save the y value of the point now; compare after move */
++ B1 = CUR.zp0.cur[A].y;
++
++ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
++ B = FT_PIX_ROUND( B1 + B ) - B1;
++
++ /*
++ * Allow delta move if using compatibility_mode, IUP has not
++ * been called, and point is touched on Y.
++ */
++ if ( !CUR.iup_called &&
++ ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
++ CUR_Func_move( &CUR.zp0, A, B );
++ }
++ B2 = CUR.zp0.cur[A].y;
++
++ /* Reverse this move if it results in a disallowed move */
++ if ( CUR.GS.freeVector.y != 0 &&
++ ( ( ( CUR.sph_tweak_flags &
++ SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
++ B1 % 64 == 0 &&
++ B2 % 64 != 0 ) ||
++ ( ( CUR.sph_tweak_flags &
++ SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
++ B1 % 64 != 0 &&
++ B2 % 64 != 0 )))
++ CUR_Func_move( &CUR.zp0, A, -B );
++ }
++#else
+ CUR_Func_move( &CUR.zp0, A, B );
++#endif /* *TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ }
+ }
+ else
+@@ -7114,26 +7671,116 @@
+ Ins_GETINFO( INS_ARG )
+ {
+ FT_Long K;
+-
+-
+ K = 0;
+
+- /* We return MS rasterizer version 1.7 for the font scaler. */
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ /********************************/
++ /* RASTERIZER VERSION */
++ /* Selector Bit: 0 */
++ /* Return Bit(s): 0-7 */
++ /* */
++ if ( ( args[0] & 1 ) != 0 && CUR.ignore_x_mode )
++ {
++ K = CUR.rasterizer_version;
++#ifdef SPH_DEBUG_MORE_VERBOSE
++ printf(" SETTING AS %d\n", CUR.rasterizer_version );
++#endif
++ }
++ else
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ if ( ( args[0] & 1 ) != 0 )
+ K = 35;
+
+- /* Has the glyph been rotated? */
++ /********************************/
++ /* GLYPH ROTATED */
++ /* Selector Bit: 1 */
++ /* Return Bit(s): 8 */
++ /* */
+ if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
+ K |= 0x80;
+
+- /* Has the glyph been stretched? */
++ /********************************/
++ /* GLYPH STRETCHED */
++ /* Selector Bit: 2 */
++ /* Return Bit(s): 9 */
++ /* */
+ if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
+ K |= 1 << 8;
+
+- /* Are we hinting for grayscale? */
++ /********************************/
++ /* HINTING FOR GRAYSCALE */
++ /* Selector Bit: 5 */
++ /* Return Bit(s): 12 */
++ /* */
+ if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
+ K |= 1 << 12;
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode && CUR.rasterizer_version >= 35 )
++ {
++ /********************************/
++ /* HINTING FOR GRAYSCALE */
++ /* Selector Bit: 5 */
++ /* Return Bit(s): 12 */
++ /* */
++ if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting )
++ K |= 1 << 12;
++
++ /********************************/
++ /* HINTING FOR SUBPIXEL */
++ /* Selector Bit: 6 */
++ /* Return Bit(s): 13 */
++ /* */
++ if ( ( args[0] & 64 ) != 0 &&
++ CUR.subpixel_hinting &&
++ CUR.rasterizer_version >= 37 )
++ {
++ K |= 1 << 13;
++
++ /* the stuff below is irrelevant if subpixel_hinting is not set */
++
++ /********************************/
++ /* COMPATIBLE WIDTHS ENABLED */
++ /* Selector Bit: 7 */
++ /* Return Bit(s): 14 */
++ /* */
++ /* Functionality still needs to be added */
++ if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths )
++ K |= 1 << 14;
++
++ /********************************/
++ /* SYMMETRICAL SMOOTHING */
++ /* Selector Bit: 8 */
++ /* Return Bit(s): 15 */
++ /* */
++ /* Functionality still needs to be added */
++ if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )
++ K |= 1 << 15;
++
++ /********************************/
++ /* HINTING FOR BGR? */
++ /* Selector Bit: 9 */
++ /* Return Bit(s): 16 */
++ /* */
++ /* Functionality still needs to be added */
++ if ( ( args[0] & 512 ) != 0 && CUR.bgr )
++ K |= 1 << 16;
++
++ if ( CUR.rasterizer_version >= 38 )
++ {
++
++ /********************************/
++ /* SUBPIXEL POSITIONED? */
++ /* Selector Bit: 10 */
++ /* Return Bit(s): 17 */
++ /* */
++ /* Functionality still needs to be added */
++ if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned )
++ K |= 1 << 17;
++ }
++ }
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ args[0] = K;
+ }
+
+@@ -7509,6 +8156,15 @@
+ cur = *exc;
+ #endif
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ if ( CUR.ignore_x_mode )
++ {
++ /* ensure some variables are set for this run */
++ CUR.iup_called = FALSE;
++ CUR.in_delta_function = FALSE;
++ }
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ /* set CVT functions */
+ CUR.tt_metrics.ratio = 0;
+ if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
+@@ -7780,7 +8436,13 @@
+ break;
+
+ case 0x2B: /* CALL */
+- Ins_CALL( EXEC_ARG_ args );
++#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 );
+ break;
+
+ case 0x2C: /* FDEF */
+@@ -7799,6 +8461,9 @@
+
+ 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 );
+ break;
+
+@@ -7958,6 +8623,12 @@
+ 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 );
+ break;
+
+diff -Nur freetype-orig/src/truetype/ttinterp.h freetype-subpixel/src/truetype/ttinterp.h
+--- freetype-orig/src/truetype/ttinterp.h 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/src/truetype/ttinterp.h 2012-06-16 10:31:58.279833085 -0500
+@@ -68,7 +68,8 @@
+ /* Rounding function */
+ typedef FT_F26Dot6
+ (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance,
+- FT_F26Dot6 compensation );
++ FT_F26Dot6 compensation,
++ FT_Int resolution );
+
+ /* Point displacement along the freedom vector routine */
+ typedef void
+@@ -107,6 +108,44 @@
+ } TT_CallRec, *TT_CallStack;
+
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++ /*************************************************************************/
++ /* */
++ /* This structure defines a rule used to tweak subpixel hinting for */
++ /* various fonts. "", 0, "", NULL value indicates to match any value. */
++ /* */
++
++ typedef struct SPH_TweakRule_
++ {
++ const char family[32];
++ const int ppem;
++ const char style[32];
++ const FT_ULong glyph;
++
++ } SPH_TweakRule;
++
++
++ typedef struct SPH_ScaleRule_
++ {
++ const char family[32];
++ const int ppem;
++ const char style[32];
++ const FT_ULong glyph;
++ const float scale;
++ } SPH_ScaleRule;
++
++#define MAX_CLASS_MEMBERS 100
++
++ typedef struct Font_Class_
++ {
++ const char name[32];
++ const char member[MAX_CLASS_MEMBERS][32];
++ } Font_Class;
++
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
++
+ /*************************************************************************/
+ /* */
+ /* The main structure for the interpreter which collects all necessary */
+@@ -218,6 +257,37 @@
+
+ FT_Bool grayscale; /* are we hinting for grayscale? */
+
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++ TT_Round_Func func_round_sphn; /* subpixel rounding function */
++
++ FT_Bool grayscale_hinting; /* Using grayscale hinting? */
++ FT_Bool subpixel_hinting; /* Using subpixel hinting? */
++ FT_Bool native_hinting; /* Using native hinting? */
++ FT_Bool ignore_x_mode; /* Standard rendering mode for */
++ /* subpixel hinting. On if gray */
++ /* or subpixel hinting is on ) */
++ FT_Bool compatibility_mode;/* Additional exceptions to */
++ /* native TT rules for legacy */
++ /* fonts. Implies ignore_x_mode. */
++
++ /* The following 3 aren't fully implemented but here for MS rasterizer */
++ /* compatibility. */
++ FT_Bool compatible_widths; /* compatible widths? */
++ FT_Bool symmetrical_smoothing;/* symmetrical_smoothing? */
++ FT_Bool bgr; /* bgr instead of rgb? */
++ FT_Bool subpixel_positioned; /* MS DW subpixel positioned */
++
++ FT_Int rasterizer_version; /* MS rasterizer version */
++
++ FT_Bool iup_called; /* IUP called for glyph? */
++ FT_Bool in_delta_function; /* inside an inline delta func? */
++
++ FT_ULong sph_tweak_flags; /* flags to control hint tweaks */
++
++ FT_Int num_delta_funcs;
++ FT_ULong inline_delta_funcs[5];
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
+ } TT_ExecContextRec;
+
+
+diff -Nur freetype-orig/src/truetype/ttobjs.h freetype-subpixel/src/truetype/ttobjs.h
+--- freetype-orig/src/truetype/ttobjs.h 2012-06-14 00:35:58.000000000 -0500
++++ freetype-subpixel/src/truetype/ttobjs.h 2012-06-15 07:31:12.163985155 -0500
+@@ -178,6 +178,7 @@
+ FT_Long end; /* where does it end? */
+ FT_UInt opc; /* function #, or instruction code */
+ FT_Bool active; /* is it active? */
++ FT_Bool inline_delta; /* is function that defines inline delta? */
+
+ } TT_DefRecord, *TT_DefArray;
+
+@@ -190,7 +191,7 @@
+ {
+ FT_Fixed xx, xy; /* transformation matrix coefficients */
+ FT_Fixed yx, yy;
+- FT_F26Dot6 ox, oy; /* offsets */
++ FT_F26Dot6 ox, oy; /* offsets */
+
+ } TT_Transform;
+
+diff -Nur freetype-orig/src/truetype/ttsubpix.c freetype-subpixel/src/truetype/ttsubpix.c
+--- freetype-orig/src/truetype/ttsubpix.c 1969-12-31 18:00:00.000000000 -0600
++++ freetype-subpixel/src/truetype/ttsubpix.c 2012-06-16 10:32:09.670447034 -0500
+@@ -0,0 +1,261 @@
++/***************************************************************************/
++/* */
++/* ttsubpix.c */
++/* */
++/* TrueType Subpixel Hinting. */
++/* */
++/* Copyright 2010-2011 by */
++/* David Turner, Robert Wilhelm, and Werner Lemberg. */
++/* */
++/* This file is part of the FreeType project, and may only be used, */
++/* modified, and distributed under the terms of the FreeType project */
++/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
++/* this file you indicate that you have read the license and */
++/* understand and accept it fully. */
++/* */
++/***************************************************************************/
++
++#include <ft2build.h>
++#include FT_INTERNAL_DEBUG_H
++#include FT_INTERNAL_CALC_H
++#include FT_INTERNAL_STREAM_H
++#include FT_INTERNAL_SFNT_H
++#include FT_TRUETYPE_TAGS_H
++#include FT_OUTLINE_H
++
++#include "ttsubpix.h"
++
++
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++ FT_LOCAL_DEF( FT_Bool )
++ is_member_of_family_class( const FT_String* detected_font_name,
++ const FT_String* rule_font_name )
++ {
++ FT_UInt i, j;
++
++ /* If font name matches rule family */
++ if ( strcmp( detected_font_name, rule_font_name ) == 0 ) return TRUE;
++
++ /* If font name is a wildcard "" */
++ if ( strcmp( rule_font_name, "" ) == 0 ) return TRUE;
++
++ /* If font name is contained in a class list */
++ for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ )
++ {
++ if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 )
++ {
++ for ( j = 0; j < MAX_CLASS_MEMBERS; j++ )
++ {
++ if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 )
++ continue;
++ if ( strcmp( FAMILY_CLASS_Rules[i].member[j], detected_font_name ) == 0 )
++ return TRUE;
++ }
++ }
++ }
++ return FALSE;
++ }
++
++
++ FT_LOCAL_DEF( FT_Bool )
++ is_member_of_style_class( const FT_String* detected_font_style,
++ const FT_String* rule_font_style )
++ {
++ FT_UInt i, j;
++
++ /* If font style matches rule style */
++ if ( strcmp( detected_font_style, rule_font_style ) == 0 ) return TRUE;
++
++ /* If font style is a wildcard "" */
++ if ( strcmp( rule_font_style, "" ) == 0 ) return TRUE;
++
++ /* If font style is contained in a class list */
++ for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ )
++ {
++ if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 )
++ {
++ for ( j = 0; j < MAX_CLASS_MEMBERS; j++ )
++ {
++ if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 )
++ continue;
++ if ( strcmp( STYLE_CLASS_Rules[i].member[j], detected_font_style ) == 0 )
++ return TRUE;
++ }
++ }
++ }
++ return FALSE;
++ }
++
++
++ FT_LOCAL_DEF( FT_Bool )
++ sph_test_tweak( TT_Face face,
++ FT_String* family,
++ int ppem,
++ FT_String* style,
++ FT_UInt glyph_index,
++ SPH_TweakRule* rule,
++ FT_UInt num_rules )
++ {
++ FT_UInt i;
++
++
++ /* rule checks may be able to be optimized further */
++ for ( i = 0; i < num_rules; i++ )
++ {
++ if ( family &&
++ ( is_member_of_family_class ( family, rule[i].family ) ) )
++ if ( rule[i].ppem == 0 ||
++ rule[i].ppem == ppem )
++ if ( style &&
++ is_member_of_style_class ( style, rule[i].style ) )
++ if ( rule[i].glyph == 0 ||
++ FT_Get_Char_Index( (FT_Face)face,
++ rule[i].glyph ) == glyph_index )
++ return TRUE;
++ }
++ return FALSE;
++ }
++
++
++ FT_LOCAL_DEF( float )
++ scale_test_tweak( TT_Face face,
++ FT_String* family,
++ int ppem,
++ FT_String* style,
++ FT_UInt glyph_index,
++ SPH_ScaleRule* rule,
++ FT_UInt num_rules )
++ {
++ FT_UInt i;
++
++
++ /* rule checks may be able to be optimized further */
++ for ( i = 0; i < num_rules; i++ )
++ {
++ if ( family &&
++ ( is_member_of_family_class ( family, rule[i].family ) ) )
++ if ( rule[i].ppem == 0 ||
++ rule[i].ppem == ppem )
++ if ( style &&
++ is_member_of_style_class( style, rule[i].style ) )
++ if ( rule[i].glyph == 0 ||
++ FT_Get_Char_Index( (FT_Face)face,
++ rule[i].glyph ) == glyph_index )
++ return rule[i].scale;
++ }
++ return 1.0;
++ }
++
++#define TWEAK_RULES( x ) \
++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
++ x##_Rules, x##_RULES_SIZE ) ) \
++ loader->exec->sph_tweak_flags |= SPH_TWEAK_##x;
++
++#define TWEAK_RULES_EXCEPTIONS( x ) \
++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
++ x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
++ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x;
++
++ FT_LOCAL_DEF( void )
++ sph_set_tweaks( TT_Loader loader,
++ FT_UInt glyph_index )
++ {
++ TT_Face face = (TT_Face)loader->face;
++ FT_String* family = face->root.family_name;
++ int ppem = loader->size->metrics.x_ppem;
++ FT_String* style = face->root.style_name;
++
++ /* Don't apply rules if style isn't set */
++ if ( !face->root.style_name ) return;
++
++#ifdef SPH_DEBUG_MORE_VERBOSE
++ printf( "%s,%d,%s,%c=%d ", family, ppem, style, glyph_index, glyph_index );
++#endif
++
++ TWEAK_RULES( PIXEL_HINTING );
++
++ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING )
++ {
++ loader->exec->ignore_x_mode = FALSE;
++ return;
++ }
++
++ 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 );
++ TWEAK_RULES( NORMAL_ROUND );
++ TWEAK_RULES( NO_ALIGNRP_AFTER_IUP );
++ 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 );
++ TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
++
++ TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
++ TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
++
++ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
++ {
++ if ( loader->exec->rasterizer_version != 35 )
++ {
++ loader->exec->rasterizer_version = 35;
++ /* must re-execute fpgm */
++ loader->exec->size->cvt_ready = FALSE;
++ tt_size_ready_bytecode( loader->exec->size,
++ FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
++ }
++ }
++ else
++ {
++ if ( loader->exec->rasterizer_version == 35 )
++ {
++ loader->exec->rasterizer_version = 37;
++ /* must re-execute fpgm */
++ loader->exec->size->cvt_ready = FALSE;
++ tt_size_ready_bytecode( loader->exec->size,
++ FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
++ }
++ }
++
++ if ( IS_HINTED( loader->load_flags ) )
++ {
++ TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
++ TWEAK_RULES( COURIER_NEW_2_HACK );
++ }
++
++ if ( sph_test_tweak( face, family, ppem, style, glyph_index,
++ COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
++ {
++ loader->exec->compatibility_mode |= TRUE;
++ loader->exec->ignore_x_mode |= TRUE;
++ }
++ else
++ loader->exec->compatibility_mode &= FALSE;
++
++ if ( IS_HINTED( loader->load_flags ) )
++ {
++ if ( sph_test_tweak( face, family, ppem, style, glyph_index,
++ COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
++ loader->exec->compatible_widths |= TRUE;
++ }
++ }
++
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
++
++/* END */
+diff -Nur freetype-orig/src/truetype/ttsubpix.h freetype-subpixel/src/truetype/ttsubpix.h
+--- freetype-orig/src/truetype/ttsubpix.h 1969-12-31 18:00:00.000000000 -0600
++++ freetype-subpixel/src/truetype/ttsubpix.h 2012-06-16 10:30:26.121956142 -0500
+@@ -0,0 +1,778 @@
++/***************************************************************************/
++/* */
++/* ttsubpix.h */
++/* */
++/* TrueType Subpixel Hinting. */
++/* */
++/* Copyright 2010-2011 by */
++/* David Turner, Robert Wilhelm, and Werner Lemberg. */
++/* */
++/* This file is part of the FreeType project, and may only be used, */
++/* modified, and distributed under the terms of the FreeType project */
++/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
++/* this file you indicate that you have read the license and */
++/* understand and accept it fully. */
++/* */
++/***************************************************************************/
++
++#ifndef __TTSUBPIX_H__
++#define __TTSUBPIX_H__
++
++#include <ft2build.h>
++#include "ttobjs.h"
++#include "ttinterp.h"
++
++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
++
++ /*************************************************************************/
++ /* */
++ /* Tweak flags that are set for each glyph by the below rules */
++ /* */
++ /* */
++#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
++
++
++ FT_LOCAL( FT_Bool )
++ sph_test_tweak( TT_Face face,
++ FT_String* family,
++ int ppem,
++ FT_String* style,
++ FT_UInt glyph_index,
++ SPH_TweakRule* rule,
++ FT_UInt num_rules );
++
++ FT_LOCAL_DEF( float )
++ scale_test_tweak( TT_Face face,
++ FT_String* family,
++ int ppem,
++ FT_String* style,
++ FT_UInt glyph_index,
++ SPH_ScaleRule* rule,
++ FT_UInt num_rules );
++
++ FT_LOCAL( void )
++ sph_set_tweaks( TT_Loader loader,
++ FT_UInt glyph_index );
++
++
++ /*************************************************************************/
++ /* */
++ /* These rules affect how the TT Interpreter does hinting, with the */
++ /* goal of doing subpixel hinting by (in general) ignoring x moves. */
++ /* Some of these rules are fixes that go above and beyond the */
++ /* stated techniques in the MS whitepaper on Cleartype, due to */
++ /* artifacts in many glyphs. So, these rules make some glyphs render */
++ /* better than they do in the MS rasterizer. */
++ /* */
++ /* "" string or 0 int/char indicates to apply to all glyphs. */
++ /* "-" used as dummy placeholders, but any non-matching string works. */
++ /* */
++ /* Some of this could arguably be implemented in fontconfig, however: */
++ /* */
++ /* - Fontconfig can't set things on a glyph-by-glyph basis. */
++ /* - The tweaks that happen here are very low-level, from an average */
++ /* user's point of view and are best implemented in the hinter */
++ /* */
++ /* The goal is to make the subpixel hinting techniques as generalized */
++ /* as possible across all fonts to prevent the need for extra rules such */
++ /* as these. */
++ /* */
++ /* The rule structure is designed so that entirely new rules can easily */
++ /* be added when a new compatibility feature is discovered. */
++ /* */
++ /* The rule structures could also use some enhancement to handle ranges. */
++ /* */
++ /* ****************** WORK IN PROGRESS ******************* */
++ /* */
++
++#define SPH_OPTION_BITMAP_WIDTHS FALSE
++#define SPH_OPTION_SET_SUBPIXEL TRUE
++#define SPH_OPTION_SET_GRAYSCALE FALSE
++#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE
++#define SPH_OPTION_SET_RASTERIZER_VERSION 37
++#define SPH_OPTION_GRIDLINES_PER_PIXEL_X 64
++#define SPH_OPTION_GRIDLINES_PER_PIXEL_Y 1
++
++#define MAX_CLASS_MEMBERS 100
++
++/* Define this to force natural (i.e. not bitmap-compatible) widths. */
++/* The default leans strongly towards natural widths except for a few */
++/* legacy fonts where a selective combination produces nicer results. */
++/* #define FORCE_NATURAL_WIDTHS */
++
++
++ /* These are "classes" of fonts that can be grouped together and used in */
++ /* rules below. A blank entry "" is required at the end of these! */
++#define FAMILY_CLASS_RULES_SIZE 7
++ Font_Class FAMILY_CLASS_Rules
++ [FAMILY_CLASS_RULES_SIZE] =
++ {
++ { "MS Legacy Fonts", { "Aharoni",
++ "Andale Mono",
++ "Andalus",
++ "Angsana New",
++ "AngsanaUPC",
++ "Arabic Transparent",
++ "Arial Black",
++ "Arial Narrow",
++ "Arial Unicode MS",
++ "Arial",
++ "Batang",
++ "Browallia New",
++ "BrowalliaUPC",
++ "Comic Sans MS",
++ "Cordia New",
++ "CordiaUPC",
++ "Courier New",
++ "DFKai-SB",
++ "David Transparent",
++ "David",
++ "DilleniaUPC",
++ "Estrangelo Edessa",
++ "EucrosiaUPC",
++ "FangSong_GB2312",
++ "Fixed Miriam Transparent",
++ "FrankRuehl",
++ "Franklin Gothic Medium",
++ "FreesiaUPC",
++ "Garamond",
++ "Gautami",
++ "Georgia",
++ "Gulim",
++ "Impact",
++ "IrisUPC",
++ "JasmineUPC",
++ "KaiTi_GB2312",
++ "KodchiangUPC",
++ "Latha",
++ "Levenim MT",
++ "LilyUPC",
++ "Lucida Console",
++ "Lucida Sans Unicode",
++ "MS Gothic",
++ "MS Mincho",
++ "MV Boli",
++ "Mangal",
++ "Marlett",
++ "Microsoft Sans Serif",
++ "Mingliu",
++ "Miriam Fixed",
++ "Miriam Transparent",
++ "Miriam",
++ "Narkisim",
++ "Palatino Linotype",
++ "Raavi",
++ "Rod Transparent",
++ "Rod",
++ "Shruti",
++ "SimHei",
++ "Simplified Arabic Fixed",
++ "Simplified Arabic",
++ "Simsun",
++ "Sylfaen",
++ "Symbol",
++ "Tahoma",
++ "Times New Roman",
++ "Traditional Arabic",
++ "Trebuchet MS",
++ "Tunga",
++ "Verdana",
++ "Webdings",
++ "Wingdings", "", }, },
++ { "Core MS Legacy Fonts", { "Arial Black",
++ "Arial Narrow",
++ "Arial Unicode MS",
++ "Arial",
++ "Comic Sans MS",
++ "Courier New",
++ "Garamond",
++ "Georgia",
++ "Impact",
++ "Lucida Console",
++ "Lucida Sans Unicode",
++ "Microsoft Sans Serif",
++ "Palatino Linotype",
++ "Tahoma",
++ "Times New Roman",
++ "Trebuchet MS",
++ "Verdana", "", }, },
++ { "Apple Legacy Fonts", { "Geneva",
++ "Times",
++ "Monaco",
++ "Century",
++ "Chalkboard",
++ "Lobster",
++ "Century Gothic",
++ "Optima",
++ "Lucida Grande",
++ "Gill Sans",
++ "Baskerville",
++ "Helvetica",
++ "Helvetica Neue", "", }, },
++ { "Legacy Sans Fonts", { "Andale Mono",
++ "Arial Unicode MS",
++ "Arial",
++ "Century Gothic",
++ "Comic Sans MS",
++ "Franklin Gothic Medium",
++ "Geneva",
++ "Lucida Console",
++ "Lucida Grande",
++ "Lucida Sans Unicode",
++ "Microsoft Sans Serif",
++ "Monaco",
++ "Tahoma",
++ "Trebuchet MS",
++ "Verdana", "", }, },
++ { "Misc Legacy Fonts", { "Dark Courier", "", }, },
++ { "Verdana Clones", { "DejaVu Sans",
++ "Bitstream Vera Sans", "", }, },
++ { "Verdana and Clones", { "DejaVu Sans",
++ "Bitstream Vera Sans",
++ "Verdana", "", }, },
++};
++
++
++ /* Define "classes" of styles that can be grouped together and used in */
++ /* rules below. A blank entry "" is required at the end of these! */
++#define STYLE_CLASS_RULES_SIZE 5
++ Font_Class STYLE_CLASS_Rules
++ [STYLE_CLASS_RULES_SIZE] =
++ {
++ { "Regular Class", { "Regular",
++ "Book",
++ "Medium",
++ "Roman",
++ "Normal", "", }, },
++ { "Regular/Italic Class", { "Regular",
++ "Book",
++ "Medium",
++ "Italic",
++ "Oblique",
++ "Roman",
++ "Normal", "", }, },
++ { "Bold/BoldItalic Class", { "Bold",
++ "Bold Italic",
++ "Black", "", }, },
++ { "Bold/Italic/BoldItalic Class", { "Bold",
++ "Bold Italic",
++ "Black",
++ "Italic",
++ "Oblique", "", }, },
++ { "Regular/Bold Class", { "Regular",
++ "Book",
++ "Medium",
++ "Normal",
++ "Roman",
++ "Bold",
++ "Black", "", }, },
++ };
++
++
++
++ /* Special fixes for known legacy fonts */
++ /* This is the primary workhorse rule for legacy fonts */
++#define COMPATIBILITY_MODE_RULES_SIZE 4
++ SPH_TweakRule COMPATIBILITY_MODE_Rules
++ [COMPATIBILITY_MODE_RULES_SIZE] =
++ {
++ { "MS Legacy Fonts", 0, "", 0 },
++ { "Apple Legacy Fonts", 0, "", 0 },
++ { "Misc Legacy Fonts", 0, "", 0 },
++ { "Verdana Clones", 0, "", 0 },
++ };
++
++
++ /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting */
++#define PIXEL_HINTING_RULES_SIZE 4
++ SPH_TweakRule PIXEL_HINTING_Rules
++ [PIXEL_HINTING_RULES_SIZE] =
++ {
++ /* These characters are almost always safe */
++ { "", 0, "", '<' },
++ { "", 0, "", '>' },
++ /* Fixes the vanishing stem */
++ { "Times New Roman", 0, "Bold", 'A' },
++ { "Times New Roman", 0, "Bold", 'V' },
++ };
++
++
++ /* 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
++ SPH_TweakRule SKIP_INLINE_DELTAS_Rules
++ [SKIP_INLINE_DELTAS_RULES_SIZE] =
++ {
++ { "-", 0, "", 0 },
++ };
++
++
++ /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */
++#define DO_SHPIX_RULES_SIZE 1
++ SPH_TweakRule DO_SHPIX_Rules
++ [DO_SHPIX_RULES_SIZE] =
++ {
++ { "-", 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_RULES_SIZE 8
++ 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' },
++ /* Fix thin middle stems */
++ { "Core MS Legacy Fonts", 0, "Regular/Bold Class", 'N' },
++ { "Lucida Grande", 0, "", 'N' },
++ { "Legacy Sans Fonts", 0, "", L'и' },
++ { "Verdana Clones", 0, "",'N' },
++ { "Ubuntu", 0, "Regular Class", 'N' },
++ /* Fix misshapen x */
++ { "Verdana", 0, "Bold", 'x' },
++ };
++
++#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 4
++ 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' },
++ };
++
++
++
++ /* Skip Y moves that move a point off a Y pixel boundary */
++ /* This fixes Tahoma, Trebuchet oddities and some issues with `$' */
++#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 5
++ SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules
++ [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
++ {
++ { "MS Legacy Fonts", 0, "", 0 },
++ { "Apple Legacy Fonts", 0, "", 0 },
++ { "Misc Legacy Fonts", 0, "", 0 },
++ { "Ubuntu", 0, "Regular Class", 0 },
++ { "Verdana Clones", 0, "", 0 },
++ };
++
++
++#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
++ SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
++ [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
++ {
++ { "-", 0, "", 0 },
++ };
++
++
++ /* Round moves that don't move a point to a Y pixel boundary */
++#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 3
++ SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules
++ [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
++ {
++ /* Droid font instructions don't snap Y to pixels */
++ { "Droid Sans", 0, "Regular/Italic Class", 0 },
++ { "Droid Sans Mono", 0, "", 0 },
++ { "Ubuntu", 0, "", 0 },
++ };
++
++#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 3
++ SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
++ [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
++ {
++ { "Droid Sans", 12, "Bold", 0 },
++ { "Droid Sans", 13, "Bold", 0 },
++ { "Droid Sans", 16, "Bold", 0 },
++ };
++
++ /* Allow a Direct_Move_X along X freedom vector if matched */
++#define ALLOW_X_DMOVEX_RULES_SIZE 2
++ SPH_TweakRule ALLOW_X_DMOVEX_Rules
++ [ALLOW_X_DMOVEX_RULES_SIZE] =
++ {
++ /* Creates a more consistent appearance for these */
++ { "Arial", 13, "Regular", 'e' },
++ { "Arial", 13, "Regular", 'o' },
++ };
++
++ /* Allow a Direct_Move along X freedom vector if matched */
++#define ALLOW_X_DMOVE_RULES_SIZE 3
++ SPH_TweakRule ALLOW_X_DMOVE_Rules
++ [ALLOW_X_DMOVE_RULES_SIZE] =
++ {
++ /* Creates a more consistent appearance for these */
++ { "Arial", 13, "Regular", 'e' },
++ { "Arial", 13, "Regular", 'o' },
++ /* Fixes vanishing diagonal in 4 */
++ { "Verdana", 0, "Regular", '4' },
++ };
++
++ /* 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
++ 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
++ SPH_TweakRule RASTERIZER_35_Rules
++ [RASTERIZER_35_RULES_SIZE] =
++ {
++ /* This seems to be the only way to make these look good */
++ { "Times New Roman", 0, "Regular", 'i' },
++ { "Times New Roman", 0, "Regular", 'j' },
++ { "Times New Roman", 0, "Regular", 'm' },
++ { "Times New Roman", 0, "Regular", 'r' },
++ { "Times New Roman", 0, "Regular", 'a' },
++ { "Times New Roman", 0, "Regular", 'n' },
++ { "Times New Roman", 0, "Regular", 'p' },
++ { "Times", 0, "", 0 },
++ };
++
++ /* Don't round to the subpixel grid. Round to pixel grid. */
++#define NORMAL_ROUND_RULES_SIZE 2
++ SPH_TweakRule NORMAL_ROUND_Rules
++ [NORMAL_ROUND_RULES_SIZE] =
++ {
++ /* Fix point "explosions" */
++ { "Courier New", 0, "", 0 },
++ { "Verdana", 10, "Regular", '4' },
++ };
++
++ /* Skip IUP instructions if matched */
++#define SKIP_IUP_RULES_SIZE 1
++ SPH_TweakRule SKIP_IUP_Rules
++ [SKIP_IUP_RULES_SIZE] =
++ {
++ { "Arial", 13, "Regular", 'a' },
++ };
++
++ /* Skip MIAP Twilight hack if matched */
++#define MIAP_HACK_RULES_SIZE 1
++ SPH_TweakRule MIAP_HACK_Rules
++ [MIAP_HACK_RULES_SIZE] =
++ {
++ { "Geneva", 12, "", 0 },
++ };
++
++ /* Skip DELTAP instructions if matched */
++#define ALWAYS_SKIP_DELTAP_RULES_SIZE 13
++ SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
++ [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
++ {
++ { "Georgia", 0, "Regular", 'k' },
++ /* fixes problems with W M w */
++ { "Trebuchet MS", 0, "Italic", 0 },
++ { "Trebuchet MS", 14, "Regular", 'e' },
++ { "Arial", 11, "Regular", 's' },
++ { "Verdana", 10, "Regular", 0 },
++ { "Verdana", 9, "Regular", 0 },
++ { "Legacy Sans Fonts", 0, "", L'й' },
++ { "Arial", 10, "Regular", '6' },
++ { "Arial", 0, "Bold/BoldItalic Class", 'a' },
++ /* Make horizontal stems consistent with the rest */
++ { "Arial", 24, "Bold", 's' },
++ { "Arial", 25, "Bold", 's' },
++ { "Arial", 24, "Bold", 'a' },
++ { "Arial", 25, "Bold", 'a' },
++ };
++
++ /* Always do DELTAP instructions if matched */
++#define ALWAYS_DO_DELTAP_RULES_SIZE 2
++ 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
++ 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
++ SPH_TweakRule MIRP_CVT_ZERO_Rules
++ [MIRP_CVT_ZERO_RULES_SIZE] =
++ {
++ { "Verdana", 0, "Regular", 0 },
++ };
++
++ /* Skip moves that meet or exceed 1 pixel */
++#define DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE 2
++ SPH_TweakRule DELTAP_SKIP_EXAGGERATED_VALUES_Rules
++ [DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE] =
++ {
++ /* Fix vanishing stems */
++ { "Ubuntu", 0, "Regular", 'M' },
++ /* Fix X at larger ppems */
++ { "Segoe UI", 0, "Light", 0 },
++ };
++
++ /* Don't allow ALIGNRP after IUP */
++#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 4
++ 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' },
++ };
++
++ /* Don't allow DELTAP after IUP */
++#define NO_DELTAP_AFTER_IUP_RULES_SIZE 2
++ SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules
++ [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
++ {
++ { "Arial", 0, "Bold", 'N' },
++ { "Verdana", 0, "Regular", '4' },
++ };
++
++ /* Don't allow CALL after IUP */
++#define NO_CALL_AFTER_IUP_RULES_SIZE 4
++ 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' },
++ };
++
++ /* De-embolden these glyphs slightly */
++#define DEEMBOLDEN_RULES_SIZE 9
++ SPH_TweakRule DEEMBOLDEN_Rules
++ [DEEMBOLDEN_RULES_SIZE] =
++ {
++ { "Courier New", 0, "Bold", 'A' },
++ { "Courier New", 0, "Bold", 'W' },
++ { "Courier New", 0, "Bold", 'w' },
++ { "Courier New", 0, "Bold", 'M' },
++ { "Courier New", 0, "Bold", 'X' },
++ { "Courier New", 0, "Bold", 'K' },
++ { "Courier New", 0, "Bold", 'x' },
++ { "Courier New", 0, "Bold", 'z' },
++ { "Courier New", 0, "Bold", 'v' },
++ };
++
++ /* Embolden these glyphs slightly */
++#define EMBOLDEN_RULES_SIZE 5
++ 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
++ 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
++ SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules
++ [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
++ {
++ { "Times New Roman", 16, "Italic", '2' },
++ { "Times New Roman", 16, "Italic", '5' },
++ { "Times New Roman", 16, "Italic", '7' },
++ { "Times New Roman", 16, "Regular", '2' },
++ { "Times New Roman", 16, "Regular", '5' },
++ { "Times New Roman", 16, "Regular", '7' },
++ { "Times New Roman", 17, "Italic", '2' },
++ { "Times New Roman", 17, "Italic", '5' },
++ { "Times New Roman", 17, "Italic", '7' },
++ { "Times New Roman", 17, "Regular", '2' },
++ { "Times New Roman", 17, "Regular", '5' },
++ { "Times New Roman", 17, "Regular", '7' },
++ };
++
++
++ /* This fudges distance on 2 to get rid of the vanishing stem issue. */
++ /* A real solution to this is certainly welcome. */
++#define COURIER_NEW_2_HACK_RULES_SIZE 15
++ SPH_TweakRule COURIER_NEW_2_HACK_Rules
++ [COURIER_NEW_2_HACK_RULES_SIZE] =
++ {
++ { "Courier New", 10, "Regular", '2' },
++ { "Courier New", 11, "Regular", '2' },
++ { "Courier New", 12, "Regular", '2' },
++ { "Courier New", 13, "Regular", '2' },
++ { "Courier New", 14, "Regular", '2' },
++ { "Courier New", 15, "Regular", '2' },
++ { "Courier New", 16, "Regular", '2' },
++ { "Courier New", 17, "Regular", '2' },
++ { "Courier New", 18, "Regular", '2' },
++ { "Courier New", 19, "Regular", '2' },
++ { "Courier New", 20, "Regular", '2' },
++ { "Courier New", 21, "Regular", '2' },
++ { "Courier New", 22, "Regular", '2' },
++ { "Courier New", 23, "Regular", '2' },
++ { "Courier New", 24, "Regular", '2' },
++ };
++
++
++#ifndef FORCE_NATURAL_WIDTHS
++
++ /* Use compatible widths with these glyphs. Compatible widths is always */
++ /* on when doing B/W TrueType instructing, but is used selectively here, */
++ /* typically on glyphs with 3 or more vertical stems. */
++#define COMPATIBLE_WIDTHS_RULES_SIZE 36
++ SPH_TweakRule COMPATIBLE_WIDTHS_Rules
++ [COMPATIBLE_WIDTHS_RULES_SIZE] =
++ {
++ { "Arial Unicode MS", 12, "Regular Class", 'm' },
++ { "Arial Unicode MS", 14, "Regular Class", 'm' },
++ { "Arial", 10, "Regular Class", L'ш' },
++ { "Arial", 11, "Regular Class", 'm' },
++ { "Arial", 12, "Regular Class", 'm' },
++ { "Arial", 12, "Regular Class", L'ш' },
++ { "Arial", 13, "Regular Class", L'ш' },
++ { "Arial", 14, "Regular Class", 'm' },
++ { "Arial", 14, "Regular Class", L'ш' },
++ { "Arial", 15, "Regular Class", L'ш' },
++ { "Arial", 17, "Regular Class", 'm' },
++ { "DejaVu Sans", 15, "Regular Class", 0 },
++ { "Microsoft Sans Serif", 11, "Regular Class", 0 },
++ { "Microsoft Sans Serif", 12, "Regular Class", 0 },
++ { "Segoe UI", 11, "Regular Class", 0 },
++ { "Segoe UI", 12, "Regular Class", 'm' },
++ { "Segoe UI", 14, "Regular Class", 'm' },
++ { "Tahoma", 11, "Regular Class", 0 },
++ { "Times New Roman", 16, "Regular Class", 'c' },
++ { "Times New Roman", 16, "Regular Class", 'm' },
++ { "Times New Roman", 16, "Regular Class", 'o' },
++ { "Times New Roman", 16, "Regular Class", 'w' },
++ { "Trebuchet MS", 12, "Regular Class", 0 },
++ { "Trebuchet MS", 14, "Regular Class", 0 },
++ { "Trebuchet MS", 15, "Regular Class", 0 },
++ { "Ubuntu", 12, "Regular Class", 'm' },
++ { "Verdana", 10, "Regular Class", L'ш' },
++ { "Verdana", 11, "Regular Class", L'ш' },
++ { "Verdana and Clones", 12, "Regular Class", 'm' },
++ { "Verdana and Clones", 12, "Regular Class", 'l' },
++ { "Verdana and Clones", 12, "Regular Class", 'i' },
++ { "Verdana and Clones", 12, "Regular Class", 'j' },
++ { "Verdana and Clones", 13, "Regular Class", 'l' },
++ { "Verdana and Clones", 13, "Regular Class", 'i' },
++ { "Verdana and Clones", 13, "Regular Class", 'j' },
++ { "Verdana and Clones", 14, "Regular Class", 'm' },
++ };
++
++
++ /* Scaling slightly in the x-direction prior to hinting results in */
++ /* more visually pleasing glyphs in certain cases. */
++ /* This sometimes needs to be coordinated with compatible width rules. */
++#define X_SCALING_RULES_SIZE 40
++ SPH_ScaleRule X_SCALING_Rules
++ [X_SCALING_RULES_SIZE] =
++ {
++ { "DejaVu Sans", 12, "Regular Class", 'm', .95 },
++ { "Verdana and Clones", 12, "Regular Class", 'a', 1.1 },
++ { "Arial", 11, "Regular Class", 'm', .975 },
++ { "Arial", 12, "Regular Class", 'm', 1.05 },
++ { "Arial", 13, "Regular Class", L'л', .95 },
++ { "Arial", 14, "Regular Class", 'm', .95 },
++ { "Arial", 15, "Regular Class", L'л', .925 },
++ { "Bitstream Vera Sans", 10, "Regular Class", 0, 1.1 },
++ { "Bitstream Vera Sans", 12, "Regular Class", 0, 1.05},
++ { "Bitstream Vera Sans", 16, "Regular Class", 0, 1.05 },
++ { "Bitstream Vera Sans", 9, "Regular Class", 0, 1.05},
++ { "DejaVu Sans", 12, "Regular Class", 'l', .975 },
++ { "DejaVu Sans", 12, "Regular Class", 'i', .975 },
++ { "DejaVu Sans", 12, "Regular Class", 'j', .975 },
++ { "DejaVu Sans", 13, "Regular Class", 'l', .95 },
++ { "DejaVu Sans", 13, "Regular Class", 'i', .95 },
++ { "DejaVu Sans", 13, "Regular Class", 'j', .95 },
++ { "DejaVu Sans", 10, "Regular Class", 0, 1.1 },
++ { "DejaVu Sans", 12, "Regular Class", 0, 1.05 },
++ { "Georgia", 10, "", 0, 1.05 },
++ { "Georgia", 11, "", 0, 1.1 },
++ { "Georgia", 12, "", 0, 1.025 },
++ { "Georgia", 13, "", 0, 1.05 },
++ { "Georgia", 16, "", 0, 1.05 },
++ { "Georgia", 17, "", 0, 1.03 },
++ { "Liberation Sans", 12, "Regular Class", 'm', 1.1 },
++ { "Lucida Grande", 11, "Regular Class", 'm', 1.1 },
++ { "Microsoft Sans Serif", 11, "Regular Class", 'm', .95 },
++ { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1.05 },
++ { "Segoe UI", 12, "Regular Class", 'H', 1.05 },
++ { "Segoe UI", 12, "Regular Class", 'm', 1.05 },
++ { "Segoe UI", 14, "Regular Class", 'm', 1.05 },
++ { "Tahoma", 11, "Regular Class", 'm', .975 },
++ { "Verdana", 10, "Regular Class", 0, 1.1 },
++ { "Verdana", 12, "Regular Class", 'm', .975 },
++ { "Verdana", 12, "Regular Class", 0, 1.05 },
++ { "Verdana", 16, "Regular Class", 0, 1.05 },
++ { "Verdana", 9, "Regular Class", 0, 1.05 },
++ { "Times New Roman", 16, "Regular Class", 'm', .95 },
++ { "Trebuchet MS", 12, "Regular Class", 'm', .95 },
++ };
++#else
++#define COMPATIBLE_WIDTHS_RULES_SIZE 1
++ SPH_TweakRule COMPATIBLE_WIDTHS_Rules
++ [COMPATIBLE_WIDTHS_RULES_SIZE] =
++ {
++ { "-", 0, "", 0 },
++ };
++
++#define X_SCALING_RULES_SIZE 1
++ SPH_ScaleRule X_SCALING_Rules
++ [X_SCALING_RULES_SIZE] =
++ {
++ { "-", 0, "", 0, 1.0 },
++ };
++#endif /* FORCE_NATURAL_WIDTHS */
++
++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++
++#endif /* __TTSUBPIX_H__ */
++
++/* END */
diff --git a/media-libs/freetype/files/freetype-enable-subpixel-hinting-infinality.patch b/media-libs/freetype/files/freetype-enable-subpixel-hinting-infinality.patch
new file mode 100644
index 0000000..a9aaea1
--- /dev/null
+++ b/media-libs/freetype/files/freetype-enable-subpixel-hinting-infinality.patch
@@ -0,0 +1,21 @@
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/include/freetype/config/ftoption.h freetype-subpixel-enabled/include/freetype/config/ftoption.h
+--- freetype-subpixel/include/freetype/config/ftoption.h 2012-06-15 07:31:12.146985731 -0500
++++ freetype-subpixel-enabled/include/freetype/config/ftoption.h 2012-06-15 07:32:18.144747500 -0500
+@@ -92,7 +92,7 @@
+ /* 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,7 +577,7 @@
+ /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */
+ /* defined. */
+ /* */
+-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
++#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+
+ /*************************************************************************/
diff --git a/media-libs/freetype/files/freetype-entire-infinality-patchset.patch b/media-libs/freetype/files/freetype-entire-infinality-patchset.patch
new file mode 100644
index 0000000..fcb039e
--- /dev/null
+++ b/media-libs/freetype/files/freetype-entire-infinality-patchset.patch
@@ -0,0 +1,4630 @@
+freetype-entire-infinality-patchset-20120615-01.patch
+-------------------------------------------------------------------
+(excludes the TT subpixel patches, which are required )
+
+This should patch to a subpixel-patched Freetype 2.4.10. Additional
+required files are also contained in the zipfile here:
+
+http://www.infinality.net/blog/infinality-freetype-patches/
+
+You will need to include this file in your profile with something like:
+ /etd/profile.d/infinality-settings.sh
+
+You'll need a file named (for 64 bit)
+/etc/ld.so.conf.d/freetype-infinality-x86_64.conf that contains:
+/usr/lib64/freetype-infinality
+
+Or a file named (for 32 bit)
+/etc/ld.so.conf.d/freetype-infinality-i386.conf that contains:
+/usr/lib/freetype-infinality
+
+Please see each file for more detailed information.
+
+If you are using this patch, you should also use the fontconfig configuration
+also found at the above link.
+
+The fedora packages I provide take care of all this for you.
+
+
+
+DISCLAIMERS:
+
+This patch will almost certainly result in a performance hit when
+freetype is rendering the glyphs. The good news is that fontconfig
+caches the glyphs so it's only the first time they are displayed that there
+could be a performance issue.
+
+I expect that if you compile freetype with this patch along with my
+TT subpixel hinting patch, you will have a complete build that works the
+way I expect it to. However, I have not tested all compile configurations
+for errors. I intend to at some point. This patch may make your system crash,
+have memory leaks, not compile, or render fonts in a way that you don't like.
+Either way, when you use this patch, you should recognize that it
+is ALPHA / BETA quality. That said, I intend to run these patches on my
+personal system, so they had better be pretty stable!
+
+
+
+Changes for 2012-06-15:
+
+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.
+ * Update to Freetype 2.4.10
+ * 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)
+
+
+Changes for 2012-04-03:
+
+Fixes:
+
+ * 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 rendering
+ * Code cleanup
+ * Prevent crashes in OSX mode (thanks Markser)
+
+
+Changes for 2011-12-23:
+
+Fixes / Tweaks:
+ * 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.
+
+
+Changes for 2011-11-17:
+
+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 > 100. 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.
+
+
+Changes for 2011-06-04:
+ MISSING
+
+ ====================================================================
+ ============= ANYTHING BELOW HERE MAY BE INACCURATE NOW ============
+ ====================================================================
+
+Changes for 2010-11-14:
+ * Rule tweaks on various fonts. Fixed the Cyrillic y issue and e issue
+ with Trebuchet, and the ^ issue with Arial. Other issues
+ (firefox and @font-face) are still present to a degree.
+
+ * A couple new rules to deal with various issues. (work in progress)
+
+ * Additional commenting.
+
+ * Some cleanup of obsolete code.
+
+ * Added some debugging code for potential future enhancements. Please
+ ignore the mess.
+
+
+Changes for 2010-10-22:
+ * I'm refocusing on just getting the subpixel looking nice, so I've stripped
+ back the rendering modes to just 2. The standard SUBPIXEL_HINTING and
+ the ADDITIONAL_TWEAKS. The rules structure is still in place. I recommend
+ using ADDITIONAL_TWEAKS mode.
+
+ * Fixed an issue with monochrome rendering that made fonts look really bad.
+ There is still an issue with them, but they are at least tolerable to
+ look at now.
+
+ * Added some testing code for detecting inline delta functions. Not sure
+ if this is useful yet.
+
+ * Added more rules to deal with certain artifacts on various fonts, like the
+ issue with < > and ^. Created some "exception" rules for certain rules.
+
+ * Reverted back to older rounding functions. The new experimental ones I
+ was trying were causing artifacts on some fonts.
+
+ * Some code cleanup.
+
+
+Changes for 2010-10-08:
+ * Fix PDF crashes.
+
+Changes for 2010-10-04:
+ * Update to freetype-2.4.3
+
+
+Changes for 2010-10-03:
+ * There are lots of changes for this one, some big, some small, and some
+ that still are not implemented. Not sure if I can remember them all
+ but I will try! THIS IS A POINT RELEASE THAT IS NOT
+ INTENDED TO WORK 100%. Some fonts and compile options may be broken
+ and the code may be inefficient and/or not syntactiacally correct.
+ That said, I do plan on using this on my system right away.
+
+ * There are now "rendering modes" for the subpixel hinting, with the idea
+ that this will enventually be able to be controlled by fontconfig. The 4
+ modes of enhanced hinting defined so far are:
+ 1) NATIVE HINTING - this is what freetype TT interpreter does by default.
+ 2) FIXED NATIVE HINTING - A slighly tweaked version of the above that
+ does "better" native rendering when displaying on LCD, for those
+ that still seem to like incorrect, thin fonts, which were only ever
+ there due to technical limitations.
+ 3) SUBPIXEL OPTIMIZED HINTING - this is straight up subpixel hinting with
+ very few tweaks. Just enough to get it working.
+ 4) COMPATIBILITY MODE HINTING - this is the sweet spot I'm working on
+ that will hopefully supplant #3 because it will work so well with all
+ fonts. The idea here is to tweak all available fonts so that each
+ renders well.
+ All of these modes either turn on or off switches in the interpreter
+ to make the fonts render properly for each mode. Right now these are only
+ compile-time options.
+
+ * Subpixel-related code has been broken out into its own files, so as to not
+ clutter up the existing code.
+
+ * The rasterizer now pays attention to the additional bits of MS rasterizer
+ v. 37, meaning that it can now indicate to fonts that it can handle
+ subpixel rendering.
+
+ * The rounding functions have been adapted to accept a grid resolution
+ variable, which lets them work on pixel and subpixel boundaries
+ automatically. Y still needs to be implemented.
+
+ * Additional conditions have been added to the switches, to further refine
+ how they are applied to different fonts.
+
+ * What all this means qualitatively is that legacy fonts now render much
+ better. There are still some that need a bit of love, like Courier New.
+
+ - Courier New has some fixes, and some breakage (Ghost pixels above bold
+ fonts, too thin on regular font)
+ - Times New Roman has some fixes and breakage (serifs, particularly)
+ - Tahoma and Trebuchet MS have been cleaned up
+ - Arial now snaps to grid better, but that causes breakage on a few glyphs
+ - Verdana 13 is now set to grid fit, but some glyhs are broken (mwxyz)
+ - Geneva and Geneva CY no longer look like turds
+ - Lucida Sans Unicode now looks arguably better than Lucida Grande
+
+
+
+Changes for 2010-09-16:
+
+ * The changes from 2010-09-14 regarding subpixel when LIGHT hinting enabled
+ have been reverted due to problems. The old behavior is back.
+
+ * Disable grayscale when subpixel is enabled. This results in better
+ behavior of some TT instructions within some fonts, like Times New Roman.
+
+ * Some modification of the tweaks, in light of above.
+
+
+Changes for 2010-09-14:
+
+ /************************** NO LONGER IN PLACE *****************************/
+ * Subpixel hinting is now used when the LIGHT hinting method and the TT
+ hinting is called. If FULL hinting is requested it will do the usual
+ behavior of the TT hinter.
+
+ This allows for all previously existing behavior, plus the new subpixel
+ hinting behavior, all in the same compile, and it makes sense in that
+ the slight hinting of the autohinter is essentially doing the same thing
+ as this, which is not forcing X-direction hints.
+
+ Previously, even if TT was selected, but LIGHT hinting was used, the
+ autohinter would still be forced. Other than this, autohint is not affected.
+ /***************************************************************************/
+
+ * Added a couple more conditionals around things to test whether subpixel
+ hinting is enabled. There were a few missing that ended up causing some
+ goofy hinting if subpixel was not enabled, but compiled in.
+
+
+
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/configure freetype-work/configure
+--- freetype-subpixel/configure 2011-12-02 13:21:55.000000000 -0600
++++ freetype-work/configure 2012-06-15 07:42:34.983820793 -0500
+@@ -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
+
+ if test "x$GNUMAKE" = x; then
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/devel/ftoption.h freetype-work/devel/ftoption.h
+--- freetype-subpixel/devel/ftoption.h 2012-06-15 07:31:12.119986648 -0500
++++ freetype-work/devel/ftoption.h 2012-06-15 17:21:09.266008295 -0500
+@@ -577,6 +577,17 @@
+
+ /*************************************************************************/
+ /* */
++ /* 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 -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/include/freetype/config/ftoption.h freetype-work/include/freetype/config/ftoption.h
+--- freetype-subpixel/include/freetype/config/ftoption.h 2012-06-15 07:31:12.146985731 -0500
++++ freetype-work/include/freetype/config/ftoption.h 2012-06-15 17:21:08.490034299 -0500
+@@ -577,6 +577,17 @@
+
+ /*************************************************************************/
+ /* */
++ /* 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 -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/autofit/aflatin.c freetype-work/src/autofit/aflatin.c
+--- freetype-subpixel/src/autofit/aflatin.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-work/src/autofit/aflatin.c 2012-06-15 07:42:35.021819509 -0500
+@@ -22,6 +22,7 @@
+
+ #include "aflatin.h"
+ #include "aferrors.h"
++#include "strings.h"
+
+
+ #ifdef AF_CONFIG_OPTION_USE_WARPER
+@@ -528,7 +529,30 @@
+ 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
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+@@ -556,7 +580,7 @@
+ {
+ AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
+ AF_LatinBlue blue = NULL;
+-
++ int threshold = 40;
+
+ for ( nn = 0; nn < Axis->blue_count; nn++ )
+ {
+@@ -566,12 +590,16 @@
+ 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
+ if ( blue )
+ {
+ FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
+- FT_Pos fitted = ( scaled + 40 ) & ~63;
+-
++ FT_Pos fitted = ( scaled + threshold ) & ~63;
+
+ if ( scaled != fitted )
+ {
+@@ -626,7 +654,6 @@
+ AF_LatinBlue blue = &axis->blues[nn];
+ FT_Pos dist;
+
+-
+ blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
+ blue->ref.fit = blue->ref.cur;
+ blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
+@@ -635,7 +662,12 @@
+
+ /* 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 always, in order to prevent fringes */
++#else
+ if ( dist <= 48 && dist >= -48 )
++#endif
+ {
+ #if 0
+ FT_Pos delta1;
+@@ -686,7 +718,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
+
+ #endif
+
+@@ -1433,6 +1470,8 @@
+ if ( dist < 0 )
+ dist = -dist;
+
++ /* round down to pixels */
++ /*dist = FT_MulFix( dist, scale ) & ~63;*/
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+@@ -1595,20 +1634,95 @@
+ 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;
+
+
+- if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
+- axis->extra_light )
+- return width;
++
++ 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
++ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
++ axis->extra_light )
++ return width;
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ /* Calculate snap value differently than standard freetype */
++ if ( /* stem_snap_light*/ autohint_snap_stem_height > 0
++ && (
++ ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )
++ || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
++ {
++ infinality_dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
++
++ if ( metrics->root.scaler.face->size->metrics.x_ppem > 9
++ && axis->width_count > 0
++ && abs ( axis->widths[0].cur - infinality_dist ) < 32
++ && axis->widths[0].cur > 52 )
++ {
++ 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 ) ) )
++ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
++ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
++#endif
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+
+@@ -1667,7 +1781,10 @@
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+- else
++ else
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( autohint_snap_stem_height < 100 )
++#endif
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+
+@@ -1675,7 +1792,9 @@
+
+
+ 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
+ if ( vertical )
+ {
+ /* in the case of vertical hinting, always round */
+@@ -1738,6 +1857,23 @@
+ }
+
+ 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
+ if ( sign )
+ dist = -dist;
+
+@@ -1760,6 +1896,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;
+
+@@ -2234,8 +2372,32 @@
+ {
+ FT_Error error;
+ int dim;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ int emboldening_strength = 0;
+
++ 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
+ error = af_glyph_hints_reload( hints, outline );
+ if ( error )
+ goto Exit;
+@@ -2292,7 +2454,54 @@
+ }
+ }
+ af_glyph_hints_save( hints, outline );
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++#if 0
++ if( metrics->root.scaler.face->style_name )
++ {
++ if ( strcasestr(metrics->root.scaler.face->style_name, "Bold")
++ || strcasestr(metrics->root.scaler.face->style_name, "Black")
++ || strcasestr(metrics->root.scaler.face->style_name, "Narrow")
++ && metrics->root.scaler.face->size->metrics.x_ppem < 15
++ || strcasestr(metrics->root.scaler.face->style_name, "Condensed")
++ && metrics->root.scaler.face->size->metrics.x_ppem < 20 )
++ goto Exit;
++ }
++ if( metrics->root.scaler.face->family_name )
++ {
++ if ( strcasestr(metrics->root.scaler.face->family_name, "Bold")
++ || strcasestr(metrics->root.scaler.face->family_name, "Black")
++ || strcasestr(metrics->root.scaler.face->family_name, "Narrow")
++ && metrics->root.scaler.face->size->metrics.x_ppem < 15
++ || strcasestr(metrics->root.scaler.face->family_name, "Condensed")
++ && metrics->root.scaler.face->size->metrics.x_ppem < 20 )
++ goto Exit;
++ }
+
++ /* if the font is particularly thin, embolden it, up to 1 px */
++ if ( use_various_tweaks
++ && metrics->axis->widths[0].cur <= FT_MulDiv ( autohint_minimum_stem_width, 64, 100)
++ && !( dim == AF_DIMENSION_VERT )
++ && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) )
++ {
++ if ( metrics->axis->widths[0].cur
++ / metrics->root.scaler.face->size->metrics.x_ppem < 5 )
++ {
++ emboldening_strength = FT_MulDiv ( autohint_minimum_stem_width, 64, 100) - metrics->axis->widths[0].cur;
++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 )
++ emboldening_strength -= 10;
++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 7 )
++ emboldening_strength -= 10;
++ }
++ if ( emboldening_strength < 0 ) emboldening_strength = 0;
++ FT_Outline_Embolden(outline,emboldening_strength);
++ }
++#endif
++ /* 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
+ Exit:
+ return error;
+ }
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/base/ftlcdfil.c freetype-work/src/base/ftlcdfil.c
+--- freetype-subpixel/src/base/ftlcdfil.c 2010-04-01 03:18:57.000000000 -0500
++++ freetype-work/src/base/ftlcdfil.c 2012-06-15 07:42:35.022819476 -0500
+@@ -21,6 +21,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
+
+@@ -287,10 +290,51 @@
+ { 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_Err_Invalid_Argument;
+
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/base/ftobjs.c freetype-work/src/base/ftobjs.c
+--- freetype-subpixel/src/base/ftobjs.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-work/src/base/ftobjs.c 2012-06-15 07:42:35.025819374 -0500
+@@ -513,6 +513,22 @@
+ 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,
+@@ -571,8 +587,33 @@
+ 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 */
++ 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_Err_Invalid_Face_Handle;
+
+@@ -652,8 +693,18 @@
+ if ( autohint )
+ {
+ FT_AutoHinter_Service 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 */
+ /* */
+ /* XXX: This is really a temporary hack that should disappear */
+@@ -691,6 +742,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,
+@@ -698,6 +753,16 @@
+ 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 );
++ ft_glyphslot_enlarge_metrics( slot, mode );
++ }
++#endif
++
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* check that the loaded outline is correct */
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/base/ftoutln.c freetype-work/src/base/ftoutln.c
+--- freetype-subpixel/src/base/ftoutln.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-work/src/base/ftoutln.c 2012-06-15 16:19:12.645429337 -0500
+@@ -897,7 +897,29 @@
+ 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_Err_Invalid_Argument;
+diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/base/ftsynth.c freetype-work/src/base/ftsynth.c
+--- freetype-subpixel/src/base/ftsynth.c 2012-06-14 23:26:45.000000000 -0500
++++ freetype-work/src/base/ftsynth.c 2012-06-15 16:36:20.612600325 -0500
+@@ -88,7 +88,26 @@
+ 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 +120,11 @@
+
+ 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 +165,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 -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' freetype-subpixel/src/smooth/ftsmooth.c freetype-work/src/smooth/ftsmooth.c
+--- freetype-subpixel/src/smooth/ftsmooth.c 2012-06-14 00:35:58.000000000 -0500
++++ freetype-work/src/smooth/ftsmooth.c 2012-06-15 07:42:35.030819204 -0500
+@@ -26,6 +26,16 @@
+
+ #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
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+@@ -34,65 +44,2822 @@
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+- render->clazz->raster_class->raster_reset( render->raster,
+- library->raster_pool,
+- library->raster_pool_size );
++ render->clazz->raster_class->raster_reset( render->raster,
++ library->raster_pool,
++ library->raster_pool_size );
++
++ return 0;
++ }
++
++
++ /* sets render-specific mode */
++ static FT_Error
++ ft_smooth_set_mode( FT_Renderer render,
++ FT_ULong mode_tag,
++ FT_Pointer data )
++ {
++ /* we simply pass it to the raster */
++ return render->clazz->raster_class->raster_set_mode( render->raster,
++ mode_tag,
++ data );
++ }
++
++ /* transform a given glyph image */
++ static FT_Error
++ ft_smooth_transform( FT_Renderer render,
++ FT_GlyphSlot slot,
++ const FT_Matrix* matrix,
++ const FT_Vector* delta )
++ {
++ FT_Error error = Smooth_Err_Ok;
++
++
++ if ( slot->format != render->glyph_format )
++ {
++ error = Smooth_Err_Invalid_Argument;
++ goto Exit;
++ }
++
++ if ( matrix )
++ FT_Outline_Transform( &slot->outline, matrix );
++
++ if ( delta )
++ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
++
++ Exit:
++ return error;
++ }
++
++
++ /* return the glyph's control box */
++ static void
++ ft_smooth_get_cbox( FT_Renderer render,
++ FT_GlyphSlot slot,
++ FT_BBox* cbox )
++ {
++ FT_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
++ gamma2 ( 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 + gamma2(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] = gamma2(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) new_line[xx-1] -= (new_line[xx-1] * strength) / 200; /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */
++ if (rightdiff < 10) new_line[xx+1] -= (new_line[xx+1] * strength) / 200; /* OPPORTUNITY FOR IMPROVEMENT */
++ }
++ 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) new_line[xx-1] -= (new_line[xx-1] * strength) / 200; /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */
++ if (rightdiff < 10) new_line[xx+1] -= (new_line[xx+1] * strength) / 200; /* OPPORTUNITY FOR IMPROVEMENT */
++ }
++ }
++ /* 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; /*this needs work.. breaks some glyphs like verdana 12 */
++ 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 strategy_use_verdana_12_hack = FALSE; /* not necessary anymore... maybe */
++ 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;
++
++ int checked_use_known_settings_on_selected_fonts_env = 0;
++ 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;
++ }
++
++ /* An incoming scale value of 1.1 indicates to do certain things */
++ /*if (*scale_value == 1.1) strategy_use_verdana_12_hack = TRUE;*/
++
++ /* reset to default */
++ *scale_value = 1.0;
++
++ 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;
++ }
++
++
++ /* 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 ( width < 4 ) 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;
++ }
++
++ known_stem_values = (Stem_Data*) malloc (columns_per_pixel * sizeof(Stem_Data)); /* only look at top 3 for now */
++ 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/*, stem_width*/;
++ 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;
++ /*stem_width = segments[num_segments].x2 - segments[num_segments].x1;*/
++ /* 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; */
++ FT_Int deviation1 = 5; /* 10 to 20 wiith 4 matches seems good, but 1 or 2 with 3 stems needs to somehow get included */
++ 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;
++ }
++
++ /* THIS WORKS, BUT NEED TO PUNISH DIAGONALS like W */
++ /*requirement2 = height / 5;
++ if (requirement2 < 3) requirement2 = 3;
++ deviation2 = 1 ;*/
++ valid_center_average = 0;
++ /* if (deviation2 < 1) deviation2 = 1;*/
++
++ 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;
++
++ /* new version */
++ 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)
++ {
++ if ((
++ /* Require no gap for edges */
++ stem_matches_ledge >= stem_match_requirement && no_gap_found_ledge
++ /* 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)
++ /* The stem occurs on the left side of glyph only */
++ && 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;
++ }
++ else if ((
++ /* Require no gap for edges */
++ stem_matches_redge >= stem_match_requirement && no_gap_found_redge
++ /* 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)
++ /* The stem occurs on the right side of glyph only */
++ && 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 the stem is within the 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] );
++ }
++
++ if (strategy_use_verdana_12_hack
++ && strcasestr(slot->face->family_name, "Verdana")
++ && ppem == 12
++ && valid_stems == 1
++ && (stems[0].center + m_horiBearingX * 12 - one_pixel < m_horiAdvance * 4
++ ||stems[0].center + m_horiBearingX * 12 - one_pixel > m_horiAdvance * 8) )
++ {
++ if (stems[0].center + m_horiBearingX * 12 - one_pixel < m_horiAdvance * 4)
++ {
++ stems[1].center = rightmost_point - one_pixel / 2;
++ stems[1].width = 1;
++ stems[1].generated = TRUE;
++ valid_stems += 1;
++ }
++ else
++ {
++ stems[1].center = leftmost_point + one_pixel / 2;
++ stems[1].width = 1;
++ stems[1].generated = TRUE;
++ valid_stems += 1;
++ }
++ strategy_always_use_distance_ceiling = TRUE;
++ }
++
++ /* 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 ) *translate_value = ( - delta ) / (columns_per_pixel * 4); /* snap left */
++ else *translate_value = (modulus -delta) / (columns_per_pixel * 4); /* snap right */
++ }
++
++ 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 && valid_stems == 3
++ && (width - 2 * columns_per_pixel) > 6 * columns_per_pixel
++ && ppem > 8
++ && (advance_stem_location - advance_leftmost_location) < stems[main_stem].width * 2 )
++ {
++ FT_Int mod_factor = 2; /*Possibly use 2 only when compatible widths is on? */
++
++ 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 )
++ {
++ FT_Int mod_factor = 2; /*Possibly use 2 only when compatible widths is on? */
++
++ 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 there is 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 ) translate_value2 = ( - delta2 ) / (columns_per_pixel * 4); /* snap left */
++ else translate_value2 = (modulus -delta2) / (columns_per_pixel * 4); /* snap right */
++
++ 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 ) new_distance = delta + stem_distance; /* stretch left */
++ else new_distance = delta - modulus + stem_distance; /* stretch right */
++
++ 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 + 0) / (float)(stem_distance + 0 );
++ *translate_value = *translate_value - ((float)(stems[main_stem].center * (float)new_distance) / (float)stem_distance - stems[main_stem].center) / 12;
+
+- return 0;
+- }
++ 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);
+
+- /* sets render-specific mode */
+- static FT_Error
+- ft_smooth_set_mode( FT_Renderer render,
+- FT_ULong mode_tag,
+- FT_Pointer data )
+- {
+- /* we simply pass it to the raster */
+- return render->clazz->raster_class->raster_set_mode( render->raster,
+- mode_tag,
+- data );
+- }
++ 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);
+
+- /* transform a given glyph image */
+- static FT_Error
+- ft_smooth_transform( FT_Renderer render,
+- FT_GlyphSlot slot,
+- const FT_Matrix* matrix,
+- const FT_Vector* delta )
+- {
+- FT_Error error = Smooth_Err_Ok;
++ 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 ");
++ }
++ }
+
++ if ( strategy_use_verdana_12_hack
++ && strcasestr(slot->face->family_name, "Verdana")
++ && ppem == 12
++ && *scale_value == 1.0 && valid_stems == 0
++ && height < 8
++ && advance_rightmost_location * 1.1 < advance_width )
++ *scale_value = 1.1;
+
+- if ( slot->format != render->glyph_format )
+- {
+- error = Smooth_Err_Invalid_Argument;
+ goto Exit;
++
+ }
+
+- if ( matrix )
+- FT_Outline_Transform( &slot->outline, matrix );
++ Exit:
+
+- if ( delta )
+- FT_Outline_Translate( &slot->outline, delta->x, delta->y );
++#define transformed_point( point ) point * *scale_value + *translate_value * 12
++
++ if (strategy_correct_out_of_bounds_outlines)
++ {
++ /* Correct if outside bitmap */
++ if (transformed_point(rightmost_point) >= width * 256 - 2 * one_third_pixel
++ && transformed_point(leftmost_point ) > one_pixel + 2 * one_third_pixel )
++ {
++ *translate_value -=64 ;
++ }
++ else if (transformed_point(leftmost_point) <= one_pixel / 2
++ && transformed_point(rightmost_point ) <= width * 256 -(one_pixel + one_pixel / 2) )
++ {
++ *translate_value += 64;
++ }
++ }
++
++ STVALUES
++
++ free(segments);
++ free(leftmost_segment);
++ free(rightmost_segment);
++
++ free(known_stem_values);
++ free(stems);
++ free(possible_stems);
++ free(leftmost_stem);
++ free(rightmost_stem);
++
++ free(centers);
+
+- Exit:
+- return error;
+ }
+
+
+- /* 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 ( slot->format == render->glyph_format )
+- FT_Outline_Get_CBox( &slot->outline, 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->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] = gamma2 ( line[xx], gamma_correction_value );*/
++
++ /* sloped */
++ /*line[xx] = gamma2 ( 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] = gamma2 ( 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,19 +2871,406 @@
+ {
+ FT_Error error;
+ FT_Outline* outline = NULL;
++ FT_Outline* outline_orig = NULL;
+ FT_BBox cbox;
+- FT_Pos width, height, pitch;
++ FT_Pos width=0, height=0, pitch=0, ppem;
+ #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ FT_Pos height_org, width_org;
+ #endif
+- FT_Bitmap* bitmap;
+- FT_Memory memory;
++ FT_Bitmap* bitmap = 0;
++ FT_Memory memory = 0;
+ FT_Int hmul = mode == FT_RENDER_MODE_LCD;
+ FT_Int vmul = mode == FT_RENDER_MODE_LCD_V;
+- FT_Pos x_shift, y_shift, x_left, y_top;
++ FT_Pos x_shift = 0, y_shift = 0, x_left = 0, y_top = 0;
+
+ FT_Raster_Params params;
+
++#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 the effect slightly in order 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 )
+@@ -129,92 +3283,174 @@
+ if ( mode != required_mode )
+ return Smooth_Err_Cannot_Render_Glyph;
+
+- outline = &slot->outline;
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++RERENDER:
++ if (align_called == 1){
+
+- /* translate the outline to the new origin if needed */
+- if ( origin )
+- FT_Outline_Translate( outline, origin->x, origin->y );
++ scaleMat.xx = FT_FixedFromFloat(scale_value);
++ scaleMat.xy = 0;
++ scaleMat.yx = 0;
++ scaleMat.yy = (1 << 16);
+
+- /* compute the control box, and grid fit it */
+- FT_Outline_Get_CBox( outline, &cbox );
++ FT_Outline_Copy(outline_orig, outline);
+
+- cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
+- cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
+- cbox.xMax = FT_PIX_CEIL( cbox.xMax );
+- cbox.yMax = FT_PIX_CEIL( cbox.yMax );
+-
+- if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
+- {
+- FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
+- " xMin = %d, xMax = %d\n",
+- cbox.xMin >> 6, cbox.xMax >> 6 ));
+- return Smooth_Err_Raster_Overflow;
+- }
+- else
+- width = ( cbox.xMax - cbox.xMin ) >> 6;
++ if (scale_value != 1.0)
++ FT_Outline_Transform( outline, &scaleMat );
+
+- if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin )
+- {
+- FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
+- " yMin = %d, yMax = %d\n",
+- cbox.yMin >> 6, cbox.yMax >> 6 ));
+- return Smooth_Err_Raster_Overflow;
++ FT_Outline_Translate( outline, translate_value+0, 0 );
++
++ FT_Outline_EmboldenXY( outline, embolden_value, 0 );
+ }
+ else
+- height = ( cbox.yMax - cbox.yMin ) >> 6;
+-
+- bitmap = &slot->bitmap;
+- memory = render->root.memory;
+-
+-#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+- width_org = width;
+- height_org = height;
++ {
+ #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 (!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 );
+
+- /* release old bitmap buffer */
+- if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+- {
+- FT_FREE( bitmap->buffer );
+- slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
++ FT_Outline_Copy(outline, outline_orig);
+ }
+
+- /* allocate new one */
+- pitch = width;
+- if ( hmul )
++ /* translate the outline to the new origin if needed */
++ if (align_called == 0)
+ {
+- width = width * 3;
+- pitch = FT_PAD_CEIL( width, 4 );
+- }
++ FT_Pos enlarge_cbox = 0;
+
+- if ( vmul )
+- height *= 3;
++ /* enlarge for grayscale rendering */
++ if ( mode == FT_RENDER_MODE_NORMAL ) enlarge_cbox = 64;
+
+- x_shift = (FT_Int) cbox.xMin;
+- y_shift = (FT_Int) cbox.yMin;
+- x_left = (FT_Int)( cbox.xMin >> 6 );
+- y_top = (FT_Int)( cbox.yMax >> 6 );
++ if ( origin )
++ FT_Outline_Translate( outline, origin->x, origin->y );
+
+-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ /* 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 );
++
++ /* compute the control box, and grid fit it */
++ FT_Outline_Get_CBox( outline, &cbox );
++
++ cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
++ cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
++ cbox.xMax = FT_PIX_CEIL( cbox.xMax );
++ cbox.yMax = FT_PIX_CEIL( cbox.yMax );
++#endif
+
+- if ( slot->library->lcd_filter_func )
+- {
+- FT_Int extra = slot->library->lcd_extra;
++ if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
++ {
++ FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
++ " xMin = %d, xMax = %d\n",
++ cbox.xMin >> 6, cbox.xMax >> 6 ));
++ return Smooth_Err_Raster_Overflow;
++ }
++ else
++ width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
++
++ if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin )
++ {
++ FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
++ " yMin = %d, yMax = %d\n",
++ cbox.yMin >> 6, cbox.yMax >> 6 ));
++ return Smooth_Err_Raster_Overflow;
++ }
++ else
++ height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
+
++ bitmap = &slot->bitmap;
++ memory = render->root.memory;
+
++#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++ width_org = width;
++ height_org = height;
++#endif
++
++ /* release old bitmap buffer */
++ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
++ {
++ FT_FREE( bitmap->buffer );
++ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
++ }
++
++ /* allocate new one */
++ pitch = width;
+ if ( hmul )
+ {
+- x_shift -= 64 * ( extra >> 1 );
+- width += 3 * extra;
+- pitch = FT_PAD_CEIL( width, 4 );
+- x_left -= extra >> 1;
++ width = width * 3;
++ pitch = FT_PAD_CEIL( width, 4 );
+ }
+
+ if ( vmul )
++ height *= 3;
++
++ x_shift = (FT_Int) cbox.xMin;
++ y_shift = (FT_Int) cbox.yMin;
++ x_left = (FT_Int)( cbox.xMin >> 6 );
++ y_top = (FT_Int)( cbox.yMax >> 6 );
++
++#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
++
++ if ( slot->library->lcd_filter_func )
+ {
+- y_shift -= 64 * ( extra >> 1 );
+- height += 3 * extra;
+- y_top += extra >> 1;
++ FT_Int extra = slot->library->lcd_extra;
++
++
++ if ( hmul )
++ {
++ x_shift -= 64 * ( extra >> 1 );
++ width += 3 * extra;
++ pitch = FT_PAD_CEIL( width, 4 );
++ x_left -= extra >> 1;
++ }
++
++ if ( vmul )
++ {
++ y_shift -= 64 * ( extra >> 1 );
++ height += 3 * extra;
++ y_top += extra >> 1;
++ }
+ }
++#endif
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+ }
+
+ #endif
+@@ -239,6 +3475,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 );
+
+ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+@@ -288,9 +3527,107 @@
+ vec->y /= 3;
+ }
+
++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
++ if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM )
++ {
++ if ( align_called == 0 && (alignment_strength > 0 || fitting_strength > 0))
++ _lcd_stem_align ( bitmap, mode, slot, &translate_value, &scale_value,
++ alignment_strength, fitting_strength, &embolden_value );
++
++ if ((translate_value != 0 || scale_value != 1.0) && align_called == 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 ( !_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 and 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/media-libs/freetype/freetype-2.4.10-r1.ebuild b/media-libs/freetype/freetype-2.4.10-r1.ebuild
new file mode 100644
index 0000000..e0bdde5
--- /dev/null
+++ b/media-libs/freetype/freetype-2.4.10-r1.ebuild
@@ -0,0 +1,142 @@
+# Copyright 1999-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI="4"
+
+inherit autotools eutils flag-o-matic libtool multilib
+
+DESCRIPTION="A high-quality and portable font engine"
+HOMEPAGE="http://www.freetype.org/"
+SRC_URI="mirror://sourceforge/freetype/${P/_/}.tar.bz2
+ utils? ( mirror://sourceforge/freetype/ft2demos-${PV}.tar.bz2 )
+ doc? ( mirror://sourceforge/freetype/${PN}-doc-${PV}.tar.bz2 )"
+
+LICENSE="FTL GPL-2"
+SLOT="2"
+KEYWORDS="~amd64 ~x86"
+IUSE="X auto-hinter bindist bzip2 debug doc fontforge lcdfilter static-libs utils"
+
+DEPEND="sys-libs/zlib
+ bzip2? ( app-arch/bzip2 )
+ X? ( x11-libs/libX11
+ x11-libs/libXau
+ x11-libs/libXdmcp )"
+
+RDEPEND="${DEPEND}
+ lcdfilter? ( media-libs/fontconfig-infinality )"
+
+src_prepare() {
+ enable_option() {
+ sed -i -e "/#define $1/a #define $1" \
+ include/freetype/config/ftoption.h \
+ || die "unable to enable option $1"
+ }
+
+ disable_option() {
+ sed -i -e "/#define $1/ { s:^:/*:; s:$:*/: }" \
+ include/freetype/config/ftoption.h \
+ || die "unable to disable option $1"
+ }
+
+ if ! use bindist; then
+ # See http://freetype.org/patents.html
+ # ClearType is covered by several Microsoft patents in the US
+ enable_option FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ fi
+
+ if use auto-hinter; then
+ disable_option TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ enable_option TT_CONFIG_OPTION_UNPATENTED_HINTING
+ fi
+
+ if use debug; then
+ enable_option FT_DEBUG_LEVEL_TRACE
+ enable_option FT_DEBUG_MEMORY
+ fi
+
+ disable_option FT_CONFIG_OPTION_OLD_INTERNALS
+
+ if use lcdfilter; then
+ epatch "${FILESDIR}"/freetype-add-subpixel-hinting-infinality.patch
+ epatch "${FILESDIR}"/freetype-entire-infinality-patchset.patch
+
+ enable_option FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ enable_option TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ fi
+
+ epatch "${FILESDIR}"/${PN}-2.3.2-enable-valid.patch
+
+ if use utils; then
+ cd "${WORKDIR}/ft2demos-${PV}"
+ sed -i -e "s:\.\.\/freetype2$:../freetype-${PV}:" Makefile || die
+ # Disable tests needing X11 when USE="-X". (bug #177597)
+ if ! use X; then
+ sed -i -e "/EXES\ +=\ ftdiff/ s:^:#:" Makefile || die
+ fi
+ fi
+
+ if use prefix; then
+ cd "${S}"/builds/unix
+ eautoreconf
+ else
+ elibtoolize
+ fi
+ epunt_cxx
+}
+
+src_configure() {
+ append-flags -fno-strict-aliasing
+ type -P gmake &> /dev/null && export GNUMAKE=gmake
+
+ # we need non-/bin/sh to run configure
+ [[ -n ${CONFIG_SHELL} ]] && \
+ sed -i -e "1s:^#![[:space:]]*/bin/sh:#!$CONFIG_SHELL:" \
+ "${S}"/builds/unix/configure
+
+ econf \
+ $(use_enable static-libs static) \
+ $(use_with bzip2)
+}
+
+src_compile() {
+ emake
+
+ if use utils; then
+ einfo "Building utils"
+ cd "${WORKDIR}/ft2demos-${PV}"
+ # fix for Prefix, bug #339334
+ emake X11_PATH="${EPREFIX}/usr/$(get_libdir)"
+ fi
+}
+
+src_install() {
+ emake DESTDIR="${D}" install
+
+ if use utils; then
+ einfo "Installing utils"
+ rm "${WORKDIR}"/ft2demos-${PV}/bin/README
+ for ft2demo in ../ft2demos-${PV}/bin/*; do
+ ./builds/unix/libtool --mode=install $(type -P install) -m 755 "$ft2demo" \
+ "${ED}"/usr/bin
+ done
+ fi
+
+ if use fontforge; then
+ # Probably fontforge needs less but this way makes things simplier...
+ einfo "Installing internal headers required for fontforge"
+ find src/truetype include/freetype/internal -name '*.h' | \
+ while read header; do
+ mkdir -p "${ED}/usr/include/freetype2/internal4fontforge/$(dirname ${header})"
+ cp ${header} "${ED}/usr/include/freetype2/internal4fontforge/$(dirname ${header})"
+ done
+ fi
+
+ prune_libtool_files
+
+ dodoc ChangeLog README
+ dodoc docs/{CHANGES,CUSTOMIZE,DEBUG,*.txt,PROBLEMS,TODO}
+
+ use doc && dohtml -r docs/*
+
+}