Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  cf2font.c                                                              */
  4. /*                                                                         */
  5. /*    Adobe's code for font instances (body).                              */
  6. /*                                                                         */
  7. /*  Copyright 2007-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.  
  41. #include "cf2glue.h"
  42. #include "cf2font.h"
  43. #include "cf2error.h"
  44. #include "cf2intrp.h"
  45.  
  46.  
  47.   /* Compute a stem darkening amount in character space. */
  48.   static void
  49.   cf2_computeDarkening( CF2_Fixed   emRatio,
  50.                         CF2_Fixed   ppem,
  51.                         CF2_Fixed   stemWidth,
  52.                         CF2_Fixed*  darkenAmount,
  53.                         CF2_Fixed   boldenAmount,
  54.                         FT_Bool     stemDarkened )
  55.   {
  56.     /* Internal calculations are done in units per thousand for */
  57.     /* convenience.                                             */
  58.     CF2_Fixed  stemWidthPer1000, scaledStem;
  59.  
  60.  
  61.     *darkenAmount = 0;
  62.  
  63.     if ( boldenAmount == 0 && !stemDarkened )
  64.       return;
  65.  
  66.     /* protect against range problems and divide by zero */
  67.     if ( emRatio < cf2_floatToFixed( .01 ) )
  68.       return;
  69.  
  70.     if ( stemDarkened )
  71.     {
  72.       /* convert from true character space to 1000 unit character space; */
  73.       /* add synthetic emboldening effect                                */
  74.  
  75.       /* we have to assure that the computation of `scaledStem' */
  76.       /* and `stemWidthPer1000' don't overflow                  */
  77.  
  78.       stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio );
  79.  
  80.       if ( emRatio > CF2_FIXED_ONE                          &&
  81.            stemWidthPer1000 <= ( stemWidth + boldenAmount ) )
  82.       {
  83.         stemWidthPer1000 = 0;                      /* to pacify compiler */
  84.         scaledStem       = cf2_intToFixed( 2333 );
  85.       }
  86.       else
  87.       {
  88.         scaledStem = FT_MulFix( stemWidthPer1000, ppem );
  89.  
  90.         if ( ppem > CF2_FIXED_ONE           &&
  91.              scaledStem <= stemWidthPer1000 )
  92.           scaledStem = cf2_intToFixed( 2333 );
  93.       }
  94.  
  95.       /*
  96.        * Total darkening amount is computed in 1000 unit character space
  97.        * using the modified 5 part curve as Avalon rasterizer.
  98.        * The darkening amount is smaller for thicker stems.
  99.        * It becomes zero when the stem is thicker than 2.333 pixels.
  100.        *
  101.        * In Avalon rasterizer,
  102.        *
  103.        *   darkenAmount = 0.5 pixels   if scaledStem <= 0.5 pixels,
  104.        *   darkenAmount = 0.333 pixels if 1 <= scaledStem <= 1.667 pixels,
  105.        *   darkenAmount = 0 pixel      if scaledStem >= 2.333 pixels,
  106.        *
  107.        * and piecewise linear in-between.
  108.        *
  109.        */
  110.       if ( scaledStem < cf2_intToFixed( 500 ) )
  111.         *darkenAmount = FT_DivFix( cf2_intToFixed( 400 ), ppem );
  112.  
  113.       else if ( scaledStem < cf2_intToFixed( 1000 ) )
  114.         *darkenAmount = FT_DivFix( cf2_intToFixed( 525 ), ppem ) -
  115.                           FT_MulFix( stemWidthPer1000,
  116.                                      cf2_floatToFixed( .25 ) );
  117.  
  118.       else if ( scaledStem < cf2_intToFixed( 1667 ) )
  119.         *darkenAmount = FT_DivFix( cf2_intToFixed( 275 ), ppem );
  120.  
  121.       else if ( scaledStem < cf2_intToFixed( 2333 ) )
  122.         *darkenAmount = FT_DivFix( cf2_intToFixed( 963 ), ppem ) -
  123.                           FT_MulFix( stemWidthPer1000,
  124.                                      cf2_floatToFixed( .413 ) );
  125.  
  126.       /* use half the amount on each side and convert back to true */
  127.       /* character space                                           */
  128.       *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio );
  129.     }
  130.  
  131.     /* add synthetic emboldening effect in character space */
  132.     *darkenAmount += boldenAmount / 2;
  133.   }
  134.  
  135.  
  136.   /* set up values for the current FontDict and matrix */
  137.  
  138.   /* caller's transform is adjusted for subpixel positioning */
  139.   static void
  140.   cf2_font_setup( CF2_Font           font,
  141.                   const CF2_Matrix*  transform )
  142.   {
  143.     /* pointer to parsed font object */
  144.     CFF_Decoder*  decoder = font->decoder;
  145.  
  146.     FT_Bool  needExtraSetup;
  147.  
  148.     /* character space units */
  149.     CF2_Fixed  boldenX = font->syntheticEmboldeningAmountX;
  150.     CF2_Fixed  boldenY = font->syntheticEmboldeningAmountY;
  151.  
  152.     CF2_Fixed  ppem;
  153.  
  154.  
  155.     /* clear previous error */
  156.     font->error = FT_Err_Ok;
  157.  
  158.     /* if a CID fontDict has changed, we need to recompute some cached */
  159.     /* data                                                            */
  160.     needExtraSetup =
  161.       (FT_Bool)( font->lastSubfont != cf2_getSubfont( decoder ) );
  162.  
  163.     /* if ppem has changed, we need to recompute some cached data         */
  164.     /* note: because of CID font matrix concatenation, ppem and transform */
  165.     /*       do not necessarily track.                                    */
  166.     ppem = cf2_getPpemY( decoder );
  167.     if ( font->ppem != ppem )
  168.     {
  169.       font->ppem     = ppem;
  170.       needExtraSetup = TRUE;
  171.     }
  172.  
  173.     /* copy hinted flag on each call */
  174.     font->hinted = (FT_Bool)( font->renderingFlags & CF2_FlagsHinted );
  175.  
  176.     /* determine if transform has changed;       */
  177.     /* include Fontmatrix but ignore translation */
  178.     if ( ft_memcmp( transform,
  179.                     &font->currentTransform,
  180.                     4 * sizeof ( CF2_Fixed ) ) != 0 )
  181.     {
  182.       /* save `key' information for `cache of one' matrix data; */
  183.       /* save client transform, without the translation         */
  184.       font->currentTransform    = *transform;
  185.       font->currentTransform.tx =
  186.       font->currentTransform.ty = cf2_intToFixed( 0 );
  187.  
  188.       /* TODO: FreeType transform is simple scalar; for now, use identity */
  189.       /*       for outer                                                  */
  190.       font->innerTransform   = *transform;
  191.       font->outerTransform.a =
  192.       font->outerTransform.d = cf2_intToFixed( 1 );
  193.       font->outerTransform.b =
  194.       font->outerTransform.c = cf2_intToFixed( 0 );
  195.  
  196.       needExtraSetup = TRUE;
  197.     }
  198.  
  199.     /*
  200.      * font->darkened is set to true if there is a stem darkening request or
  201.      * the font is synthetic emboldened.
  202.      * font->darkened controls whether to adjust blue zones, winding order,
  203.      * and hinting.
  204.      *
  205.      */
  206.     if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) )
  207.     {
  208.       font->stemDarkened =
  209.         (FT_Bool)( font->renderingFlags & CF2_FlagsDarkened );
  210.  
  211.       /* blue zones depend on darkened flag */
  212.       needExtraSetup = TRUE;
  213.     }
  214.  
  215.     /* recompute variables that are dependent on transform or FontDict or */
  216.     /* darken flag                                                        */
  217.     if ( needExtraSetup )
  218.     {
  219.       /* StdVW is found in the private dictionary;                       */
  220.       /* recompute darkening amounts whenever private dictionary or      */
  221.       /* transform change                                                */
  222.       /* Note: a rendering flag turns darkening on or off, so we want to */
  223.       /*       store the `on' amounts;                                   */
  224.       /*       darkening amount is computed in character space           */
  225.       /* TODO: testing size-dependent darkening here;                    */
  226.       /*       what to do for rotations?                                 */
  227.  
  228.       CF2_Fixed  emRatio;
  229.       CF2_Fixed  stdHW;
  230.       CF2_Int    unitsPerEm = font->unitsPerEm;
  231.  
  232.  
  233.       if ( unitsPerEm == 0 )
  234.         unitsPerEm = 1000;
  235.  
  236.       ppem = FT_MAX( cf2_intToFixed( 4 ),
  237.                      font->ppem ); /* use minimum ppem of 4 */
  238.  
  239. #if 0
  240.       /* since vstem is measured in the x-direction, we use the `a' member */
  241.       /* of the fontMatrix                                                 */
  242.       emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a );
  243. #endif
  244.  
  245.       /* Freetype does not preserve the fontMatrix when parsing; use */
  246.       /* unitsPerEm instead.                                         */
  247.       /* TODO: check precision of this                               */
  248.       emRatio     = cf2_intToFixed( 1000 ) / unitsPerEm;
  249.       font->stdVW = cf2_getStdVW( decoder );
  250.  
  251.       if ( font->stdVW <= 0 )
  252.         font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
  253.  
  254.       if ( boldenX > 0 )
  255.       {
  256.         /* Ensure that boldenX is at least 1 pixel for synthetic bold font */
  257.         /* (similar to what Avalon does)                                   */
  258.         boldenX = FT_MAX( boldenX,
  259.                           FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) );
  260.  
  261.         /* Synthetic emboldening adds at least 1 pixel to darkenX, while */
  262.         /* stem darkening adds at most half pixel.  Since the purpose of */
  263.         /* stem darkening (readability at small sizes) is met with       */
  264.         /* synthetic emboldening, no need to add stem darkening for a    */
  265.         /* synthetic bold font.                                          */
  266.         cf2_computeDarkening( emRatio,
  267.                               ppem,
  268.                               font->stdVW,
  269.                               &font->darkenX,
  270.                               boldenX,
  271.                               FALSE );
  272.       }
  273.       else
  274.         cf2_computeDarkening( emRatio,
  275.                               ppem,
  276.                               font->stdVW,
  277.                               &font->darkenX,
  278.                               0,
  279.                               font->stemDarkened );
  280.  
  281. #if 0
  282.       /* since hstem is measured in the y-direction, we use the `d' member */
  283.       /* of the fontMatrix                                                 */
  284.       /* TODO: use the same units per em as above; check this              */
  285.       emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d );
  286. #endif
  287.  
  288.       /* set the default stem width, because it must be the same for all */
  289.       /* family members;                                                 */
  290.       /* choose a constant for StdHW that depends on font contrast       */
  291.       stdHW = cf2_getStdHW( decoder );
  292.  
  293.       if ( stdHW > 0 && font->stdVW > 2 * stdHW )
  294.         font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
  295.       else
  296.       {
  297.         /* low contrast font gets less hstem darkening */
  298.         font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio );
  299.       }
  300.  
  301.       cf2_computeDarkening( emRatio,
  302.                             ppem,
  303.                             font->stdHW,
  304.                             &font->darkenY,
  305.                             boldenY,
  306.                             font->stemDarkened );
  307.  
  308.       if ( font->darkenX != 0 || font->darkenY != 0 )
  309.         font->darkened = TRUE;
  310.       else
  311.         font->darkened = FALSE;
  312.  
  313.       font->reverseWinding = FALSE; /* initial expectation is CCW */
  314.  
  315.       /* compute blue zones for this instance */
  316.       cf2_blues_init( &font->blues, font );
  317.     }
  318.   }
  319.  
  320.  
  321.   /* equivalent to AdobeGetOutline */
  322.   FT_LOCAL_DEF( FT_Error )
  323.   cf2_getGlyphOutline( CF2_Font           font,
  324.                        CF2_Buffer         charstring,
  325.                        const CF2_Matrix*  transform,
  326.                        CF2_F16Dot16*      glyphWidth )
  327.   {
  328.     FT_Error  lastError = FT_Err_Ok;
  329.  
  330.     FT_Vector  translation;
  331.  
  332. #if 0
  333.     FT_Vector  advancePoint;
  334. #endif
  335.  
  336.     CF2_Fixed  advWidth = 0;
  337.     FT_Bool    needWinding;
  338.  
  339.  
  340.     /* Note: use both integer and fraction for outlines.  This allows bbox */
  341.     /*       to come out directly.                                         */
  342.  
  343.     translation.x = transform->tx;
  344.     translation.y = transform->ty;
  345.  
  346.     /* set up values based on transform */
  347.     cf2_font_setup( font, transform );
  348.     if ( font->error )
  349.       goto exit;                      /* setup encountered an error */
  350.  
  351.     /* reset darken direction */
  352.     font->reverseWinding = FALSE;
  353.  
  354.     /* winding order only affects darkening */
  355.     needWinding = font->darkened;
  356.  
  357.     while ( 1 )
  358.     {
  359.       /* reset output buffer */
  360.       cf2_outline_reset( &font->outline );
  361.  
  362.       /* build the outline, passing the full translation */
  363.       cf2_interpT2CharString( font,
  364.                               charstring,
  365.                               (CF2_OutlineCallbacks)&font->outline,
  366.                               &translation,
  367.                               FALSE,
  368.                               0,
  369.                               0,
  370.                               &advWidth );
  371.  
  372.       if ( font->error )
  373.         goto exit;
  374.  
  375.       if ( !needWinding )
  376.         break;
  377.  
  378.       /* check winding order */
  379.       if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */
  380.         break;
  381.  
  382.       /* invert darkening and render again                            */
  383.       /* TODO: this should be a parameter to getOutline-computeOffset */
  384.       font->reverseWinding = TRUE;
  385.  
  386.       needWinding = FALSE;    /* exit after next iteration */
  387.     }
  388.  
  389.     /* finish storing client outline */
  390.     cf2_outline_close( &font->outline );
  391.  
  392.   exit:
  393.     /* FreeType just wants the advance width; there is no translation */
  394.     *glyphWidth = advWidth;
  395.  
  396.     /* free resources and collect errors from objects we've used */
  397.     cf2_setError( &font->error, lastError );
  398.  
  399.     return font->error;
  400.   }
  401.  
  402.  
  403. /* END */
  404.