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