Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
cf2font.c
Go to the documentation of this file.
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 = FALSE;
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 = font->lastSubfont != cf2_getSubfont( decoder );
161 
162  /* if ppem has changed, we need to recompute some cached data */
163  /* note: because of CID font matrix concatenation, ppem and transform */
164  /* do not necessarily track. */
165  ppem = cf2_getPpemY( decoder );
166  if ( font->ppem != ppem )
167  {
168  font->ppem = ppem;
169  needExtraSetup = TRUE;
170  }
171 
172  /* copy hinted flag on each call */
173  font->hinted = font->renderingFlags & CF2_FlagsHinted;
174 
175  /* determine if transform has changed; */
176  /* include Fontmatrix but ignore translation */
177  if ( ft_memcmp( transform,
178  &font->currentTransform,
179  4 * sizeof ( CF2_Fixed ) ) != 0 )
180  {
181  /* save `key' information for `cache of one' matrix data; */
182  /* save client transform, without the translation */
183  font->currentTransform = *transform;
184  font->currentTransform.tx =
185  font->currentTransform.ty = cf2_intToFixed( 0 );
186 
187  /* TODO: FreeType transform is simple scalar; for now, use identity */
188  /* for outer */
189  font->innerTransform = *transform;
190  font->outerTransform.a =
191  font->outerTransform.d = cf2_intToFixed( 1 );
192  font->outerTransform.b =
193  font->outerTransform.c = cf2_intToFixed( 0 );
194 
195  needExtraSetup = TRUE;
196  }
197 
198  /*
199  * font->darkened is set to true if there is a stem darkening request or
200  * the font is synthetic emboldened.
201  * font->darkened controls whether to adjust blue zones, winding order,
202  * and hinting.
203  *
204  */
205  if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) )
206  {
208 
209  /* blue zones depend on darkened flag */
210  needExtraSetup = TRUE;
211  }
212 
213  /* recompute variables that are dependent on transform or FontDict or */
214  /* darken flag */
215  if ( needExtraSetup )
216  {
217  /* StdVW is found in the private dictionary; */
218  /* recompute darkening amounts whenever private dictionary or */
219  /* transform change */
220  /* Note: a rendering flag turns darkening on or off, so we want to */
221  /* store the `on' amounts; */
222  /* darkening amount is computed in character space */
223  /* TODO: testing size-dependent darkening here; */
224  /* what to do for rotations? */
225 
226  CF2_Fixed emRatio;
227  CF2_Fixed stdHW;
228  CF2_Int unitsPerEm = font->unitsPerEm;
229 
230 
231  if ( unitsPerEm == 0 )
232  unitsPerEm = 1000;
233 
234  ppem = FT_MAX( cf2_intToFixed( 4 ),
235  font->ppem ); /* use minimum ppem of 4 */
236 
237 #if 0
238  /* since vstem is measured in the x-direction, we use the `a' member */
239  /* of the fontMatrix */
240  emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a );
241 #endif
242 
243  /* Freetype does not preserve the fontMatrix when parsing; use */
244  /* unitsPerEm instead. */
245  /* TODO: check precision of this */
246  emRatio = cf2_intToFixed( 1000 ) / unitsPerEm;
247  font->stdVW = cf2_getStdVW( decoder );
248 
249  if ( font->stdVW <= 0 )
250  font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
251 
252  if ( boldenX > 0 )
253  {
254  /* Ensure that boldenX is at least 1 pixel for synthetic bold font */
255  /* (similar to what Avalon does) */
256  boldenX = FT_MAX( boldenX,
257  FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) );
258 
259  /* Synthetic emboldening adds at least 1 pixel to darkenX, while */
260  /* stem darkening adds at most half pixel. Since the purpose of */
261  /* stem darkening (readability at small sizes) is met with */
262  /* synthetic emboldening, no need to add stem darkening for a */
263  /* synthetic bold font. */
264  cf2_computeDarkening( emRatio,
265  ppem,
266  font->stdVW,
267  &font->darkenX,
268  boldenX,
269  FALSE );
270  }
271  else
272  cf2_computeDarkening( emRatio,
273  ppem,
274  font->stdVW,
275  &font->darkenX,
276  0,
277  font->stemDarkened );
278 
279 #if 0
280  /* since hstem is measured in the y-direction, we use the `d' member */
281  /* of the fontMatrix */
282  /* TODO: use the same units per em as above; check this */
283  emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d );
284 #endif
285 
286  /* set the default stem width, because it must be the same for all */
287  /* family members; */
288  /* choose a constant for StdHW that depends on font contrast */
289  stdHW = cf2_getStdHW( decoder );
290 
291  if ( stdHW > 0 && font->stdVW > 2 * stdHW )
292  font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
293  else
294  {
295  /* low contrast font gets less hstem darkening */
296  font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio );
297  }
298 
299  cf2_computeDarkening( emRatio,
300  ppem,
301  font->stdHW,
302  &font->darkenY,
303  boldenY,
304  font->stemDarkened );
305 
306  if ( font->darkenX != 0 || font->darkenY != 0 )
307  font->darkened = TRUE;
308  else
309  font->darkened = FALSE;
310 
311  font->reverseWinding = FALSE; /* initial expectation is CCW */
312 
313  /* compute blue zones for this instance */
314  cf2_blues_init( &font->blues, font );
315  }
316  }
317 
318 
319  /* equivalent to AdobeGetOutline */
322  CF2_Buffer charstring,
323  const CF2_Matrix* transform,
324  CF2_F16Dot16* glyphWidth )
325  {
326  FT_Error lastError = FT_Err_Ok;
327 
328  FT_Vector translation;
329 
330 #if 0
331  FT_Vector advancePoint;
332 #endif
333 
334  CF2_Fixed advWidth;
335  FT_Bool needWinding;
336 
337 
338  /* Note: use both integer and fraction for outlines. This allows bbox */
339  /* to come out directly. */
340 
341  translation.x = transform->tx;
342  translation.y = transform->ty;
343 
344  /* set up values based on transform */
345  cf2_font_setup( font, transform );
346  if ( font->error )
347  goto exit; /* setup encountered an error */
348 
349  /* reset darken direction */
350  font->reverseWinding = FALSE;
351 
352  /* winding order only affects darkening */
353  needWinding = font->darkened;
354 
355  while ( 1 )
356  {
357  /* reset output buffer */
358  cf2_outline_reset( &font->outline );
359 
360  /* build the outline, passing the full translation */
362  charstring,
363  (CF2_OutlineCallbacks)&font->outline,
364  &translation,
365  FALSE,
366  0,
367  0,
368  &advWidth );
369 
370  if ( font->error )
371  goto exit;
372 
373  if ( !needWinding )
374  break;
375 
376  /* check winding order */
377  if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */
378  break;
379 
380  /* invert darkening and render again */
381  /* TODO: this should be a parameter to getOutline-computeOffset */
382  font->reverseWinding = TRUE;
383 
384  needWinding = FALSE; /* exit after next iteration */
385  }
386 
387  /* finish storing client outline */
388  cf2_outline_close( &font->outline );
389 
390  /* FreeType just wants the advance width; there is no translation */
391  *glyphWidth = advWidth;
392 
393  /* free resources and collect errors from objects we've used */
394  exit:
395  cf2_setError( &font->error, lastError );
396 
397  return font->error;
398  }
399 
400 
401 /* END */
cf2_getStdVW(CFF_Decoder *decoder)
Definition: cf2ft.c:392
#define CF2_FlagsHinted
Definition: cf2glue.h:56
#define CF2_Int
Definition: cf2types.h:65
int FT_Error
Definition: fttypes.h:296
FT_Bool reverseWinding
Definition: cf2font.h:94
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:586
CF2_F16Dot16 d
Definition: cf2glue.h:81
CF2_F16Dot16 ty
Definition: cf2glue.h:83
CF2_F16Dot16 a
Definition: cf2glue.h:78
CF2_Fixed stdHW
Definition: cf2font.h:90
sizeof(AF_ModuleRec)
CFF_SubFont lastSubfont
Definition: cf2font.h:79
CF2_Fixed darkenY
Definition: cf2font.h:92
CF2_Fixed syntheticEmboldeningAmountY
Definition: cf2font.h:74
#define CF2_FIXED_ONE
Definition: cf2fixed.h:54
#define CF2_FlagsDarkened
Definition: cf2glue.h:58
cf2_blues_init(CF2_Blues blues, CF2_Font font)
Definition: cf2blues.c:66
cf2_interpT2CharString(CF2_Font font, CF2_Buffer buf, CF2_OutlineCallbacks callbacks, const FT_Vector *translation, FT_Bool doingSeac, CF2_Fixed curX, CF2_Fixed curY, CF2_Fixed *width)
Definition: cf2intrp.c:417
return FT_Err_Ok
Definition: ftbbox.c:645
CF2_Fixed syntheticEmboldeningAmountX
Definition: cf2font.h:73
FT_Bool stemDarkened
Definition: cf2font.h:86
CF2_Matrix outerTransform
Definition: cf2font.h:68
FT_Error error
Definition: cf2font.h:58
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
#define const
Definition: zconf.h:91
CF2_RenderingFlags renderingFlags
Definition: cf2font.h:60
CF2_Fixed ppem
Definition: cf2font.h:69
CF2_F16Dot16 b
Definition: cf2glue.h:79
FT_Bool hinted
Definition: cf2font.h:83
cf2_getGlyphWidth(CF2_Font font, CF2_Buffer charstring, const CF2_Matrix *transform, CF2_F16Dot16 *glyphWidth)
Definition: cf2font.c:321
CF2_Matrix innerTransform
Definition: cf2font.h:67
cf2_getSubfont(CFF_Decoder *decoder)
Definition: cf2ft.c:366
CF2_F16Dot16 c
Definition: cf2glue.h:80
FT_Pos x
Definition: ftimage.h:77
#define CF2_Fixed
Definition: cf2fixed.h:48
#define cf2_intToFixed(i)
Definition: cf2fixed.h:60
FT_Bool darkened
Definition: cf2font.h:84
FT_Pos y
Definition: ftimage.h:78
#define FT_MAX(a, b)
Definition: ftobjs.h:71
CF2_BluesRec blues
Definition: cf2font.h:97
cf2_outline_reset(CF2_Outline outline)
Definition: cf2ft.c:610
#define FALSE
Definition: ftobjs.h:57
FT_Int32 CF2_F16Dot16
Definition: cf2types.h:69
CFF_Decoder * decoder
Definition: cf2font.h:78
CF2_Matrix currentTransform
Definition: cf2font.h:66
CF2_F16Dot16 tx
Definition: cf2glue.h:82
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:485
#define ft_memcmp
Definition: ftstdlib.h:80
cf2_getPpemY(CFF_Decoder *decoder)
Definition: cf2ft.c:376
#define cf2_floatToFixed(f)
Definition: cf2fixed.h:66
cf2_outline_close(CF2_Outline outline)
Definition: cf2ft.c:624
GLuint GLenum GLenum transform
CF2_Int unitsPerEm
Definition: cf2font.h:71
cf2_getStdHW(CFF_Decoder *decoder)
Definition: cf2ft.c:402
CF2_Fixed stdVW
Definition: cf2font.h:89
#define TRUE
Definition: ftobjs.h:53
FT_BEGIN_HEADER struct CF2_BufferRec_ * CF2_Buffer
cf2_setError(FT_Error *error, FT_Error value)
Definition: cf2error.c:44
CF2_Fixed darkenX
Definition: cf2font.h:91
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:236