Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  cf2blues.c                                                             */
  4. /*                                                                         */
  5. /*    Adobe's code for handling Blue Zones (body).                         */
  6. /*                                                                         */
  7. /*  Copyright 2009-2013 Adobe Systems Incorporated.                        */
  8. /*                                                                         */
  9. /*  This software, and all works of authorship, whether in source or       */
  10. /*  object code form as indicated by the copyright notice(s) included      */
  11. /*  herein (collectively, the "Work") is made available, and may only be   */
  12. /*  used, modified, and distributed under the FreeType Project License,    */
  13. /*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
  14. /*  FreeType Project License, each contributor to the Work hereby grants   */
  15. /*  to any individual or legal entity exercising permissions granted by    */
  16. /*  the FreeType Project License and this section (hereafter, "You" or     */
  17. /*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
  18. /*  royalty-free, irrevocable (except as stated in this section) patent    */
  19. /*  license to make, have made, use, offer to sell, sell, import, and      */
  20. /*  otherwise transfer the Work, where such license applies only to those  */
  21. /*  patent claims licensable by such contributor that are necessarily      */
  22. /*  infringed by their contribution(s) alone or by combination of their    */
  23. /*  contribution(s) with the Work to which such contribution(s) was        */
  24. /*  submitted.  If You institute patent litigation against any entity      */
  25. /*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
  26. /*  the Work or a contribution incorporated within the Work constitutes    */
  27. /*  direct or contributory patent infringement, then any patent licenses   */
  28. /*  granted to You under this License for that Work shall terminate as of  */
  29. /*  the date such litigation is filed.                                     */
  30. /*                                                                         */
  31. /*  By using, modifying, or distributing the Work you indicate that you    */
  32. /*  have read and understood the terms and conditions of the               */
  33. /*  FreeType Project License as well as those provided in this section,    */
  34. /*  and you accept them fully.                                             */
  35. /*                                                                         */
  36. /***************************************************************************/
  37.  
  38.  
  39. #include "cf2ft.h"
  40. #include FT_INTERNAL_DEBUG_H
  41.  
  42. #include "cf2blues.h"
  43. #include "cf2hints.h"
  44. #include "cf2font.h"
  45.  
  46.  
  47.   /*************************************************************************/
  48.   /*                                                                       */
  49.   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  50.   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  51.   /* messages during execution.                                            */
  52.   /*                                                                       */
  53. #undef  FT_COMPONENT
  54. #define FT_COMPONENT  trace_cf2blues
  55.  
  56.  
  57.   /*
  58.    * For blue values, the FreeType parser produces an array of integers,
  59.    * while the Adobe CFF engine produces an array of fixed.
  60.    * Define a macro to convert FreeType to fixed.
  61.    */
  62. #define cf2_blueToFixed( x )  cf2_intToFixed( x )
  63.  
  64.  
  65.   FT_LOCAL_DEF( void )
  66.   cf2_blues_init( CF2_Blues  blues,
  67.                   CF2_Font   font )
  68.   {
  69.     /* pointer to parsed font object */
  70.     CFF_Decoder*  decoder = font->decoder;
  71.  
  72.     CF2_Fixed  zoneHeight;
  73.     CF2_Fixed  maxZoneHeight = 0;
  74.     CF2_Fixed  csUnitsPerPixel;
  75.  
  76.     size_t  numBlueValues;
  77.     size_t  numOtherBlues;
  78.     size_t  numFamilyBlues;
  79.     size_t  numFamilyOtherBlues;
  80.  
  81.     FT_Pos*  blueValues;
  82.     FT_Pos*  otherBlues;
  83.     FT_Pos*  familyBlues;
  84.     FT_Pos*  familyOtherBlues;
  85.  
  86.     size_t     i;
  87.     CF2_Fixed  emBoxBottom, emBoxTop;
  88.  
  89.     CF2_Int  unitsPerEm = font->unitsPerEm;
  90.  
  91.  
  92.     if ( unitsPerEm == 0 )
  93.       unitsPerEm = 1000;
  94.  
  95.     FT_ZERO( blues );
  96.     blues->scale = font->innerTransform.d;
  97.  
  98.     cf2_getBlueMetrics( decoder,
  99.                         &blues->blueScale,
  100.                         &blues->blueShift,
  101.                         &blues->blueFuzz );
  102.  
  103.     cf2_getBlueValues( decoder, &numBlueValues, &blueValues );
  104.     cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues );
  105.     cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues );
  106.     cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues );
  107.  
  108.     /*
  109.      * synthetic em box hint heuristic
  110.      *
  111.      * Apply this when ideographic dictionary (LanguageGroup 1) has no
  112.      * real alignment zones.  Adobe tools generate dummy zones at -250 and
  113.      * 1100 for a 1000 unit em.  Fonts with ICF-based alignment zones
  114.      * should not enable the heuristic.  When the heuristic is enabled,
  115.      * the font's blue zones are ignored.
  116.      *
  117.      */
  118.  
  119.     /* get em box from OS/2 typoAscender/Descender                      */
  120.     /* TODO: FreeType does not parse these metrics.  Skip them for now. */
  121. #if 0
  122.     FCM_getHorizontalLineMetrics( &e,
  123.                                   font->font,
  124.                                   &ascender,
  125.                                   &descender,
  126.                                   &linegap );
  127.     if ( ascender - descender == unitsPerEm )
  128.     {
  129.       emBoxBottom = cf2_intToFixed( descender );
  130.       emBoxTop    = cf2_intToFixed( ascender );
  131.     }
  132.     else
  133. #endif
  134.     {
  135.       emBoxBottom = CF2_ICF_Bottom;
  136.       emBoxTop    = CF2_ICF_Top;
  137.     }
  138.  
  139.     if ( cf2_getLanguageGroup( decoder ) == 1                   &&
  140.          ( numBlueValues == 0                                 ||
  141.            ( numBlueValues == 4                             &&
  142.              cf2_blueToFixed( blueValues[0] ) < emBoxBottom &&
  143.              cf2_blueToFixed( blueValues[1] ) < emBoxBottom &&
  144.              cf2_blueToFixed( blueValues[2] ) > emBoxTop    &&
  145.              cf2_blueToFixed( blueValues[3] ) > emBoxTop    ) ) )
  146.     {
  147.       /*
  148.        * Construct hint edges suitable for synthetic ghost hints at top
  149.        * and bottom of em box.  +-CF2_MIN_COUNTER allows for unhinted
  150.        * features above or below the last hinted edge.  This also gives a
  151.        * net 1 pixel boost to the height of ideographic glyphs.
  152.        *
  153.        * Note: Adjust synthetic hints outward by epsilon (0x.0001) to
  154.        *       avoid interference.  E.g., some fonts have real hints at
  155.        *       880 and -120.
  156.        */
  157.  
  158.       blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON;
  159.       blues->emBoxBottomEdge.dsCoord = cf2_fixedRound(
  160.                                          FT_MulFix(
  161.                                            blues->emBoxBottomEdge.csCoord,
  162.                                            blues->scale ) ) -
  163.                                        CF2_MIN_COUNTER;
  164.       blues->emBoxBottomEdge.scale   = blues->scale;
  165.       blues->emBoxBottomEdge.flags   = CF2_GhostBottom |
  166.                                        CF2_Locked |
  167.                                        CF2_Synthetic;
  168.  
  169.       blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON +
  170.                                     2 * font->darkenY;
  171.       blues->emBoxTopEdge.dsCoord = cf2_fixedRound(
  172.                                       FT_MulFix(
  173.                                         blues->emBoxTopEdge.csCoord,
  174.                                         blues->scale ) ) +
  175.                                     CF2_MIN_COUNTER;
  176.       blues->emBoxTopEdge.scale   = blues->scale;
  177.       blues->emBoxTopEdge.flags   = CF2_GhostTop |
  178.                                     CF2_Locked |
  179.                                     CF2_Synthetic;
  180.  
  181.       blues->doEmBoxHints = TRUE;    /* enable the heuristic */
  182.  
  183.       return;
  184.     }
  185.  
  186.     /* copy `BlueValues' and `OtherBlues' to a combined array of top and */
  187.     /* bottom zones                                                      */
  188.     for ( i = 0; i < numBlueValues; i += 2 )
  189.     {
  190.       blues->zone[blues->count].csBottomEdge =
  191.         cf2_blueToFixed( blueValues[i] );
  192.       blues->zone[blues->count].csTopEdge =
  193.         cf2_blueToFixed( blueValues[i + 1] );
  194.  
  195.       zoneHeight = blues->zone[blues->count].csTopEdge -
  196.                    blues->zone[blues->count].csBottomEdge;
  197.  
  198.       if ( zoneHeight < 0 )
  199.       {
  200.         FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
  201.         continue;   /* reject this zone */
  202.       }
  203.  
  204.       if ( zoneHeight > maxZoneHeight )
  205.       {
  206.         /* take maximum before darkening adjustment      */
  207.         /* so overshoot suppression point doesn't change */
  208.         maxZoneHeight = zoneHeight;
  209.       }
  210.  
  211.       /* adjust both edges of top zone upward by twice darkening amount */
  212.       if ( i != 0 )
  213.       {
  214.         blues->zone[blues->count].csTopEdge    += 2 * font->darkenY;
  215.         blues->zone[blues->count].csBottomEdge += 2 * font->darkenY;
  216.       }
  217.  
  218.       /* first `BlueValue' is bottom zone; others are top */
  219.       if ( i == 0 )
  220.       {
  221.         blues->zone[blues->count].bottomZone =
  222.           TRUE;
  223.         blues->zone[blues->count].csFlatEdge =
  224.           blues->zone[blues->count].csTopEdge;
  225.       }
  226.       else
  227.       {
  228.         blues->zone[blues->count].bottomZone =
  229.           FALSE;
  230.         blues->zone[blues->count].csFlatEdge =
  231.           blues->zone[blues->count].csBottomEdge;
  232.       }
  233.  
  234.       blues->count += 1;
  235.     }
  236.  
  237.     for ( i = 0; i < numOtherBlues; i += 2 )
  238.     {
  239.       blues->zone[blues->count].csBottomEdge =
  240.         cf2_blueToFixed( otherBlues[i] );
  241.       blues->zone[blues->count].csTopEdge =
  242.         cf2_blueToFixed( otherBlues[i + 1] );
  243.  
  244.       zoneHeight = blues->zone[blues->count].csTopEdge -
  245.                    blues->zone[blues->count].csBottomEdge;
  246.  
  247.       if ( zoneHeight < 0 )
  248.       {
  249.         FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
  250.         continue;   /* reject this zone */
  251.       }
  252.  
  253.       if ( zoneHeight > maxZoneHeight )
  254.       {
  255.         /* take maximum before darkening adjustment      */
  256.         /* so overshoot suppression point doesn't change */
  257.         maxZoneHeight = zoneHeight;
  258.       }
  259.  
  260.       /* Note: bottom zones are not adjusted for darkening amount */
  261.  
  262.       /* all OtherBlues are bottom zone */
  263.       blues->zone[blues->count].bottomZone =
  264.         TRUE;
  265.       blues->zone[blues->count].csFlatEdge =
  266.         blues->zone[blues->count].csTopEdge;
  267.  
  268.       blues->count += 1;
  269.     }
  270.  
  271.     /* Adjust for FamilyBlues */
  272.  
  273.     /* Search for the nearest flat edge in `FamilyBlues' or                */
  274.     /* `FamilyOtherBlues'.  According to the Black Book, any matching edge */
  275.     /* must be within one device pixel                                     */
  276.  
  277.     csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale );
  278.  
  279.     /* loop on all zones in this font */
  280.     for ( i = 0; i < blues->count; i++ )
  281.     {
  282.       size_t     j;
  283.       CF2_Fixed  minDiff;
  284.       CF2_Fixed  flatFamilyEdge, diff;
  285.       /* value for this font */
  286.       CF2_Fixed  flatEdge = blues->zone[i].csFlatEdge;
  287.  
  288.  
  289.       if ( blues->zone[i].bottomZone )
  290.       {
  291.         /* In a bottom zone, the top edge is the flat edge.             */
  292.         /* Search `FamilyOtherBlues' for bottom zones; look for closest */
  293.         /* Family edge that is within the one pixel threshold.          */
  294.  
  295.         minDiff = CF2_FIXED_MAX;
  296.  
  297.         for ( j = 0; j < numFamilyOtherBlues; j += 2 )
  298.         {
  299.           /* top edge */
  300.           flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] );
  301.  
  302.           diff = cf2_fixedAbs( flatEdge - flatFamilyEdge );
  303.  
  304.           if ( diff < minDiff && diff < csUnitsPerPixel )
  305.           {
  306.             blues->zone[i].csFlatEdge = flatFamilyEdge;
  307.             minDiff                   = diff;
  308.  
  309.             if ( diff == 0 )
  310.               break;
  311.           }
  312.         }
  313.  
  314.         /* check the first member of FamilyBlues, which is a bottom zone */
  315.         if ( numFamilyBlues >= 2 )
  316.         {
  317.           /* top edge */
  318.           flatFamilyEdge = cf2_blueToFixed( familyBlues[1] );
  319.  
  320.           diff = cf2_fixedAbs( flatEdge - flatFamilyEdge );
  321.  
  322.           if ( diff < minDiff && diff < csUnitsPerPixel )
  323.             blues->zone[i].csFlatEdge = flatFamilyEdge;
  324.         }
  325.       }
  326.       else
  327.       {
  328.         /* In a top zone, the bottom edge is the flat edge.                */
  329.         /* Search `FamilyBlues' for top zones; skip first zone, which is a */
  330.         /* bottom zone; look for closest Family edge that is within the    */
  331.         /* one pixel threshold                                             */
  332.  
  333.         minDiff = CF2_FIXED_MAX;
  334.  
  335.         for ( j = 2; j < numFamilyBlues; j += 2 )
  336.         {
  337.           /* bottom edge */
  338.           flatFamilyEdge = cf2_blueToFixed( familyBlues[j] );
  339.  
  340.           /* adjust edges of top zone upward by twice darkening amount */
  341.           flatFamilyEdge += 2 * font->darkenY;      /* bottom edge */
  342.  
  343.           diff = cf2_fixedAbs( flatEdge - flatFamilyEdge );
  344.  
  345.           if ( diff < minDiff && diff < csUnitsPerPixel )
  346.           {
  347.             blues->zone[i].csFlatEdge = flatFamilyEdge;
  348.             minDiff                   = diff;
  349.  
  350.             if ( diff == 0 )
  351.               break;
  352.           }
  353.         }
  354.       }
  355.     }
  356.  
  357.     /* TODO: enforce separation of zones, including BlueFuzz */
  358.  
  359.     /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */
  360.     /* `bcsetup.c'.                                               */
  361.  
  362.     if ( maxZoneHeight > 0 )
  363.     {
  364.       if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ),
  365.                                          maxZoneHeight ) )
  366.       {
  367.         /* clamp at maximum scale */
  368.         blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ),
  369.                                       maxZoneHeight );
  370.       }
  371.  
  372.       /*
  373.        * TODO: Revisit the bug fix for 613448.  The minimum scale
  374.        *       requirement catches a number of library fonts.  For
  375.        *       example, with default BlueScale (.039625) and 0.4 minimum,
  376.        *       the test below catches any font with maxZoneHeight < 10.1.
  377.        *       There are library fonts ranging from 2 to 10 that get
  378.        *       caught, including e.g., Eurostile LT Std Medium with
  379.        *       maxZoneHeight of 6.
  380.        *
  381.        */
  382. #if 0
  383.       if ( blueScale < .4 / maxZoneHeight )
  384.       {
  385.         tetraphilia_assert( 0 );
  386.         /* clamp at minimum scale, per bug 0613448 fix */
  387.         blueScale = .4 / maxZoneHeight;
  388.       }
  389. #endif
  390.  
  391.     }
  392.  
  393.     /*
  394.      * Suppress overshoot and boost blue zones at small sizes.  Boost
  395.      * amount varies linearly from 0.5 pixel near 0 to 0 pixel at
  396.      * blueScale cutoff.
  397.      * Note: This boost amount is different from the coretype heuristic.
  398.      *
  399.      */
  400.  
  401.     if ( blues->scale < blues->blueScale )
  402.     {
  403.       blues->suppressOvershoot = TRUE;
  404.  
  405.       /* Change rounding threshold for `dsFlatEdge'.                    */
  406.       /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */
  407.       /*       10ppem Arial                                             */
  408.  
  409.       blues->boost = FT_MulFix(
  410.                        cf2_floatToFixed( .6 ),
  411.                        ( cf2_intToFixed( 1 ) -
  412.                          FT_DivFix( blues->scale,
  413.                                     blues->blueScale ) ) );
  414.       if ( blues->boost > 0x7FFF )
  415.       {
  416.         /* boost must remain less than 0.5, or baseline could go negative */
  417.         blues->boost = 0x7FFF;
  418.       }
  419.     }
  420.  
  421.     /* boost and darkening have similar effects; don't do both */
  422.     if ( font->stemDarkened )
  423.       blues->boost = 0;
  424.  
  425.     /* set device space alignment for each zone;    */
  426.     /* apply boost amount before rounding flat edge */
  427.  
  428.     for ( i = 0; i < blues->count; i++ )
  429.     {
  430.       if ( blues->zone[i].bottomZone )
  431.         blues->zone[i].dsFlatEdge = cf2_fixedRound(
  432.                                       FT_MulFix(
  433.                                         blues->zone[i].csFlatEdge,
  434.                                         blues->scale ) -
  435.                                       blues->boost );
  436.       else
  437.         blues->zone[i].dsFlatEdge = cf2_fixedRound(
  438.                                       FT_MulFix(
  439.                                         blues->zone[i].csFlatEdge,
  440.                                         blues->scale ) +
  441.                                       blues->boost );
  442.     }
  443.   }
  444.  
  445.  
  446.   /*
  447.    * Check whether `stemHint' is captured by one of the blue zones.
  448.    *
  449.    * Zero, one or both edges may be valid; only valid edges can be
  450.    * captured.  For compatibility with CoolType, search top and bottom
  451.    * zones in the same pass (see `BlueLock').  If a hint is captured,
  452.    * return true and position the edge(s) in one of 3 ways:
  453.    *
  454.    *  1) If `BlueScale' suppresses overshoot, position the captured edge
  455.    *     at the flat edge of the zone.
  456.    *  2) If overshoot is not suppressed and `BlueShift' requires
  457.    *     overshoot, position the captured edge a minimum of 1 device pixel
  458.    *     from the flat edge.
  459.    *  3) If overshoot is not suppressed or required, position the captured
  460.    *     edge at the nearest device pixel.
  461.    *
  462.    */
  463.   FT_LOCAL_DEF( FT_Bool )
  464.   cf2_blues_capture( const CF2_Blues  blues,
  465.                      CF2_Hint         bottomHintEdge,
  466.                      CF2_Hint         topHintEdge )
  467.   {
  468.     /* TODO: validate? */
  469.     CF2_Fixed  csFuzz = blues->blueFuzz;
  470.  
  471.     /* new position of captured edge */
  472.     CF2_Fixed  dsNew;
  473.  
  474.     /* amount that hint is moved when positioned */
  475.     CF2_Fixed  dsMove = 0;
  476.  
  477.     FT_Bool   captured = FALSE;
  478.     CF2_UInt  i;
  479.  
  480.  
  481.     /* assert edge flags are consistent */
  482.     FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) &&
  483.                !cf2_hint_isBottom( topHintEdge ) );
  484.  
  485.     /* TODO: search once without blue fuzz for compatibility with coretype? */
  486.     for ( i = 0; i < blues->count; i++ )
  487.     {
  488.       if ( blues->zone[i].bottomZone           &&
  489.            cf2_hint_isBottom( bottomHintEdge ) )
  490.       {
  491.         if ( ( blues->zone[i].csBottomEdge - csFuzz ) <=
  492.                bottomHintEdge->csCoord                   &&
  493.              bottomHintEdge->csCoord <=
  494.                ( blues->zone[i].csTopEdge + csFuzz )     )
  495.         {
  496.           /* bottom edge captured by bottom zone */
  497.  
  498.           if ( blues->suppressOvershoot )
  499.             dsNew = blues->zone[i].dsFlatEdge;
  500.  
  501.           else if ( ( blues->zone[i].csTopEdge - bottomHintEdge->csCoord ) >=
  502.                       blues->blueShift )
  503.           {
  504.             /* guarantee minimum of 1 pixel overshoot */
  505.             dsNew = FT_MIN(
  506.                       cf2_fixedRound( bottomHintEdge->dsCoord ),
  507.                       blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) );
  508.           }
  509.  
  510.           else
  511.           {
  512.             /* simply round captured edge */
  513.             dsNew = cf2_fixedRound( bottomHintEdge->dsCoord );
  514.           }
  515.  
  516.           dsMove   = dsNew - bottomHintEdge->dsCoord;
  517.           captured = TRUE;
  518.  
  519.           break;
  520.         }
  521.       }
  522.  
  523.       if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) )
  524.       {
  525.         if ( ( blues->zone[i].csBottomEdge - csFuzz ) <=
  526.                topHintEdge->csCoord                      &&
  527.              topHintEdge->csCoord <=
  528.                ( blues->zone[i].csTopEdge + csFuzz )     )
  529.         {
  530.           /* top edge captured by top zone */
  531.  
  532.           if ( blues->suppressOvershoot )
  533.             dsNew = blues->zone[i].dsFlatEdge;
  534.  
  535.           else if ( ( topHintEdge->csCoord - blues->zone[i].csBottomEdge ) >=
  536.                       blues->blueShift )
  537.           {
  538.             /* guarantee minimum of 1 pixel overshoot */
  539.             dsNew = FT_MAX(
  540.                       cf2_fixedRound( topHintEdge->dsCoord ),
  541.                       blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) );
  542.           }
  543.  
  544.           else
  545.           {
  546.             /* simply round captured edge */
  547.             dsNew = cf2_fixedRound( topHintEdge->dsCoord );
  548.           }
  549.  
  550.           dsMove   = dsNew - topHintEdge->dsCoord;
  551.           captured = TRUE;
  552.  
  553.           break;
  554.         }
  555.       }
  556.     }
  557.  
  558.     if ( captured )
  559.     {
  560.       /* move both edges and flag them `locked' */
  561.       if ( cf2_hint_isValid( bottomHintEdge ) )
  562.       {
  563.         bottomHintEdge->dsCoord += dsMove;
  564.         cf2_hint_lock( bottomHintEdge );
  565.       }
  566.  
  567.       if ( cf2_hint_isValid( topHintEdge ) )
  568.       {
  569.         topHintEdge->dsCoord += dsMove;
  570.         cf2_hint_lock( topHintEdge );
  571.       }
  572.     }
  573.  
  574.     return captured;
  575.   }
  576.  
  577.  
  578. /* END */
  579.