Guest User

Untitled

a guest
Mar 17th, 2013
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 195.40 KB | None | 0 0
  1. freetype-entire-infinality-patchset-20111223-01.patch
  2. -------------------------------------------------------------------
  3. (excludes the TT subpixel patches, which are required )
  4.  
  5. This should patch to a subpixel-patched Freetype 2.4.8.  Additional
  6. required files are also contained in the zipfile here:
  7.  
  8. http://www.infinality.net/blog/infinality-freetype-patches/
  9.  
  10. You will need to include this file in your profile with something like:
  11.   /etd/profile.d/infinality-settings.sh
  12.  
  13. You'll need a file named (for 64 bit)
  14. /etc/ld.so.conf.d/freetype-infinality-x86_64.conf that contains:
  15. /usr/lib64/freetype-infinality
  16.  
  17. Or a file named (for 32 bit)
  18. /etc/ld.so.conf.d/freetype-infinality-i386.conf that contains:
  19. /usr/lib/freetype-infinality
  20.  
  21. Please see each file for more detailed information.
  22.  
  23. If you are using this patch, you should also use the fontconfig configuration
  24. also found at the above link.
  25.  
  26. The fedora packages I provide take care of all this for you.
  27.  
  28.  
  29.  
  30. DISCLAIMERS:
  31.  
  32. This patch will almost certainly result in a performance hit when
  33. freetype is rendering the glyphs.  The good news is that fontconfig
  34. caches the glyphs so it's only the first time they are displayed that there
  35. could be a performance issue.
  36.  
  37. I expect that if you compile freetype with this patch along with my
  38. TT subpixel hinting patch, you will have a complete build that works the
  39. way I expect it to.  However, I have not tested all compile configurations
  40. for errors.  I intend to at some point.  This patch may make your system crash,
  41. have memory leaks, not compile, or render fonts in a way that you don't like.
  42. Either way, when you use this patch, you should recognize that it
  43. is ALPHA / BETA quality.  That said, I intend to run these patches on my
  44. personal system, so they had better be pretty stable!
  45.  
  46.  
  47. Changes for 2011-12-23:
  48.  
  49. Fixes / Tweaks:
  50. * Courier New Hack for '2'.  
  51. * Tweak Arial 16px a bit.
  52. * Various tweaks on Courier New, Times NR, Arial, Verdana and others that
  53.   create a general improvement in appearance at certain ppems.
  54. * Fixes on some Cyrillic glyphs.
  55. * Pragmata Pro and Pragmata added to patches.
  56. * Be a little more conservative in the way "known settings" of fonts are done.
  57. * Many small improvements to the subpixel hinting patch.
  58. * Fix a crasher in the Windows sharpening algorithm.
  59. * Noticible improvement on spacing in Tahoma 11px, Arial 11px, and other Arial
  60.   clones.  Me likey.
  61. * Code fixes to prevent some warnings and possible crashes.  (Thanks banta)
  62. * Fix Opera and Firefox crashes.  slot->face->style_name and
  63.   slot->face->family_name need to be checked for not NULL before using.
  64.  
  65.  
  66. Changes for 2011-11-17:
  67.  
  68. Features:
  69. * Added a post-render, pre-lcd-filter filter that attempts to duplicate windows
  70.   sharpness / graininess.  Controlled by
  71.   INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH.  
  72. * Added a fringe filter, intended mostly for autohint (but still effective
  73.   for certain cases of TT hinting).  This attempts to remove gray fringes that
  74.   sometimes occur on horizontal stems and angled serifs and doodads
  75.   (Times, Segoe '1', etc.)
  76. * Added a grayscale filter.
  77. * Added brightness/contrast filter.
  78. * Substantial improvements in the stem alignment algorithm!  Wow!
  79. * Stem alignment now also happens on grayscale antialiased fonts (rgba=none).
  80.  
  81. Fixes / Tweaks:
  82. * Changes inside of local.conf, which are documented there.
  83. * Removed an artificial shift of 1/8 pixel to the right on stem aligned glyphs
  84.   which should result in sharper looking alignment.
  85. * Added XFT_SETTINGS into infinality-settings.sh.  This means it will require
  86.   less configuration on the end-user side.
  87. * Fixed code to not touch bold, thin, narrow or italic faces for scale or
  88.   alignment (until they can be properly accounted for).
  89. * Added -lm dependency to the code again.  (It seems to sneak off now and then)
  90. * Changed autohinter horizontal stem stem snapping from on/off to use a value
  91.   between 0 and 100.
  92. * Functions getenv() and system() were crashing evince in _lcd_stem_align()
  93.   at odd times.  A workaround has been put in place.
  94. * Moved _lcd_stem_align and all other filters into ftsmooth.c, which is a better place.
  95. * Use malloc() in _lcd_stem_align for allocating structs and arrays of structs
  96.   instead of what I learned in C++ class 10+ years ago.  Should prevent abiword
  97.   from crashing with large pt sizes like 3000.  (A workaround has been put
  98.   in place to automatically skip alignment on any ppem > 100.  This will
  99.   prevent the crashes until the real solution can be figured out.)
  100. * Fix some compiler warnings.  Some are still present.
  101. * Added "m" control to alignment algorithm.  This will cause all stems to m
  102.   (or other 3-pronged glyphs) to get aligned to pixels.  It still needs a bit
  103.   of work, as it makes the best looking glyph size change.  This is because
  104.   the glyph now needs to snap stems to only even or odd pixels, not single ones.
  105. * Added rules to allow "compatible widths" (i.e. widths if the font were being
  106.   bitmap TT hinted) on a glyph by glyph basis and tweaked certain fonts like
  107.   arial, verdana, times new roman, segoe ui, and trebuchet to use them.
  108. * Don't stem align anything below 9 ppem because it is not consistently good.
  109.  * When doing stem alignment, automatically align stems to center of pixel or
  110.    start of pixel when necessary.  When horizontal stems start snapping to 2 px,
  111.    so should the vertical ones in order for it to look nice.
  112.  * A Verdana 12 hack to make it render more like Windows.  This notoriously
  113.    poor looking ppem now looks as good as Verdana 13 without needing fontconfig
  114.    replacement.
  115.  * Courier New now looks good, and possibly better than Windows rendering, with
  116.    TT or autohint rendering.  By the way, the hinters of Courier New should
  117.    either be commended or executed.
  118.  * Improvements in overshoot artifact and fringe correction-  Freesans at large
  119.    ppem looks nice now.  Overshoots on letters like 6, g, s, 3, etc. will
  120.    now be rounded to integer pixels.
  121.  * Wrap all infinality code within a macro that is set in ftoption.h:  
  122.    #ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET.  Makes it easier to identify
  123.    in the code and allows for easy compliation with or without the patches set.
  124.  * Variable renaming for more clarity, in code and in environment variables.
  125.  * Move stretching code into Freetype instead of relying on programs to handle
  126.    fontconfig matrix (they SUCK at it... *cough* Chrome *cough*).
  127.  * Additional modifications to the TT subpixel rendering rules for corrections
  128.    to Georgia, DejaVu Sans, Times New Roman, Courier New and a couple others.
  129.  * A general improvement in the way autohinted fonts render, particularly on
  130.    ones that normally look fragile or thin.  Examples include Optima, Freemono,
  131.    Freeserif, Raleway, MgOpen, etc.  I'm doing what Windows does, which is
  132.   brightness/contrast adjustment, except you don't see rainbows.  
  133.  
  134.  
  135. Changes for 2011-06-04:
  136.   MISSING
  137.  
  138.   ====================================================================
  139.   ============= ANYTHING BELOW HERE MAY BE INACCURATE NOW ============
  140.   ====================================================================
  141.  
  142. Changes for 2010-11-14:
  143.  * Rule tweaks on various fonts.  Fixed the Cyrillic y issue and e issue
  144.    with Trebuchet, and the ^ issue with Arial.  Other issues
  145.    (firefox and @font-face) are still present to a degree.
  146.  
  147.  * A couple new rules to deal with various issues.  (work in progress)
  148.  
  149.  * Additional commenting.
  150.  
  151.  * Some cleanup of obsolete code.
  152.  
  153.  * Added some debugging code for potential future enhancements.  Please
  154.    ignore the mess.
  155.  
  156.  
  157. Changes for 2010-10-22:
  158.  * I'm refocusing on just getting the subpixel looking nice, so I've stripped
  159.    back the rendering modes to just 2.  The standard SUBPIXEL_HINTING and
  160.    the ADDITIONAL_TWEAKS.  The rules structure is still in place. I recommend
  161.    using ADDITIONAL_TWEAKS mode.
  162.  
  163.  * Fixed an issue with monochrome rendering that made fonts look really bad.
  164.    There is still an issue with them, but they are at least tolerable to
  165.    look at now.
  166.  
  167.  * Added some testing code for detecting inline delta functions.  Not sure
  168.    if this is useful yet.
  169.  
  170.  * Added more rules to deal with certain artifacts on various fonts, like the
  171.    issue with < > and ^.  Created some "exception" rules for certain rules.
  172.  
  173.  * Reverted back to older rounding functions.  The new experimental ones I
  174.    was trying were causing artifacts on some fonts.
  175.  
  176.  * Some code cleanup.
  177.  
  178.  
  179. Changes for 2010-10-08:
  180.  * Fix PDF crashes.
  181.  
  182. Changes for 2010-10-04:
  183.  * Update to freetype-2.4.3
  184.  
  185.  
  186. Changes for 2010-10-03:
  187.  * There are lots of changes for this one, some big, some small, and some
  188.    that still are not implemented.  Not sure if I can remember them all
  189.    but I will try!  THIS IS A POINT RELEASE THAT IS NOT
  190.    INTENDED TO WORK 100%.  Some fonts and compile options may be broken
  191.    and the code may be inefficient and/or not syntactiacally correct.
  192.    That said, I do plan on using this on my system right away.
  193.  
  194.  * There are now "rendering modes" for the subpixel hinting, with the idea
  195.    that this will enventually be able to be controlled by fontconfig.  The 4
  196.    modes of enhanced hinting defined so far are:
  197.     1) NATIVE HINTING - this is what freetype TT interpreter does by default.
  198.     2) FIXED NATIVE HINTING - A slighly tweaked version of the above that
  199.        does "better" native rendering when displaying on LCD, for those
  200.        that still seem to like incorrect, thin fonts, which were only ever
  201.        there due to technical limitations.
  202.     3) SUBPIXEL OPTIMIZED HINTING - this is straight up subpixel hinting with
  203.        very few tweaks.  Just enough to get it working.
  204.     4) COMPATIBILITY MODE HINTING - this is the sweet spot I'm working on
  205.       that will hopefully supplant #3 because it will work so well with all
  206.       fonts.  The idea here is to tweak all available fonts so that each
  207.       renders well.
  208.   All of these modes either turn on or off switches in the interpreter
  209.   to make the fonts render properly for each mode.  Right now these are only
  210.   compile-time options.
  211.  
  212. * Subpixel-related code has been broken out into its own files, so as to not
  213.   clutter up the existing code.
  214.  
  215. * The rasterizer now pays attention to the additional bits of MS rasterizer
  216.   v. 37, meaning that it can now indicate to fonts that it can handle
  217.   subpixel rendering.
  218.  
  219. * The rounding functions have been adapted to accept a grid resolution
  220.   variable, which lets them work on pixel and subpixel boundaries
  221.   automatically.  Y still needs to be implemented.
  222.  
  223. * Additional conditions have been added to the switches, to further refine
  224.   how they are applied to different fonts.
  225.  
  226. * What all this means qualitatively is that legacy fonts now render much
  227.   better.  There are still some that need a bit of love, like Courier New.
  228.  
  229.   - Courier New has some fixes, and some breakage (Ghost pixels above bold
  230.     fonts, too thin on regular font)
  231.   - Times New Roman has some fixes and breakage (serifs, particularly)
  232.   - Tahoma and Trebuchet MS have been cleaned up
  233.   - Arial now snaps to grid better, but that causes breakage on a few glyphs
  234.   - Verdana 13 is now set to grid fit, but some glyhs are broken (mwxyz)
  235.   - Geneva and Geneva CY no longer look like turds
  236.   - Lucida Sans Unicode now looks arguably better than Lucida Grande
  237.  
  238.  
  239.  
  240. Changes for 2010-09-16:
  241.  
  242. * The changes from 2010-09-14 regarding subpixel when LIGHT hinting enabled
  243.   have been reverted due to problems.  The old behavior is back.
  244.  
  245. * Disable grayscale when subpixel is enabled.  This results in better
  246.   behavior of some TT instructions within some fonts, like Times New Roman.
  247.  
  248. * Some modification of the tweaks, in light of above.
  249.  
  250.  
  251. Changes for 2010-09-14:
  252.  
  253. /************************** NO LONGER IN PLACE *****************************/
  254. * Subpixel hinting is now used when the LIGHT hinting method and the TT
  255.   hinting is called.  If FULL hinting is requested it will do the usual
  256.   behavior of the TT hinter.
  257.  
  258.   This allows for all previously existing behavior, plus the new subpixel
  259.   hinting behavior, all in the same compile, and it makes sense in that
  260.   the slight hinting of the autohinter is essentially doing the same thing
  261.   as this, which is not forcing X-direction hints.
  262.  
  263.   Previously, even if TT was selected, but LIGHT hinting was used, the
  264.   autohinter would still be forced. Other than this, autohint is not affected.
  265. /***************************************************************************/
  266.  
  267. * Added a couple more conditionals around things to test whether subpixel
  268.   hinting is enabled.  There were a few missing that ended up causing some
  269.   goofy hinting if subpixel was not enabled, but compiled in.
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' configure.orig configure
  277. --- configure.orig  2010-10-05 05:25:56.000000000 -0500
  278. +++ configure   2011-11-17 21:00:16.199774763 -0600
  279. @@ -13,6 +13,8 @@
  280. # Call the `configure' script located in `builds/unix'.
  281. #
  282.  
  283. +export LDFLAGS="$LDFLAGS -lm"
  284. +
  285. rm -f config.mk builds/unix/unix-def.mk builds/unix/unix-cc.mk
  286.  
  287. if test "x$GNUMAKE" = x; then
  288. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' include/freetype/config/ftoption.h.orig include/freetype/config/ftoption.h
  289. --- include/freetype/config/ftoption.h.orig 2011-11-17 20:59:44.149885785 -0600
  290. +++ include/freetype/config/ftoption.h 2011-11-17 21:00:16.225773867 -0600
  291. @@ -473,6 +473,19 @@
  292.  
  293.  
  294.   /*************************************************************************/
  295. +  /*                                                                       */
  296. +  /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable     */
  297. +  /* all additional infinality patches, which are configured via env       */
  298. +  /* variables.                                                            */
  299. +  /*                                                                       */
  300. +  /*   This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING and          */
  301. +  /*   TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS to be           */
  302. +  /*   defined.                                                            */
  303. +  /*                                                                       */
  304. +#define FT_CONFIG_OPTION_INFINALITY_PATCHSET
  305. +
  306. +
  307. +  /*************************************************************************/
  308.   /*************************************************************************/
  309.   /****                                                                 ****/
  310.   /****        S F N T   D R I V E R    C O N F I G U R A T I O N       ****/
  311. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' include/freetype/ftoutln.h.orig include/freetype/ftoutln.h
  312. --- include/freetype/ftoutln.h.orig 2011-04-12 17:25:07.000000000 -0500
  313. +++ include/freetype/ftoutln.h  2011-12-12 18:30:36.308161754 -0600
  314. @@ -349,6 +349,10 @@
  315.   FT_Outline_Embolden( FT_Outline*  outline,
  316.                        FT_Pos       strength );
  317.  
  318. +  FT_EXPORT( FT_Error )
  319. +  FT_Outline_Embolden_XY( FT_Outline*  outline,
  320. +                       FT_Pos       strength_x,
  321. +                       FT_Pos       strength_y  );  
  322.  
  323.   /*************************************************************************/
  324.   /*                                                                       */
  325. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/autofit/aflatin.c.orig src/autofit/aflatin.c
  326. --- src/autofit/aflatin.c.orig  2011-06-20 12:03:27.000000000 -0500
  327. +++ src/autofit/aflatin.c   2011-12-12 18:11:57.518724747 -0600
  328. @@ -22,6 +22,7 @@
  329.  
  330. #include "aflatin.h"
  331. #include "aferrors.h"
  332. +#include "strings.h"
  333.  
  334.  
  335. #ifdef AF_CONFIG_OPTION_USE_WARPER
  336. @@ -528,7 +529,30 @@
  337.     FT_Pos        delta;
  338.     AF_LatinAxis  axis;
  339.     FT_UInt       nn;
  340. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  341. +    int checked_adjust_heights_env = 0;
  342. +    FT_Bool adjust_heights = FALSE;
  343.  
  344. +    if ( checked_adjust_heights_env == 0 )
  345. +    {
  346. +      char *adjust_heights_env = getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" );
  347. +      if ( adjust_heights_env != NULL )
  348. +      {
  349. +        if ( strcasecmp(adjust_heights_env, "default" ) != 0 )
  350. +        {
  351. +          if ( strcasecmp(adjust_heights_env, "true") == 0)
  352. +            adjust_heights = TRUE;
  353. +          else if ( strcasecmp(adjust_heights_env, "1") == 0)
  354. +            adjust_heights = TRUE;
  355. +          else if ( strcasecmp(adjust_heights_env, "on") == 0)
  356. +            adjust_heights = TRUE;
  357. +          else if ( strcasecmp(adjust_heights_env, "yes") == 0)
  358. +            adjust_heights = TRUE;
  359. +        }
  360. +      }
  361. +      checked_adjust_heights_env = 1;
  362. +    }
  363. +#endif
  364.  
  365.     if ( dim == AF_DIMENSION_HORZ )
  366.     {
  367. @@ -537,8 +561,8 @@
  368.     }
  369.     else
  370.     {
  371. -      scale = scaler->y_scale;
  372. -      delta = scaler->y_delta;
  373. +      scale = scaler->y_scale /* * 1.033*/;
  374. +      delta = scaler->y_delta /*- 16*/;
  375.     }
  376.  
  377.     axis = &metrics->axis[dim];
  378. @@ -556,7 +580,7 @@
  379.     {
  380.       AF_LatinAxis  Axis = &metrics->axis[AF_DIMENSION_VERT];
  381.       AF_LatinBlue  blue = NULL;
  382. -
  383. +      int threshold = 40;
  384.  
  385.       for ( nn = 0; nn < Axis->blue_count; nn++ )
  386.       {
  387. @@ -566,12 +590,16 @@
  388.           break;
  389.         }
  390.       }
  391. -
  392. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  393. +      if ( adjust_heights
  394. +        && metrics->root.scaler.face->size->metrics.x_ppem < 15
  395. +        && metrics->root.scaler.face->size->metrics.x_ppem > 5 )
  396. +        threshold = 52;
  397. +#endif
  398.       if ( blue )
  399.       {
  400.         FT_Pos  scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
  401. -        FT_Pos  fitted = ( scaled + 40 ) & ~63;
  402. -
  403. +        FT_Pos  fitted = ( scaled + threshold ) & ~63;
  404.  
  405.         if ( scaled != fitted )
  406.         {
  407. @@ -626,7 +654,6 @@
  408.         AF_LatinBlue  blue = &axis->blues[nn];
  409.         FT_Pos        dist;
  410.  
  411. -
  412.         blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
  413.         blue->ref.fit   = blue->ref.cur;
  414.         blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
  415. @@ -635,7 +662,12 @@
  416.  
  417.         /* a blue zone is only active if it is less than 3/4 pixels tall */
  418.         dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
  419. +
  420. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  421. +        /* Do always, in order to prevent fringes */
  422. +#else        
  423.         if ( dist <= 48 && dist >= -48 )
  424. +#endif          
  425.         {
  426. #if 0
  427.           FT_Pos  delta1;
  428. @@ -686,7 +718,12 @@
  429.             delta2 = -delta2;
  430.  
  431.           blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
  432. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET          
  433. +          /* Round to prevent fringes */
  434. +          blue->shoot.fit = FT_PIX_ROUND( blue->ref.fit - delta2 );
  435. +#else
  436.           blue->shoot.fit = blue->ref.fit - delta2;
  437. +#endif          
  438.  
  439. #endif
  440.  
  441. @@ -1432,6 +1469,8 @@
  442.               if ( dist < 0 )
  443.                 dist = -dist;
  444.  
  445. +              /* round down to pixels */
  446. +              /*dist = FT_MulFix( dist, scale ) & ~63;*/
  447.               dist = FT_MulFix( dist, scale );
  448.               if ( dist < best_dist )
  449.               {
  450. @@ -1594,20 +1633,95 @@
  451.     FT_Pos           dist     = width;
  452.     FT_Int           sign     = 0;
  453.     FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
  454. -
  455. -
  456. -    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
  457. -         axis->extra_light                       )
  458. -      return width;
  459. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  460. +    FT_Int           infinality_dist = 0;
  461. +    
  462. +    
  463. +
  464. +    FT_UInt autohint_snap_stem_height = 0;
  465. +    FT_UInt checked_autohint_snap_stem_height = 0;
  466. +    
  467. +    if ( checked_autohint_snap_stem_height == 0)
  468. +    {
  469. +      char *autohint_snap_stem_height_env = getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" );
  470. +      if ( autohint_snap_stem_height_env != NULL )
  471. +      {
  472. +        sscanf ( autohint_snap_stem_height_env, "%u", &autohint_snap_stem_height );
  473. +        if      (autohint_snap_stem_height > 100 ) autohint_snap_stem_height = 100;
  474. +        else if (autohint_snap_stem_height < 0 ) autohint_snap_stem_height = 0;
  475. +      }
  476. +      checked_autohint_snap_stem_height = 1;
  477. +    }    
  478. +
  479. +    if ( autohint_snap_stem_height == 0 )
  480. +#endif      
  481. +      if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
  482. +            axis->extra_light                      )
  483. +        return width;
  484.  
  485.     if ( dist < 0 )
  486.     {
  487.       dist = -width;
  488.       sign = 1;
  489.     }
  490. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  491. +    /* Calculate snap value differently than standard freetype */
  492. +    if ( /* stem_snap_light*/ autohint_snap_stem_height > 0
  493. +      && (
  494. +           ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )
  495. +      ||   ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
  496. +    {
  497. +      infinality_dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
  498. +
  499. +      if ( metrics->root.scaler.face->size->metrics.x_ppem > 9
  500. +        && axis->width_count > 0
  501. +        && abs ( axis->widths[0].cur - infinality_dist ) < 32
  502. +        && axis->widths[0].cur > 52 )
  503. +      {
  504. +        if ( strstr(metrics->root.scaler.face->style_name, "Regular")
  505. +          || strstr(metrics->root.scaler.face->style_name, "Book")
  506. +          || strstr(metrics->root.scaler.face->style_name, "Medium")
  507. +          || strcmp(metrics->root.scaler.face->style_name, "Italic") == 0
  508. +          || strcmp(metrics->root.scaler.face->style_name, "Oblique") == 0 )
  509. +        {
  510. +          /* regular weight */
  511. +          if ( axis->widths[0].cur < 64 ) infinality_dist = 64 ;
  512. +          else if (axis->widths[0].cur  < 88) infinality_dist = 64;
  513. +          else if (axis->widths[0].cur  < 160) infinality_dist = 128;
  514. +          else if (axis->widths[0].cur  < 240) infinality_dist = 190;
  515. +          else infinality_dist = ( infinality_dist ) & ~63;
  516. +        }
  517. +        else
  518. +        {
  519. +          /* bold gets a different threshold */
  520. +          if ( axis->widths[0].cur < 64 ) infinality_dist = 64 ;
  521. +          else if (axis->widths[0].cur  < 108) infinality_dist = 64;
  522. +          else if (axis->widths[0].cur  < 160) infinality_dist = 128;
  523. +          else if (axis->widths[0].cur  < 222) infinality_dist = 190;
  524. +          else if (axis->widths[0].cur  < 288) infinality_dist = 254;
  525. +          else infinality_dist = ( infinality_dist + 16 ) & ~63;
  526. +        }
  527. +
  528. +      }
  529. +      if (infinality_dist < 52)
  530. +      {
  531. +        if (metrics->root.scaler.face->size->metrics.x_ppem < 9 )
  532. +        {
  533.  
  534. -    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
  535. -         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
  536. +          if (infinality_dist < 32) infinality_dist = 32;
  537. +        }
  538. +        else
  539. +          infinality_dist = 64;
  540. +      }
  541. +    }
  542. +    else if ( autohint_snap_stem_height < 100
  543. +      && (( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
  544. +         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
  545. +#else
  546. +      
  547. +    if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
  548. +         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
  549. +#endif      
  550.     {
  551.       /* smooth hinting process: very lightly quantize the stem width */
  552.  
  553. @@ -1666,7 +1780,10 @@
  554.           dist = ( dist + 32 ) & ~63;
  555.       }
  556.     }
  557. -    else
  558. +    else
  559. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET        
  560. +      if ( autohint_snap_stem_height < 100 )
  561. +#endif        
  562.     {
  563.       /* strong hinting process: snap the stem width to integer pixels */
  564.  
  565. @@ -1674,7 +1791,9 @@
  566.  
  567.  
  568.       dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
  569. -
  570. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  571. +      if ( autohint_snap_stem_height > 0 ) goto Done_Width;
  572. +#endif
  573.       if ( vertical )
  574.       {
  575.         /* in the case of vertical hinting, always round */
  576. @@ -1737,6 +1856,23 @@
  577.     }
  578.  
  579.   Done_Width:
  580. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  581. +    if (axis->widths[0].cur > 42 )
  582. +      /* weighted average */
  583. +      dist = (dist * (100 - autohint_snap_stem_height) + infinality_dist * autohint_snap_stem_height ) / 100;  
  584. +
  585. +      {
  586. +        int factor = 100;
  587. +        if (axis->standard_width < 100)
  588. +          factor = axis->standard_width;
  589. +
  590. +        if (metrics->root.scaler.face->size->metrics.x_ppem >=9  && dist < 52 ) dist += ((52 - dist) * factor) / 100;
  591. +        if (metrics->root.scaler.face->size->metrics.x_ppem <9  && dist < 32 ) dist += ((32 - dist) * factor) / 100;
  592. +        
  593. +        if (axis->standard_width > 100 && metrics->root.scaler.face->size->metrics.x_ppem >=11  && dist < 64 ) dist = 64;
  594. +        if (axis->standard_width > 100 && metrics->root.scaler.face->size->metrics.x_ppem >=9  && dist < 52 ) dist = 52;      
  595. +      }
  596. +#endif    
  597.     if ( sign )
  598.       dist = -dist;
  599.  
  600. @@ -1759,6 +1895,8 @@
  601.                              (AF_Edge_Flags)base_edge->flags,
  602.                              (AF_Edge_Flags)stem_edge->flags );
  603.  
  604. +/* if fitted_width causes stem_edge->pos to land basically on top of an existing
  605. + * stem_edge->pos, then add or remove 64.  Need to figure out a way to do this */
  606.  
  607.     stem_edge->pos = base_edge->pos + fitted_width;
  608.  
  609. @@ -2233,8 +2371,32 @@
  610.   {
  611.     FT_Error  error;
  612.     int       dim;
  613. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET      
  614. +    int       emboldening_strength = 0;
  615.  
  616. -
  617. +    int checked_use_various_tweaks_env = 0;
  618. +    FT_Bool use_various_tweaks = FALSE;
  619. +    
  620. +    if ( checked_use_various_tweaks_env == 0 )
  621. +    {
  622. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  623. +      if ( use_various_tweaks_env != NULL )
  624. +      {
  625. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  626. +        {
  627. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0)
  628. +            use_various_tweaks = TRUE;
  629. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0)
  630. +            use_various_tweaks = TRUE;
  631. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0)
  632. +            use_various_tweaks = TRUE;
  633. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0)
  634. +            use_various_tweaks = TRUE;
  635. +        }
  636. +      }
  637. +      checked_use_various_tweaks_env = 1;
  638. +    }
  639. +#endif
  640.     error = af_glyph_hints_reload( hints, outline );
  641.     if ( error )
  642.       goto Exit;
  643. @@ -2291,7 +2453,54 @@
  644.       }
  645.     }
  646.     af_glyph_hints_save( hints, outline );
  647. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET    
  648. +#if 0
  649. +    if( metrics->root.scaler.face->style_name )
  650. +    {
  651. +      if ( strcasestr(metrics->root.scaler.face->style_name, "Bold")  
  652. +        || strcasestr(metrics->root.scaler.face->style_name, "Black")          
  653. +        || strcasestr(metrics->root.scaler.face->style_name, "Narrow")
  654. +               && metrics->root.scaler.face->size->metrics.x_ppem < 15  
  655. +        || strcasestr(metrics->root.scaler.face->style_name, "Condensed")
  656. +               && metrics->root.scaler.face->size->metrics.x_ppem < 20 )        
  657. +            goto Exit;
  658. +    }
  659. +    if( metrics->root.scaler.face->family_name )
  660. +    {
  661. +      if ( strcasestr(metrics->root.scaler.face->family_name, "Bold")  
  662. +        || strcasestr(metrics->root.scaler.face->family_name, "Black")          
  663. +        || strcasestr(metrics->root.scaler.face->family_name, "Narrow")
  664. +               && metrics->root.scaler.face->size->metrics.x_ppem < 15
  665. +        || strcasestr(metrics->root.scaler.face->family_name, "Condensed")
  666. +               && metrics->root.scaler.face->size->metrics.x_ppem < 20 )        
  667. +            goto Exit;
  668. +    }  
  669.  
  670. +    /* if the font is particularly thin, embolden it, up to 1 px */
  671. +    if ( use_various_tweaks
  672. +      && metrics->axis->widths[0].cur <= FT_MulDiv ( autohint_minimum_stem_width, 64, 100)
  673. +      && !( dim == AF_DIMENSION_VERT )
  674. +      && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) )
  675. +    {
  676. +      if ( metrics->axis->widths[0].cur
  677. +        / metrics->root.scaler.face->size->metrics.x_ppem < 5 )
  678. +      {
  679. +         emboldening_strength = FT_MulDiv ( autohint_minimum_stem_width, 64, 100) - metrics->axis->widths[0].cur;
  680. +        if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 )
  681. +          emboldening_strength -= 10;
  682. +        if ( metrics->root.scaler.face->size->metrics.x_ppem < 7 )
  683. +          emboldening_strength -= 10;            
  684. +      }
  685. +      if ( emboldening_strength < 0 ) emboldening_strength = 0;
  686. +      FT_Outline_Embolden(outline,emboldening_strength);
  687. +    }
  688. +#endif
  689. +    /* Save this width for use in ftsmooth.c.  This is a shameful hack */
  690. +    const char* c1 = "CUR_WIDTH";
  691. +    char c2[8];
  692. +    snprintf(c2,8,"%ld",metrics->axis->widths[0].cur);
  693. +    setenv(c1, c2, 1);
  694. +#endif
  695.   Exit:
  696.     return error;
  697.   }
  698. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/autofit/afloader.c.orig src/autofit/afloader.c
  699. --- src/autofit/afloader.c.orig 2011-04-18 09:24:17.000000000 -0500
  700. +++ src/autofit/afloader.c  2011-11-28 21:51:34.373981498 -0600
  701. @@ -190,8 +190,8 @@
  702.         AF_Edge       edge2 = edge1 +
  703.                               axis->num_edges - 1; /* rightmost edge */
  704.  
  705. -
  706. -        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
  707. +/* dont hint metrics - temporary until different hinting can be done */
  708. +        if ( /*FALSE &&*/ axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
  709.         {
  710.           old_rsb = loader->pp2.x - edge2->opos;
  711.           old_lsb = edge1->opos;
  712. @@ -224,7 +224,8 @@
  713.           slot->lsb_delta = loader->pp1.x - pp1x_uh;
  714.           slot->rsb_delta = loader->pp2.x - pp2x_uh;
  715.         }
  716. -        else
  717. +/* dont hint metrics - temporary until different hinting can be done */        
  718. +        else /*if (FALSE)*/
  719.         {
  720.           FT_Pos  pp1x = loader->pp1.x;
  721.           FT_Pos  pp2x = loader->pp2.x;
  722. @@ -410,6 +411,9 @@
  723. #endif
  724.       FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
  725.  
  726. +  /*    slot->metrics.horiBearingX_o = bbox.xMin;  
  727. +      slot->metrics.width_o        = bbox.xMax - bbox.xMin;       */
  728. +      
  729.       bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
  730.       bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
  731.       bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
  732. @@ -456,6 +460,7 @@
  733.       slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
  734.                                              metrics->scaler.y_scale );
  735.  
  736. +    /*  slot->metrics.horiAdvance_o = slot->metrics.horiAdvance;*/
  737.       slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
  738.       slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
  739.  
  740. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/base/ftlcdfil.c.orig src/base/ftlcdfil.c
  741. --- src/base/ftlcdfil.c.orig    2010-04-01 03:18:57.000000000 -0500
  742. +++ src/base/ftlcdfil.c 2011-11-30 20:05:45.371694287 -0600
  743. @@ -21,6 +21,9 @@
  744. #include FT_IMAGE_H
  745. #include FT_INTERNAL_OBJECTS_H
  746.  
  747. +#include <math.h>
  748. +#include <string.h>
  749. +#include <strings.h>
  750.  
  751. #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  752.  
  753. @@ -287,10 +290,51 @@
  754.                             { 0x00, 0x55, 0x56, 0x55, 0x00 };
  755.     /* the values here sum up to a value larger than 256, */
  756.     /* providing a cheap gamma correction                 */
  757. -    static const FT_Byte  default_filter[5] =
  758. +    static FT_Byte  default_filter[5] =
  759.                             { 0x10, 0x40, 0x70, 0x40, 0x10 };
  760. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  761. +    int checked_filter_params_env = 0;
  762.  
  763. +    if ( checked_filter_params_env == 0 )
  764. +    {
  765. +      char *filter_params = getenv( "INFINALITY_FT_FILTER_PARAMS" );
  766. +      if ( filter_params != NULL && strcmp(filter_params, "") != 0 )
  767. +      {
  768. +        float f1, f2, f3, f4, f5;
  769. +
  770. +        if ( strcasecmp(filter_params, "default" ) != 0)
  771. +        {
  772. +          int args_assigned = 0;
  773. +          args_assigned = sscanf ( filter_params, "%f %f %f %f %f", &f1, &f2, &f3, &f4, &f5 );
  774.  
  775. +          if ( args_assigned == 5 )
  776. +          {
  777. +            if ( f1 + f2 + f3 + f4 + f5 > 5 )
  778. +            {
  779. +              /* Assume we were given integers instead of floats */
  780. +              /* 0 to 100 */
  781. +              default_filter[0] = (FT_Byte) (f1 * 2.55f + 0.5f);
  782. +              default_filter[1] = (FT_Byte) (f2 * 2.55f + 0.5f);
  783. +              default_filter[2] = (FT_Byte) (f3 * 2.55f + 0.5f);
  784. +              default_filter[3] = (FT_Byte) (f4 * 2.55f + 0.5f);
  785. +              default_filter[4] = (FT_Byte) (f5 * 2.55f + 0.5f);
  786. +            }
  787. +            else
  788. +            {
  789. +              /* Assume we were given floating point values */
  790. +              /* 0 to 1.0 */
  791. +              default_filter[0] = (FT_Byte) (f1 * 255.0f + 0.5f);
  792. +              default_filter[1] = (FT_Byte) (f2 * 255.0f + 0.5f);
  793. +              default_filter[2] = (FT_Byte) (f3 * 255.0f + 0.5f);
  794. +              default_filter[3] = (FT_Byte) (f4 * 255.0f + 0.5f);
  795. +              default_filter[4] = (FT_Byte) (f5 * 255.0f + 0.5f);
  796. +            }
  797. +          }
  798. +        }
  799. +      }
  800. +      checked_filter_params_env = 1;
  801. +    }
  802. +#endif
  803.     if ( !library )
  804.       return FT_Err_Invalid_Argument;
  805.  
  806. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/base/ftobjs.c.orig src/base/ftobjs.c
  807. --- src/base/ftobjs.c.orig  2011-10-15 02:32:41.000000000 -0500
  808. +++ src/base/ftobjs.c   2011-11-17 21:00:16.231773659 -0600
  809. @@ -567,8 +567,27 @@
  810.     FT_Bool       autohint = FALSE;
  811.     FT_Module     hinter;
  812.     TT_Face       ttface = (TT_Face)face;
  813. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  814.  
  815. +    int checked_use_various_tweaks_env = FALSE;
  816. +    FT_Bool use_various_tweaks = FALSE;
  817.  
  818. +    if ( !checked_use_various_tweaks_env )
  819. +    {
  820. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  821. +      if ( use_various_tweaks_env != NULL )
  822. +      {
  823. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  824. +        {
  825. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0) use_various_tweaks = TRUE;
  826. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0) use_various_tweaks = TRUE;
  827. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0) use_various_tweaks = TRUE;
  828. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0) use_various_tweaks = TRUE;
  829. +        }
  830. +      }
  831. +      checked_use_various_tweaks_env = 1;
  832. +    }
  833. +#endif
  834.     if ( !face || !face->size || !face->glyph )
  835.       return FT_Err_Invalid_Face_Handle;
  836.  
  837. @@ -648,8 +667,22 @@
  838.     if ( autohint )
  839.     {
  840.       FT_AutoHinter_Service  hinting;
  841. -
  842. -
  843. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  844. +      if ( use_various_tweaks )
  845. +      {
  846. +        load_flags = 66088;
  847. +        /* attempt to force slight hinting here, but doesn't work */
  848. +        /* the above hack does though, until I can figure out the below */
  849. +
  850. +        /*load_flags &= ~FT_RENDER_MODE_NORMAL;
  851. +        load_flags &= ~FT_LOAD_TARGET_NORMAL;
  852. +        load_flags &= ~FT_LOAD_NO_AUTOHINT;
  853. +        load_flags |= FT_RENDER_MODE_LIGHT;
  854. +        load_flags |= FT_LOAD_TARGET_LIGHT;
  855. +        load_flags |= FT_LOAD_FORCE_AUTOHINT;*/
  856. +        /*printf("%d ", load_flags);*/
  857. +      }
  858. +#endif
  859.        /* try to load embedded bitmaps first if available            */
  860.        /*                                                            */
  861.        /* XXX: This is really a temporary hack that should disappear */
  862. @@ -687,6 +720,10 @@
  863.      }
  864.      else
  865.      {
  866. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET        
  867. +      char* c1 = "CUR_WIDTH";
  868. +      char* c2 = "0";
  869. +#endif      
  870.        error = driver->clazz->load_glyph( slot,
  871.                                           face->size,
  872.                                           glyph_index,
  873. @@ -694,6 +731,10 @@
  874.        if ( error )
  875.          goto Exit;
  876.  
  877. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  878. +      setenv(c1, c2, 1);
  879. +#endif
  880. +
  881.        if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
  882.        {
  883.          /* check that the loaded outline is correct */
  884. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/base/ftoutln.c.orig src/base/ftoutln.c
  885. --- src/base/ftoutln.c.orig 2010-06-27 08:03:58.000000000 -0500
  886. +++ src/base/ftoutln.c  2011-12-23 19:37:59.293160172 -0600
  887. @@ -887,8 +887,30 @@
  888.      FT_Angle    rotate, angle_in, angle_out;
  889.      FT_Int      c, n, first;
  890.      FT_Int      orientation;
  891. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  892. +    int checked_use_various_tweaks_env = 0;
  893. +    FT_Bool use_various_tweaks = FALSE;
  894.  
  895. -
  896. +    if ( checked_use_various_tweaks_env == 0 )
  897. +    {
  898. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  899. +      if ( use_various_tweaks_env != NULL )
  900. +      {
  901. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  902. +        {
  903. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0)
  904. +            use_various_tweaks = TRUE;
  905. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0)
  906. +            use_various_tweaks = TRUE;
  907. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0)
  908. +            use_various_tweaks = TRUE;
  909. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0)
  910. +            use_various_tweaks = TRUE;
  911. +        }
  912. +      }
  913. +      checked_use_various_tweaks_env = 1;
  914. +    }
  915. +#endif
  916.      if ( !outline )
  917.        return FT_Err_Invalid_Argument;
  918.  
  919. @@ -957,6 +979,9 @@
  920.          }
  921.  
  922.          outline->points[n].x = v_cur.x + strength + in.x;
  923. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET        
  924. +        if ( !use_various_tweaks )
  925. +#endif          
  926.          outline->points[n].y = v_cur.y + strength + in.y;
  927.  
  928.          v_prev = v_cur;
  929. @@ -969,6 +994,99 @@
  930.      return FT_Err_Ok;
  931.    }
  932.  
  933. +  
  934. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET  
  935. +  /* documentation is in ftoutln.h */
  936. +
  937. +  FT_EXPORT_DEF( FT_Error )
  938. +  FT_Outline_Embolden_XY( FT_Outline*  outline,
  939. +                       FT_Pos       strength_x,
  940. +                       FT_Pos       strength_y  )
  941. +  {
  942. +    FT_Vector*  points;
  943. +    FT_Vector   v_prev, v_first, v_next, v_cur;
  944. +    FT_Angle    rotate, angle_in, angle_out;
  945. +    FT_Int      c, n, first;
  946. +    FT_Int      orientation;
  947. +
  948. +    if ( !outline )
  949. +      return FT_Err_Invalid_Argument;
  950. +
  951. +    orientation = FT_Outline_Get_Orientation( outline );
  952. +    if ( orientation == FT_ORIENTATION_NONE )
  953. +    {
  954. +      if ( outline->n_contours )
  955. +        return FT_Err_Invalid_Argument;
  956. +      else
  957. +        return FT_Err_Ok;
  958. +    }
  959. +
  960. +    if ( orientation == FT_ORIENTATION_TRUETYPE )
  961. +      rotate = -FT_ANGLE_PI2;
  962. +    else
  963. +      rotate = FT_ANGLE_PI2;
  964. +
  965. +    points = outline->points;
  966. +
  967. +    first = 0;
  968. +    for ( c = 0; c < outline->n_contours; c++ )
  969. +    {
  970. +      int  last = outline->contours[c];
  971. +
  972. +
  973. +      v_first = points[first];
  974. +      v_prev  = points[last];
  975. +      v_cur   = v_first;
  976. +
  977. +      for ( n = first; n <= last; n++ )
  978. +      {
  979. +        FT_Vector  in, out;
  980. +        FT_Angle   angle_diff;
  981. +        FT_Pos     d, dy;
  982. +        FT_Fixed   scale;
  983. +
  984. +
  985. +        if ( n < last )
  986. +          v_next = points[n + 1];
  987. +        else
  988. +          v_next = v_first;
  989. +
  990. +        /* compute the in and out vectors */
  991. +        in.x = v_cur.x - v_prev.x;
  992. +        in.y = v_cur.y - v_prev.y;
  993. +
  994. +        out.x = v_next.x - v_cur.x;
  995. +        out.y = v_next.y - v_cur.y;
  996. +
  997. +        angle_in   = FT_Atan2( in.x, in.y );
  998. +        angle_out  = FT_Atan2( out.x, out.y );
  999. +        angle_diff = FT_Angle_Diff( angle_in, angle_out );
  1000. +        scale      = FT_Cos( angle_diff / 2 );
  1001. +
  1002. +        if ( scale < 0x4000L && scale > -0x4000L )
  1003. +          in.x = in.y = 0;
  1004. +        else
  1005. +        {
  1006. +          d = FT_DivFix( strength_x, scale );
  1007. +          dy = FT_DivFix( strength_y, scale );
  1008. +          
  1009. +          FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
  1010. +          FT_Vector_From_Polar( &in, dy, angle_in + angle_diff / 2 - rotate );          
  1011. +        }
  1012. +
  1013. +        outline->points[n].x = v_cur.x + strength_x + in.x;
  1014. +        outline->points[n].y = v_cur.y + strength_y + in.y;
  1015. +
  1016. +        v_prev = v_cur;
  1017. +        v_cur  = v_next;
  1018. +      }
  1019. +
  1020. +      first = last + 1;
  1021. +    }
  1022. +
  1023. +    return FT_Err_Ok;
  1024. +  }  
  1025. +#endif  
  1026.  
  1027.    /* documentation is in ftoutln.h */
  1028.  
  1029. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/base/ftsynth.c.orig src/base/ftsynth.c
  1030. --- src/base/ftsynth.c.orig 2010-09-11 01:28:32.000000000 -0500
  1031. +++ src/base/ftsynth.c  2011-12-01 19:00:13.275375244 -0600
  1032. @@ -87,7 +87,26 @@
  1033.      FT_Face     face    = slot->face;
  1034.      FT_Error    error;
  1035.      FT_Pos      xstr, ystr;
  1036. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  1037. +    int checked_use_various_tweaks_env = 0;
  1038. +    FT_Bool use_various_tweaks = FALSE;
  1039.  
  1040. +    if ( checked_use_various_tweaks_env == 0 )
  1041. +    {
  1042. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  1043. +      if ( use_various_tweaks_env != NULL )
  1044. +      {
  1045. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  1046. +        {
  1047. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0) use_various_tweaks = TRUE;
  1048. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0) use_various_tweaks = TRUE;
  1049. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0) use_various_tweaks = TRUE;
  1050. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0) use_various_tweaks = TRUE;
  1051. +        }
  1052. +      }
  1053. +      checked_use_various_tweaks_env = 1;
  1054. +    }
  1055. +#endif
  1056.  
  1057.      if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
  1058.           slot->format != FT_GLYPH_FORMAT_BITMAP  )
  1059. @@ -146,6 +165,9 @@
  1060.      slot->metrics.width        += xstr;
  1061.      slot->metrics.height       += ystr;
  1062.      slot->metrics.horiBearingY += ystr;
  1063. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET    
  1064. +    if ( !use_various_tweaks )
  1065. +#endif      
  1066.      slot->metrics.horiAdvance  += xstr;
  1067.      slot->metrics.vertBearingX -= xstr / 2;
  1068.      slot->metrics.vertBearingY += ystr;
  1069. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/smooth/ftsmooth.c.orig src/smooth/ftsmooth.c
  1070. --- src/smooth/ftsmooth.c.orig  2011-05-29 23:46:55.000000000 -0500
  1071. +++ src/smooth/ftsmooth.c   2011-12-23 19:38:36.591875446 -0600
  1072. @@ -26,6 +26,16 @@
  1073.  
  1074.  #include "ftsmerrs.h"
  1075.  
  1076. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  1077. +#include <math.h>
  1078. +#include "../../include/freetype/ftbitmap.h"
  1079. +#include "strings.h"
  1080. +#include "../autofit/aflatin.h"
  1081. +#include "../../include/freetype/ftoutln.h"
  1082. +
  1083. +#define verbose FALSE
  1084. +#define STVALUES if (verbose) printf ("scale:%f translate:%ld ", *scale_value, *translate_value);
  1085. +#endif
  1086.  
  1087.    /* initialize renderer -- init its raster */
  1088.    static FT_Error
  1089. @@ -34,65 +44,2818 @@
  1090.      FT_Library  library = FT_MODULE_LIBRARY( render );
  1091.  
  1092.  
  1093. -    render->clazz->raster_class->raster_reset( render->raster,
  1094. -                                               library->raster_pool,
  1095. -                                               library->raster_pool_size );
  1096. +    render->clazz->raster_class->raster_reset( render->raster,
  1097. +                                               library->raster_pool,
  1098. +                                               library->raster_pool_size );
  1099. +
  1100. +    return 0;
  1101. +  }
  1102. +
  1103. +
  1104. +  /* sets render-specific mode */
  1105. +  static FT_Error
  1106. +  ft_smooth_set_mode( FT_Renderer  render,
  1107. +                      FT_ULong     mode_tag,
  1108. +                      FT_Pointer   data )
  1109. +  {
  1110. +    /* we simply pass it to the raster */
  1111. +    return render->clazz->raster_class->raster_set_mode( render->raster,
  1112. +                                                         mode_tag,
  1113. +                                                         data );
  1114. +  }
  1115. +
  1116. +  /* transform a given glyph image */
  1117. +  static FT_Error
  1118. +  ft_smooth_transform( FT_Renderer       render,
  1119. +                       FT_GlyphSlot      slot,
  1120. +                       const FT_Matrix*  matrix,
  1121. +                       const FT_Vector*  delta )
  1122. +  {
  1123. +    FT_Error  error = Smooth_Err_Ok;
  1124. +
  1125. +
  1126. +    if ( slot->format != render->glyph_format )
  1127. +    {
  1128. +      error = Smooth_Err_Invalid_Argument;
  1129. +      goto Exit;
  1130. +    }
  1131. +
  1132. +    if ( matrix )
  1133. +      FT_Outline_Transform( &slot->outline, matrix );
  1134. +
  1135. +    if ( delta )
  1136. +      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
  1137. +
  1138. +  Exit:
  1139. +    return error;
  1140. +  }
  1141. +
  1142. +
  1143. +  /* return the glyph's control box */
  1144. +  static void
  1145. +  ft_smooth_get_cbox( FT_Renderer   render,
  1146. +                      FT_GlyphSlot  slot,
  1147. +                      FT_BBox*      cbox )
  1148. +  {
  1149. +    FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
  1150. +
  1151. +    if ( slot->format == render->glyph_format )
  1152. +      FT_Outline_Get_CBox( &slot->outline, cbox );
  1153. +  }
  1154. +
  1155. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  1156. +  static FT_Fixed FT_FixedFromFloat(float f)
  1157. +  {
  1158. +    short value = f;
  1159. +    unsigned short fract = (f - value) * 0xFFFF;
  1160. +    return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
  1161. +  }
  1162. +
  1163. +
  1164. +  /* ChromeOS sharpening algorithm */
  1165. +  /* soften the sub-pixel anti-aliasing and sharpen */
  1166. +  static void
  1167. +  _ft_lcd_chromeos_sharpen( FT_Bitmap*      bitmap,
  1168. +                        FT_Render_Mode  mode,
  1169. +                        FT_Byte         cutoff,
  1170. +                        double          gamma_value )
  1171. +  {
  1172. +    static FT_Bool initialized_gamma = FALSE;
  1173. +    static unsigned short gamma_ramp[256];
  1174. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1175. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1176. +    int    ii;
  1177. +
  1178. +    if (!initialized_gamma)
  1179. +    {
  1180. +      initialized_gamma = TRUE;
  1181. +      /* linear to voltage */
  1182. +      for ( ii = 0; ii < 256; ii++ )
  1183. +      {
  1184. +        gamma_ramp[ii] = (unsigned char)
  1185. +                         ( pow( (double)ii/255.0, gamma_value ) * 255.0f );
  1186. +        if (gamma_ramp[ii] < cutoff) {
  1187. +          gamma_ramp[ii] = 0;
  1188. +        }
  1189. +      }
  1190. +    }
  1191. +
  1192. +    /* horizontal in-place sub-pixel sharpening filter */
  1193. +    if ( mode == FT_RENDER_MODE_LCD)
  1194. +    {
  1195. +      FT_Byte*  line = bitmap->buffer;
  1196. +      for ( ; height > 0; height--, line += bitmap->pitch )
  1197. +      {
  1198. +        FT_UInt  xx;
  1199. +        for ( xx = 0; xx < width; xx++ )
  1200. +        {
  1201. +          line[xx] = gamma_ramp[line[xx]];
  1202. +        }
  1203. +      }
  1204. +    }
  1205. +  }
  1206. +
  1207. +  /* simple linear scale to handle various sliding values */
  1208. +  float
  1209. +  sliding_scale ( int            min_value,
  1210. +                      int        max_value,
  1211. +                      float      min_amount,
  1212. +                      float      max_amount,
  1213. +                      int        cur_value )
  1214. +  {
  1215. +
  1216. +    float m = (min_amount - max_amount) / (float)(min_value - max_value);
  1217. +    float result = (((float)cur_value * m) + (max_amount - max_value * m)) ;
  1218. +
  1219. +    if (min_amount < max_amount)
  1220. +    {
  1221. +      if (result < min_amount) return min_amount;
  1222. +      if (result > max_amount) return max_amount;
  1223. +    }
  1224. +    else
  1225. +    {
  1226. +      if (result < max_amount) return max_amount;
  1227. +      if (result > min_amount) return min_amount;
  1228. +    }
  1229. +
  1230. +    return result;
  1231. +  }
  1232. +
  1233. +
  1234. +  /* brightness and contrast adjustment on the bitmap */
  1235. +  static FT_Bool
  1236. +  _ft_bitmap_bc  ( FT_Bitmap*       bitmap,
  1237. +                      float         brightness,
  1238. +                      float         contrast )
  1239. +  {
  1240. +
  1241. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1242. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1243. +    FT_Byte*  line = bitmap->buffer;
  1244. +    FT_UInt  xx;
  1245. +
  1246. +    if ( brightness == 0 && contrast == 0 ) return FALSE;
  1247. +
  1248. +    for (height = (FT_UInt)bitmap->rows;
  1249. +          height > 0;
  1250. +          height--, line += bitmap->pitch )
  1251. +    {
  1252. +      for ( xx = 0; xx < width - 1; xx += 1 )
  1253. +      {
  1254. +        if ( line[xx] > 0)
  1255. +        {
  1256. +        float value = (float)(255 - line[xx]) / 256.0;
  1257. +        FT_Int result = 0;
  1258. +
  1259. +          if (brightness < 0.0)  value = value * ( 1.0 + brightness);
  1260. +            else value = value + ((1.0 - value) * brightness);
  1261. +          value = (value - 0.5) * (tan ((contrast + 1.0) * 3.141592/4.0) ) + 0.5;
  1262. +
  1263. +          result = (FT_Int)(255.0 - (value) * 256.0);
  1264. +
  1265. +          if (result < 0) result = 0;
  1266. +          if (result > 255) result = 255;
  1267. +
  1268. +          line[xx] = result;
  1269. +        }
  1270. +      }
  1271. +    }
  1272. +    return TRUE;
  1273. +  }
  1274. +
  1275. +
  1276. +  /* Filter to mimic Windows-style sharpening */
  1277. +  /* Determined via 100% experimentation.     */
  1278. +  static void
  1279. +  _ft_lcd_windows_sharpen( FT_Bitmap*      bitmap,
  1280. +                      FT_Render_Mode  mode,
  1281. +                      FT_UInt         strength,
  1282. +                      FT_Library      library )
  1283. +  {
  1284. +
  1285. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1286. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1287. +
  1288. +    FT_Byte*  new_line;
  1289. +    FT_Byte*  line = bitmap->buffer;
  1290. +
  1291. +    FT_Bitmap   new_bitmap;
  1292. +
  1293. +    FT_Bitmap_New(&new_bitmap);
  1294. +
  1295. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1296. +    new_line = (&new_bitmap)->buffer;
  1297. +
  1298. +    if (strength > 0)
  1299. +      for (height = (FT_UInt)bitmap->rows;
  1300. +           height > 0;
  1301. +           height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1302. +    {
  1303. +      FT_UInt  xx, threshold = 128;
  1304. +      FT_Byte*  prevline = line - bitmap->pitch;
  1305. +      FT_Byte*  nextline = line + bitmap->pitch;
  1306. +
  1307. +      FT_Byte*  new_prevline = new_line - bitmap->pitch;
  1308. +      FT_Byte*  new_nextline = new_line + bitmap->pitch;
  1309. +
  1310. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1311. +      {
  1312. +        /* subpixel grid       sp11 sp21 sp31   */
  1313. +        /* where sp22 is       sp12 sp22 sp32   */
  1314. +        /* current subpixel.   sp13 sp23 sp33   */
  1315. +
  1316. +        FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
  1317. +          prevdiff, nextdiff, sp11, sp21, sp31, sp12, sp22, sp32,
  1318. +          sp13, sp23, sp33;
  1319. +
  1320. +        sp12 = line [xx-1];
  1321. +        sp22 = line [xx];
  1322. +        sp32 = line [xx+1];
  1323. +
  1324. +        if (height == bitmap->rows)
  1325. +        {
  1326. +          prevtotal = sp11 = sp21 = sp31 = 0;
  1327. +          prevdiff = sp22;
  1328. +          lefttotal = sp12 + sp13;
  1329. +          righttotal = sp32 + sp33;
  1330. +        }
  1331. +        else
  1332. +        {
  1333. +          prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
  1334. +          sp11 = prevline [xx-1];
  1335. +          sp21 = prevline [xx];
  1336. +          sp31 = prevline [xx+1];
  1337. +          prevdiff = sp22 - sp21;
  1338. +          lefttotal = sp11 + sp12 + sp13;
  1339. +          righttotal = sp31 + sp32 + sp33;
  1340. +        }
  1341. +
  1342. +
  1343. +        if (height == 1)
  1344. +        {
  1345. +          nexttotal = sp13 = sp23 = sp33 = 0;
  1346. +          nextdiff = sp22;
  1347. +          lefttotal = sp11 + sp12;
  1348. +          righttotal = sp31 + sp32;
  1349. +        }
  1350. +        else
  1351. +        {
  1352. +          nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
  1353. +          sp13 = nextline [xx-1];
  1354. +          sp23 = nextline [xx];
  1355. +          sp33 = nextline [xx+1];
  1356. +          nextdiff = sp23 - sp22;
  1357. +          lefttotal = sp11 + sp12 + sp13;
  1358. +          righttotal = sp31 + sp32 + sp33;
  1359. +        }
  1360. +
  1361. +        sidesdiff = lefttotal - righttotal;
  1362. +        if (sidesdiff < 0) sidesdiff *= -1;
  1363. +        if (prevdiff < 0) prevdiff *= -1;
  1364. +        if (nextdiff < 0) nextdiff *= -1;
  1365. +
  1366. +        /* if the current pixel is less than threshold, and greater than 0  */
  1367. +        if ( sp22 <= threshold && sp22 > 0 )
  1368. +        {
  1369. +          /* A pixel is horizontally isolated if: */
  1370. +          /* 1: All upper adjecent pixels are >= threshold */
  1371. +          if ( prevtotal >= nexttotal                && abs (sp11 - sp12) > 5 && abs (sp21 - sp22) > 5 && abs (sp31 - sp32) > 5  /* not a vert stem end */
  1372. +            && sp11 >= threshold
  1373. +            && sp21 >= threshold
  1374. +            && sp31 >= threshold && abs (sp23 - sp22) > 15  /* not on a vert stem */
  1375. +            )
  1376. +          {
  1377. +            /* darken upper adjacent subpixel;  lighten current */
  1378. +            if (height != (FT_UInt)bitmap->rows) new_prevline[xx] += ((255 - new_prevline[xx]) * strength) / 100 ;
  1379. +            new_line[xx] -= (new_line[xx] * strength) / 100;
  1380. +
  1381. +            if (height != 1 && height != (FT_UInt)bitmap->rows) if (new_nextline[xx] > 155 + (100 - strength)) new_prevline[xx] = 255;
  1382. +
  1383. +          }
  1384. +          else if ( nexttotal > prevtotal     && abs (sp13 - sp12) > 5 && abs (sp23 - sp22) > 5 && abs (sp33 - sp32) > 5
  1385. +          /* 2: All lower adjecent pixels are >= threshold */
  1386. +            && sp13 >= threshold
  1387. +            && sp23 >= threshold
  1388. +            && sp33 >= threshold && abs (sp22 - sp21) > 15
  1389. +            )
  1390. +          {
  1391. +            /* darken lower adjacent subpixel;  lighten current */
  1392. +            if (height != 1)  new_nextline[xx] += (255 - new_nextline[xx]) * strength / 100 ;
  1393. +            new_line[xx] -= (new_line[xx] * strength) / 100;
  1394. +
  1395. +            if (height != 1) if (new_nextline[xx] > 155 + (100 - strength)) new_nextline[xx] = 255;
  1396. +
  1397. +          }
  1398. +        }
  1399. +        else if ( sp22 > threshold && sp22 < 255 )
  1400. +        {
  1401. +          if ( sp11 <= threshold    && abs (sp13 - sp12) > 5 && abs (sp23 - sp22) > 5 && abs (sp33 - sp32) > 5
  1402. +            && sp21 <= threshold
  1403. +            && sp31 <= threshold
  1404. +            && prevtotal <= nexttotal && abs (sp22 - sp21) > 15
  1405. +            )
  1406. +          {
  1407. +            /* bring this subpixel 1/3 of the way to 255 at 100% strength */
  1408. +            new_line[xx] += (strength * (255 - new_line[xx]))/100 ;
  1409. +            if (height != (FT_UInt)bitmap->rows) new_prevline[xx] -= (new_prevline[xx] * strength) / 300;
  1410. +          }
  1411. +          else if (
  1412. +            sp13 <= threshold        &&  abs (sp11 - sp12) > 5 && abs (sp21 - sp22) > 5 && abs (sp31 - sp32) > 5
  1413. +            && sp23 <= threshold
  1414. +            && sp33 <= threshold &&
  1415. +            nexttotal < prevtotal && abs (sp23 - sp22) > 15
  1416. +
  1417. +            )
  1418. +          {
  1419. +            new_line[xx] += (strength * (255 - new_line[xx]))/100 ;
  1420. +            if (height != 1) new_nextline[xx] -= (new_nextline[xx] * strength) / 300;
  1421. +          }
  1422. +        }
  1423. +      }
  1424. +    }
  1425. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1426. +    FT_Bitmap_Done(library, &new_bitmap);
  1427. +  }
  1428. +
  1429. +
  1430. +  static void
  1431. +  _ft_lcd_darken_x  ( FT_Bitmap*      bitmap,
  1432. +                      FT_Render_Mode  mode,
  1433. +                      FT_UInt         strength,
  1434. +                      FT_Library      library )
  1435. +  {
  1436. +
  1437. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1438. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1439. +
  1440. +    FT_Byte*  new_line;
  1441. +    FT_Byte*  line = bitmap->buffer;
  1442. +
  1443. +    FT_Bitmap   new_bitmap;
  1444. +
  1445. +    int factor1,factor2;
  1446. +    int bias = 0;
  1447. +
  1448. +    FT_Bitmap_New(&new_bitmap);
  1449. +
  1450. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1451. +    new_line = (&new_bitmap)->buffer;
  1452. +
  1453. +    if (strength > 0)
  1454. +      for (height = (FT_UInt)bitmap->rows;
  1455. +           height > 0;
  1456. +           height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1457. +    {
  1458. +      FT_UInt  xx;
  1459. +      FT_Byte*  prevline = line - bitmap->pitch;
  1460. +      FT_Byte*  nextline = line + bitmap->pitch;
  1461. +
  1462. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1463. +      {
  1464. +        /* subpixel grid       sp11 sp21 sp31   */
  1465. +        /* where sp22 is       sp12 sp22 sp32   */
  1466. +        /* current subpixel.   sp13 sp23 sp33   */
  1467. +
  1468. +        FT_Int sp21, sp12, sp22, sp32, sp23;
  1469. +
  1470. +        sp12 = line [xx-1];
  1471. +        sp22 = line [xx];
  1472. +        sp32 = line [xx+1];
  1473. +
  1474. +        if (height == bitmap->rows)
  1475. +        {
  1476. +          sp21 = 0;
  1477. +        }
  1478. +        else
  1479. +        {
  1480. +          sp21 = prevline [xx];
  1481. +        }
  1482. +
  1483. +        if (height == 1)
  1484. +        {
  1485. +          sp23 = 0;
  1486. +
  1487. +        }
  1488. +        else
  1489. +        {
  1490. +          sp23 = nextline [xx];
  1491. +        }
  1492. +
  1493. +        /* darken subpixel if neighbor above and below are much less than */
  1494. +        /* safer but less effective */
  1495. +        factor1 = 5;
  1496. +        factor2 = 5;
  1497. +
  1498. +        /* make matches in the middle of glyph slightly darker */
  1499. +        /*if (height > 1 && height < (FT_UInt)bitmap->rows) bias = 1;*/
  1500. +
  1501. +        if ( sp22 > factor1 * sp21 && sp22  > factor1 * sp23 && sp22 > factor2  && sp12 > 16 && sp32 > 16 )
  1502. +          if (new_line[xx] < (strength * 255) / 100 )
  1503. +            new_line[xx] = (strength * 255) / 100 + bias * (255 - (strength * 255) / 100) / 3;
  1504. +
  1505. +      }
  1506. +    }
  1507. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1508. +    FT_Bitmap_Done(library, &new_bitmap);
  1509. +  }
  1510. +
  1511. +
  1512. +  static void
  1513. +  _ft_lcd_darken_y  ( FT_Bitmap*      bitmap,
  1514. +                      FT_Render_Mode  mode,
  1515. +                      FT_UInt         strength,
  1516. +                      FT_Library      library )
  1517. +  {
  1518. +
  1519. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1520. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1521. +
  1522. +    FT_Byte*  new_line;
  1523. +    FT_Byte*  line = bitmap->buffer;
  1524. +
  1525. +    FT_Bitmap   new_bitmap;
  1526. +
  1527. +    FT_Bitmap_New(&new_bitmap);
  1528. +
  1529. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1530. +    new_line = (&new_bitmap)->buffer;
  1531. +
  1532. +    if (strength > 0)
  1533. +      for (height = (FT_UInt)bitmap->rows;
  1534. +           height > 0;
  1535. +           height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1536. +    {
  1537. +
  1538. +      FT_UInt  xx;
  1539. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1540. +      {
  1541. +        if (line[xx] > line[xx-1] && line[xx] > line[xx+1])
  1542. +        {
  1543. +           if (new_line[xx] > 0) new_line[xx] += (strength * (255 - new_line[xx]))  / 100;
  1544. +           new_line[xx-1] += (strength * (255 - line[xx-1]))  / 100;
  1545. +           new_line[xx+1] += (strength * (255 - line[xx+1]))  / 100;
  1546. +        }
  1547. +      }
  1548. +    }
  1549. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1550. +    FT_Bitmap_Done(library, &new_bitmap);
  1551. +  }
  1552. +
  1553. +
  1554. +  static void
  1555. +  _ft_bitmap_cap  ( FT_Bitmap*      bitmap,
  1556. +                      FT_UInt         strength,
  1557. +                      FT_Library      library )
  1558. +  {
  1559. +
  1560. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1561. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1562. +
  1563. +    FT_Byte*  new_line;
  1564. +    FT_Byte*  line = bitmap->buffer;
  1565. +
  1566. +    FT_UInt cur_value = 0;
  1567. +
  1568. +    FT_Bitmap   new_bitmap;
  1569. +
  1570. +    FT_Bitmap_New(&new_bitmap);
  1571. +
  1572. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1573. +    new_line = (&new_bitmap)->buffer;
  1574. +
  1575. +    if (strength > 0)
  1576. +      for (height = (FT_UInt)bitmap->rows;
  1577. +           height > 0;
  1578. +           height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1579. +    {
  1580. +
  1581. +      FT_UInt  xx;
  1582. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1583. +      {
  1584. +        cur_value = (new_line[xx-1] + new_line[xx] + new_line[xx+1]) / 3;
  1585. +        if (cur_value > (strength * 255) / 100 )
  1586. +        {
  1587. +          FT_UInt new_factor = (strength * 255) / 100;
  1588. +           new_line[xx] = (new_line[xx] * new_factor)  / cur_value;
  1589. +           new_line[xx+1] = (new_line[xx+1] * new_factor)  / cur_value;
  1590. +           new_line[xx-1] = (new_line[xx-1] * new_factor)  / cur_value;
  1591. +        }
  1592. +      }
  1593. +    }
  1594. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1595. +    FT_Bitmap_Done(library, &new_bitmap);
  1596. +  }
  1597. +
  1598. +
  1599. +  int
  1600. +  gamma2 ( int val, float value )
  1601. +  {
  1602. +    return 256 * (1.0 - pow((1.0 - (float)val/ 256.0) , 1.0/value));
  1603. +  }
  1604. +
  1605. +
  1606. +
  1607. +  static void
  1608. +  _ft_bitmap_embolden  ( FT_Bitmap*      bitmap,
  1609. +                      FT_UInt         strength,
  1610. +                      FT_Library      library )
  1611. +  {
  1612. +
  1613. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1614. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1615. +
  1616. +    FT_Byte*  new_line;
  1617. +    FT_Byte*  line = bitmap->buffer;
  1618. +    FT_Bitmap   new_bitmap;
  1619. +    FT_UInt  xx;
  1620. +
  1621. +    FT_Bitmap_New(&new_bitmap);
  1622. +
  1623. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1624. +
  1625. +    new_line = (&new_bitmap)->buffer;
  1626. +
  1627. +    if (strength > 0)
  1628. +      for (height = (FT_UInt)bitmap->rows;
  1629. +           height > 0;
  1630. +           height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1631. +    {
  1632. +
  1633. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1634. +      {
  1635. +
  1636. +        FT_Int new_value = 0;
  1637. +
  1638. +        new_value = (strength * line [xx-1]) / 100 + gamma2(line [xx], .75) + (strength * line [xx+1]) / 100;
  1639. +        if (new_value > 255) new_value = 255;
  1640. +
  1641. +        new_line[xx] = new_value;
  1642. +
  1643. +      }
  1644. +    }
  1645. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1646. +    FT_Bitmap_Done(library, &new_bitmap);
  1647. +  }
  1648. +
  1649. +
  1650. +
  1651. +  static void
  1652. +  _ft_bitmap_gamma  ( FT_Bitmap*      bitmap,
  1653. +                      float         strength )
  1654. +  {
  1655. +
  1656. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1657. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1658. +
  1659. +    FT_Byte*  line = bitmap->buffer;
  1660. +
  1661. +    FT_UInt  xx;
  1662. +
  1663. +    if (strength > 0)
  1664. +      for (height = (FT_UInt)bitmap->rows;
  1665. +           height > 0;
  1666. +           height--, line += bitmap->pitch )
  1667. +    {
  1668. +
  1669. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1670. +      {
  1671. +        if (abs(line[xx-1] - line[xx]) < 20 || abs(line[xx+1] - line[xx]) < 20)
  1672. +        line [xx] = gamma2(line [xx], strength) ;
  1673. +
  1674. +      }
  1675. +
  1676. +    }
  1677. +  }
  1678. +
  1679. +
  1680. +  /* Fringe filter */
  1681. +  static void
  1682. +  _ft_lcd_fringe_filter ( FT_Bitmap*      bitmap,
  1683. +                      FT_Render_Mode  mode,
  1684. +                      FT_UInt         strength,
  1685. +                      FT_Library      library )
  1686. +  {
  1687. +
  1688. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1689. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1690. +    FT_Byte*  new_line;
  1691. +    FT_Byte*  line = bitmap->buffer;
  1692. +
  1693. +    FT_Bitmap   new_bitmap;
  1694. +    FT_Bitmap_New(&new_bitmap);
  1695. +
  1696. +
  1697. +    line = bitmap->buffer;
  1698. +    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
  1699. +    new_line = (&new_bitmap)->buffer;
  1700. +    for (height = (FT_UInt)bitmap->rows  ; height > 0; height--, line += bitmap->pitch, new_line += bitmap->pitch )
  1701. +    {
  1702. +      /* Threshold set to 1/2 pixel intensity */
  1703. +      FT_UInt  xx, threshold = 128;
  1704. +
  1705. +      /* Hack to make this work when bitmap is at first or last line */
  1706. +      FT_Int   fudge = bitmap->pitch * (height == (FT_UInt)bitmap->rows);
  1707. +
  1708. +
  1709. +      FT_Byte*  prevline = line - bitmap->pitch + fudge;
  1710. +      FT_Byte*  nextline = line + bitmap->pitch;
  1711. +
  1712. +      for ( xx = 1; xx < width - 1; xx += 1 )
  1713. +      {
  1714. +        /* subpixel grid       sp11 sp21 sp31   */
  1715. +        /* where sp22 is       sp12 sp22 sp32   */
  1716. +        /* current subpixel.   sp13 sp23 sp33   */
  1717. +
  1718. +        FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
  1719. +          leftdiff, rightdiff, prevdiff, nextdiff, sp11, sp21, sp31,
  1720. +          sp12, sp22, sp32, sp13, sp23, sp33;
  1721. +
  1722. +        sp12 = line [xx-1];
  1723. +        sp22 = line [xx];
  1724. +        sp32 = line [xx+1];
  1725. +
  1726. +        /* if at max height fake out some values */
  1727. +        if (height == (FT_UInt)bitmap->rows)
  1728. +        {
  1729. +          prevtotal = sp11 = sp21 = sp31 = 0;
  1730. +          prevdiff = sp22;
  1731. +          lefttotal = sp12 + sp13;
  1732. +          righttotal = sp32 + sp33;
  1733. +        }
  1734. +        else
  1735. +        {
  1736. +          prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
  1737. +          sp11 = prevline [xx-1];
  1738. +          sp21 = prevline [xx];
  1739. +          sp31 = prevline [xx+1];
  1740. +          prevdiff = sp22 - sp21;
  1741. +          lefttotal = sp11 + sp12 + sp13;
  1742. +          righttotal = sp31 + sp32 + sp33;
  1743. +        }
  1744. +
  1745. +        /* if at min height fake out some values */
  1746. +        if (height == 1)
  1747. +        {
  1748. +          nexttotal = sp13 = sp23 = sp33 = 0;
  1749. +          nextdiff = sp22;
  1750. +          lefttotal = sp11 + sp12;
  1751. +          righttotal = sp31 + sp32;
  1752. +        }
  1753. +        else
  1754. +        {
  1755. +          nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
  1756. +          sp13 = nextline [xx-1];
  1757. +          sp23 = nextline [xx];
  1758. +          sp33 = nextline [xx+1];
  1759. +          nextdiff = sp23 - sp22;
  1760. +          lefttotal = sp11 + sp12 + sp13;
  1761. +          righttotal = sp31 + sp32 + sp33;
  1762. +        }
  1763. +
  1764. +        sidesdiff = lefttotal - righttotal;
  1765. +        leftdiff = sp22 - sp12;
  1766. +        rightdiff = sp32 - sp22;
  1767. +        if (sidesdiff < 0) sidesdiff *= -1;
  1768. +        if (prevdiff < 0) prevdiff *= -1;
  1769. +        if (nextdiff < 0) nextdiff *= -1;
  1770. +        if (leftdiff < 0) leftdiff *= -1;
  1771. +        if (rightdiff < 0) rightdiff *= -1;
  1772. +
  1773. +        /* if the current subpixel is less than threshold, and varies only
  1774. +          slightly to left or right, lighten it */
  1775. +        if ( sp22 <= threshold && sp22 > 0 && (leftdiff < 10 || rightdiff < 10 ) )
  1776. +        {
  1777. +          /* A pixel is horizontally isolated if: */
  1778. +          /* 1: All upper adjecent subpixels are >= threshold and all lower
  1779. +             adjacent ones are essentially white */
  1780. +          if ( prevtotal >= nexttotal
  1781. +            && sp11 >= threshold
  1782. +            && sp21 >= threshold
  1783. +            && sp31 >= threshold
  1784. +            && sp13 < 2
  1785. +            && sp23 < 2
  1786. +            && sp33 < 2
  1787. +            )
  1788. +
  1789. +          {
  1790. +            new_line[xx] -= (new_line[xx] * strength) / 100;
  1791. +            if (leftdiff < 10) new_line[xx-1] -= (new_line[xx-1] * strength) / 200;  /* OPPORTUNITY FOR IMPROVEMENT  - keep going left until 255? */
  1792. +            if (rightdiff < 10) new_line[xx+1] -= (new_line[xx+1] * strength) / 200;  /* OPPORTUNITY FOR IMPROVEMENT */
  1793. +          }
  1794. +          else if ( nexttotal > prevtotal
  1795. +          /* 2: the inverse of above */
  1796. +            && sp13 >= threshold
  1797. +            && sp23 >= threshold
  1798. +            && sp33 >= threshold
  1799. +            && sp11 < 2
  1800. +            && sp21 < 2
  1801. +            && sp31 < 2
  1802. +            )
  1803. +          {
  1804. +            new_line[xx] -= (new_line[xx] * strength) / 100;
  1805. +            if (leftdiff < 10) new_line[xx-1] -= (new_line[xx-1] * strength) / 200;  /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255?  */
  1806. +            if (rightdiff < 10) new_line[xx+1] -= (new_line[xx+1] * strength) / 200;  /* OPPORTUNITY FOR IMPROVEMENT */
  1807. +          }
  1808. +        }
  1809. +        /* otherwise if the current subpixel is more than threshold, and varies
  1810. +          slightly to left or right, darken it */
  1811. +        else if ( sp22 > threshold && sp22 < 255 && (leftdiff < 10 || rightdiff < 10 ) )
  1812. +        {
  1813. +          if ( sp11 <= 2
  1814. +            && sp21 <= 2
  1815. +            && sp31 <= 2
  1816. +            && sp13 >= threshold
  1817. +            && sp23 >= threshold
  1818. +            && sp33 >= threshold
  1819. +            &&
  1820. +            prevtotal < nexttotal
  1821. +            )
  1822. +
  1823. +          {
  1824. +            new_line[xx] += ((255 - new_line[xx]) * strength) / 100;
  1825. +          }
  1826. +          else if (
  1827. +            sp13 <= 2
  1828. +            && sp23 <= 2
  1829. +            && sp33 <= 2 &&
  1830. +            nexttotal < prevtotal
  1831. +            && sp11 >= threshold
  1832. +            && sp21 >= threshold
  1833. +            && sp31 >= threshold
  1834. +
  1835. +            )
  1836. +          {
  1837. +              new_line[xx] += ((255 - new_line[xx]) * strength) / 100;
  1838. +          }
  1839. +        }
  1840. +      }
  1841. +    }
  1842. +    FT_Bitmap_Copy(library, &new_bitmap, bitmap);
  1843. +    FT_Bitmap_Done(library, &new_bitmap);
  1844. +  }
  1845. +
  1846. +
  1847. +  /* Grayscale filter */
  1848. +  static void
  1849. +  _ft_lcd_grayscale_filter ( FT_Bitmap*      bitmap,
  1850. +                      FT_Render_Mode  mode,
  1851. +                      FT_UInt         strength,
  1852. +                      FT_Library      library )
  1853. +  {
  1854. +
  1855. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  1856. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  1857. +    FT_Byte*  line = bitmap->buffer;
  1858. +
  1859. +    for (height = (FT_UInt)bitmap->rows; height > 0; height--, line += bitmap->pitch )
  1860. +    {
  1861. +      FT_UInt xx;
  1862. +      for ( xx = 0; xx < width - 1; xx += 3 )
  1863. +      {
  1864. +        FT_UInt total = line [xx] + line [xx + 1] + line [xx + 2];
  1865. +        line[xx] =   ( (100-strength) * line[xx]   + strength * (total / 3) ) / 100;
  1866. +        line[xx+1] = ( (100-strength) * line[xx+1] + strength * (total / 3) ) / 100;
  1867. +        line[xx+2] = ( (100-strength) * line[xx+2] + strength * (total / 3) ) / 100;
  1868. +      }
  1869. +    }
  1870. +  }
  1871. +
  1872. +
  1873. +
  1874. +  /*************************************************************************/
  1875. +  /*                                                                       */
  1876. +  /*                                                                       */
  1877. +  /*                                                                       */
  1878. +  /*                                                                       */
  1879. +  /*                                                                       */
  1880. +  /*                                                                       */
  1881. +
  1882. +
  1883. +  typedef struct  SA_Rule_
  1884. +  {
  1885. +    const char  family[32];
  1886. +    const int   ppem[5];
  1887. +  } SA_Rule;
  1888. +
  1889. +#define STEM_WIDTH_2_PPEM 18
  1890. +#define MAX_PPEM 100
  1891. +
  1892. +
  1893. +
  1894. +/* "Font name", {ppem where stem width becomes 1,
  1895. + *               ppem where stem width becomes 2... etc.} */
  1896. +/* 100 means auto-calculate */
  1897. +#define SNAPPING_STEM_WIDTHS_RULES_SIZE 21
  1898. +  SA_Rule  SNAPPING_STEM_WIDTHS_Rules
  1899. +    [SNAPPING_STEM_WIDTHS_RULES_SIZE] =
  1900. +    {
  1901. +      { "Andale Mono",          {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1902. +      { "Arial Narrow",         {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1903. +      { "Calibri",              {10, 19, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1904. +      { "Cantarell",            {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1905. +      { "Century Gothic",       {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1906. +      { "Comfortaa",            {10, 19, 22, MAX_PPEM, MAX_PPEM} },
  1907. +      { "Consolas",             {10, 20, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1908. +      { "Corbel",               {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1909. +      { "Futura",               {10, 14, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1910. +      { "Gill Sans",            {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1911. +      { "Helvetica CY",         {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1912. +      { "Inconsolata",          {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1913. +      { "Liberation Sans Narrow", {10, 22, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1914. +      { "Liberation Sans",      {10, 19, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1915. +      { "Lucida Grande",        {10, 16, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1916. +      { "Lucida Sans Unicode",  {10, 16, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1917. +      { "Luxi Sans",            {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1918. +      { "Open Sans",            {10, 20, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1919. +      { "Rokkitt",              {10, 21, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1920. +      { "Segoe UI",             {10, 23, MAX_PPEM, MAX_PPEM, MAX_PPEM} },
  1921. +      { "Trebuchet MS",         {10, 17, STEM_WIDTH_2_PPEM, MAX_PPEM, MAX_PPEM} },
  1922. +    };
  1923. +
  1924. +
  1925. +/* "Font name", {ppem, scale_up=1|scale_down=0} */
  1926. +#define SNAPPING_STEM_SCALING_RULES_SIZE 31
  1927. +  SA_Rule  SNAPPING_STEM_SCALING_Rules
  1928. +    [SNAPPING_STEM_SCALING_RULES_SIZE] =
  1929. +    {
  1930. +      { "Andale Mono", {11, 1,} },
  1931. +      { "Bitstream Vera Sans", {12, 1,} },
  1932. +      { "Calibri", {15, 1,} },
  1933. +      { "Calibri", {17, 1,} },
  1934. +      { "Calibri", {18, 1,} },
  1935. +      { "Candara", {14, 1,} },
  1936. +      { "Candara", {17, 1,} },
  1937. +      { "Canwell", {13, 0,} },
  1938. +      { "Comfortaa", {11, 0,} },
  1939. +      { "Consolas", {11, 1,} },
  1940. +      { "DejaVu Sans", {12, 1,} },
  1941. +      { "Freesans", {16, 0,} },
  1942. +      { "Freeserif", {13, 1,} },
  1943. +      { "Freeserif", {17, 1,} },
  1944. +      { "Inconsolata", {12, 1,} },
  1945. +      { "Inconsolata", {15, 1,} },
  1946. +      { "Lucida Grande", {13, 1,} },
  1947. +      { "Myriad Pro", {14, 1,} },
  1948. +      { "Myriad Pro", {17, 1,} },
  1949. +      { "Nina", {11, 0,} },
  1950. +      { "Nina", {12, 0,} },
  1951. +      { "Nina", {13, 0,} },
  1952. +      { "Optima", {17, 1,} },
  1953. +      { "Raleway", {15, 0,} },
  1954. +      { "Samba", {11, 0,} },
  1955. +      { "Times New Roman", {17, 1,} },
  1956. +      { "Trebuchet MS", {17, 0,} },
  1957. +      { "Trebuchet MS", {13, 0,} },
  1958. +      { "Trebuchet MS", {20, 1,} },      
  1959. +      { "Verdana", {12, 1,} },
  1960. +      { "Verdana", {15, 1,} },
  1961. +    };
  1962. +
  1963. +
  1964. +/* "Font name", {ppem, scale_up=1|scale_down=0} */
  1965. +#define SNAPPING_M_RULES_SIZE 7
  1966. +  SA_Rule  SNAPPING_M_Rules
  1967. +    [SNAPPING_M_RULES_SIZE] =
  1968. +    {
  1969. +      { "Courier New", {13, 1,} },
  1970. +      { "Courier New", {14, 1,} },
  1971. +      { "Droid Sans Mono", {12, 0,} },
  1972. +      { "Bitstream Vera Sans", {12, 0,} },      
  1973. +      { "DejaVu Sans", {12, 0,} },      
  1974. +      { "Essential PragmataPro", {13, 0,} },
  1975. +      { "Essential PragmataPro", {14, 0,} },
  1976. +    };
  1977. +
  1978. +
  1979. +/* "Font name", {ppem, ppem} */
  1980. +#define SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE 1
  1981. +  SA_Rule  SNAPPING_SYNTHESIZE_STEMS_Rules
  1982. +    [SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE] =
  1983. +    {
  1984. +      { "---", {13, 13,} },
  1985. +    };
  1986. +
  1987. +
  1988. +/* "Font name", {ppem, ppem} */
  1989. +#define SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE 1
  1990. +  SA_Rule  SNAPPING_NO_BEARING_CORRECTION_Rules
  1991. +    [SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE] =
  1992. +    {
  1993. +      { "Times New Roman", {0, 100,} },
  1994. +    };
  1995. +
  1996. +    
  1997. +/* "Font name", {ppem, ppem} */
  1998. +#define SNAPPING_EDGE_DETECTION_RULES_SIZE 8
  1999. +  SA_Rule  SNAPPING_EDGE_DETECTION_Rules
  2000. +    [SNAPPING_EDGE_DETECTION_RULES_SIZE] =
  2001. +    {
  2002. +      { "Tahoma", {11, 11,} },
  2003. +      { "Courier New", {10, 12,} },      
  2004. +      { "Arial", {11, 11,} },
  2005. +      { "Arial", {13, 13,} },        
  2006. +      { "Liberation Sans", {11, 11,} },
  2007. +      { "FreeSans", {11, 11,} },
  2008. +      { "FreeSans", {13, 13,} },        
  2009. +      { "Palatino Linotype", {0, 100,} },          
  2010. +    };
  2011. +  
  2012. +/* "Font name", {ppem, translate_value} */
  2013. +#define SNAPPING_STEM_TRANSLATING_RULES_SIZE 6
  2014. +  SA_Rule  SNAPPING_STEM_TRANSLATING_Rules
  2015. +    [SNAPPING_STEM_TRANSLATING_RULES_SIZE] =
  2016. +    {
  2017. +      { "Arial", {11, 32,} },
  2018. +      { "Arial Unicode MS", {11, 32,} },
  2019. +      { "FreeSans", {11, 32,} },
  2020. +      { "Arimo", {11, 32,} },
  2021. +      { "Liberation Sans", {11, 32,} },
  2022. +      { "Tahoma", {11, 32,} },    
  2023. +    };
  2024. +
  2025. +/* "Font name", {ppem, translate_value} */
  2026. +#define SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE 72
  2027. +  SA_Rule  SNAPPING_STEM_TRANSLATING_ONLY_Rules
  2028. +    [SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE] =
  2029. +    {
  2030. +      { "Arial Unicode MS", {10, 16,} },
  2031. +      { "Arial Unicode MS", {8, 32,} },
  2032. +      { "Arial Unicode MS", {9, 32,} },
  2033. +      { "Arial", {10, 16,} },
  2034. +      { "Arial", {8, 32,} },
  2035. +      { "Arial", {9, 32,} },
  2036. +      { "Arial", {16, -24,} },      
  2037. +      { "Arimo", {10, 8,} },
  2038. +      { "Arimo", {8, 32,} },
  2039. +      { "Arimo", {9, 32,} },
  2040. +      { "Bitstream Vera Sans", {8, 16,} },
  2041. +      { "Calibri", {10, 16,} },
  2042. +      { "Calibri", {15, 0,} },      
  2043. +      { "Candara", {10, 16,} },
  2044. +      { "Cantarell", {11, 0} },
  2045. +      { "Cantarell", {12, 0} },
  2046. +      { "Consolas", {8, 32,} },
  2047. +      { "Consolas", {9, 32,} },
  2048. +      { "Corbel", {10, 16,} },
  2049. +      { "Dejavu Sans Mono", {7, 16,} },
  2050. +      { "Dejavu Sans Mono", {8, 32,} },
  2051. +      { "Dejavu Sans Mono", {9, 16,} },
  2052. +      { "Dejavu Sans", {8, 16,} },
  2053. +      { "Dejavu Sans", {15, -20,} },      
  2054. +      { "Droid Sans", {8, 16,} },
  2055. +      { "Droid Sans", {9, 16,} },
  2056. +      { "Freesans", {10, 16,} },
  2057. +      { "Freesans", {9, 8,} },
  2058. +      { "Georgia", {13, 16,} },
  2059. +      { "Georgia", {14, 16,} },
  2060. +      { "Georgia", {15, 0,} },
  2061. +      { "Inconsolata", {10, 24,} },
  2062. +      { "Inconsolata", {9, 32,} },
  2063. +      { "Liberation Sans", {10, 8,} },
  2064. +      { "Liberation Sans", {8, 32,} },
  2065. +      { "Liberation Sans", {9, 32,} },
  2066. +      { "Lucida Grande", {13, 24,} },
  2067. +      { "Lucida Grande", {14, 24,} },
  2068. +      { "Lucida Grande", {8, 16,} },
  2069. +      { "Lucida Grande", {9, 16,} },
  2070. +      { "Lucida Sans Unicode", {13, 24,} },
  2071. +      { "Lucida Sans Unicode", {14, 24,} },
  2072. +      { "Lucida Sans Unicode", {8, 16,} },
  2073. +      { "Lucida Sans Unicode", {9, 16,} },
  2074. +      { "Microsoft Sans Serif", {10, 16,} },
  2075. +      { "Microsoft Sans Serif", {8, 32,} },
  2076. +      { "Microsoft Sans Serif", {9, 32,} },
  2077. +      { "Myriad Pro", {10, 16,} },
  2078. +      { "Myriad Pro", {11, 0,} },
  2079. +      { "Myriad Pro", {9, 16,} },
  2080. +      { "Open Sans", {10, 16,} },
  2081. +      { "Open Sans", {9, 16,} },
  2082. +      { "Optima", {10, 0} },
  2083. +      { "Optima", {11, 0} },
  2084. +      { "Optima", {12, 0} },
  2085. +      { "Segoe UI", {10, 0,} },
  2086. +      { "Segoe UI", {7, 32,} },
  2087. +      { "Segoe UI", {8, 16,} },
  2088. +      { "Segoe UI", {9, 24,} },
  2089. +      { "Tahoma", {7, 32,} },
  2090. +      { "Tahoma", {8, 32,} },
  2091. +      { "Tahoma", {9, 32,} },
  2092. +      { "Times New Roman", {17, 8,} },      
  2093. +      { "Trebuchet MS", {10, 16,} },
  2094. +      { "Trebuchet MS", {11, 0,} },
  2095. +      { "Trebuchet MS", {8, 32,} },
  2096. +      { "Trebuchet MS", {9, 32,} },
  2097. +      { "Verdana", {8, 16,} },
  2098. +      { "Verdana", {15, 16,} },      
  2099. +      { "Verdana", {14, 32,} },  
  2100. +      { "Verdana", {18, 32,} },        
  2101. +      { "Verdana", {19, 24,} },      
  2102. +    };
  2103. +
  2104. +
  2105. +/* "Font name", {start ppem, end ppem} */
  2106. +#define ALWAYS_USE_100_RULES_SIZE 46
  2107. +  SA_Rule  ALWAYS_USE_100_Rules
  2108. +    [ALWAYS_USE_100_RULES_SIZE] =
  2109. +    {
  2110. +      { "Andale Mono", {0, MAX_PPEM,} },
  2111. +      { "Arial Unicode MS", {0, MAX_PPEM,} },
  2112. +      { "Arial", {0, MAX_PPEM,} },
  2113. +      { "Arimo", {0, MAX_PPEM,} },
  2114. +      { "Bitstream Vera Sans Mono", {0, MAX_PPEM,} },
  2115. +      { "Bitstream Vera Sans", {10, 14,} },
  2116. +      { "Bitstream Vera Sans", {16, 17,} },
  2117. +      { "Calibri", {23, MAX_PPEM,} },
  2118. +      { "Consolas", {0, MAX_PPEM,} },
  2119. +      { "Courier New", {12, 12,} },
  2120. +      { "Courier", {0, MAX_PPEM,} },
  2121. +      { "Cousine", {0, MAX_PPEM,} },
  2122. +      { "DejaVu Sans Mono", {0, MAX_PPEM,} },
  2123. +      { "DejaVu Sans", {10, 14,} },
  2124. +      { "DejaVu Sans", {16, 17,} },
  2125. +      { "Droid Sans", {12, 12,} },
  2126. +      { "Droid Sans", {15, 15,} },
  2127. +      { "FreeMono", {0, MAX_PPEM,} },
  2128. +      { "FreeSans", {0, MAX_PPEM,} },
  2129. +      { "Liberation Mono", {0, MAX_PPEM,} },
  2130. +      { "Lucida Console", {0, MAX_PPEM,} },
  2131. +      { "Luxi Sans", {13, 13,} },
  2132. +      { "Microsoft Sans Serif", {0, MAX_PPEM,} },
  2133. +      { "Monaco", {0, MAX_PPEM,} },
  2134. +      { "Segoe UI", {11, 12,} },
  2135. +      { "Segoe UI", {14, 14,} },
  2136. +      { "Tahoma", {11, 11,} },
  2137. +      { "Tahoma", {14, MAX_PPEM,} },
  2138. +      { "Times New Roman", {14, 14,} },
  2139. +      { "Times New Roman", {16, 16,} },
  2140. +      { "Trebuchet MS", {13, 13,} },
  2141. +      { "Ubuntu", {12, 13,} },
  2142. +      { "Ubuntu", {15, 15,} },
  2143. +      { "Verdana", {0, 14,} },
  2144. +      { "Verdana", {16, MAX_PPEM,} },
  2145. +      { "Pragmata", {0, MAX_PPEM,} },      
  2146. +      { "Essential PragmataPro", {0, MAX_PPEM,} },        
  2147. +    };
  2148. +
  2149. +
  2150. +
  2151. +
  2152. +#define AUTOHINT_BRIGHTNESS_RULES_SIZE 3
  2153. +  SA_Rule  BRIGHTNESS_Rules
  2154. +    [AUTOHINT_BRIGHTNESS_RULES_SIZE] =
  2155. +    {
  2156. +      { "Baskerville", {0, -20,} },
  2157. +      { "Garamond", {0, -20,} },
  2158. +      { "Optima", {0, -20,} },
  2159. +    };
  2160. +
  2161. +#define AUTOHINT_CONTRAST_RULES_SIZE 3
  2162. +  SA_Rule  CONTRAST_Rules
  2163. +    [AUTOHINT_CONTRAST_RULES_SIZE] =
  2164. +    {
  2165. +      { "Baskerville", {0, 25,} },
  2166. +      { "Garamond", {0, 25,} },
  2167. +      { "Optima", {0, 25,} },
  2168. +    };
  2169. +
  2170. +#if 0
  2171. +#define STEM_SPACING_RULES_SIZE 3
  2172. +  SA_Rule  STEM_SPACING_Rules
  2173. +    [STEM_SPACING_RULES_SIZE] =
  2174. +    {
  2175. +      { "Tahoma", {10, 12, 18, 18, 30} },
  2176. +      { "Arial", {10, 11, 23, 25, 30} },
  2177. +      { "Freesans", {10, 12, 18, 18, 30} },
  2178. +    };
  2179. +
  2180. +#define STEM_START_RULES_SIZE 3
  2181. +  SA_Rule  STEM_START_Rules
  2182. +    [STEM_START_RULES_SIZE] =
  2183. +    {
  2184. +      { "Tahoma", {14, 17, 30, 100, 100} },
  2185. +      { "Arial", {11, 18, 23, 30, 30} },
  2186. +      { "Freesans", {10, 18, 18, 25, 30} },
  2187. +    };
  2188. +#endif
  2189. +
  2190. +  typedef struct  Stem_Data_
  2191. +  {
  2192. +    FT_Int       stem_width;
  2193. +    FT_Int       stem_spacing;
  2194. +    FT_Int       stem_start;
  2195. +    FT_Int       stem_scaling;
  2196. +    FT_Int       stem_translating_only;
  2197. +    FT_Int       stem_translating;    
  2198. +    FT_Int       brightness;
  2199. +    FT_Int       contrast;
  2200. +    FT_Bool      use_100;
  2201. +    FT_Bool      synth_stems;
  2202. +    FT_Bool      edge_detection;
  2203. +    FT_Bool      bearing_correction;
  2204. +    FT_Int       m;
  2205. +  } Stem_Data;
  2206. +
  2207. +
  2208. +  typedef struct  Stem_Segment_
  2209. +  {
  2210. +    FT_Long       x1;
  2211. +    FT_Long       x2;
  2212. +    FT_Int        y;
  2213. +  } Stem_Segment;
  2214. +
  2215. +  typedef struct  Stem_Center_
  2216. +  {
  2217. +    FT_Long       x;
  2218. +    FT_Long       y;
  2219. +    FT_Long       w;
  2220. +    FT_Long       x1;
  2221. +    FT_Long       x2;
  2222. +  } Stem_Center;
  2223. +
  2224. +  typedef struct  Stem_
  2225. +  {
  2226. +    FT_Long       center;
  2227. +    FT_Long       count;
  2228. +    FT_Long       rcount; /* used to count within a range in possible stems */
  2229. +    FT_Long       width;
  2230. +    FT_Long       height;
  2231. +    FT_Short      zone;  /* 1 2 or 3 */
  2232. +    FT_Bool       generated;
  2233. +  } Stem;
  2234. +
  2235. +
  2236. +  static void
  2237. +  swap_stem ( Stem* s1, Stem* s2 )
  2238. +  {
  2239. +    Stem s;
  2240. +    s.center = s1->center;
  2241. +    s.count  = s1->count;
  2242. +    s.rcount = s1->rcount;
  2243. +    s.width  = s1->width;
  2244. +    s.zone   = s1->zone;
  2245. +    s.generated = s1->generated;
  2246. +
  2247. +    s1->center = s2->center;
  2248. +    s1->count  = s2->count;
  2249. +    s1->rcount = s2->rcount;
  2250. +    s1->width  = s2->width;
  2251. +    s1->zone   = s2->zone;
  2252. +    s1->generated = s2->generated;
  2253. +
  2254. +    s2->center = s.center;
  2255. +    s2->count  = s.count;
  2256. +    s2->rcount = s.rcount;
  2257. +    s2->width  = s.width;
  2258. +    s2->zone   = s.zone;
  2259. +    s2->generated = s.generated;
  2260. +  }
  2261. +
  2262. +
  2263. +  FT_LOCAL_DEF( void )
  2264. +  sa_fill_known_stem_values (
  2265. +                  FT_String*      family,
  2266. +                  int             ppem,
  2267. +                  FT_String*      style,
  2268. +                  FT_UInt         num_stems,
  2269. +                  Stem_Data*      known_stem_values )
  2270. +  {
  2271. +    FT_Int  i, j;
  2272. +    if (verbose) printf("%s ", family);
  2273. +
  2274. +    i = 0;
  2275. +    while ( i < SNAPPING_STEM_WIDTHS_RULES_SIZE )
  2276. +    {
  2277. +      if ( family                                    &&
  2278. +           ( strcasecmp( SNAPPING_STEM_WIDTHS_Rules[i].family, family ) == 0 ) )
  2279. +      {
  2280. +        j = 0;
  2281. +        known_stem_values->stem_width = 1;
  2282. +
  2283. +        while (j < 4)
  2284. +        {
  2285. +          if (SNAPPING_STEM_WIDTHS_Rules[i].ppem[j] == MAX_PPEM )
  2286. +          {
  2287. +            known_stem_values->stem_width = -1;  /* use default */
  2288. +            j = 5;
  2289. +            i = SNAPPING_STEM_WIDTHS_RULES_SIZE;
  2290. +          }
  2291. +          else if (ppem < SNAPPING_STEM_WIDTHS_Rules[i].ppem[j])
  2292. +          {
  2293. +            known_stem_values->stem_width = j;
  2294. +            j = 5;
  2295. +            i = SNAPPING_STEM_WIDTHS_RULES_SIZE;
  2296. +          }
  2297. +          j++;
  2298. +        }
  2299. +      }
  2300. +      i++;
  2301. +    }
  2302. +
  2303. +    i = 0;
  2304. +    while ( i < SNAPPING_STEM_SCALING_RULES_SIZE )
  2305. +    {
  2306. +      if ( family                                    &&
  2307. +           ( strcasecmp( SNAPPING_STEM_SCALING_Rules[i].family, family ) == 0 ) )
  2308. +      {
  2309. +        known_stem_values->stem_scaling = -1;  /* default */
  2310. +
  2311. +        if (ppem == SNAPPING_STEM_SCALING_Rules[i].ppem[0])
  2312. +        {
  2313. +          known_stem_values->stem_scaling = SNAPPING_STEM_SCALING_Rules[i].ppem[1];
  2314. +          i = SNAPPING_STEM_SCALING_RULES_SIZE;
  2315. +        }
  2316. +      }
  2317. +      i++;
  2318. +    }
  2319. +
  2320. +
  2321. +    i = 0;
  2322. +    while ( i < SNAPPING_M_RULES_SIZE )
  2323. +    {
  2324. +      if ( family                                    &&
  2325. +           ( strcasecmp( SNAPPING_M_Rules[i].family, family ) == 0 ) )
  2326. +      {
  2327. +        known_stem_values->m = -1;  /* default */
  2328. +
  2329. +        if (ppem == SNAPPING_M_Rules[i].ppem[0])
  2330. +        {
  2331. +          known_stem_values->m = SNAPPING_M_Rules[i].ppem[1];
  2332. +          i = SNAPPING_M_RULES_SIZE;
  2333. +        }
  2334. +      }
  2335. +      i++;
  2336. +    }
  2337. +
  2338. +    i = 0;
  2339. +    while ( i < SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE )
  2340. +    {
  2341. +      if ( family                                    &&
  2342. +           ( strcasecmp( SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].family, family ) == 0 ) )
  2343. +      {
  2344. +        known_stem_values->stem_translating_only = -1024;  /* default */
  2345. +
  2346. +        if (ppem == SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[0]
  2347. +            || SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[0] == 0)
  2348. +        {
  2349. +          known_stem_values->stem_translating_only = SNAPPING_STEM_TRANSLATING_ONLY_Rules[i].ppem[1];
  2350. +          i = SNAPPING_STEM_TRANSLATING_ONLY_RULES_SIZE;
  2351. +        }
  2352. +      }
  2353. +      i++;
  2354. +    }
  2355. +
  2356. +    i = 0;
  2357. +    while ( i < SNAPPING_STEM_TRANSLATING_RULES_SIZE )
  2358. +    {
  2359. +      if ( family                                    &&
  2360. +           ( strcasecmp( SNAPPING_STEM_TRANSLATING_Rules[i].family, family ) == 0 ) )
  2361. +      {
  2362. +        known_stem_values->stem_translating = 0;  /* default */
  2363. +
  2364. +        if (ppem == SNAPPING_STEM_TRANSLATING_Rules[i].ppem[0]
  2365. +            || SNAPPING_STEM_TRANSLATING_Rules[i].ppem[0] == 0)
  2366. +        {
  2367. +          known_stem_values->stem_translating = SNAPPING_STEM_TRANSLATING_Rules[i].ppem[1];
  2368. +          i = SNAPPING_STEM_TRANSLATING_RULES_SIZE;
  2369. +        }
  2370. +      }
  2371. +      i++;
  2372. +    }
  2373. +
  2374. +
  2375. +    i = 0;
  2376. +    while ( i < ALWAYS_USE_100_RULES_SIZE )
  2377. +    {
  2378. +      if ( family                                    &&
  2379. +           ( strcasecmp( ALWAYS_USE_100_Rules[i].family, family ) == 0 ) )
  2380. +      {
  2381. +        known_stem_values->use_100 = FALSE;  /* default */
  2382. +
  2383. +        if (ppem >= ALWAYS_USE_100_Rules[i].ppem[0] && ppem <= ALWAYS_USE_100_Rules[i].ppem[1] )
  2384. +        {
  2385. +          known_stem_values->use_100 = TRUE;
  2386. +          i = ALWAYS_USE_100_RULES_SIZE;
  2387. +        }
  2388. +      }
  2389. +      i++;
  2390. +    }
  2391. +
  2392. +
  2393. +    i = 0;
  2394. +    while ( i < SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE )
  2395. +    {
  2396. +      if ( family                                    &&
  2397. +           ( strcasecmp( SNAPPING_SYNTHESIZE_STEMS_Rules[i].family, family ) == 0 ) )
  2398. +      {
  2399. +        known_stem_values->synth_stems = FALSE;  /* default */
  2400. +
  2401. +        if (ppem >= SNAPPING_SYNTHESIZE_STEMS_Rules[i].ppem[0] && ppem <= SNAPPING_SYNTHESIZE_STEMS_Rules[i].ppem[1] )
  2402. +        {
  2403. +          known_stem_values->synth_stems = TRUE;
  2404. +          i = SNAPPING_SYNTHESIZE_STEMS_RULES_SIZE;
  2405. +        }
  2406. +      }
  2407. +      i++;
  2408. +    }
  2409. +
  2410. +
  2411. +    i = 0;
  2412. +    while ( i < SNAPPING_EDGE_DETECTION_RULES_SIZE )
  2413. +    {
  2414. +      if ( family                                    &&
  2415. +           ( strcasecmp( SNAPPING_EDGE_DETECTION_Rules[i].family, family ) == 0 ) )
  2416. +      {
  2417. +        known_stem_values->edge_detection = FALSE;  /* default */
  2418. +
  2419. +        if (ppem >= SNAPPING_EDGE_DETECTION_Rules[i].ppem[0] && ppem <= SNAPPING_EDGE_DETECTION_Rules[i].ppem[1] )
  2420. +        {
  2421. +          known_stem_values->edge_detection = TRUE;
  2422. +          i = SNAPPING_EDGE_DETECTION_RULES_SIZE;
  2423. +        }
  2424. +      }
  2425. +      i++;
  2426. +    }
  2427. +
  2428. +    
  2429. +    i = 0;
  2430. +    while ( i < SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE )
  2431. +    {
  2432. +      if ( family                                    &&
  2433. +           ( strcasecmp( SNAPPING_NO_BEARING_CORRECTION_Rules[i].family, family ) == 0 ) )
  2434. +      {
  2435. +        known_stem_values->bearing_correction = TRUE;  /* default */
  2436. +
  2437. +        if (ppem >= SNAPPING_NO_BEARING_CORRECTION_Rules[i].ppem[0] && ppem <= SNAPPING_NO_BEARING_CORRECTION_Rules[i].ppem[1] )
  2438. +        {
  2439. +          known_stem_values->bearing_correction = FALSE;
  2440. +          i = SNAPPING_NO_BEARING_CORRECTION_RULES_SIZE;
  2441. +        }
  2442. +      }
  2443. +      i++;
  2444. +    }
  2445. +
  2446. +        
  2447. +#if 0
  2448. +    i = 0;
  2449. +    while ( i < AUTOHINT_BRIGHTNESS_RULES_SIZE )
  2450. +    {
  2451. +      if ( family                                    &&
  2452. +           ( strcasecmp( BRIGHTNESS_Rules[i].family, family ) == 0 ) )
  2453. +      {
  2454. +        known_stem_values->brightness = 0.0;
  2455. +
  2456. +        if (ppem == BRIGHTNESS_Rules[i].ppem[0] || BRIGHTNESS_Rules[i].ppem[0] == 0)
  2457. +        {
  2458. +          known_stem_values->brightness = BRIGHTNESS_Rules[i].ppem[1];
  2459. +          i = AUTOHINT_BRIGHTNESS_RULES_SIZE;
  2460. +        }
  2461. +      }
  2462. +      i++;
  2463. +    }
  2464. +
  2465. +    i = 0;
  2466. +    while ( i < AUTOHINT_CONTRAST_RULES_SIZE )
  2467. +    {
  2468. +      if ( family                                    &&
  2469. +           ( strcasecmp( CONTRAST_Rules[i].family, family ) == 0 ) )
  2470. +      {
  2471. +        known_stem_values->contrast = 0.0;
  2472. +
  2473. +        if (ppem == CONTRAST_Rules[i].ppem[0] || CONTRAST_Rules[i].ppem[0] == 0)
  2474. +        {
  2475. +          known_stem_values->contrast = CONTRAST_Rules[i].ppem[1];
  2476. +          i = AUTOHINT_CONTRAST_RULES_SIZE;
  2477. +        }
  2478. +      }
  2479. +      i++;
  2480. +    }
  2481. +
  2482. +    for ( i = 0; i <= STEM_SPACING_RULES_SIZE; i++ )
  2483. +    {
  2484. +      if ( family                                    &&
  2485. +           ( strcasecmp( STEM_SPACING_Rules[i].family, family ) == 0 ) )
  2486. +      {
  2487. +        j = 0;
  2488. +        known_stem_values->stem_spacing = 2;  /* default */
  2489. +
  2490. +        while (j < 4)
  2491. +        {
  2492. +          if (ppem < STEM_SPACING_Rules[i].ppem[j])
  2493. +          {
  2494. +            known_stem_values->stem_spacing = j;
  2495. +            j = 5;
  2496. +          }
  2497. +          j++;
  2498. +        }
  2499. +      }
  2500. +    }
  2501. +
  2502. +
  2503. +    for ( i = 0; i <= STEM_START_RULES_SIZE; i++ )
  2504. +    {
  2505. +      if ( family                                    &&
  2506. +           ( strcasecmp( STEM_START_Rules[i].family, family ) == 0 ) )
  2507. +      {
  2508. +        j = 0;
  2509. +        known_stem_values->stem_start = 1;  /* default */
  2510. +
  2511. +        while (j < 4)
  2512. +        {
  2513. +          if (ppem < STEM_START_Rules[i].ppem[j])
  2514. +          {
  2515. +            known_stem_values->stem_start = j;
  2516. +            j = 5;
  2517. +          }
  2518. +          j++;
  2519. +        }
  2520. +      }
  2521. +    }
  2522. +#endif
  2523. +  }
  2524. +
  2525. +
  2526. +  FT_LOCAL_DEF( FT_Int )
  2527. +  get_contrast (
  2528. +                  FT_String*      family,
  2529. +                  int             ppem)
  2530. +  {
  2531. +    FT_Int  i;
  2532. +    if (verbose) printf("%s ", family);
  2533. +
  2534. +    i = 0;
  2535. +    while ( i < AUTOHINT_CONTRAST_RULES_SIZE )
  2536. +    {
  2537. +      if ( family                                    &&
  2538. +           ( strcasecmp( CONTRAST_Rules[i].family, family ) == 0 ) )
  2539. +      {
  2540. +        if (ppem == CONTRAST_Rules[i].ppem[0] || CONTRAST_Rules[i].ppem[0] == 0)
  2541. +        {
  2542. +          return CONTRAST_Rules[i].ppem[1];
  2543. +        }
  2544. +      }
  2545. +      i++;
  2546. +    }
  2547. +    return 0;
  2548. +  }
  2549. +
  2550. +
  2551. +  FT_LOCAL_DEF( FT_Int )
  2552. +  get_brightness (
  2553. +                  FT_String*      family,
  2554. +                  int             ppem)
  2555. +  {
  2556. +    FT_Int  i;
  2557. +    if (verbose) printf("%s ", family);
  2558. +
  2559. +    i = 0;
  2560. +    while ( i < AUTOHINT_BRIGHTNESS_RULES_SIZE )
  2561. +    {
  2562. +      if ( family                                    &&
  2563. +           ( strcasecmp( BRIGHTNESS_Rules[i].family, family ) == 0 ) )
  2564. +      {
  2565. +        if (ppem == BRIGHTNESS_Rules[i].ppem[0] || BRIGHTNESS_Rules[i].ppem[0] == 0)
  2566. +        {
  2567. +          return BRIGHTNESS_Rules[i].ppem[1];
  2568. +        }
  2569. +      }
  2570. +      i++;
  2571. +    }
  2572. +    return 0;
  2573. +  }
  2574. +
  2575. +
  2576. +  /* Stem alignment for bitmaps;  A hack with very nice results */
  2577. +  /* Ideally this could be implemented on the outline, prior to
  2578. +   * rasterization.  Possible future enhancement is to use the
  2579. +   * warper code to achieve this */
  2580. +  static void
  2581. +  _lcd_stem_align ( FT_Bitmap*      bitmap,
  2582. +                    FT_Render_Mode  mode,
  2583. +                      FT_GlyphSlot   slot,
  2584. +                      FT_Long*       translate_value,
  2585. +                      float*         scale_value,
  2586. +                      FT_UInt       alignment_strength,
  2587. +                      FT_UInt       fitting_strength,
  2588. +                      float*        embolden_value
  2589. +                  )
  2590. +  {
  2591. +    FT_UInt   width   = (FT_UInt)bitmap->width;
  2592. +    FT_UInt   height  = (FT_UInt)bitmap->rows;
  2593. +
  2594. +    Stem_Segment*   segments;
  2595. +    Stem_Segment*   leftmost_segment;
  2596. +    Stem_Segment*   rightmost_segment;
  2597. +    Stem_Segment*   leftmost_segment_not_extrema;
  2598. +    Stem_Segment*   rightmost_segment_not_extrema;
  2599. +    Stem*           stems;
  2600. +    Stem*           possible_stems;
  2601. +    Stem*           leftmost_stem;
  2602. +    Stem*           rightmost_stem;
  2603. +    Stem_Data*      known_stem_values;
  2604. +    Stem_Center*    centers;
  2605. +    FT_Long         leftmost_point = width * 256;
  2606. +    FT_Long         rightmost_point = 0;
  2607. +    FT_Long         leftmost_point_not_extrema = width * 256;
  2608. +    FT_Long         rightmost_point_not_extrema = 0;
  2609. +    FT_Long         num_segments = 0;
  2610. +    FT_Long         num_centers = 0;
  2611. +    FT_Long         stem_centers[width * 256];
  2612. +    FT_UInt         h;
  2613. +    FT_ULong        valid_stems = 0, valid_possible_stems = 0;
  2614. +    FT_Long         center, stem_matches, stem_matches_ledge;
  2615. +    FT_Long         stem_matches_redge, next_center, last_matching_center;
  2616. +    FT_Long         last_matching_ledge, last_matching_redge, this_center;
  2617. +    FT_Int          max_strength;
  2618. +    FT_Byte*        line = bitmap->buffer;
  2619. +    FT_UInt         current_value = 0;
  2620. +    FT_UInt         xx;
  2621. +    FT_Long         linearHoriAdvance = slot->linearHoriAdvance >> 10;
  2622. +
  2623. +    FT_Int          m_horiBearingX = slot->metrics.horiBearingX;
  2624. +    FT_Int          m_horiAdvance = slot->metrics.horiAdvance;
  2625. +    FT_Int          m_width = slot->metrics.width;
  2626. +    FT_Pos          one_pixel = 768;
  2627. +    FT_Pos          one_third_pixel = 256;
  2628. +    FT_Int          columns_per_pixel = 3;
  2629. +    /*FT_Int          extra_columns = 6;*/
  2630. +
  2631. +    /* on / off flags for testing different features */
  2632. +    FT_Bool         strategy_translate_using_closest_stem = TRUE;
  2633. +    FT_Bool         strategy_scale_to_closest_centers = FALSE;
  2634. +    FT_Bool         strategy_scale_to_closest_centers_up_only = FALSE;
  2635. +    FT_Bool         strategy_always_use_distance_ceiling = FALSE;
  2636. +    FT_Bool         strategy_auto_change_center_offset = TRUE;
  2637. +    FT_Bool         strategy_use_m_control = FALSE;
  2638. +    FT_Bool         strategy_correct_out_of_bounds_outlines = FALSE;   /*this needs work.. breaks some glyphs like verdana 12 */
  2639. +    FT_Bool         strategy_also_use_edge_detection_for_stems = FALSE;
  2640. +    FT_Bool         strategy_use_strengths = TRUE;
  2641. +    FT_Bool         strategy_synthesize_stems = FALSE;
  2642. +    FT_Bool         strategy_bearing_correction = TRUE;
  2643. +    FT_Bool         strategy_use_d_correction = TRUE;
  2644. +    FT_Bool         strategy_fit_to_width = FALSE;
  2645. +    /*FT_Bool         strategy_center_glyph = FALSE;*/
  2646. +    FT_Bool         strategy_use_verdana_12_hack = TRUE;
  2647. +    FT_Bool         has_serifs = FALSE;
  2648. +    FT_Bool         autohinted = FALSE;
  2649. +
  2650. +    const FT_Int    MIN_PPEM = 7;
  2651. +    /*const FT_Int    MAX_PPEM = 100;*/
  2652. +    const FT_Int    MAX_STEMS = 3;
  2653. +    FT_Int          ppem = 0;
  2654. +
  2655. +    int checked_use_known_settings_on_selected_fonts_env = 0;
  2656. +    FT_Bool use_known_settings_on_selected_fonts = FALSE;
  2657. +
  2658. +    int cur_width;
  2659. +    char *cur_width_env = getenv( "CUR_WIDTH" );
  2660. +
  2661. +    if ( cur_width_env != NULL ){
  2662. +      sscanf ( cur_width_env, "%d", &cur_width );
  2663. +      if (cur_width != 0) autohinted = TRUE;
  2664. +    }
  2665. +
  2666. +    /* An incoming scale value of 1.1 indicates to do certain things */
  2667. +    /*if (*scale_value == 1.1) strategy_use_verdana_12_hack = TRUE;*/
  2668. +
  2669. +    /* reset to default */
  2670. +    *scale_value = 1.0;
  2671. +
  2672. +    if ( checked_use_known_settings_on_selected_fonts_env == 0 )
  2673. +    {
  2674. +      char *use_known_settings_on_selected_fonts_env = getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
  2675. +      if ( use_known_settings_on_selected_fonts_env != NULL )
  2676. +      {
  2677. +        if ( strcasecmp(use_known_settings_on_selected_fonts_env, "default" ) != 0 )
  2678. +        {
  2679. +          if ( strcasecmp(use_known_settings_on_selected_fonts_env, "true") == 0)
  2680. +            use_known_settings_on_selected_fonts = TRUE;
  2681. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "1") == 0)
  2682. +            use_known_settings_on_selected_fonts = TRUE;
  2683. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "on") == 0)
  2684. +            use_known_settings_on_selected_fonts = TRUE;
  2685. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "yes") == 0)
  2686. +            use_known_settings_on_selected_fonts = TRUE;
  2687. +        }
  2688. +      }
  2689. +      checked_use_known_settings_on_selected_fonts_env = 1;
  2690. +    }
  2691. +
  2692. +
  2693. +    /* Simply return in odd cases where these don't seem to be set */
  2694. +    /* Flash and some pdf viewers will crash otherwise */
  2695. +    if ( !slot->face || !slot->face->size || !slot->face->size->metrics.x_ppem )
  2696. +      return;
  2697. +    if ( slot->face->size->metrics.x_ppem > MAX_PPEM ) return;
  2698. +    /*if ( width < 4 ) return;*/
  2699. +
  2700. +    if ( slot->face->size->metrics.x_ppem < MIN_PPEM ) return;
  2701. +
  2702. +    if ( !FT_IS_SCALABLE( slot->face ) ) return;
  2703. +
  2704. +    ppem = slot->face->size->metrics.x_ppem;
  2705. +
  2706. +
  2707. +    /* only perform alignment on styles we know, that aren't bold or italic */
  2708. +    /* perhaps detection could be added on those that are not set? */
  2709. +    /* Require certain ppems for narrow and light fonts */
  2710. +    if( slot->face->style_name )
  2711. +    {
  2712. +      if ( strcasestr(slot->face->style_name, "Italic")
  2713. +        || strcasestr(slot->face->style_name, "Oblique")
  2714. +        || strcasestr(slot->face->style_name, "Script")
  2715. +        || strcasestr(slot->face->style_name, "Handwriting")
  2716. +        || strcasestr(slot->face->style_name, "Bold")
  2717. +        || strcasestr(slot->face->style_name, "Black")
  2718. +        || ( ( strcasestr(slot->face->style_name, "Extra Thin")
  2719. +           || strcasestr(slot->face->style_name, "Extra Light") )
  2720. +               && ppem < 10 )
  2721. +        || ( strcasestr(slot->face->style_name, "Thin")
  2722. +               && ppem < 10 )
  2723. +        || ( strcasestr(slot->face->style_name, "Light")
  2724. +               && ppem < 10 )
  2725. +        || ( strcasestr(slot->face->style_name, "Narrow")
  2726. +               && ppem < 15 )
  2727. +        || ( strcasestr(slot->face->style_name, "Condensed")
  2728. +               && ppem < 20 ) )
  2729. +            return;
  2730. +    }
  2731. +
  2732. +    if( slot->face->family_name )
  2733. +    {
  2734. +      if ( strcasestr(slot->face->family_name, "Italic")
  2735. +        || strcasestr(slot->face->family_name, "Oblique")
  2736. +        || strcasestr(slot->face->family_name, "Script")
  2737. +        || strcasestr(slot->face->family_name, "Handwriting")
  2738. +        || strcasestr(slot->face->family_name, "Bold")
  2739. +        || strcasestr(slot->face->family_name, "Black")
  2740. +        || ( ( strcasestr(slot->face->family_name, "Extra Thin")
  2741. +           || strcasestr(slot->face->family_name, "Extra Light") )
  2742. +               && ppem < 10 )
  2743. +        || ( strcasestr(slot->face->family_name, "Thin")
  2744. +               && ppem < 10 )
  2745. +        || ( strcasestr(slot->face->family_name, "Light")
  2746. +               && ppem < 10 )
  2747. +        || ( strcasestr(slot->face->family_name, "Narrow")
  2748. +               && ppem < 15 )
  2749. +        || ( strcasestr(slot->face->family_name, "Condensed")
  2750. +               && ppem < 20 ) )
  2751. +            return;
  2752. +    }
  2753. +    else if ( slot->face->style_flags )
  2754. +    {
  2755. +      if ( slot->face->style_flags & FT_STYLE_FLAG_ITALIC
  2756. +        || slot->face->style_flags & FT_STYLE_FLAG_BOLD
  2757. +        || FT_IS_TRICKY( slot->face ) )
  2758. +        return;
  2759. +    }
  2760. +    else return;
  2761. +
  2762. +    if( slot->face->family_name )
  2763. +    {
  2764. +      if ( strcasestr(slot->face->family_name, "Courier")
  2765. +        || strcasestr(slot->face->family_name, "Serif")
  2766. +        || strcasestr(slot->face->family_name, "Times"))
  2767. +        has_serifs = TRUE;
  2768. +    }
  2769. +
  2770. +    if ( mode != FT_RENDER_MODE_LCD )
  2771. +    {
  2772. +      columns_per_pixel = 1;
  2773. +      one_pixel = 256;
  2774. +      one_third_pixel = 85;
  2775. +      /*extra_columns = 0;*/
  2776. +      /* until this can be figured out just return */
  2777. +      /* There are issues with missing glyphs */
  2778. +      return;    
  2779. +    }
  2780. +
  2781. +    known_stem_values = (Stem_Data*) malloc (columns_per_pixel * sizeof(Stem_Data));  /* only look at top 3 for now */
  2782. +    known_stem_values->stem_spacing = -1;
  2783. +    known_stem_values->stem_width = -1;
  2784. +    known_stem_values->stem_start = -1;
  2785. +    known_stem_values->stem_scaling = -1;
  2786. +    known_stem_values->stem_translating_only = -1024;
  2787. +    known_stem_values->stem_translating = 0;    
  2788. +    known_stem_values->brightness = 0;
  2789. +    known_stem_values->contrast = 0;
  2790. +    known_stem_values->use_100 = FALSE;
  2791. +    known_stem_values->m = -1;
  2792. +    known_stem_values->synth_stems = FALSE;
  2793. +    known_stem_values->bearing_correction = TRUE;    
  2794. +
  2795. +    if (use_known_settings_on_selected_fonts)
  2796. +    {
  2797. +      sa_fill_known_stem_values ( slot->face->family_name,
  2798. +                                  ppem, slot->face->style_name,
  2799. +                                  valid_stems, known_stem_values );
  2800. +      if (verbose)
  2801. +        printf ("width:%d,spacing:%d,start:%d,scaling:%d,translate:%d ",
  2802. +                known_stem_values->stem_width, known_stem_values->stem_spacing,
  2803. +                known_stem_values->stem_start, known_stem_values->stem_scaling,
  2804. +                known_stem_values->stem_translating_only) ;
  2805. +    }
  2806. +
  2807. +    /* translate value may be set for < 10 */
  2808. +    if (use_known_settings_on_selected_fonts && known_stem_values->stem_translating_only > -1024 )
  2809. +    {
  2810. +      *translate_value = known_stem_values->stem_translating_only;
  2811. +      return;
  2812. +    }
  2813. +
  2814. +    if (use_known_settings_on_selected_fonts && known_stem_values->bearing_correction == FALSE )
  2815. +    {
  2816. +      strategy_bearing_correction = FALSE;
  2817. +    }
  2818. +    
  2819. +    if ( known_stem_values->use_100 || known_stem_values->m >= 0)
  2820. +    {
  2821. +      alignment_strength = fitting_strength = 100;
  2822. +      strategy_use_m_control = TRUE;
  2823. +    }
  2824. +
  2825. +    if ( known_stem_values->edge_detection )
  2826. +    {
  2827. +      strategy_also_use_edge_detection_for_stems = TRUE;
  2828. +    }
  2829. +    
  2830. +    if ( ppem < 9 )   return;
  2831. +    if ( ppem > 20 ) strategy_use_m_control = TRUE;
  2832. +
  2833. +    /* Allocate */
  2834. +    segments = (Stem_Segment*) malloc( (1) * sizeof (Stem_Segment));
  2835. +    leftmost_segment = (Stem_Segment*)  malloc( sizeof (Stem_Segment));
  2836. +    leftmost_segment_not_extrema = (Stem_Segment*)  malloc( sizeof (Stem_Segment));
  2837. +    rightmost_segment = (Stem_Segment*)  malloc( sizeof (Stem_Segment));
  2838. +    rightmost_segment_not_extrema = (Stem_Segment*)  malloc( sizeof (Stem_Segment));
  2839. +
  2840. +    stems = (Stem*) malloc (MAX_STEMS * sizeof(Stem));
  2841. +    possible_stems = (Stem*) malloc (MAX_STEMS * sizeof(Stem));
  2842. +    leftmost_stem = (Stem*) malloc ( sizeof(Stem));
  2843. +    rightmost_stem = (Stem*) malloc ( sizeof(Stem));
  2844. +    centers = (Stem_Center*) malloc ( (1) * sizeof(Stem_Center));
  2845. +
  2846. +    if (verbose) printf("\n");
  2847. +
  2848. +    /* Initialize */
  2849. +    for ( xx = 0; xx < width * 256; xx += 1 )
  2850. +    {
  2851. +      stem_centers[xx] = 0;
  2852. +    }
  2853. +    for ( xx = 0; xx < num_segments; xx += 1 )
  2854. +    {
  2855. +      segments[xx].x1 = 0;
  2856. +      segments[xx].x2 = 0;
  2857. +      segments[xx].y = 0;
  2858. +    }
  2859. +    rightmost_segment->x1 = 0;
  2860. +    rightmost_segment->x2 = 0;
  2861. +    rightmost_segment->y = 0;
  2862. +    leftmost_segment->x1 = 99999999;
  2863. +    leftmost_segment->x2 = 0;
  2864. +    leftmost_segment->y = 0;
  2865. +
  2866. +    rightmost_segment_not_extrema->x1 = 0;
  2867. +    rightmost_segment_not_extrema->x2 = 0;
  2868. +    rightmost_segment_not_extrema->y = 0;
  2869. +    leftmost_segment_not_extrema->x1 = 99999999;
  2870. +    leftmost_segment_not_extrema->x2 = 0;
  2871. +    leftmost_segment_not_extrema->y = 0;
  2872. +
  2873. +    /* Locate stem centers for later processing */
  2874. +    for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch )
  2875. +    {
  2876. +      current_value = 0;
  2877. +      /* Calculate various sums and stem widths of glyph */
  2878. +      for ( xx = 0; xx < width; xx += 1 )
  2879. +      {
  2880. +        /* Reallocate */
  2881. +        segments = (Stem_Segment*) realloc( segments, (num_segments + 1) * sizeof (Stem_Segment));
  2882. +
  2883. +        /* if line is white, and now has color, it's the start of a stem */
  2884. +        if (current_value == 0 && line[xx] > 0)
  2885. +        {
  2886. +          /* start of stem */
  2887. +          segments[num_segments].x1 = 256 * (xx) + (255 - line[xx]);
  2888. +          segments[num_segments].y = h;
  2889. +        }
  2890. +
  2891. +        /* otherwise, if it's currently black and the new value is 0, it's the end of a stem */
  2892. +        else if ( ( current_value > 0 && line[xx] == 0 )
  2893. +          || ( current_value > 0 && xx == width - 1 ) )
  2894. +        {
  2895. +          FT_Long stem_center_x/*, stem_width*/;
  2896. +          segments[num_segments].x2 = 256 * (xx-1) + line[xx-1];
  2897. +
  2898. +          if (xx == width - 1) segments[num_segments].x2 += line[xx];
  2899. +
  2900. +          /*stem center is average of start and end of stem */
  2901. +          stem_center_x = (segments[num_segments].x2 + segments[num_segments].x1) / 2;
  2902. +          /*stem_width = segments[num_segments].x2 - segments[num_segments].x1;*/
  2903. +          /* Reallocate */
  2904. +          centers = (Stem_Center*) realloc ( centers, (num_centers + 1) * sizeof(Stem_Center));
  2905. +          centers[num_centers].x = stem_center_x;
  2906. +          centers[num_centers].y = h;
  2907. +          centers[num_centers].x1 = segments[num_segments].x1;
  2908. +          centers[num_centers].x2 = segments[num_segments].x2;
  2909. +
  2910. +          num_centers++;
  2911. +
  2912. +          stem_centers[stem_center_x] += 1;
  2913. +
  2914. +          /* Find left and rightmost points for later calculations */
  2915. +          /* OR - Favor ones that aren't on the top or bottom if possible to prevent v and w from getting caught later */
  2916. +          if ( segments[num_segments].x1 < leftmost_segment->x1
  2917. +            || ( segments[num_segments].y > 1 && segments[num_segments].y < height
  2918. +              && segments[num_segments].x1 == leftmost_segment->x1 ) )
  2919. +          {
  2920. +            leftmost_segment->x1 = segments[num_segments].x1;
  2921. +            leftmost_segment->x2 = segments[num_segments].x2;
  2922. +            leftmost_segment->y = h;
  2923. +          }
  2924. +          if (segments[num_segments].x2 > rightmost_segment->x2
  2925. +            || ( segments[num_segments].y > 1 && segments[num_segments].y < height
  2926. +              && segments[num_segments].x1 == rightmost_segment->x1 ) )
  2927. +          {
  2928. +            rightmost_segment->x1 = segments[num_segments].x1;
  2929. +            rightmost_segment->x2 = segments[num_segments].x2;
  2930. +            rightmost_segment->y = h;
  2931. +          }
  2932. +
  2933. +          if (segments[num_segments].x1 < leftmost_segment_not_extrema->x1
  2934. +            || ( segments[num_segments].y > 1 && segments[num_segments].y < height
  2935. +              && segments[num_segments].x1 == leftmost_segment_not_extrema->x1
  2936. +              && h < (FT_UInt)bitmap->rows && h > 0 ) )
  2937. +          {
  2938. +            leftmost_segment_not_extrema->x1 = segments[num_segments].x1;
  2939. +            leftmost_segment_not_extrema->x2 = segments[num_segments].x2;
  2940. +            leftmost_segment_not_extrema->y = h;
  2941. +          }
  2942. +          if (segments[num_segments].x2 > rightmost_segment_not_extrema->x2
  2943. +            || ( segments[num_segments].y > 1 && segments[num_segments].y < height
  2944. +              && segments[num_segments].x1 == rightmost_segment_not_extrema->x1
  2945. +              && h < (FT_UInt)bitmap->rows && h > 0 ) )
  2946. +          {
  2947. +            rightmost_segment_not_extrema->x1 = segments[num_segments].x1;
  2948. +            rightmost_segment_not_extrema->x2 = segments[num_segments].x2;
  2949. +            rightmost_segment_not_extrema->y = h;
  2950. +          }
  2951. +
  2952. +          if (segments[num_segments].x1 < leftmost_point)
  2953. +          {
  2954. +            leftmost_point = segments[num_segments].x1;
  2955. +          }
  2956. +          if (segments[num_segments].x2 > rightmost_point)
  2957. +          {
  2958. +            rightmost_point = segments[num_segments].x2;
  2959. +          }
  2960. +
  2961. +          if (segments[num_segments].x1 < leftmost_point_not_extrema
  2962. +            && h < (FT_UInt)bitmap->rows && h > 0)
  2963. +          {
  2964. +            leftmost_point_not_extrema = segments[num_segments].x1;
  2965. +          }
  2966. +          if (segments[num_segments].x2 > rightmost_point_not_extrema
  2967. +              && h < (FT_UInt)bitmap->rows && h > 0)
  2968. +          {
  2969. +            rightmost_point_not_extrema = segments[num_segments].x2;
  2970. +          }
  2971. +
  2972. +          num_segments++;
  2973. +        }
  2974. +        /* else - other conditions - need some error checking here */
  2975. +
  2976. +        current_value = line[xx];
  2977. +      }
  2978. +    }
  2979. +
  2980. +    /* initialize */
  2981. +    for ( xx = 0; xx < MAX_STEMS; xx +=1 )
  2982. +    {
  2983. +      stems[xx].center = 0;
  2984. +      stems[xx].count = 0;
  2985. +      stems[xx].width = 0;
  2986. +      stems[xx].height = 0;
  2987. +      possible_stems[xx].center = 0;
  2988. +      possible_stems[xx].count = 0;
  2989. +      possible_stems[xx].width = 0;
  2990. +      possible_stems[xx].height = 0;
  2991. +    }
  2992. +    valid_stems = 0;
  2993. +    valid_possible_stems = 0;
  2994. +
  2995. +    /* Determine which centers belong to stems */
  2996. +    center = 0;
  2997. +
  2998. +    while ( center < num_centers )
  2999. +    {
  3000. +      /* slope at within which to consider a point part of a stem */
  3001. +      /*const FT_UInt slope = 1;
  3002. +      const FT_UInt topslope = (256 * 3) / 10;    */
  3003. +      FT_Int deviation1 = 5;  /* 10 to 20 wiith 4 matches seems good, but 1 or 2 with 3 stems needs to somehow get included */
  3004. +      FT_Int deviation2=-1, requirement1 = 4, stem_match_requirement = 3;
  3005. +      FT_Int best_height = 0, center_difference_in_height;
  3006. +      FT_Int center_difference_in_width, valid_center_average;
  3007. +      FT_Int smallest_width_ledge, smallest_width_redge;
  3008. +      FT_Int x1_difference_in_width, x2_difference_in_width;
  3009. +      FT_Bool large_gap_found = FALSE, no_gap_found = FALSE;
  3010. +      FT_Bool large_gap_found_ledge = FALSE, no_gap_found_ledge = FALSE;
  3011. +      FT_Bool large_gap_found_redge = FALSE, no_gap_found_redge = FALSE;
  3012. +      FT_Bool stem_detected = FALSE;
  3013. +      FT_Int set_width_to, set_center_to;
  3014. +
  3015. +      /* seems to not do damage */
  3016. +      /* May not be effective */
  3017. +      requirement1 = height / 4;
  3018. +      if (requirement1 < 5) requirement1 = 5;
  3019. +      deviation1 = 20;
  3020. +      deviation2 = 20;
  3021. +
  3022. +      if (columns_per_pixel == 1)
  3023. +      {
  3024. +        deviation1 = deviation2 = 10;
  3025. +      }
  3026. +
  3027. +      if ((FT_Int)bitmap->rows <= 6) deviation1 = 25;
  3028. +      if ((FT_Int)bitmap->rows <= 6) deviation2 = 25;
  3029. +
  3030. +      if (columns_per_pixel == 1 && (FT_Int)bitmap->rows <= 6)
  3031. +      {
  3032. +        deviation1 = deviation2 = 12;
  3033. +      }
  3034. +
  3035. +      /* THIS WORKS, BUT NEED TO PUNISH DIAGONALS like W */
  3036. +      /*requirement2 = height / 5;
  3037. +      if (requirement2 < 3) requirement2 = 3;
  3038. +      deviation2 = 1 ;*/
  3039. +      valid_center_average = 0;
  3040. +     /* if (deviation2 < 1) deviation2 = 1;*/
  3041. +
  3042. +      large_gap_found = large_gap_found_ledge = large_gap_found_redge = FALSE;
  3043. +      no_gap_found = no_gap_found_ledge = no_gap_found_redge = FALSE;
  3044. +      stem_detected = FALSE;
  3045. +
  3046. +      if (ppem < 11)
  3047. +      {
  3048. +        requirement1 = 4;
  3049. +      }
  3050. +      if (ppem > 18 )
  3051. +      {
  3052. +        stem_match_requirement = height / 4;
  3053. +        if (stem_match_requirement < 3) stem_match_requirement = 3;
  3054. +      }
  3055. +
  3056. +      smallest_width_ledge = smallest_width_redge = width * 256;
  3057. +      stem_matches = 0;
  3058. +      stem_matches_ledge = 0;
  3059. +      stem_matches_redge = 0;
  3060. +      last_matching_center = -1;
  3061. +      last_matching_ledge = -1;
  3062. +      last_matching_redge = -1;
  3063. +
  3064. +      /* set currently looked at center to center value */
  3065. +      this_center = center;
  3066. +      next_center = 0;
  3067. +
  3068. +      /* For each center, compare with all other centers to see if others match the properties of this one */
  3069. +      while ( next_center < num_centers )
  3070. +      {
  3071. +
  3072. +        /* calculate differences */
  3073. +        center_difference_in_width = abs (centers[this_center].x - centers[next_center].x);
  3074. +        center_difference_in_height = abs (centers[this_center].y - centers[next_center].y);
  3075. +        x1_difference_in_width = abs (centers[this_center].x1 - centers[next_center].x1);
  3076. +        x2_difference_in_width = abs (centers[this_center].x2 - centers[next_center].x2);
  3077. +
  3078. +
  3079. +        /* property - stem center points that align */
  3080. +        /* 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 */
  3081. +        if ( center_difference_in_width  <  center_difference_in_height * deviation1
  3082. +          && center_difference_in_height <= (FT_Int)bitmap->rows / 2
  3083. +          /* prevents w from getting caught ---- but also kills m */
  3084. +        && (x1_difference_in_width < center_difference_in_height * deviation2
  3085. +        || x2_difference_in_width < center_difference_in_height * deviation2 )
  3086. +
  3087. +        )
  3088. +        {
  3089. +          stem_matches += 1;
  3090. +          valid_center_average += centers[next_center].x;
  3091. +          /* try to find where the matching centers are far apart */
  3092. +          if (last_matching_center >= 0
  3093. +            && abs(centers[last_matching_center].y - centers[next_center].y) >= (FT_Int)bitmap->rows / 2)
  3094. +            large_gap_found = TRUE;
  3095. +          /* try to find where matching centers are next to each other */
  3096. +          if (last_matching_center >= 0
  3097. +            && abs(centers[last_matching_center].y - centers[next_center].y) == 1)
  3098. +            no_gap_found = TRUE;
  3099. +          last_matching_center = next_center;
  3100. +        }
  3101. +
  3102. +        if (strategy_also_use_edge_detection_for_stems){
  3103. +          /* property - stem left edge points that align */
  3104. +          /* if the center is within range, the center is less than 1/2 the height away */
  3105. +          if ( x1_difference_in_width  <  center_difference_in_height * deviation1
  3106. +            && center_difference_in_height <= (FT_Int)bitmap->rows / 2 )
  3107. +          {
  3108. +            stem_matches_ledge += 1;
  3109. +            /* may not need for edges */
  3110. +            /*valid_center_average += centers[next_center].x;  */
  3111. +
  3112. +            if (centers[next_center].x2 - centers[next_center].x1 < smallest_width_ledge )
  3113. +              smallest_width_ledge = centers[next_center].x2 - centers[next_center].x1;
  3114. +
  3115. +            /* try to find where the matching centers are far apart */
  3116. +            if (last_matching_ledge >= 0
  3117. +              && abs(centers[last_matching_ledge].y - centers[next_center].y) >= (FT_Int)bitmap->rows / 2)
  3118. +              large_gap_found_ledge = TRUE;
  3119. +            /* try to find where matching centers are next to each other */
  3120. +            if (last_matching_ledge >= 0
  3121. +              && abs(centers[last_matching_ledge].y - centers[next_center].y) == 1)
  3122. +              no_gap_found_ledge = TRUE;
  3123. +            last_matching_ledge = next_center;
  3124. +          }
  3125. +        }
  3126. +
  3127. +        if (strategy_also_use_edge_detection_for_stems){
  3128. +          /* property - stem right edge points that align */
  3129. +          /* if the center is within range, the center is less than 1/2 the height away */
  3130. +          if ( x2_difference_in_width  <  center_difference_in_height * deviation1
  3131. +            && center_difference_in_height <= (FT_Int)bitmap->rows / 2 )
  3132. +          {
  3133. +            stem_matches_redge += 1;
  3134. +            /* may not need for edges */
  3135. +            /*valid_center_average += centers[next_center].x; */
  3136. +
  3137. +            if (centers[next_center].x2 - centers[next_center].x1 < smallest_width_redge )
  3138. +              smallest_width_redge = centers[next_center].x2 - centers[next_center].x1;
  3139. +
  3140. +            /* try to find where the matching centers are far apart */
  3141. +            if (last_matching_redge >= 0
  3142. +              && abs(centers[last_matching_redge].y - centers[next_center].y) >= (FT_Int)bitmap->rows / 2)
  3143. +              large_gap_found_redge = TRUE;
  3144. +            /* try to find where matching centers are next to each other */
  3145. +            if (last_matching_redge >= 0
  3146. +              && abs(centers[last_matching_redge].y - centers[next_center].y) == 1)
  3147. +              no_gap_found_redge = TRUE;
  3148. +            last_matching_redge = next_center;
  3149. +          }
  3150. +        }
  3151. +
  3152. +        next_center++;
  3153. +      }
  3154. +
  3155. +      if (stem_matches > 0 ) valid_center_average /= stem_matches;
  3156. +
  3157. +      best_height = stem_matches;
  3158. +
  3159. +      /* new version */
  3160. +      if ( ( stem_matches >= stem_match_requirement
  3161. +            || ( ( (FT_Int)bitmap->rows <= 6 || ppem < 11)
  3162. +              && stem_matches >= 2
  3163. +              && abs(valid_center_average - centers[center].x) < deviation1 /2 )
  3164. +            /* try to catch tightly aligned stuff where the matching centers are next to each other only */
  3165. +            || ( stem_matches == 2
  3166. +              && abs(valid_center_average - centers[center].x) <= deviation1 /2
  3167. +              && no_gap_found && ppem < 18 )    /* catches things like times 16 u but gets a lot of w's too */
  3168. +            /* stem width is less than 1/3 of the bitmap width, or bitmap_width is small */
  3169. +           )
  3170. +           &&
  3171. +           ( centers[center].x2 - centers[center].x1 < (m_horiAdvance * 12) / 2
  3172. +             || m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) )
  3173. +      {
  3174. +        stem_detected = TRUE;
  3175. +        set_width_to = centers[center].x2 - centers[center].x1;
  3176. +        best_height = stem_matches;
  3177. +        set_center_to = centers[center].x;
  3178. +
  3179. +      }
  3180. +      /* see if edges found anything */
  3181. +      if (strategy_also_use_edge_detection_for_stems && !stem_detected)
  3182. +      {
  3183. +        if ((
  3184. +        /* Require no gap for edges */
  3185. +         stem_matches_ledge >= stem_match_requirement && no_gap_found_ledge
  3186. +        /* stem width is less than 1/3 of the bitmap width, or bitmap_width is small */
  3187. +         ) && ( centers[center].x2 - centers[center].x1 < (m_horiAdvance * 12) / 2
  3188. +           || m_horiAdvance * 12 <= columns_per_pixel * one_pixel)
  3189. +         /* The stem occurs on the left side of glyph only */
  3190. +           && centers[center].x < (m_horiAdvance * 12) / 2
  3191. +
  3192. +        )
  3193. +        {
  3194. +          stem_detected = TRUE;
  3195. +          set_width_to = smallest_width_ledge;
  3196. +          best_height = stem_matches_ledge;
  3197. +          set_center_to = centers[center].x1 + set_width_to / 2;
  3198. +          stem_matches = stem_matches_ledge;
  3199. +        }
  3200. +        else if ((
  3201. +        /* Require no gap for edges */
  3202. +         stem_matches_redge >= stem_match_requirement  && no_gap_found_redge
  3203. +        /* stem width is less than 1/3 of the bitmap width, or bitmap_width is small */
  3204. +         ) && ( centers[center].x2 - centers[center].x1 < (m_horiAdvance * 12) / 2
  3205. +           || m_horiAdvance * 12 <= columns_per_pixel * one_pixel)
  3206. +         /* The stem occurs on the right side of glyph only */
  3207. +           && centers[center].x > (m_horiAdvance * 12) / 2
  3208. +        )
  3209. +        {
  3210. +          stem_detected = TRUE;
  3211. +          set_width_to = smallest_width_redge;
  3212. +          best_height = stem_matches_redge;
  3213. +          set_center_to = centers[center].x2 - set_width_to / 2;
  3214. +          stem_matches = stem_matches_redge;
  3215. +        }
  3216. +      }
  3217. +
  3218. +
  3219. +      /*store and/or replace highest occurrences with 3 or more centers */
  3220. +      /* because this matched, it will become the top dog regardless */
  3221. +      if ( stem_detected )
  3222. +      if ( stem_matches > possible_stems[0].height )
  3223. +      {
  3224. +        /* if this is the first stem just go ahead */
  3225. +        if (valid_possible_stems == 0)
  3226. +        {
  3227. +          valid_possible_stems = 1;
  3228. +          possible_stems[0].center = set_center_to;
  3229. +          possible_stems[0].count  = stem_matches;
  3230. +          possible_stems[0].width  = set_width_to;
  3231. +          possible_stems[0].height = stem_matches;
  3232. +        }
  3233. +
  3234. +        /* otherwise, if there is already a stem */
  3235. +        else if (valid_possible_stems == 1 )
  3236. +        {
  3237. +          /* if the stem is within the range of existing one, replace existing one */
  3238. +
  3239. +          /* if the stem isn't within the range of this one swap it with next one first */
  3240. +          if (abs(set_center_to - possible_stems[0].center) >= one_pixel * 2)
  3241. +          {
  3242. +            swap_stem ( &possible_stems[0], &possible_stems[1] );
  3243. +            valid_possible_stems = 2;
  3244. +          }
  3245. +          possible_stems[0].center = set_center_to;
  3246. +          possible_stems[0].count  = stem_matches;
  3247. +          possible_stems[0].width  = set_width_to;
  3248. +          possible_stems[0].height = stem_matches;
  3249. +        }
  3250. +
  3251. +        /* otherwise if there are already 2 stems */
  3252. +        else if (valid_possible_stems >= 2 )
  3253. +        {
  3254. +          /* if the stem is within the range of existing one, replace existing one */
  3255. +          if ( abs(set_center_to - possible_stems[0].center) <= one_pixel * 2)
  3256. +          {
  3257. +            possible_stems[0].center = set_center_to;
  3258. +            possible_stems[0].count  = stem_matches;
  3259. +            possible_stems[0].width  = set_width_to;
  3260. +            possible_stems[0].height = stem_matches;
  3261. +          }
  3262. +          /* if the stem isn't within the range of this one */
  3263. +          else
  3264. +          {
  3265. +            /* see if within range of next one and swap if so and proceed overwriting it */
  3266. +            if ( abs(set_center_to - possible_stems[1].center) <= one_pixel * 2)
  3267. +            {
  3268. +              swap_stem ( &possible_stems[0], &possible_stems[1] );
  3269. +            }
  3270. +
  3271. +            /* otherwise see if in range of third one */
  3272. +            else if ( abs(set_center_to - possible_stems[2].center) <= one_pixel * 2)
  3273. +            {
  3274. +              swap_stem ( &possible_stems[0], &possible_stems[2] );
  3275. +            }
  3276. +
  3277. +            /* otherwise this is the new top dog, so demote everything */
  3278. +            else
  3279. +            {
  3280. +              swap_stem ( &possible_stems[1], &possible_stems[2] );
  3281. +              swap_stem ( &possible_stems[0], &possible_stems[1] );
  3282. +              valid_possible_stems += 1;
  3283. +            }
  3284. +            possible_stems[0].center = set_center_to;
  3285. +            possible_stems[0].count  = stem_matches;
  3286. +            possible_stems[0].width  = set_width_to;
  3287. +            possible_stems[0].height = stem_matches;
  3288. +          }
  3289. +        }
  3290. +      }
  3291. +
  3292. +      else if ( stem_matches > possible_stems[1].height  && set_center_to != 0)
  3293. +      {
  3294. +
  3295. +        /* make sure it doesn't match the first stem */
  3296. +        if ( abs(set_center_to - possible_stems[0].center) >= one_pixel * 2 )
  3297. +        {
  3298. +
  3299. +          /* if this is the second stem */
  3300. +          if (valid_possible_stems == 1)  valid_possible_stems = 2;
  3301. +
  3302. +          /* otherwise if there is already a stem here */
  3303. +          else if (valid_possible_stems >= 2 )
  3304. +          {
  3305. +            /* if it doesn't match the second stem, proceed to swap out with the third */
  3306. +            /* if it does, replace it */
  3307. +            if ( abs(set_center_to - possible_stems[1].center) >= one_pixel * 2 )
  3308. +            {
  3309. +              swap_stem ( &possible_stems[1], &possible_stems[2] );
  3310. +              valid_possible_stems +=1;
  3311. +            }
  3312. +          }
  3313. +          possible_stems[1].center = set_center_to;
  3314. +          possible_stems[1].count  = stem_matches;
  3315. +          possible_stems[1].width  = set_width_to;
  3316. +          possible_stems[1].height = stem_matches;
  3317. +        }
  3318. +      }
  3319. +
  3320. +      else if ( stem_matches > possible_stems[2].height && set_center_to != 0)
  3321. +      {
  3322. +        /* if it doesn't match the first or second one */
  3323. +        if ( abs(set_center_to - possible_stems[0].center) >= one_pixel * 2
  3324. +          && abs(set_center_to - possible_stems[1].center) >= one_pixel * 2)
  3325. +
  3326. +        {
  3327. +          if (valid_possible_stems == 2)
  3328. +          {
  3329. +            valid_possible_stems += 1;
  3330. +          }
  3331. +          possible_stems[2].center = set_center_to;
  3332. +          possible_stems[2].count  = stem_matches;
  3333. +          possible_stems[2].width  = set_width_to;
  3334. +          possible_stems[1].height = stem_matches;
  3335. +        }
  3336. +      }
  3337. +      if (valid_possible_stems > 3) valid_possible_stems = 3;
  3338. +
  3339. +      center++;
  3340. +    }
  3341. +
  3342. +    /* promote to stem */
  3343. +    if (valid_possible_stems > 0)
  3344. +    {
  3345. +      stems[0].center = possible_stems[0].center;
  3346. +      stems[0].count  = possible_stems[0].count;
  3347. +      stems[0].width  = possible_stems[0].width;
  3348. +      stems[0].height  = possible_stems[0].height;
  3349. +      stems[0].generated = FALSE;
  3350. +      valid_stems++;
  3351. +    }
  3352. +
  3353. +    if (valid_stems == 1 && valid_possible_stems > 1)
  3354. +    {
  3355. +      stems[1].center = possible_stems[1].center;
  3356. +      stems[1].count  = possible_stems[1].count;
  3357. +      stems[1].width  = possible_stems[1].width;
  3358. +      stems[1].height  = possible_stems[1].height;
  3359. +      stems[1].generated = FALSE;
  3360. +      valid_stems++;
  3361. +    }
  3362. +
  3363. +    if (valid_stems == 2 && valid_possible_stems > 2 && possible_stems[2].center != 0 )
  3364. +    {
  3365. +      stems[2].center = possible_stems[2].center;
  3366. +      stems[2].count  = possible_stems[2].count;
  3367. +      stems[2].width  = possible_stems[2].width;
  3368. +      stems[2].height  = possible_stems[2].height;
  3369. +      stems[2].generated = FALSE;
  3370. +      valid_stems++;
  3371. +    }
  3372. +
  3373. +    /* sort stems in x direction */
  3374. +    if ( valid_stems == 3)
  3375. +    {
  3376. +      if (stems[0].center > stems[1].center)
  3377. +        swap_stem ( &stems[0], &stems[1] );
  3378. +      if (stems[0].center > stems[2].center)
  3379. +        swap_stem ( &stems[1], &stems[2] );
  3380. +      if (stems[1].center > stems[2].center)
  3381. +        swap_stem ( &stems[1], &stems[2] );
  3382. +      if (stems[0].center > stems[1].center)
  3383. +        swap_stem ( &stems[0], &stems[1] );
  3384. +
  3385. +      /* only look at first and last stem for now */
  3386. +      swap_stem ( &stems[1], &stems[2] );
  3387. +    }
  3388. +
  3389. +    if (strategy_use_verdana_12_hack
  3390. +      && strcasestr(slot->face->family_name, "Verdana")
  3391. +      && ppem == 12
  3392. +      && valid_stems == 1
  3393. +      && (stems[0].center + m_horiBearingX * 12 - one_pixel < m_horiAdvance * 4
  3394. +        ||stems[0].center + m_horiBearingX * 12 - one_pixel > m_horiAdvance * 8) )
  3395. +    {
  3396. +      if (stems[0].center + m_horiBearingX * 12 - one_pixel < m_horiAdvance * 4)
  3397. +      {
  3398. +          stems[1].center = rightmost_point - one_pixel / 2;
  3399. +          stems[1].width = 1;
  3400. +          stems[1].generated = TRUE;
  3401. +          valid_stems += 1;
  3402. +      }
  3403. +      else
  3404. +      {
  3405. +          stems[1].center = leftmost_point + one_pixel / 2;
  3406. +          stems[1].width = 1;
  3407. +          stems[1].generated = TRUE;
  3408. +          valid_stems += 1;
  3409. +      }
  3410. +      strategy_always_use_distance_ceiling = TRUE;
  3411. +    }
  3412. +
  3413. +   /* synthesize stems - Works, but needs work */
  3414. +   if ( (strategy_synthesize_stems || known_stem_values->synth_stems) && valid_stems  == 0 && ppem > 10 )
  3415. +    {
  3416. +      /* 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 */
  3417. +      if (leftmost_segment_not_extrema->x1 == leftmost_point_not_extrema
  3418. +        && abs(leftmost_segment_not_extrema->x2 - leftmost_segment_not_extrema->x1)
  3419. +          < (rightmost_point_not_extrema - leftmost_point_not_extrema)/3
  3420. +        && leftmost_segment_not_extrema->y
  3421. +          < height && leftmost_segment_not_extrema->y > 1 )
  3422. +      {
  3423. +        stems[valid_stems].center = (leftmost_segment_not_extrema->x2 + leftmost_segment_not_extrema->x1) / 2;
  3424. +        stems[valid_stems].width = leftmost_segment_not_extrema->x2 - leftmost_segment_not_extrema->x1;
  3425. +        stems[valid_stems].generated = TRUE;
  3426. +        valid_stems += 1;
  3427. +      }
  3428. +
  3429. +
  3430. +      if (rightmost_segment_not_extrema->x2 == rightmost_point_not_extrema
  3431. +        && abs(rightmost_segment_not_extrema->x2 - rightmost_segment_not_extrema->x1)
  3432. +         < (rightmost_point_not_extrema - leftmost_point_not_extrema)/3
  3433. +                  && rightmost_segment_not_extrema->y < height && rightmost_segment_not_extrema->y > 1 )
  3434. +      {
  3435. +        stems[valid_stems].center = (rightmost_segment_not_extrema->x2 + rightmost_segment_not_extrema->x1) / 2;
  3436. +        stems[valid_stems].width = rightmost_segment_not_extrema->x2 - rightmost_segment_not_extrema->x1;
  3437. +        stems[valid_stems].generated = TRUE;
  3438. +        valid_stems += 1;
  3439. +      }
  3440. +
  3441. +    }
  3442. +
  3443. +    /* sort stems in x direction */
  3444. +    if (valid_stems > 1 && stems[0].center > stems[1].center)
  3445. +      swap_stem ( &stems[0], &stems[1] );
  3446. +
  3447. +    if ( valid_stems == 0 && known_stem_values->stem_translating != 0 )
  3448. +    {
  3449. +      *translate_value += known_stem_values->stem_translating;
  3450. +      
  3451. +      if (strategy_use_strengths )
  3452. +      {
  3453. +        /* consider 1/2 pixel the max when strength is at 100%, unless translate is already greater than that */
  3454. +        FT_Int strength_cutoff = 32;
  3455. +        if (abs(*translate_value) > strength_cutoff) strength_cutoff = *translate_value;
  3456. +        max_strength = (strength_cutoff * alignment_strength) / 100;
  3457. +        if (*translate_value < -max_strength) *translate_value = -max_strength;
  3458. +        else if  (*translate_value > max_strength) *translate_value = max_strength;
  3459. +      }      
  3460. +    }
  3461. +    else
  3462. +    /* Start snapping */
  3463. +    {
  3464. +      FT_Int center_offset;
  3465. +      FT_Int modulus;
  3466. +      FT_Int delta, delta2;
  3467. +      FT_Long stem_distance = 1, new_distance = 1;
  3468. +      FT_Int distance_floor, distance_ceiling;
  3469. +      FT_Int translate_value2 = 0;
  3470. +      FT_Int main_stem = 0;
  3471. +      FT_Int lbearing = m_horiBearingX * 12;
  3472. +      FT_Int bitmap_stem_location = stems[0].center;
  3473. +      FT_Int advance_stem_location = bitmap_stem_location + lbearing - one_pixel;
  3474. +      FT_Int advance_width = m_horiAdvance * 12;
  3475. +      FT_Int original_advance_width = 12 * (slot->linearHoriAdvance >> 10);
  3476. +      FT_Int glyph_width = rightmost_point - leftmost_point;
  3477. +      FT_Int stem_width = stems[0].width;
  3478. +      FT_Int advance_leftmost_location = leftmost_point + lbearing - one_pixel;
  3479. +      FT_Int advance_rightmost_location = rightmost_point + lbearing - one_pixel;
  3480. +
  3481. +#define proposed_transformed_point(point) \
  3482. +  point * (float)(new_distance) / (float)(stem_distance) \
  3483. +  + *translate_value * 12 - ( stems[main_stem].center * (float)(new_distance) \
  3484. +  / (float)(stem_distance) - stems[main_stem].center)
  3485. +
  3486. +#define proposed_translated_point(point) point + *translate_value * 12
  3487. +
  3488. +      center_offset = one_pixel / 2;   /* half pixel */
  3489. +      modulus = one_pixel;            /* whole pixel */
  3490. +
  3491. +      /* Determine center_offset via known values */
  3492. +      if (known_stem_values->stem_width >= 0)
  3493. +      {
  3494. +        if (known_stem_values->stem_width % 2 == 0)
  3495. +        {
  3496. +          center_offset = 0;
  3497. +        }
  3498. +        else
  3499. +        {
  3500. +          center_offset = one_pixel / 2;
  3501. +        }
  3502. +      }
  3503. +      /* otherwise do intelligent guessing, if set */
  3504. +      else if ( strategy_auto_change_center_offset
  3505. +        && ppem >= STEM_WIDTH_2_PPEM
  3506. +        && stems[0].width < one_pixel * 1.45)
  3507. +      {
  3508. +        center_offset = one_pixel / 2;
  3509. +      }
  3510. +      else if ( strategy_auto_change_center_offset
  3511. +        && ppem >= STEM_WIDTH_2_PPEM
  3512. +        && stems[0].width >= one_pixel * 1.45
  3513. +        && stems[0].width < one_pixel * 2.6)
  3514. +      {
  3515. +        center_offset = 0;
  3516. +      }
  3517. +      else if ( strategy_auto_change_center_offset
  3518. +        && ppem >= STEM_WIDTH_2_PPEM
  3519. +        && stems[0].width >= one_pixel * 2.6
  3520. +        && stems[0].width < one_pixel * 3.6)
  3521. +      {
  3522. +        center_offset = one_pixel / 2;
  3523. +      }
  3524. +      else if ( strategy_auto_change_center_offset && ppem >= STEM_WIDTH_2_PPEM )
  3525. +        center_offset = (one_pixel * ((((int)(stems[0].width + one_pixel / 2)) / one_pixel ) % 2) ) / 2;
  3526. +
  3527. +      /* Snap to closest translate and scale values by default */
  3528. +      if (valid_stems >= 1)
  3529. +      {
  3530. +        /* closest snapping point for stem 0 */
  3531. +        delta = (stems[0].center  + center_offset) % (modulus);
  3532. +
  3533. +        if (delta < modulus / 2 ) *translate_value = ( - delta  ) / (columns_per_pixel * 4);  /* snap left */
  3534. +        else *translate_value = (modulus -delta) / (columns_per_pixel * 4);      /* snap right */
  3535. +      }
  3536. +
  3537. +      if (strategy_use_d_correction)
  3538. +      {
  3539. +        /* if the only stem is in the last 1/3 of glyph width, the advance is
  3540. +         * 6 pixels, the ppem 11, and doing so doesn't violate bitmap boundaries,
  3541. +         * force it to snap right */
  3542. +        if (valid_stems == 1 && advance_stem_location > (advance_width * 2) / 3
  3543. +          && advance_width == 6 * one_pixel
  3544. +          && rightmost_point + modulus - delta <= ( width - (columns_per_pixel * 2) / 3) * 256
  3545. +          && ppem == 11
  3546. +        )
  3547. +          *translate_value = (modulus -delta) / (columns_per_pixel * 4);
  3548. +      }
  3549. +
  3550. +      if (strategy_use_strengths )
  3551. +      {
  3552. +        /* consider 1/2 pixel the max when strength is at 100%, unless translate is already greater than that */
  3553. +        FT_Int strength_cutoff = 32;
  3554. +        if (abs(*translate_value) > strength_cutoff) strength_cutoff = *translate_value;
  3555. +        max_strength = (strength_cutoff * alignment_strength) / 100;
  3556. +        if (*translate_value < -max_strength) *translate_value = -max_strength;
  3557. +        else if  (*translate_value > max_strength) *translate_value = max_strength;
  3558. +      }
  3559. +
  3560. +      /* If 2 stems is detected, scale distance between in order to land on pixels */
  3561. +      if ( valid_stems >= 2)
  3562. +      {
  3563. +        stem_distance = abs(stems[1].center - stems[0].center);
  3564. +
  3565. +        delta = stem_distance % ( modulus );
  3566. +        new_distance = stem_distance - delta;
  3567. +
  3568. +        distance_floor = stem_distance - delta;
  3569. +        distance_ceiling = stem_distance + (modulus -  delta);
  3570. +
  3571. +        if (delta < modulus / 2 ) new_distance = distance_floor;
  3572. +        else new_distance = distance_ceiling;
  3573. +
  3574. +        if ( columns_per_pixel == 3 && valid_stems == 3 && strategy_use_m_control && valid_stems == 3
  3575. +          && (width - 2 * columns_per_pixel) > 6 * columns_per_pixel
  3576. +          && ppem > 8
  3577. +          && (advance_stem_location - advance_leftmost_location) < stems[main_stem].width * 2 )
  3578. +        {
  3579. +          FT_Int mod_factor = 2;   /*Possibly use 2 only when compatible widths is on? */
  3580. +
  3581. +          if (verbose) printf ("USING M CONTROL ");
  3582. +          distance_floor = stem_distance - stem_distance % ( modulus * mod_factor) ;
  3583. +          distance_ceiling = distance_floor + modulus * mod_factor;
  3584. +
  3585. +          new_distance = distance_ceiling;
  3586. +
  3587. +          /* force certain ideal situations */
  3588. +          /* these 2 are mostly safe to do */
  3589. +          if (distance_ceiling + one_pixel * columns_per_pixel == advance_width
  3590. +            && (stem_width < one_pixel * 1.25 ))
  3591. +            new_distance = distance_ceiling;
  3592. +          /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER THAT NUDGE IS UP OR DOWN */
  3593. +          else if (stem_distance + one_pixel * 2.6 >= advance_width
  3594. +            && (stem_width < one_pixel * 1.25 ))
  3595. +            new_distance = distance_ceiling;
  3596. +
  3597. +          if (proposed_transformed_point(leftmost_point) < one_third_pixel * 2
  3598. +            || proposed_transformed_point(rightmost_point) > (width -2 ) * one_third_pixel)
  3599. +            new_distance = distance_floor;
  3600. +
  3601. +          /* NEED TO IGNORE SERIF Ms HERE */
  3602. +          /* perhaps check bitmap boundaries instead??? */
  3603. +          if (strategy_bearing_correction && new_distance == distance_ceiling)
  3604. +          {
  3605. +            /* Correct if bearings are made substantially worse (more than 1/3 a pixel beyond advance) */
  3606. +            if (proposed_transformed_point(advance_rightmost_location) > advance_width + one_third_pixel
  3607. +            &&  proposed_transformed_point(advance_rightmost_location) > advance_rightmost_location
  3608. +            && -proposed_transformed_point(advance_leftmost_location ) < advance_rightmost_location - advance_width
  3609. +            )
  3610. +              new_distance = distance_floor;
  3611. +          }
  3612. +
  3613. +          if ( known_stem_values->m >= 0 )
  3614. +          {
  3615. +            if ( known_stem_values->m == 0 ) new_distance = distance_floor;
  3616. +            else new_distance = distance_ceiling;
  3617. +          }
  3618. +
  3619. +          if ( (rightmost_point - leftmost_point) - ((rightmost_point * *scale_value) - (leftmost_point * *scale_value)) >= one_pixel * 1.5   )
  3620. +          {
  3621. +            *scale_value = 1.0;
  3622. +            *translate_value = 0;
  3623. +            goto Exit;
  3624. +          }
  3625. +
  3626. +        }
  3627. +        else if ( columns_per_pixel == 1 && valid_stems == 3 && strategy_use_m_control && valid_stems == 3
  3628. +          && width >= 6 * columns_per_pixel
  3629. +          && ppem > 8
  3630. +          && (advance_stem_location - advance_leftmost_location) < stems[main_stem].width * 2 )
  3631. +        {
  3632. +          FT_Int mod_factor = 2;   /*Possibly use 2 only when compatible widths is on? */
  3633. +
  3634. +          if (verbose) printf ("USING M CONTROL ");
  3635. +          distance_floor = stem_distance - stem_distance % ( modulus * mod_factor) ;
  3636. +          distance_ceiling = distance_floor + modulus * mod_factor;
  3637. +
  3638. +          new_distance = distance_ceiling;
  3639. +
  3640. +          /* force certain ideal situations */
  3641. +          /* these 2 are mostly safe to do */
  3642. +          if (distance_ceiling + one_pixel * columns_per_pixel == advance_width
  3643. +            && (stem_width < one_pixel * 1.25 )) new_distance = distance_ceiling;
  3644. +          /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER THAT NUDGE IS UP OR DOWN */
  3645. +          else if (stem_distance + one_pixel * 2.6 >= advance_width
  3646. +            && (stem_width < one_pixel * 1.25 ))
  3647. +            new_distance = distance_ceiling;
  3648. +
  3649. +          if (proposed_transformed_point(leftmost_point) < 0
  3650. +            || proposed_transformed_point(rightmost_point) > (width) * one_pixel - 2*one_third_pixel)
  3651. +            new_distance = distance_floor;
  3652. +
  3653. +          /* NEED TO IGNORE SERIF Ms HERE */
  3654. +          /* perhaps check bitmap boundaries instead??? */
  3655. +          if (strategy_bearing_correction && new_distance == distance_ceiling)
  3656. +          {
  3657. +            /* Correct if bearings are made substantially worse (more than 1/3 a pixel beyond advance) */
  3658. +            if (proposed_transformed_point(advance_rightmost_location) > advance_width + one_third_pixel
  3659. +            &&  proposed_transformed_point(advance_rightmost_location) > advance_rightmost_location
  3660. +            && -proposed_transformed_point(advance_leftmost_location ) < advance_rightmost_location - advance_width
  3661. +            )
  3662. +              new_distance = distance_floor;
  3663. +          }
  3664. +
  3665. +          if ( known_stem_values->m >= 0 )
  3666. +          {
  3667. +            if ( known_stem_values->m == 0 ) new_distance = distance_floor;
  3668. +            else new_distance = distance_ceiling;
  3669. +          }
  3670. +
  3671. +
  3672. +          if ( (rightmost_point - leftmost_point) - ((rightmost_point * *scale_value) - (leftmost_point * *scale_value)) >= one_pixel * 1.5   )
  3673. +          {
  3674. +            *scale_value = 1.0;
  3675. +            *translate_value = 0;
  3676. +            goto Exit;
  3677. +          }
  3678. +
  3679. +        }
  3680. +        else
  3681. +        {
  3682. +          if (strategy_fit_to_width)
  3683. +          {
  3684. +            new_distance = advance_width - 3 * one_pixel;
  3685. +          }
  3686. +          else if (known_stem_values->stem_scaling >= 0)
  3687. +          {
  3688. +            if (known_stem_values->stem_scaling > 0) new_distance = distance_ceiling;
  3689. +            else new_distance = distance_floor;
  3690. +
  3691. +            /* enforce advance width boundaries */
  3692. +            /* TOO RESTRICTIVE ON SERIF FONTS */
  3693. +            if ( proposed_transformed_point(advance_rightmost_location) >= advance_width
  3694. +              || proposed_transformed_point(advance_leftmost_location) <= 0
  3695. +            ) new_distance = distance_floor;
  3696. +
  3697. +            /* enforce literal bitmap boundaries if there is no translate room */
  3698. +            if ( ( proposed_transformed_point(rightmost_point) >= width * 256
  3699. +                || proposed_transformed_point(leftmost_point ) <= one_pixel )
  3700. +              && new_distance + one_pixel * 3 > advance_width )
  3701. +              new_distance = distance_floor;
  3702. +
  3703. +          }
  3704. +          else if (strategy_translate_using_closest_stem)
  3705. +          {
  3706. +            /* closest snapping point for stem 1 */
  3707. +            delta2 = (stems[1].center  + center_offset) % (modulus);
  3708. +
  3709. +            if (delta2 < modulus / 2 ) translate_value2 = ( - delta2  ) / (columns_per_pixel * 4);  /* snap left */
  3710. +            else translate_value2 = (modulus -delta2) / (columns_per_pixel * 4);      /* snap right */
  3711. +
  3712. +            if (abs(translate_value2) < abs(*translate_value))
  3713. +            {
  3714. +              *translate_value = translate_value2;
  3715. +              main_stem = 1;
  3716. +            }
  3717. +
  3718. +          }
  3719. +          else if (strategy_scale_to_closest_centers)
  3720. +          {
  3721. +            /* closest snapping point for stem 0 */
  3722. +            delta = (stems[0].center  + center_offset) % (modulus);
  3723. +            delta2 = (stems[1].center  + center_offset) % (modulus);
  3724. +
  3725. +            if (delta < modulus / 2 ) new_distance = delta + stem_distance;  /* stretch left */
  3726. +            else new_distance = delta - modulus + stem_distance;      /* stretch right */
  3727. +
  3728. +            if (delta2 < modulus / 2 ) new_distance -= delta2;  /* stretch left */
  3729. +            else new_distance += modulus - delta2;      /* stretch right */
  3730. +
  3731. +          }
  3732. +          else if (strategy_scale_to_closest_centers_up_only)
  3733. +          {
  3734. +            FT_Int net_change = 0;
  3735. +
  3736. +            /* closest snapping point for stem 0 */
  3737. +            delta = (stems[0].center + center_offset) % (modulus);
  3738. +            delta2 = (stems[1].center + center_offset) % (modulus);
  3739. +
  3740. +            if (delta < modulus / 2 ) net_change = delta;  /* stretch left */
  3741. +            else net_change = -(modulus - delta);      /* stretch right */
  3742. +
  3743. +            if (delta2 < modulus / 2 ) net_change -= delta2;  /* stretch left */
  3744. +            else net_change += modulus - delta2;      /* stretch right */
  3745. +
  3746. +            if (net_change > 0
  3747. +              && proposed_transformed_point(advance_rightmost_location) < advance_width
  3748. +              && proposed_transformed_point(advance_leftmost_location) > 0
  3749. +            ) new_distance = distance_ceiling;
  3750. +          }
  3751. +
  3752. +          else if (strategy_always_use_distance_ceiling)
  3753. +          {
  3754. +            if ( proposed_transformed_point(advance_rightmost_location) < advance_width
  3755. +              && proposed_transformed_point(advance_leftmost_location) > 0
  3756. +            )
  3757. +            new_distance = distance_ceiling;
  3758. +          }
  3759. +        }
  3760. +
  3761. +        if (strategy_use_strengths)
  3762. +        {
  3763. +          FT_Int strength_cutoff = center_offset;
  3764. +          delta2 = new_distance - stem_distance;
  3765. +          if (abs(delta2) > strength_cutoff) strength_cutoff = delta2;
  3766. +
  3767. +          max_strength = (strength_cutoff * fitting_strength) / 100;
  3768. +          if (delta2 < -max_strength ) new_distance = stem_distance - max_strength;
  3769. +          else if  (delta2 > max_strength)  new_distance = stem_distance + max_strength;
  3770. +        }
  3771. +
  3772. +        *scale_value = (float)(new_distance  + 0) / (float)(stem_distance  + 0 );
  3773. +        *translate_value = *translate_value - ((float)(stems[main_stem].center * (float)new_distance) / (float)stem_distance - stems[main_stem].center) / 12;
  3774.  
  3775. -    return 0;
  3776. -  }
  3777. +        if (valid_stems == 2) *embolden_value = (64.0 / *scale_value - 64.0);
  3778. +        if (valid_stems == 3) *embolden_value = (64.0 / *scale_value - 64.0) / 1.5;
  3779. +      }
  3780.  
  3781. +      if (verbose) printf ("%lu stems:", valid_stems);
  3782.  
  3783. -  /* sets render-specific mode */
  3784. -  static FT_Error
  3785. -  ft_smooth_set_mode( FT_Renderer  render,
  3786. -                      FT_ULong     mode_tag,
  3787. -                      FT_Pointer   data )
  3788. -  {
  3789. -    /* we simply pass it to the raster */
  3790. -    return render->clazz->raster_class->raster_set_mode( render->raster,
  3791. -                                                         mode_tag,
  3792. -                                                         data );
  3793. -  }
  3794. +      if (valid_stems == 1 && verbose)
  3795. +        printf ("1 stem:    bitmapwidth:%d glyphwidth:%f glyph_width:%f center:%f bearing:%f advance:%f lhadvance:%f stemwidth:%f %d %d",
  3796. +                (width - 6) / columns_per_pixel,
  3797. +                (float)m_width / 64.0,
  3798. +                (float)glyph_width / (float)one_pixel,
  3799. +                (float)((float)advance_stem_location) / (float)one_pixel,
  3800. +                (float)m_horiBearingX / 64.0,
  3801. +                (float)m_horiAdvance / 64.0,
  3802. +                (float)linearHoriAdvance / 64.0,
  3803. +                (float)stems[0].width / (float)one_pixel,
  3804. +                advance_width, original_advance_width
  3805. +               );
  3806. +      else if (valid_stems >= 2 && verbose)
  3807. +        printf ("%lu stems: bitmapwidth:%d center1:%f center2:%f difference:%f bearing:%f advance:%f advstemloc:%f ",
  3808. +                valid_stems,
  3809. +                (width - 6) / columns_per_pixel,
  3810. +                ((float)advance_stem_location) / (float)one_pixel,
  3811. +                ((float)advance_stem_location + (float)abs(stems[1].center - stems[0].center)) / (float)one_pixel,
  3812. +                ((float)abs(stems[1].center - stems[0].center)) / (float)one_pixel,
  3813. +                (float)m_horiBearingX / 64.0,
  3814. +                (float)m_horiAdvance / 64.0,
  3815. +                (float)advance_stem_location / (float)one_pixel);
  3816.  
  3817. -  /* transform a given glyph image */
  3818. -  static FT_Error
  3819. -  ft_smooth_transform( FT_Renderer       render,
  3820. -                       FT_GlyphSlot      slot,
  3821. -                       const FT_Matrix*  matrix,
  3822. -                       const FT_Vector*  delta )
  3823. -  {
  3824. -    FT_Error  error = Smooth_Err_Ok;
  3825. +      if (strategy_bearing_correction)
  3826. +      {
  3827. +        /* Correct if negative bearings are made substantially worse (more than 1/3 a pixel) */
  3828. +        if (proposed_transformed_point(advance_rightmost_location) > advance_width
  3829. +        &&  proposed_transformed_point(advance_rightmost_location) > advance_rightmost_location
  3830. +        && -proposed_transformed_point(advance_leftmost_location ) < advance_rightmost_location - advance_width
  3831. +        && *translate_value > one_third_pixel / (columns_per_pixel * 4) )
  3832. +        {
  3833. +          *translate_value -=64 ;
  3834. +          if (verbose) printf ("TRANSLATING -64 ");
  3835. +        }
  3836. +      }
  3837.  
  3838. +      if ( strategy_use_verdana_12_hack
  3839. +        && strcasestr(slot->face->family_name, "Verdana")
  3840. +        && ppem == 12
  3841. +        && *scale_value == 1.0 && valid_stems == 0
  3842. +        && height < 8
  3843. +        && advance_rightmost_location * 1.1 < advance_width )
  3844. +        *scale_value = 1.1;
  3845.  
  3846. -    if ( slot->format != render->glyph_format )
  3847. -    {
  3848. -      error = Smooth_Err_Invalid_Argument;
  3849.        goto Exit;
  3850. +
  3851.      }
  3852.  
  3853. -    if ( matrix )
  3854. -      FT_Outline_Transform( &slot->outline, matrix );
  3855. +  Exit:
  3856.  
  3857. -    if ( delta )
  3858. -      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
  3859. +#define transformed_point( point )  point * *scale_value + *translate_value * 12
  3860. +
  3861. +    if (strategy_correct_out_of_bounds_outlines)
  3862. +    {
  3863. +      /* Correct if outside bitmap */
  3864. +      if (transformed_point(rightmost_point) >= width * 256 - 2 * one_third_pixel
  3865. +        && transformed_point(leftmost_point ) > one_pixel + 2 * one_third_pixel )
  3866. +      {
  3867. +        *translate_value -=64 ;
  3868. +      }
  3869. +      else if (transformed_point(leftmost_point) <= one_pixel / 2
  3870. +        && transformed_point(rightmost_point ) <= width * 256 -(one_pixel +  one_pixel / 2) )
  3871. +      {
  3872. +        *translate_value += 64;
  3873. +      }
  3874. +    }
  3875. +
  3876. +    STVALUES
  3877. +
  3878. +    free(segments);
  3879. +    free(leftmost_segment);
  3880. +    free(rightmost_segment);
  3881. +
  3882. +    free(known_stem_values);
  3883. +    free(stems);
  3884. +    free(possible_stems);
  3885. +    free(leftmost_stem);
  3886. +    free(rightmost_stem);
  3887. +
  3888. +    free(centers);
  3889.  
  3890. -  Exit:
  3891. -    return error;
  3892.    }
  3893.  
  3894.  
  3895. -  /* return the glyph's control box */
  3896. +  /* Gamma correction */
  3897.    static void
  3898. -  ft_smooth_get_cbox( FT_Renderer   render,
  3899. -                      FT_GlyphSlot  slot,
  3900. -                      FT_BBox*      cbox )
  3901. +  _ft_lcd_gamma_correction_correction ( FT_Bitmap*      bitmap,
  3902. +                      FT_Render_Mode  mode,
  3903. +                      FT_GlyphSlot   slot,
  3904. +                      float          gamma_correction_lt,
  3905. +                      float          gamma_correction_value)
  3906.    {
  3907. -    FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
  3908. +    if ( gamma_correction_value != 1.0 )
  3909. +    {
  3910. +      FT_UInt   width   = (FT_UInt)bitmap->width;
  3911. +      FT_UInt   height  = (FT_UInt)bitmap->rows;
  3912. +      FT_Byte*  line = bitmap->buffer;
  3913. +      float ppem = (float)slot->face->size->metrics.x_ppem;
  3914.  
  3915. -    if ( slot->format == render->glyph_format )
  3916. -      FT_Outline_Get_CBox( &slot->outline, cbox );
  3917. +      if ( !slot->face || !slot->face->size ) return;
  3918. +
  3919. +      if (ppem >= 5 )
  3920. +        for (height = (FT_UInt)bitmap->rows; height > 0; height--, line += bitmap->pitch )
  3921. +        {
  3922. +          FT_UInt  xx;
  3923. +
  3924. +          for ( xx = 0; xx < width; xx += 1 )
  3925. +          {
  3926. +            /*normal*/
  3927. +            /*line[xx] = gamma2 ( line[xx], gamma_correction_value );*/
  3928. +
  3929. +            /* sloped */
  3930. +            /*line[xx] = gamma2 ( line[xx], gamma_correction_value - 5
  3931. +            * (1-gamma_correction_value)/(gamma_correction_lt -5)
  3932. +            + ((1-gamma_correction_value)/(gamma_correction_lt -5)) * ppem );*/
  3933. +
  3934. +            /* 1/3-sloped */
  3935. +            line[xx] = gamma2 ( line[xx], gamma_correction_value - 5
  3936. +            * ((1-gamma_correction_value)/(3*(gamma_correction_lt -5)))
  3937. +            * + ((1-gamma_correction_value)/(3*(gamma_correction_lt -5))) * ppem );
  3938. +          }
  3939. +        }
  3940. +    }
  3941.    }
  3942.  
  3943. +#endif
  3944. +
  3945.  
  3946.    /* convert a slot's glyph image into a bitmap */
  3947.    static FT_Error
  3948. @@ -104,19 +2867,406 @@
  3949.    {
  3950.      FT_Error     error;
  3951.      FT_Outline*  outline = NULL;
  3952. +    FT_Outline*  outline_orig = NULL;
  3953.      FT_BBox      cbox;
  3954. -    FT_UInt      width, height, pitch;
  3955. +    FT_UInt      width=0, height=0, pitch=0, ppem;
  3956.  #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  3957.      FT_UInt      height_org, width_org;
  3958.  #endif
  3959. -    FT_Bitmap*   bitmap;
  3960. -    FT_Memory    memory;
  3961. +    FT_Bitmap*   bitmap = 0;
  3962. +    FT_Memory    memory = 0;
  3963.      FT_Int       hmul = mode == FT_RENDER_MODE_LCD;
  3964.      FT_Int       vmul = mode == FT_RENDER_MODE_LCD_V;
  3965. -    FT_Pos       x_shift, y_shift, x_left, y_top;
  3966. +    FT_Pos       x_shift = 0, y_shift = 0, x_left = 0, y_top = 0;
  3967.  
  3968.      FT_Raster_Params  params;
  3969.  
  3970. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  3971. +    FT_Matrix    scaleMat;
  3972. +    FT_Long      translate_value = 0;
  3973. +    float        scale_value = 1.0;
  3974. +    FT_Int       align_called = 0;
  3975. +
  3976. +
  3977. +    int          chromeos_style_sharpening_strength = 0;
  3978. +    int          checked_chromeos_style_sharpening_strength = 0;
  3979. +    int          alignment_strength = 0;
  3980. +    int          fitting_strength = 0;
  3981. +    FT_UInt      checked_alignment_strength = 0;
  3982. +    FT_UInt      checked_fitting_strength = 0;
  3983. +    FT_UInt      checked_fringe_filter_strength = 0;
  3984. +    int          fringe_filter_strength = 0;
  3985. +    FT_UInt      checked_grayscale_filter_strength = 0;
  3986. +    int          grayscale_filter_strength = 0;
  3987. +
  3988. +    FT_UInt      checked_autohint_horizontal_stem_darken_strength = 0;
  3989. +    int          autohint_horizontal_stem_darken_strength = 0;
  3990. +
  3991. +    FT_UInt      checked_autohint_vertical_stem_darken_strength = 0;
  3992. +    int          autohint_vertical_stem_darken_strength = 0;
  3993. +
  3994. +    int          windows_style_sharpening_strength = 0;
  3995. +    FT_UInt      checked_windows_style_sharpening_strength = 0;
  3996. +    float        gamma_correction_value = 1;
  3997. +    float        gamma_correction_lt = 0;
  3998. +    FT_UInt      checked_gamma_correction_value = 0;
  3999. +
  4000. +    FT_Int       brightness_value = 0.0;
  4001. +    FT_UInt      checked_brightness_value = 0;
  4002. +
  4003. +    FT_Int       contrast_value = 0.0;
  4004. +    FT_UInt      checked_contrast_value = 0;
  4005. +
  4006. +    FT_Int       snapping_sliding_scale_value = 0;
  4007. +    FT_UInt      checked_snapping_sliding_scale_value = 0;
  4008. +
  4009. +    FT_Int       global_embolden_x_value = 0;
  4010. +    FT_UInt      checked_global_embolden_x_value = 0;    
  4011. +    
  4012. +    FT_Int       global_embolden_y_value = 0;
  4013. +    FT_UInt      checked_global_embolden_y_value = 0;    
  4014. +    
  4015. +    FT_Int       bold_embolden_x_value = 0;
  4016. +    FT_UInt      checked_bold_embolden_x_value = 0;    
  4017. +    
  4018. +    FT_Int       bold_embolden_y_value = 0;
  4019. +    FT_UInt      checked_bold_embolden_y_value = 0;    
  4020. +    
  4021. +    FT_Byte      chromeos_cutoff;
  4022. +    double       chromeos_gamma_value;
  4023. +
  4024. +    float        embolden_value = 0.0;
  4025. +    FT_Bool      autohinted = FALSE;
  4026. +
  4027. +    FT_UInt autohint_minimum_stem_height = 0;
  4028. +    FT_UInt checked_autohint_minimum_stem_height = 0;
  4029. +
  4030. +    int checked_use_various_tweaks_env = 0;
  4031. +    FT_Bool use_various_tweaks = FALSE;
  4032. +
  4033. +    int cur_width;
  4034. +    char *cur_width_env = getenv( "CUR_WIDTH" );
  4035. +
  4036. +    const FT_Int    MIN_PPEM = 1;
  4037. +    /*const FT_Int    MAX_PPEM = 100;    */
  4038. +
  4039. +    int checked_use_known_settings_on_selected_fonts_env = 0;
  4040. +    FT_Bool use_known_settings_on_selected_fonts = FALSE;
  4041. +
  4042. +    if ( slot->face && slot->face->size && slot->face->size->metrics.x_ppem )
  4043. +      ppem = slot->face->size->metrics.x_ppem;
  4044. +    else ppem = 0;
  4045. +
  4046. +    if ( cur_width_env != NULL ){
  4047. +      sscanf ( cur_width_env, "%d", &cur_width );
  4048. +      if (cur_width != 0) autohinted = TRUE;
  4049. +    }
  4050. +
  4051. +    if ( checked_use_known_settings_on_selected_fonts_env == 0 )
  4052. +    {
  4053. +      char *use_known_settings_on_selected_fonts_env = getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
  4054. +      if ( use_known_settings_on_selected_fonts_env != NULL )
  4055. +      {
  4056. +        if ( strcasecmp(use_known_settings_on_selected_fonts_env, "default" ) != 0 )
  4057. +        {
  4058. +          if ( strcasecmp(use_known_settings_on_selected_fonts_env, "true") == 0)
  4059. +            use_known_settings_on_selected_fonts = TRUE;
  4060. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "1") == 0)
  4061. +            use_known_settings_on_selected_fonts = TRUE;
  4062. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "on") == 0)
  4063. +            use_known_settings_on_selected_fonts = TRUE;
  4064. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "yes") == 0)
  4065. +            use_known_settings_on_selected_fonts = TRUE;
  4066. +        }
  4067. +      }
  4068. +      checked_use_known_settings_on_selected_fonts_env = 1;
  4069. +    }
  4070. +
  4071. +    if ( checked_use_various_tweaks_env == 0 )
  4072. +    {
  4073. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  4074. +      if ( use_various_tweaks_env != NULL )
  4075. +      {
  4076. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  4077. +        {
  4078. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0)
  4079. +            use_various_tweaks = TRUE;
  4080. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0)
  4081. +            use_various_tweaks = TRUE;
  4082. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0)
  4083. +            use_various_tweaks = TRUE;
  4084. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0)
  4085. +            use_various_tweaks = TRUE;
  4086. +        }
  4087. +      }
  4088. +      checked_use_various_tweaks_env = 1;
  4089. +    }
  4090. +
  4091. +    if ( checked_autohint_minimum_stem_height == 0)
  4092. +    {
  4093. +      char *autohint_minimum_stem_height_env = getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" );
  4094. +      if ( autohint_minimum_stem_height_env != NULL )
  4095. +      {
  4096. +        sscanf ( autohint_minimum_stem_height_env, "%u", &autohint_minimum_stem_height );
  4097. +        if      (autohint_minimum_stem_height > 100 ) autohint_minimum_stem_height = 100;
  4098. +        else if (autohint_minimum_stem_height < 0 ) autohint_minimum_stem_height = 0;
  4099. +      }
  4100. +      checked_autohint_minimum_stem_height = 1;
  4101. +    }
  4102. +
  4103. +    if ( checked_snapping_sliding_scale_value == 0)
  4104. +    {
  4105. +      char *snapping_sliding_scale_env = getenv ( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" );
  4106. +      if ( snapping_sliding_scale_env != NULL )
  4107. +      {
  4108. +        sscanf ( snapping_sliding_scale_env, "%d", &snapping_sliding_scale_value );
  4109. +        if      (snapping_sliding_scale_value > MAX_PPEM ) snapping_sliding_scale_value = 0;
  4110. +        else if (snapping_sliding_scale_value < 0 ) snapping_sliding_scale_value = 0;
  4111. +
  4112. +        if (snapping_sliding_scale_value < 11 && snapping_sliding_scale_value > 0 ) snapping_sliding_scale_value = 11;
  4113. +      }
  4114. +      checked_snapping_sliding_scale_value = 1;
  4115. +    }
  4116. +
  4117. +    if ( checked_alignment_strength == 0)
  4118. +    {
  4119. +      char *alignment_strength_env = getenv ( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" );
  4120. +      if ( alignment_strength_env != NULL )
  4121. +      {
  4122. +        sscanf ( alignment_strength_env, "%d", &alignment_strength );
  4123. +        if      (alignment_strength > 100 ) alignment_strength = 100;
  4124. +        else if (alignment_strength < 0 ) alignment_strength = 0;
  4125. +      }
  4126. +      if      (alignment_strength > 100 ) alignment_strength = 100;
  4127. +      checked_alignment_strength = 1;
  4128. +      if (snapping_sliding_scale_value != 0)
  4129. +        alignment_strength = sliding_scale ( 10, snapping_sliding_scale_value, alignment_strength, 100, ppem);
  4130. +    }
  4131. +
  4132. +    if ( checked_fitting_strength == 0)
  4133. +    {
  4134. +      char *fitting_strength_env = getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
  4135. +      if ( fitting_strength_env != NULL )
  4136. +      {
  4137. +        sscanf ( fitting_strength_env, "%d", &fitting_strength );
  4138. +        if      (fitting_strength > 100 ) fitting_strength = 100;
  4139. +        else if (fitting_strength < 0 ) fitting_strength = 0;
  4140. +      }
  4141. +      if      (fitting_strength > 100 ) fitting_strength = 100;
  4142. +      checked_fitting_strength = 1;
  4143. +      if (snapping_sliding_scale_value != 0)
  4144. +        fitting_strength = sliding_scale ( 10, snapping_sliding_scale_value, fitting_strength, 100, ppem);
  4145. +    }
  4146. +
  4147. +    if ( checked_chromeos_style_sharpening_strength == 0)
  4148. +    {
  4149. +      char *chromeos_style_sharpening_strength_env = getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" );
  4150. +      if ( chromeos_style_sharpening_strength_env != NULL )
  4151. +      {
  4152. +        sscanf ( chromeos_style_sharpening_strength_env, "%d", &chromeos_style_sharpening_strength );
  4153. +        if      (chromeos_style_sharpening_strength > 100 )
  4154. +          chromeos_style_sharpening_strength = 100;
  4155. +        else if (chromeos_style_sharpening_strength < 0 )
  4156. +          chromeos_style_sharpening_strength = 0;
  4157. +      }
  4158. +      if (ppem > 10)
  4159. +        chromeos_style_sharpening_strength =
  4160. +        (chromeos_style_sharpening_strength * ppem) / 10;
  4161. +      if      (chromeos_style_sharpening_strength > 100 )
  4162. +        chromeos_style_sharpening_strength = 100;
  4163. +      checked_chromeos_style_sharpening_strength = 1;
  4164. +    }
  4165. +
  4166. +
  4167. +    if ( checked_brightness_value == 0)
  4168. +    {
  4169. +      char *brightness_env = getenv( "INFINALITY_FT_BRIGHTNESS" );
  4170. +      if ( brightness_env != NULL )
  4171. +      {
  4172. +        sscanf ( brightness_env, "%d", &brightness_value );
  4173. +        if      (brightness_value > 100 )
  4174. +          brightness_value = 100;
  4175. +        else if (brightness_value < -100 )
  4176. +          brightness_value = 0;
  4177. +      }
  4178. +      checked_brightness_value = 1;
  4179. +    }
  4180. +
  4181. +    if ( checked_contrast_value == 0)
  4182. +    {
  4183. +      char *contrast_env = getenv( "INFINALITY_FT_CONTRAST" );
  4184. +      if ( contrast_env != NULL )
  4185. +      {
  4186. +        sscanf ( contrast_env, "%d", &contrast_value );
  4187. +        if      (contrast_value > 100 )
  4188. +          contrast_value = 100;
  4189. +        else if (contrast_value < -100 )
  4190. +          contrast_value = 100;
  4191. +      }
  4192. +      checked_contrast_value = 1;
  4193. +    }
  4194. +
  4195. +    if ( checked_windows_style_sharpening_strength == 0)
  4196. +    {
  4197. +      char *windows_style_sharpening_strength_env = getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" );
  4198. +      if ( windows_style_sharpening_strength_env != NULL )
  4199. +      {
  4200. +        sscanf ( windows_style_sharpening_strength_env, "%d", &windows_style_sharpening_strength );
  4201. +        if      (windows_style_sharpening_strength > 100 ) windows_style_sharpening_strength = 100;
  4202. +        else if (windows_style_sharpening_strength < 0 ) windows_style_sharpening_strength = 0;
  4203. +      }
  4204. +      /* Decrease the effect slightly in order to have a more linear increase in sharpness */
  4205. +      windows_style_sharpening_strength =
  4206. +      (( windows_style_sharpening_strength * windows_style_sharpening_strength ) / 100 + windows_style_sharpening_strength) / 2;
  4207. +      checked_windows_style_sharpening_strength = 1;
  4208. +    }
  4209. +
  4210. +    if ( checked_gamma_correction_value == 0 )
  4211. +    {
  4212. +      char *gamma_correction_value_env = getenv( "INFINALITY_FT_GAMMA_CORRECTION" );
  4213. +      if ( gamma_correction_value_env != NULL )
  4214. +      {
  4215. +        float f1, f2;
  4216. +
  4217. +        if ( strcasecmp(gamma_correction_value_env, "default" ) != 0)
  4218. +        {
  4219. +          sscanf ( gamma_correction_value_env, "%f %f", &f1, &f2 );
  4220. +          gamma_correction_lt = f1;
  4221. +          gamma_correction_value = f2 / 100.0;
  4222. +        }
  4223. +        if ( gamma_correction_value < .01 ) gamma_correction_value = 1.0;
  4224. +      }
  4225. +      checked_gamma_correction_value = 1;
  4226. +    }
  4227. +
  4228. +    /* set gamma value to 1 if out of range */
  4229. +    if ( slot->face && slot->face->size && slot->face->size->metrics.x_ppem )
  4230. +    {
  4231. +      if ( slot->face->size->metrics.x_ppem >= gamma_correction_lt )
  4232. +      {
  4233. +        gamma_correction_value = 1;
  4234. +      }
  4235. +    }
  4236. +    else gamma_correction_value = 1;
  4237. +
  4238. +
  4239. +    if ( checked_fringe_filter_strength == 0)
  4240. +    {
  4241. +      char *fringe_filter_strength_env = getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" );
  4242. +      if ( fringe_filter_strength_env != NULL )
  4243. +      {
  4244. +        sscanf ( fringe_filter_strength_env, "%d", &fringe_filter_strength );
  4245. +        if      (fringe_filter_strength > 100 ) fringe_filter_strength = 100;
  4246. +        else if (fringe_filter_strength < 0 ) fringe_filter_strength = 0;
  4247. +      }
  4248. +      checked_fringe_filter_strength = 1;
  4249. +    }
  4250. +
  4251. +
  4252. +    if ( checked_grayscale_filter_strength == 0)
  4253. +    {
  4254. +      char *grayscale_filter_strength_env = getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" );
  4255. +      if ( grayscale_filter_strength_env != NULL )
  4256. +      {
  4257. +        sscanf ( grayscale_filter_strength_env, "%d", &grayscale_filter_strength );
  4258. +        if      (grayscale_filter_strength > 100 ) grayscale_filter_strength = 100;
  4259. +        else if (grayscale_filter_strength < 0 ) grayscale_filter_strength = 0;
  4260. +      }
  4261. +      checked_grayscale_filter_strength = 1;
  4262. +    }
  4263. +
  4264. +
  4265. +    if ( checked_autohint_horizontal_stem_darken_strength == 0)
  4266. +    {
  4267. +      char *autohint_horizontal_stem_darken_strength_env = getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" );
  4268. +      if ( autohint_horizontal_stem_darken_strength_env != NULL )
  4269. +      {
  4270. +        sscanf ( autohint_horizontal_stem_darken_strength_env, "%d", &autohint_horizontal_stem_darken_strength );
  4271. +        if      (autohint_horizontal_stem_darken_strength > 100 ) autohint_horizontal_stem_darken_strength = 100;
  4272. +        else if (autohint_horizontal_stem_darken_strength < 0 ) autohint_horizontal_stem_darken_strength = 0;
  4273. +      }
  4274. +      checked_autohint_horizontal_stem_darken_strength = 1;
  4275. +    }
  4276. +
  4277. +    if ( checked_autohint_vertical_stem_darken_strength == 0)
  4278. +    {
  4279. +      char *autohint_vertical_stem_darken_strength_env = getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" );
  4280. +      if ( autohint_vertical_stem_darken_strength_env != NULL )
  4281. +      {
  4282. +        sscanf ( autohint_vertical_stem_darken_strength_env, "%d", &autohint_vertical_stem_darken_strength );
  4283. +        if      (autohint_vertical_stem_darken_strength > 100 ) autohint_vertical_stem_darken_strength = 100;
  4284. +        else if (autohint_horizontal_stem_darken_strength < 0 ) autohint_vertical_stem_darken_strength = 0;
  4285. +      }
  4286. +      checked_autohint_vertical_stem_darken_strength = 1;
  4287. +    }
  4288. +    
  4289. +    if ( checked_global_embolden_x_value == 0)
  4290. +    {
  4291. +      char *global_embolden_x_env = getenv ( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" );
  4292. +      if ( global_embolden_x_env != NULL )
  4293. +      {
  4294. +        sscanf ( global_embolden_x_env, "%d", &global_embolden_x_value );
  4295. +        if      (global_embolden_x_value > 128 ) global_embolden_x_value = 128;
  4296. +        else if (global_embolden_x_value < -128 ) global_embolden_x_value = -128;
  4297. +      }
  4298. +      checked_global_embolden_x_value = 1;
  4299. +    }    
  4300. +    
  4301. +    if ( checked_global_embolden_y_value == 0)
  4302. +    {
  4303. +      char *global_embolden_y_env = getenv ( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" );
  4304. +      if ( global_embolden_y_env != NULL )
  4305. +      {
  4306. +        sscanf ( global_embolden_y_env, "%d", &global_embolden_y_value );
  4307. +        if      (global_embolden_y_value > 128 ) global_embolden_y_value = 128;
  4308. +        else if (global_embolden_y_value < -128 ) global_embolden_y_value = -128;
  4309. +      }
  4310. +      checked_global_embolden_y_value = 1;
  4311. +    }    
  4312. +    
  4313. +    
  4314. +    if ( checked_bold_embolden_x_value == 0)
  4315. +    {
  4316. +      char *bold_embolden_x_env = getenv ( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" );
  4317. +      if ( bold_embolden_x_env != NULL )
  4318. +      {
  4319. +        sscanf ( bold_embolden_x_env, "%d", &bold_embolden_x_value );
  4320. +        if      (bold_embolden_x_value > 128 ) bold_embolden_x_value = 128;
  4321. +        else if (bold_embolden_x_value < -128 ) bold_embolden_x_value = -128;
  4322. +
  4323. +      }
  4324. +      checked_bold_embolden_x_value = 1;
  4325. +    }    
  4326. +    
  4327. +    if ( checked_bold_embolden_y_value == 0)
  4328. +    {
  4329. +      char *bold_embolden_y_env = getenv ( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" );
  4330. +      if ( bold_embolden_y_env != NULL )
  4331. +      {
  4332. +        sscanf ( bold_embolden_y_env, "%d", &bold_embolden_y_value );
  4333. +        if      (bold_embolden_y_value > 128 ) bold_embolden_y_value = 128;
  4334. +        else if (bold_embolden_y_value < -128 ) bold_embolden_y_value = -128;
  4335. +
  4336. +      }
  4337. +      checked_bold_embolden_y_value = 1;
  4338. +    }    
  4339. +    
  4340. +    
  4341. +
  4342. +    if( use_various_tweaks && slot->face && slot->face->style_name )
  4343. +    {
  4344. +      /* needs to also check for artifical italics */
  4345. +      if ( strcasestr(slot->face->style_name, "Italic")
  4346. +        || strcasestr(slot->face->style_name, "Oblique") )
  4347. +      {
  4348. +        windows_style_sharpening_strength = 0;
  4349. +        chromeos_style_sharpening_strength = 0;
  4350. +      }
  4351. +    }
  4352. +
  4353. +    /*if (fitting_strength == 100) scale_value = 1.1;*/
  4354. +
  4355. +#endif
  4356.  
  4357.      /* check glyph image format */
  4358.      if ( slot->format != render->glyph_format )
  4359. @@ -129,92 +3279,174 @@
  4360.      if ( mode != required_mode )
  4361.        return Smooth_Err_Cannot_Render_Glyph;
  4362.  
  4363. -    outline = &slot->outline;
  4364. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4365. +RERENDER:
  4366. +    if (align_called == 1){
  4367.  
  4368. -    /* translate the outline to the new origin if needed */
  4369. -    if ( origin )
  4370. -      FT_Outline_Translate( outline, origin->x, origin->y );
  4371. +      scaleMat.xx = FT_FixedFromFloat(scale_value);
  4372. +      scaleMat.xy = 0;
  4373. +      scaleMat.yx = 0;
  4374. +      scaleMat.yy = (1 << 16);
  4375.  
  4376. -    /* compute the control box, and grid fit it */
  4377. -    FT_Outline_Get_CBox( outline, &cbox );
  4378. +      FT_Outline_Copy(outline_orig, outline);
  4379.  
  4380. -    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
  4381. -    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
  4382. -    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
  4383. -    cbox.yMax = FT_PIX_CEIL( cbox.yMax );
  4384. -
  4385. -    if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
  4386. -    {
  4387. -      FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
  4388. -                 " xMin = %d, xMax = %d\n",
  4389. -                 cbox.xMin >> 6, cbox.xMax >> 6 ));
  4390. -      return Smooth_Err_Raster_Overflow;
  4391. +      if (scale_value != 1.0)
  4392. +        FT_Outline_Transform( outline, &scaleMat );
  4393. +
  4394. +      FT_Outline_Translate( outline, translate_value+0, 0 );
  4395. +
  4396. +      FT_Outline_Embolden( outline, embolden_value );
  4397.      }
  4398.      else
  4399. -      width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
  4400. -
  4401. -    if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin )
  4402.      {
  4403. -      FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
  4404. -                 " yMin = %d, yMax = %d\n",
  4405. -                 cbox.yMin >> 6, cbox.yMax >> 6 ));
  4406. -      return Smooth_Err_Raster_Overflow;
  4407. +#endif
  4408. +      outline = &slot->outline;
  4409. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4410. +      /* Need to get this PRIOR to embolden, otherwise bad things happen */
  4411. +      FT_Outline_Get_CBox( outline, &cbox );
  4412. +
  4413. +      /* Various hacks that need to be turned into a new rule set */
  4414. +      if ( !autohinted
  4415. +        && use_known_settings_on_selected_fonts
  4416. +        && mode == FT_RENDER_MODE_LCD && slot->face->family_name  && slot->face->style_name
  4417. +        && ( strcasestr(slot->face->family_name, "Courier New" )
  4418. +          && ( strcasestr(slot->face->style_name, "Regular" )
  4419. +            || strcasestr(slot->face->style_name, "Italic" ) ) ) )
  4420. +        FT_Outline_Embolden( outline, 24 );
  4421. +
  4422. +      if (!autohinted
  4423. +        && use_known_settings_on_selected_fonts
  4424. +        && mode == FT_RENDER_MODE_LCD && slot->face->family_name  && slot->face->style_name
  4425. +         && strcasestr(slot->face->family_name, "Times New Roman" )
  4426. +           && strcasestr(slot->face->style_name, "Italic" ) )
  4427. +        FT_Outline_Embolden( outline, 12 );
  4428. +
  4429. +      if ( use_known_settings_on_selected_fonts
  4430. +        && autohinted && mode == FT_RENDER_MODE_LCD  && slot->face->family_name  && slot->face->style_name
  4431. +        && strcasestr(slot->face->family_name, "FreeSerif" )
  4432. +        && strcasestr(slot->face->style_name, "Italic" ) )
  4433. +        FT_Outline_Embolden( outline, 8 );  
  4434. +
  4435. +      if( global_embolden_x_value != 0 || global_embolden_y_value != 0 )
  4436. +            FT_Outline_Embolden_XY( outline, global_embolden_x_value, global_embolden_y_value );  
  4437. +        
  4438. +      if( (bold_embolden_x_value != 0 || bold_embolden_y_value != 0)
  4439. +        && (slot->face->style_name
  4440. +          && ( strcasestr(slot->face->style_name, "Bold")
  4441. +            || strcasestr(slot->face->style_name, "Black") )
  4442. +          || ( slot->face->style_flags
  4443. +            && slot->face->style_flags & FT_STYLE_FLAG_BOLD ) ) )
  4444. +            FT_Outline_Embolden_XY( outline, bold_embolden_x_value, bold_embolden_y_value );  
  4445. +      
  4446. +      FT_Outline_Copy(outline, outline_orig);
  4447.      }
  4448. -    else
  4449. -      height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
  4450.  
  4451. -    bitmap = &slot->bitmap;
  4452. -    memory = render->root.memory;
  4453. +    /* translate the outline to the new origin if needed */
  4454. +    if (align_called == 0)
  4455. +    {
  4456. +      FT_Pos enlarge_cbox = 0;
  4457.  
  4458. -#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  4459. -    width_org  = width;
  4460. -    height_org = height;
  4461. -#endif
  4462. +      /* enlarge for grayscale rendering */
  4463. +      if ( mode == FT_RENDER_MODE_NORMAL ) enlarge_cbox = 64;
  4464.  
  4465. -    /* release old bitmap buffer */
  4466. -    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
  4467. -    {
  4468. -      FT_FREE( bitmap->buffer );
  4469. -      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
  4470. -    }
  4471. +      if ( origin )
  4472. +        FT_Outline_Translate( outline, origin->x, origin->y );
  4473.  
  4474. -    /* allocate new one */
  4475. -    pitch = width;
  4476. -    if ( hmul )
  4477. -    {
  4478. -      width = width * 3;
  4479. -      pitch = FT_PAD_CEIL( width, 4 );
  4480. -    }
  4481. +      /* compute the control box, and grid fit it */
  4482. +      /*FT_Outline_Get_CBox( outline, &cbox );*/
  4483. +
  4484. +      cbox.xMin = FT_PIX_FLOOR( cbox.xMin - enlarge_cbox );
  4485. +      cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
  4486. +      cbox.xMax = FT_PIX_CEIL( cbox.xMax + enlarge_cbox );
  4487. +      cbox.yMax = FT_PIX_CEIL( cbox.yMax );
  4488. +#else
  4489. +      if ( origin )
  4490. +        FT_Outline_Translate( outline, origin->x, origin->y );
  4491. +
  4492. +      /* compute the control box, and grid fit it */
  4493. +      FT_Outline_Get_CBox( outline, &cbox );
  4494. +
  4495. +      cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
  4496. +      cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
  4497. +      cbox.xMax = FT_PIX_CEIL( cbox.xMax );
  4498. +      cbox.yMax = FT_PIX_CEIL( cbox.yMax );
  4499. +#endif
  4500.  
  4501. -    if ( vmul )
  4502. -      height *= 3;
  4503. +      if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
  4504. +      {
  4505. +        FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
  4506. +                  " xMin = %d, xMax = %d\n",
  4507. +                  cbox.xMin >> 6, cbox.xMax >> 6 ));
  4508. +        return Smooth_Err_Raster_Overflow;
  4509. +      }
  4510. +      else
  4511. +        width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
  4512.  
  4513. -    x_shift = (FT_Int) cbox.xMin;
  4514. -    y_shift = (FT_Int) cbox.yMin;
  4515. -    x_left  = (FT_Int)( cbox.xMin >> 6 );
  4516. -    y_top   = (FT_Int)( cbox.yMax >> 6 );
  4517. +      if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin )
  4518. +      {
  4519. +        FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
  4520. +                  " yMin = %d, yMax = %d\n",
  4521. +                  cbox.yMin >> 6, cbox.yMax >> 6 ));
  4522. +        return Smooth_Err_Raster_Overflow;
  4523. +      }
  4524. +      else
  4525. +        height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
  4526.  
  4527. -#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  4528. +      bitmap = &slot->bitmap;
  4529. +      memory = render->root.memory;
  4530.  
  4531. -    if ( slot->library->lcd_filter_func )
  4532. -    {
  4533. -      FT_Int  extra = slot->library->lcd_extra;
  4534. +#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  4535. +      width_org  = width;
  4536. +      height_org = height;
  4537. +#endif
  4538.  
  4539. +      /* release old bitmap buffer */
  4540. +      if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
  4541. +      {
  4542. +        FT_FREE( bitmap->buffer );
  4543. +        slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
  4544. +      }
  4545.  
  4546. +      /* allocate new one */
  4547. +      pitch = width;
  4548.        if ( hmul )
  4549.        {
  4550. -        x_shift -= 64 * ( extra >> 1 );
  4551. -        width   += 3 * extra;
  4552. -        pitch    = FT_PAD_CEIL( width, 4 );
  4553. -        x_left  -= extra >> 1;
  4554. +        width = width * 3;
  4555. +        pitch = FT_PAD_CEIL( width, 4 );
  4556.        }
  4557.  
  4558.        if ( vmul )
  4559. +        height *= 3;
  4560. +
  4561. +      x_shift = (FT_Int) cbox.xMin;
  4562. +      y_shift = (FT_Int) cbox.yMin;
  4563. +      x_left  = (FT_Int)( cbox.xMin >> 6 );
  4564. +      y_top   = (FT_Int)( cbox.yMax >> 6 );
  4565. +
  4566. +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
  4567. +
  4568. +      if ( slot->library->lcd_filter_func )
  4569.        {
  4570. -        y_shift -= 64 * ( extra >> 1 );
  4571. -        height  += 3 * extra;
  4572. -        y_top   += extra >> 1;
  4573. +        FT_Int  extra = slot->library->lcd_extra;
  4574. +
  4575. +
  4576. +        if ( hmul )
  4577. +        {
  4578. +          x_shift -= 64 * ( extra >> 1 );
  4579. +          width   += 3 * extra;
  4580. +          pitch    = FT_PAD_CEIL( width, 4 );
  4581. +          x_left  -= extra >> 1;
  4582. +        }
  4583. +
  4584. +        if ( vmul )
  4585. +        {
  4586. +          y_shift -= 64 * ( extra >> 1 );
  4587. +          height  += 3 * extra;
  4588. +          y_top   += extra >> 1;
  4589. +        }
  4590.        }
  4591. +#endif
  4592. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4593.      }
  4594.  
  4595.  #endif
  4596. @@ -239,6 +3471,9 @@
  4597.      bitmap->pitch      = pitch;
  4598.  
  4599.      /* translate outline to render it into the bitmap */
  4600. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4601. +    if (align_called == 0)
  4602. +#endif
  4603.      FT_Outline_Translate( outline, -x_shift, -y_shift );
  4604.  
  4605.      if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
  4606. @@ -288,9 +3523,104 @@
  4607.            vec->y /= 3;
  4608.      }
  4609.  
  4610. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4611. +    if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM )
  4612. +    {
  4613. +      if ( align_called == 0 && (alignment_strength > 0 || fitting_strength > 0))
  4614. +        _lcd_stem_align ( bitmap, mode, slot, &translate_value, &scale_value,
  4615. +                          alignment_strength, fitting_strength, &embolden_value );
  4616. +
  4617. +      if ((translate_value != 0 || scale_value != 1.0) && align_called == 0)
  4618. +      {
  4619. +        align_called = 1;
  4620. +        goto RERENDER;
  4621. +      }
  4622. +
  4623. +      if ( mode == FT_RENDER_MODE_LCD )
  4624. +      {
  4625. +
  4626. +        if (fringe_filter_strength > 0 /*&& autohinted*/)
  4627. +          _ft_lcd_fringe_filter( bitmap, mode, fringe_filter_strength, slot->library );
  4628. +
  4629. +        if ( gamma_correction_lt > 0 && gamma_correction_value != 1.0 )
  4630. +          _ft_lcd_gamma_correction_correction( bitmap, mode, slot, gamma_correction_lt, gamma_correction_value );
  4631. +
  4632. +        chromeos_cutoff = (FT_Byte)(0.5 * 255.0) * (chromeos_style_sharpening_strength / 100.0);
  4633. +        chromeos_gamma_value = 1;
  4634. +
  4635. +        if (chromeos_style_sharpening_strength > 0)
  4636. +          _ft_lcd_chromeos_sharpen( bitmap, mode, chromeos_cutoff, chromeos_gamma_value );
  4637. +
  4638. +        if (ppem > 8)
  4639. +          if (windows_style_sharpening_strength > 0)
  4640. +            _ft_lcd_windows_sharpen( bitmap, mode, windows_style_sharpening_strength, slot->library );
  4641. +
  4642. +        if (autohinted && (cur_width * 100) / 64 > autohint_horizontal_stem_darken_strength
  4643. +          && autohint_horizontal_stem_darken_strength != 0)
  4644. +          autohint_horizontal_stem_darken_strength = (cur_width * 100) / 64;
  4645. +
  4646. +        if (autohint_horizontal_stem_darken_strength > 100)
  4647. +          autohint_horizontal_stem_darken_strength = 100;
  4648. +
  4649. +        /* only do on autohinted fonts */
  4650. +        /* Necessary to do on some non-thin fonts, which is why it is outside */
  4651. +        /* of the below conditional */
  4652. +        if (autohint_horizontal_stem_darken_strength > 0 && autohinted )
  4653. +          _ft_lcd_darken_x ( bitmap, mode, autohint_horizontal_stem_darken_strength, slot->library );
  4654. +
  4655. +        /* Enhance thin fonts */
  4656. +        if (autohinted)
  4657. +        {
  4658. +          /* if forcibly set use that, otherwise make a good estimate */
  4659. +          if ( !_ft_bitmap_bc ( bitmap, (float)get_brightness(slot->face->family_name, ppem) / 300.0,
  4660. +            (float)get_contrast(slot->face->family_name, ppem) / 300.0))
  4661. +          {
  4662. +            FT_Bool is_fixed_name = FALSE;
  4663. +            if ( slot->face->family_name
  4664. +              && strcasestr(slot->face->family_name, "Mono") )
  4665. +              is_fixed_name = TRUE;
  4666. +            
  4667. +            /* Darken vertical stems */
  4668. +            _ft_lcd_darken_y ( bitmap, mode, autohint_vertical_stem_darken_strength, slot->library);
  4669. +
  4670. +            /* Adjust brightness and contrast automatically based on stem width */
  4671. +            if (cur_width != 0 &&  cur_width < 30 )  cur_width = 30;
  4672. +            if (cur_width >= 30 && cur_width <= 60  )
  4673. +            {
  4674. +              float ppem_factor       = sliding_scale ( 5, 11, 0.0, 1.0, ppem);
  4675. +              float brightness_factor = sliding_scale ( 30, 52, -.3, 0.0, cur_width);
  4676. +              float contrast_factor   = sliding_scale ( 30, 52, .45, 0.0, cur_width);
  4677. +              _ft_bitmap_bc ( bitmap, ppem_factor * brightness_factor, ppem_factor * contrast_factor);
  4678. +
  4679. +              /* Only cap variable width thin-stemmed fonts */
  4680. +              if (!FT_IS_FIXED_WIDTH( slot->face ) && !is_fixed_name)
  4681. +                _ft_bitmap_cap ( bitmap, (cur_width * 150) / 64, slot->library );
  4682. +            }
  4683. +          }
  4684. +        }
  4685. +
  4686. +
  4687. +        if ( slot->library->lcd_filter_func )
  4688. +          slot->library->lcd_filter_func( bitmap, mode, slot->library );
  4689. +
  4690. +        if (grayscale_filter_strength > 0)
  4691. +          _ft_lcd_grayscale_filter( bitmap, mode, grayscale_filter_strength, slot->library );
  4692. +
  4693. +      }
  4694. +
  4695. +      /* Global values */
  4696. +      if (brightness_value != 0 || contrast_value != 0)
  4697. +        _ft_bitmap_bc ( bitmap, (float)brightness_value / 300.0, (float)contrast_value / 300.0);
  4698. +
  4699. +      FT_Outline_Done( slot->library, outline_orig );
  4700. +    }
  4701. +    else if ( mode == FT_RENDER_MODE_LCD && slot->library->lcd_filter_func )
  4702. +          slot->library->lcd_filter_func( bitmap, mode, slot->library );
  4703. +#else
  4704.      if ( slot->library->lcd_filter_func )
  4705.        slot->library->lcd_filter_func( bitmap, mode, slot->library );
  4706.  
  4707. +#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
  4708.  #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
  4709.  
  4710.      /* render outline into bitmap */
  4711. @@ -449,7 +3779,7 @@
  4712.  
  4713.  
  4714.    FT_DEFINE_RENDERER(ft_smooth_lcd_renderer_class,
  4715. -  
  4716. +
  4717.        FT_MODULE_RENDERER,
  4718.        sizeof( FT_RendererRec ),
  4719.  
  4720. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/truetype/ttgload.c.orig src/truetype/ttgload.c
  4721. --- src/truetype/ttgload.c.orig 2011-12-23 19:40:19.001348135 -0600
  4722. +++ src/truetype/ttgload.c  2011-12-23 19:27:37.964564475 -0600
  4723. @@ -830,9 +830,51 @@
  4724.        loader->pp4 = zone->cur[zone->n_points - 1];
  4725.      }
  4726.  
  4727. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4728. +    if  ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
  4729. +      FT_Outline_Embolden(&loader->gloader->current.outline, -24);
  4730. +
  4731. +    else if  ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
  4732. +      FT_Outline_Embolden(&loader->gloader->current.outline, 24);
  4733. +#endif
  4734.      return TT_Err_Ok;
  4735.    }
  4736.  
  4737. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4738. +  FT_LOCAL_DEF( float )
  4739. +  scale_test_tweak( TT_Face         face,
  4740. +                  FT_String*      family,
  4741. +                  int             ppem,
  4742. +                  FT_String*      style,
  4743. +                  FT_UInt         glyph_index,
  4744. +                  SPH_ScaleRule*  rule,
  4745. +                  FT_UInt         num_rules )
  4746. +  {
  4747. +    FT_UInt  i;
  4748. +
  4749. +
  4750. +    /* rule checks may be able to be optimized further */
  4751. +    for ( i = 0; i < num_rules; i++ )
  4752. +    {
  4753. +      if ( family                                    &&
  4754. +           ( strcmp( rule[i].family, "" ) == 0     ||
  4755. +             strcmp( rule[i].family, family ) == 0 ) )
  4756. +        if ( rule[i].ppem == 0    ||
  4757. +             rule[i].ppem == ppem )
  4758. +          if ( ( style                            &&
  4759. +                 strcmp( rule[i].style, "" ) == 0 ) ||
  4760. +               strcmp( rule[i].style, style ) == 0  )
  4761. +            if ( rule[i].glyph == 0                                ||
  4762. +                 FT_Get_Char_Index( (FT_Face)face,
  4763. +                                    rule[i].glyph ) == glyph_index )
  4764. +      {
  4765. +        /* printf( "%s,%d,%s,%c ", family, ppem, style, rule[i].glyph ); */
  4766. +        return rule[i].scale;
  4767. +      }
  4768. +    }
  4769. +    return 1.0;
  4770. +  }
  4771. +#endif
  4772.  
  4773.    /*************************************************************************/
  4774.    /*                                                                       */
  4775. @@ -852,6 +894,54 @@
  4776.      FT_Outline*     outline;
  4777.      FT_Int          n_points;
  4778.  
  4779. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4780. +    int checked_use_various_tweaks_env = 0;
  4781. +    FT_Bool use_various_tweaks = FALSE;
  4782. +
  4783. +    TT_Face     face   = (TT_Face)loader->face;
  4784. +    FT_String*  family = face->root.family_name;
  4785. +    int         ppem   = loader->size->metrics.x_ppem;
  4786. +    FT_String*  style  = face->root.style_name;
  4787. +    float       x_scale_factor = 1.0;
  4788. +    float       y_scale_factor = 1.0;
  4789. +
  4790. +    int          fitting_strength = 0;
  4791. +    FT_UInt      checked_fitting_strength = 0;
  4792. +
  4793. +    if ( checked_use_various_tweaks_env == 0 )
  4794. +    {
  4795. +      char *use_various_tweaks_env = getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
  4796. +      if ( use_various_tweaks_env != NULL )
  4797. +      {
  4798. +        if ( strcasecmp(use_various_tweaks_env, "default" ) != 0 )
  4799. +        {
  4800. +          if ( strcasecmp(use_various_tweaks_env, "true") == 0)
  4801. +            use_various_tweaks = TRUE;
  4802. +          else if ( strcasecmp(use_various_tweaks_env, "1") == 0)
  4803. +            use_various_tweaks = TRUE;
  4804. +          else if ( strcasecmp(use_various_tweaks_env, "on") == 0)
  4805. +            use_various_tweaks = TRUE;
  4806. +          else if ( strcasecmp(use_various_tweaks_env, "yes") == 0)
  4807. +            use_various_tweaks = TRUE;
  4808. +        }
  4809. +      }
  4810. +      checked_use_various_tweaks_env = 1;
  4811. +    }
  4812. +
  4813. +    if ( checked_fitting_strength == 0)
  4814. +    {
  4815. +      char *fitting_strength_env = getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
  4816. +      if ( fitting_strength_env != NULL )
  4817. +      {
  4818. +        sscanf ( fitting_strength_env, "%d", &fitting_strength );
  4819. +        if      (fitting_strength > 100 ) fitting_strength = 100;
  4820. +        else if (fitting_strength < 0 ) fitting_strength = 0;
  4821. +      }
  4822. +        if      (fitting_strength > 100 ) fitting_strength = 100;
  4823. +      checked_fitting_strength = 1;
  4824. +    }
  4825. +
  4826. +#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
  4827.  
  4828.      outline  = &gloader->current.outline;
  4829.      n_points = outline->n_points;
  4830. @@ -905,14 +995,36 @@
  4831.        FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur,
  4832.                       loader->zone.n_points + 4 );
  4833.      }
  4834. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4835. +    /* scale, but only if enabled and only if TT hinting is being used */
  4836. +    if ( fitting_strength > 0 && use_various_tweaks && IS_HINTED( loader->load_flags ) )
  4837. +    {
  4838. +      x_scale_factor = scale_test_tweak( face, family, ppem, style, loader->glyph_index, X_SCALING_Rules, X_SCALING_RULES_SIZE );
  4839. +      /* Enabling this causes problems even though supposedly not being used in rules - need to figure out */
  4840. +      /*y_scale_factor = scale_test_tweak( face, family, ppem, style, loader->glyph_index, Y_SCALING_Rules, Y_SCALING_RULES_SIZE );*/
  4841. +    }
  4842.  
  4843.      /* scale the glyph */
  4844. -    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
  4845. +#endif
  4846. +    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0
  4847. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4848. +      || x_scale_factor != 1.0 || y_scale_factor != 1.0
  4849. +#endif
  4850. +    )
  4851.      {
  4852.        FT_Vector*  vec     = outline->points;
  4853.        FT_Vector*  limit   = outline->points + n_points;
  4854. -      FT_Fixed    x_scale = ((TT_Size)loader->size)->metrics.x_scale;
  4855. -      FT_Fixed    y_scale = ((TT_Size)loader->size)->metrics.y_scale;
  4856. +      FT_Fixed    x_scale = ((TT_Size)loader->size)->metrics.x_scale
  4857. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4858. +      * x_scale_factor
  4859. +#endif
  4860. +      ;
  4861. +
  4862. +      FT_Fixed    y_scale = ((TT_Size)loader->size)->metrics.y_scale
  4863. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4864. +      * y_scale_factor
  4865. +#endif
  4866. +      ;
  4867.  
  4868.  
  4869.        for ( ; vec < limit; vec++ )
  4870. @@ -1682,7 +1794,11 @@
  4871.                                             glyph_index );
  4872.  
  4873.  #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
  4874. -      if ( ( !enhanced_mode || SPH_OPTION_BITMAP_WIDTHS ) && widthp )
  4875. +      if ( (
  4876. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4877. +        ( enhanced_mode && loader->exec->compatible_widths ) ||
  4878. +#endif
  4879. +        !enhanced_mode || SPH_OPTION_BITMAP_WIDTHS ) && widthp )
  4880.  #else
  4881.        if ( widthp )
  4882.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
  4883. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/truetype/ttinterp.c.orig src/truetype/ttinterp.c
  4884. --- src/truetype/ttinterp.c.orig    2011-12-23 19:46:15.342075740 -0600
  4885. +++ fsrc/truetype/ttinterp.c    2011-12-23 19:27:09.459546599 -0600
  4886. @@ -6754,7 +6754,14 @@
  4887.        if ( ( org_dist ^ cvt_dist ) < 0 )
  4888.          cvt_dist = -cvt_dist;
  4889.      }
  4890. -
  4891. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4892. +    if ( CUR.GS.freeVector.y != 0                               &&
  4893. +                ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
  4894. +    {
  4895. +      if ( cur_dist < -64 ) cvt_dist -= 16;
  4896. +      else if ( cur_dist > 64  && cur_dist < 84) cvt_dist += 32;
  4897. +    }
  4898. +#endif
  4899.      /* control value cut-in and round */
  4900.  
  4901.      if ( ( CUR.opcode & 4 ) != 0 )
  4902. @@ -6811,7 +6818,13 @@
  4903.                                   CUR.GS.minimum_distance, 64 );
  4904.        }
  4905.      }
  4906. -    
  4907. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4908. +    if ( CUR.GS.freeVector.y != 0
  4909. +      && ( CUR.opcode & 16 ) == 0
  4910. +      && ( CUR.opcode & 8 ) == 0
  4911. +      && ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
  4912. +      distance +=48;        
  4913. +#endif  
  4914.  #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
  4915.      if ( CUR.enhanced_mode                                                   &&
  4916.           ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_INLINE_MOVES ) )
  4917. @@ -6834,6 +6847,11 @@
  4918.          CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
  4919.        }
  4920.      }
  4921. +    
  4922. +   /* else if ( CUR.enhanced_mode                                                   &&    CUR.GS.freeVector.y != 0 &&
  4923. +    abs(distance - cur_dist) > 32 && ( CUR.sph_tweak_flags & SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) )
  4924. +        CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) + FT_PIX_ROUND (distance - cur_dist) );  */
  4925. +        
  4926.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
  4927.  
  4928.    Fail:
  4929. @@ -7707,8 +7725,27 @@
  4930.    Ins_GETINFO( INS_ARG )
  4931.    {
  4932.      FT_Long  K;
  4933. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4934. +    /* INFINALITY ENVVAR TO FORCE SUBPIXEL INTERPRETER (useful in debugging) */
  4935. +    FT_UInt force_subpixel_interpreter = 0;
  4936. +    FT_UInt checked_force_subpixel_interpreter = 0;
  4937.  
  4938. -
  4939. +    if ( checked_force_subpixel_interpreter == 0)
  4940. +    {
  4941. +      char *force_subpixel_interpreter_env = getenv( "INFINALITY_FT_DEBUG_FORCE_SUBPIXEL_INTERPRETER" );
  4942. +      if ( force_subpixel_interpreter_env != NULL )
  4943. +      {
  4944. +        if ( strcasecmp(force_subpixel_interpreter_env, "default" ) != 0 )
  4945. +        {
  4946. +          if ( strcasecmp(force_subpixel_interpreter_env, "true") == 0) force_subpixel_interpreter = TRUE;
  4947. +          else if ( strcasecmp(force_subpixel_interpreter_env, "1") == 0) force_subpixel_interpreter = TRUE;
  4948. +          else if ( strcasecmp(force_subpixel_interpreter_env, "on") == 0) force_subpixel_interpreter = TRUE;
  4949. +          else if ( strcasecmp(force_subpixel_interpreter_env, "yes") == 0) force_subpixel_interpreter = TRUE;
  4950. +        }
  4951. +      }
  4952. +      checked_force_subpixel_interpreter = 1;
  4953. +    }
  4954. +#endif
  4955.      K = 0;
  4956.  
  4957.      /********************************/
  4958. @@ -7809,7 +7846,14 @@
  4959.        }
  4960.      }
  4961.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
  4962. -
  4963. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4964. +    /* INFINALITY ENVVAR TO FORCE SUBPIXEL INTERPRETER (useful in debugging) */
  4965. +    if ( force_subpixel_interpreter )
  4966. +    {
  4967. +      K |= 1 << 13;
  4968. +      CUR.subpixel_hinting = TRUE;
  4969. +    }
  4970. +#endif
  4971.      args[0] = K;
  4972.    }
  4973.  
  4974. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/truetype/ttsubpix.c.orig src/truetype/ttsubpix.c
  4975. --- src/truetype/ttsubpix.c.orig    2011-12-23 19:49:27.948443055 -0600
  4976. +++ src/truetype/ttsubpix.c 2011-12-23 19:49:42.707934810 -0600
  4977. @@ -84,6 +84,49 @@
  4978.      int         ppem   = loader->size->metrics.x_ppem;
  4979.      FT_String*  style  = face->root.style_name;
  4980.  
  4981. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  4982. +    int checked_use_known_settings_on_selected_fonts_env = 0;
  4983. +    FT_Bool use_known_settings_on_selected_fonts = FALSE;
  4984. +
  4985. +    int          fitting_strength = 0;
  4986. +    FT_UInt      checked_fitting_strength = 0;
  4987. +
  4988. +    if ( checked_use_known_settings_on_selected_fonts_env == 0 )
  4989. +    {
  4990. +      char *use_known_settings_on_selected_fonts_env = getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
  4991. +      if ( use_known_settings_on_selected_fonts_env != NULL )
  4992. +      {
  4993. +        if ( strcasecmp(use_known_settings_on_selected_fonts_env, "default" ) != 0 )
  4994. +        {
  4995. +          if ( strcasecmp(use_known_settings_on_selected_fonts_env, "true") == 0)
  4996. +            use_known_settings_on_selected_fonts = TRUE;
  4997. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "1") == 0)
  4998. +            use_known_settings_on_selected_fonts = TRUE;
  4999. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "on") == 0)
  5000. +            use_known_settings_on_selected_fonts = TRUE;
  5001. +          else if ( strcasecmp(use_known_settings_on_selected_fonts_env, "yes") == 0)
  5002. +            use_known_settings_on_selected_fonts = TRUE;
  5003. +        }
  5004. +      }
  5005. +      checked_use_known_settings_on_selected_fonts_env = 1;
  5006. +    }
  5007. +
  5008. +    if ( checked_fitting_strength == 0)
  5009. +    {
  5010. +      char *fitting_strength_env = getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
  5011. +      if ( fitting_strength_env != NULL )
  5012. +      {
  5013. +        sscanf ( fitting_strength_env, "%d", &fitting_strength );
  5014. +        if      (fitting_strength > 100 ) fitting_strength = 100;
  5015. +        else if (fitting_strength < 0 ) fitting_strength = 0;
  5016. +      }
  5017. +        if      (fitting_strength > 100 ) fitting_strength = 100;
  5018. +      checked_fitting_strength = 1;
  5019. +    }
  5020. +
  5021. +
  5022. +#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
  5023. +
  5024.      /* Don't apply rules if style isn't set */
  5025.      if ( !face->root.style_name ) return;
  5026.  
  5027. @@ -161,6 +204,19 @@
  5028.          tt_size_ready_bytecode( loader->exec->size, FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );        
  5029.        }
  5030.      }      
  5031. +
  5032. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  5033. +    /* These tweaks require the TT interpreter to be on for this glyph */
  5034. +    if (IS_HINTED( loader->load_flags ) && use_known_settings_on_selected_fonts )
  5035. +    {
  5036. +      TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
  5037. +      TWEAK_RULES( COURIER_NEW_2_HACK );
  5038. +      
  5039. +      if (sph_test_tweak( face, family, ppem, style, glyph_index,
  5040. +           COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
  5041. +        loader->exec->compatible_widths |= TRUE;
  5042. +    }
  5043. +#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
  5044.    }
  5045.  
  5046.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */
  5047. diff -Nur -x '*~' -x '*.rej' -x '*.orig' -x '*.SUP' src/truetype/ttsubpix.h.orig src/truetype/ttsubpix.h
  5048. --- src/truetype/ttsubpix.h.orig    2011-12-23 19:52:30.830145677 -0600
  5049. +++ src/truetype/ttsubpix.h 2011-12-23 19:50:59.479291216 -0600
  5050. @@ -55,6 +55,10 @@
  5051.  #define SPH_TWEAK_NO_CALL_AFTER_IUP           0x0800000
  5052.  #define SPH_TWEAK_SKIP_INLINE_DELTAS          0x1000000
  5053.  
  5054. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  5055. +#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK        0x4000000
  5056. +#define SPH_TWEAK_COURIER_NEW_2_HACK          0x8000000
  5057. +#endif
  5058.  
  5059.    FT_LOCAL( FT_Bool )
  5060.    sph_test_tweak( TT_Face         face,
  5061. @@ -950,6 +954,149 @@
  5062.  
  5063.  
  5064.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */
  5065. +
  5066. +#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
  5067. +  /* use compatible widths with these */
  5068. +#define COMPATIBLE_WIDTHS_RULES_SIZE 32
  5069. +  SPH_TweakRule  COMPATIBLE_WIDTHS_Rules
  5070. +                   [COMPATIBLE_WIDTHS_RULES_SIZE] =
  5071. +                 {
  5072. +                   { "Arial Unicode MS", 12, "Regular", 'm' },
  5073. +                   { "Arial Unicode MS", 14, "Regular", 'm' },
  5074. +                   { "Arial", 10, "Regular", L'ш' },
  5075. +                   { "Arial", 11, "Regular", 'm' },
  5076. +                   { "Arial", 12, "Regular", 'm' },
  5077. +                   { "Arial", 12, "Regular", L'ш' },
  5078. +                   { "Arial", 13, "Regular", L'ш' },
  5079. +                   { "Arial", 14, "Regular", 'm' },
  5080. +                   { "Arial", 14, "Regular", L'ш' },
  5081. +                   { "Arial", 15, "Regular", L'ш' },
  5082. +                   { "Arial", 17, "Regular", 'm' },
  5083. +                   { "DejaVu Sans", 12, "Book", 0 },
  5084. +                   { "DejaVu Sans", 15, "Book", 0 },
  5085. +                   { "Georgia", 13, "Regular", 0 },
  5086. +                   { "Microsoft Sans Serif", 11, "Regular", 0 },
  5087. +                   { "Microsoft Sans Serif", 12, "Regular", 0 },
  5088. +                   { "Segoe UI", 11, "Regular", 0 },
  5089. +                   { "Segoe UI", 12, "Regular", 'm' },
  5090. +                   { "Segoe UI", 14, "Regular", 'm' },
  5091. +                   { "Tahoma", 11, "Regular", 0 },
  5092. +                   { "Times New Roman", 16, "Regular", 'c' },
  5093. +                   { "Times New Roman", 16, "Regular", 'm' },
  5094. +                   { "Times New Roman", 16, "Regular", 'o' },
  5095. +                   { "Times New Roman", 16, "Regular", 'w' },
  5096. +                   { "Trebuchet MS", 12, "Regular", 0 },
  5097. +                   { "Trebuchet MS", 14, "Regular", 0 },
  5098. +                   { "Trebuchet MS", 15, "Regular", 0 },
  5099. +                   { "Verdana", 10, "Regular", L'ш' },
  5100. +                   { "Verdana", 11, "Regular", L'ш' },
  5101. +                   { "Verdana", 12, "Regular", 0 },
  5102. +                   { "Verdana", 13, "Regular", 'U' },
  5103. +                   { "Verdana", 14, "Regular", 'm' },
  5104. +                 };
  5105. +
  5106. +
  5107. +#if 0
  5108. +
  5109. +#define FAMILY_CLASS_RULES_SIZE 2
  5110. +  Font_Class FAMILY_CLASS_Rules
  5111. +                   [FAMILY_CLASS_RULES_SIZE] =
  5112. +                 {
  5113. +                   { "Verdana Class", { "Verdana", "DejaVu Sans", "Bitstream Vera Sans", "", "", "", "", }, },
  5114. +                   { "Arial Class", { "Arial", "Liberation Sans", "Freesans", "Arimo", "", "", "", }, },
  5115. +                 };
  5116. +
  5117. +#define STYLE_CLASS_RULES_SIZE 1
  5118. +  Font_Class STYLE_CLASS_Rules
  5119. +                   [STYLE_CLASS_RULES_SIZE] =
  5120. +                 {
  5121. +                   { "Regular Class", { "Regular", "Book", "Medium", "", "", "", "", }, },
  5122. +                 };
  5123. +
  5124. +#endif
  5125. +
  5126. +#define X_SCALING_RULES_SIZE 24
  5127. +  SPH_ScaleRule  X_SCALING_Rules
  5128. +                   [X_SCALING_RULES_SIZE] =
  5129. +                 {
  5130. +                   { "Bitstream Vera Sans", 10, "Roman", 0, 1.1 },
  5131. +                   { "Bitstream Vera Sans", 16, "Roman", 0, 1.05 },
  5132. +                   { "Bitstream Vera Sans", 9, "Roman", 0, 1.05},
  5133. +                   { "Bitstream Vera Sans", 12, "Roman", 0, 1.05},
  5134. +                   { "DejaVu Sans", 10, "Book", 0, 1.1 },
  5135. +                   { "DejaVu Sans", 12, "Book", 0, 1.05 },
  5136. +                   { "Georgia", 10, "", 0, 1.05},
  5137. +                   { "Georgia", 11, "", 0, 1.1},
  5138. +                   { "Georgia", 12, "", 0, 1.025},
  5139. +                   { "Georgia", 13, "", 0, 1.05},
  5140. +                   { "Georgia", 16, "", 0, 1.05 },
  5141. +                   { "Georgia", 17, "", 0, 1.03 },
  5142. +                   { "Liberation Sans", 12, "Regular", 'm', 1.1 },
  5143. +                   { "Lucida Grande", 11, "Regular", 'm', 1.1 },
  5144. +                   { "Segoe UI", 14, "Regular", 'm', 1.05},
  5145. +                   { "Verdana", 10, "Regular", 0, 1.1 },
  5146. +                   { "Verdana", 13, "Regular", 'U', .90 },
  5147. +                   { "Verdana", 16, "Regular", 0, 1.05 },
  5148. +                   { "Verdana", 9, "Regular", 0, 1.05},
  5149. +                   { "Verdana", 12, "Regular", 'a', 1.05},
  5150. +                   { "Verdana", 12, "Regular", 'W', 1.05},
  5151. +                   { "Arial", 13, "Regular", L'л', .95 },
  5152. +                   { "Arial", 15, "Regular", L'л', .925 },
  5153. +                   { "Arial", 14, "Regular", 'm', .95 },
  5154. +
  5155. +                 };
  5156. +
  5157. +#define Y_SCALING_RULES_SIZE 1
  5158. +  SPH_ScaleRule  Y_SCALING_Rules
  5159. +                   [Y_SCALING_RULES_SIZE] =
  5160. +                 {
  5161. +                   { "-", 0, "", 0, 1.2 },
  5162. +                 };
  5163. +
  5164. +
  5165. +#define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
  5166. +  SPH_TweakRule  TIMES_NEW_ROMAN_HACK_Rules
  5167. +                   [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
  5168. +                 {
  5169. +                   { "Times New Roman", 16, "Italic", '2' },
  5170. +                   { "Times New Roman", 16, "Italic", '5' },
  5171. +                   { "Times New Roman", 16, "Italic", '7' },
  5172. +                   { "Times New Roman", 16, "Regular", '2' },
  5173. +                   { "Times New Roman", 16, "Regular", '5' },
  5174. +                   { "Times New Roman", 16, "Regular", '7' },
  5175. +                   { "Times New Roman", 17, "Italic", '2' },
  5176. +                   { "Times New Roman", 17, "Italic", '5' },
  5177. +                   { "Times New Roman", 17, "Italic", '7' },
  5178. +                   { "Times New Roman", 17, "Regular", '2' },
  5179. +                   { "Times New Roman", 17, "Regular", '5' },
  5180. +                   { "Times New Roman", 17, "Regular", '7' },
  5181. +                 };
  5182. +
  5183. +
  5184. +#define COURIER_NEW_2_HACK_RULES_SIZE 15
  5185. +  SPH_TweakRule  COURIER_NEW_2_HACK_Rules
  5186. +                   [COURIER_NEW_2_HACK_RULES_SIZE] =
  5187. +                 {
  5188. +                   { "Courier New", 10, "Regular", '2' },
  5189. +                   { "Courier New", 11, "Regular", '2' },
  5190. +                   { "Courier New", 12, "Regular", '2' },
  5191. +                   { "Courier New", 13, "Regular", '2' },
  5192. +                   { "Courier New", 14, "Regular", '2' },
  5193. +                   { "Courier New", 15, "Regular", '2' },
  5194. +                   { "Courier New", 16, "Regular", '2' },
  5195. +                   { "Courier New", 17, "Regular", '2' },
  5196. +                   { "Courier New", 18, "Regular", '2' },
  5197. +                   { "Courier New", 19, "Regular", '2' },
  5198. +                   { "Courier New", 20, "Regular", '2' },
  5199. +                   { "Courier New", 21, "Regular", '2' },
  5200. +                   { "Courier New", 22, "Regular", '2' },
  5201. +                   { "Courier New", 23, "Regular", '2' },
  5202. +                   { "Courier New", 24, "Regular", '2' },
  5203. +                 };
  5204. +
  5205. +
  5206. +#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
  5207. +
  5208.  #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
  5209.  
  5210.  #endif /* __TTSUBPIX_H__ */
Advertisement
Add Comment
Please, Sign In to add comment