ReactOS  0.4.14-dev-606-g14ebc0b
pshints.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* pshints.c */
4 /* */
5 /* Adobe's code for handling CFF hints (body). */
6 /* */
7 /* Copyright 2007-2014 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 "psft.h"
40 #include FT_INTERNAL_DEBUG_H
41 
42 #include "psglue.h"
43 #include "psfont.h"
44 #include "pshints.h"
45 #include "psintrp.h"
46 
47 
48  /*************************************************************************/
49  /* */
50  /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
51  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
52  /* messages during execution. */
53  /* */
54 #undef FT_COMPONENT
55 #define FT_COMPONENT trace_cf2hints
56 
57 
58  typedef struct CF2_HintMoveRec_
59  {
60  size_t j; /* index of upper hint map edge */
61  CF2_Fixed moveUp; /* adjustment to optimum position */
62 
64 
65 
66  /* Compute angular momentum for winding order detection. It is called */
67  /* for all lines and curves, but not necessarily in element order. */
68  static CF2_Int
70  CF2_Fixed y1,
71  CF2_Fixed x2,
72  CF2_Fixed y2 )
73  {
74  /* cross product of pt1 position from origin with pt2 position from */
75  /* pt1; we reduce the precision so that the result fits into 32 bits */
76 
77  return ( x1 >> 16 ) * ( SUB_INT32( y2, y1 ) >> 16 ) -
78  ( y1 >> 16 ) * ( SUB_INT32( x2, x1 ) >> 16 );
79  }
80 
81 
82  /*
83  * Construct from a StemHint; this is used as a parameter to
84  * `cf2_blues_capture'.
85  * `hintOrigin' is the character space displacement of a seac accent.
86  * Adjust stem hint for darkening here.
87  *
88  */
89  static void
91  const CF2_ArrStack stemHintArray,
92  size_t indexStemHint,
93  const CF2_Font font,
94  CF2_Fixed hintOrigin,
96  FT_Bool bottom )
97  {
99  const CF2_StemHintRec* stemHint;
100 
101 
102  FT_ZERO( hint );
103 
104  stemHint = (const CF2_StemHintRec*)cf2_arrstack_getPointer(
105  stemHintArray,
106  indexStemHint );
107 
108  width = SUB_INT32( stemHint->max, stemHint->min );
109 
110  if ( width == cf2_intToFixed( -21 ) )
111  {
112  /* ghost bottom */
113 
114  if ( bottom )
115  {
116  hint->csCoord = stemHint->max;
117  hint->flags = CF2_GhostBottom;
118  }
119  else
120  hint->flags = 0;
121  }
122 
123  else if ( width == cf2_intToFixed( -20 ) )
124  {
125  /* ghost top */
126 
127  if ( bottom )
128  hint->flags = 0;
129  else
130  {
131  hint->csCoord = stemHint->min;
132  hint->flags = CF2_GhostTop;
133  }
134  }
135 
136  else if ( width < 0 )
137  {
138  /* inverted pair */
139 
140  /*
141  * Hints with negative widths were produced by an early version of a
142  * non-Adobe font tool. The Type 2 spec allows edge (ghost) hints
143  * with negative widths, but says
144  *
145  * All other negative widths have undefined meaning.
146  *
147  * CoolType has a silent workaround that negates the hint width; for
148  * permissive mode, we do the same here.
149  *
150  * Note: Such fonts cannot use ghost hints, but should otherwise work.
151  * Note: Some poor hints in our faux fonts can produce negative
152  * widths at some blends. For example, see a light weight of
153  * `u' in ASerifMM.
154  *
155  */
156  if ( bottom )
157  {
158  hint->csCoord = stemHint->max;
159  hint->flags = CF2_PairBottom;
160  }
161  else
162  {
163  hint->csCoord = stemHint->min;
164  hint->flags = CF2_PairTop;
165  }
166  }
167 
168  else
169  {
170  /* normal pair */
171 
172  if ( bottom )
173  {
174  hint->csCoord = stemHint->min;
175  hint->flags = CF2_PairBottom;
176  }
177  else
178  {
179  hint->csCoord = stemHint->max;
180  hint->flags = CF2_PairTop;
181  }
182  }
183 
184  /* Now that ghost hints have been detected, adjust this edge for */
185  /* darkening. Bottoms are not changed; tops are incremented by twice */
186  /* `darkenY'. */
187  if ( cf2_hint_isTop( hint ) )
188  hint->csCoord = ADD_INT32( hint->csCoord, 2 * font->darkenY );
189 
190  hint->csCoord = ADD_INT32( hint->csCoord, hintOrigin );
191  hint->scale = scale;
192  hint->index = indexStemHint; /* index in original stem hint array */
193 
194  /* if original stem hint has been used, use the same position */
195  if ( hint->flags != 0 && stemHint->used )
196  {
197  if ( cf2_hint_isTop( hint ) )
198  hint->dsCoord = stemHint->maxDS;
199  else
200  hint->dsCoord = stemHint->minDS;
201 
202  cf2_hint_lock( hint );
203  }
204  else
205  hint->dsCoord = FT_MulFix( hint->csCoord, scale );
206  }
207 
208 
209  /* initialize an invalid hint map element */
210  static void
212  {
213  FT_ZERO( hint );
214  }
215 
216 
219  {
220  return (FT_Bool)( hint->flags != 0 );
221  }
222 
223 
224  static FT_Bool
226  {
227  return (FT_Bool)( ( hint->flags &
228  ( CF2_PairBottom | CF2_PairTop ) ) != 0 );
229  }
230 
231 
232  static FT_Bool
234  {
235  return (FT_Bool)( ( hint->flags & CF2_PairTop ) != 0 );
236  }
237 
238 
241  {
242  return (FT_Bool)( ( hint->flags &
243  ( CF2_PairTop | CF2_GhostTop ) ) != 0 );
244  }
245 
246 
249  {
250  return (FT_Bool)( ( hint->flags &
251  ( CF2_PairBottom | CF2_GhostBottom ) ) != 0 );
252  }
253 
254 
255  static FT_Bool
257  {
258  return (FT_Bool)( ( hint->flags & CF2_Locked ) != 0 );
259  }
260 
261 
262  static FT_Bool
264  {
265  return (FT_Bool)( ( hint->flags & CF2_Synthetic ) != 0 );
266  }
267 
268 
269  FT_LOCAL_DEF( void )
271  {
272  hint->flags |= CF2_Locked;
273  }
274 
275 
276  FT_LOCAL_DEF( void )
278  CF2_Font font,
279  CF2_HintMap initialMap,
280  CF2_ArrStack hintMoves,
281  CF2_Fixed scale )
282  {
283  FT_ZERO( hintmap );
284 
285  /* copy parameters from font instance */
286  hintmap->hinted = font->hinted;
287  hintmap->scale = scale;
288  hintmap->font = font;
289  hintmap->initialHintMap = initialMap;
290  /* will clear in `cf2_hintmap_adjustHints' */
291  hintmap->hintMoves = hintMoves;
292  }
293 
294 
295  static FT_Bool
297  {
298  return hintmap->isValid;
299  }
300 
301 
302  static void
304  {
305 #ifdef FT_DEBUG_LEVEL_TRACE
306  CF2_UInt i;
307 
308 
309  FT_TRACE6(( " index csCoord dsCoord scale flags\n" ));
310 
311  for ( i = 0; i < hintmap->count; i++ )
312  {
313  CF2_Hint hint = &hintmap->edge[i];
314 
315 
316  FT_TRACE6(( " %3d %7.2f %7.2f %5d %s%s%s%s\n",
317  hint->index,
318  hint->csCoord / 65536.0,
319  hint->dsCoord / ( hint->scale * 1.0 ),
320  hint->scale,
321  ( cf2_hint_isPair( hint ) ? "p" : "g" ),
322  ( cf2_hint_isTop( hint ) ? "t" : "b" ),
323  ( cf2_hint_isLocked( hint ) ? "L" : ""),
324  ( cf2_hint_isSynthetic( hint ) ? "S" : "" ) ));
325  }
326 #else
327  FT_UNUSED( hintmap );
328 #endif
329  }
330 
331 
332  /* transform character space coordinate to device space using hint map */
333  static CF2_Fixed
335  CF2_Fixed csCoord )
336  {
337  if ( hintmap->count == 0 || ! hintmap->hinted )
338  {
339  /* there are no hints; use uniform scale and zero offset */
340  return FT_MulFix( csCoord, hintmap->scale );
341  }
342  else
343  {
344  /* start linear search from last hit */
345  CF2_UInt i = hintmap->lastIndex;
346 
347 
348  FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
349 
350  /* search up */
351  while ( i < hintmap->count - 1 &&
352  csCoord >= hintmap->edge[i + 1].csCoord )
353  i += 1;
354 
355  /* search down */
356  while ( i > 0 && csCoord < hintmap->edge[i].csCoord )
357  i -= 1;
358 
359  hintmap->lastIndex = i;
360 
361  if ( i == 0 && csCoord < hintmap->edge[0].csCoord )
362  {
363  /* special case for points below first edge: use uniform scale */
364  return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
365  hintmap->edge[0].csCoord ),
366  hintmap->scale ),
367  hintmap->edge[0].dsCoord );
368  }
369  else
370  {
371  /*
372  * Note: entries with duplicate csCoord are allowed.
373  * Use edge[i], the highest entry where csCoord >= entry[i].csCoord
374  */
375  return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
376  hintmap->edge[i].csCoord ),
377  hintmap->edge[i].scale ),
378  hintmap->edge[i].dsCoord );
379  }
380  }
381  }
382 
383 
384  /*
385  * This hinting policy moves a hint pair in device space so that one of
386  * its two edges is on a device pixel boundary (its fractional part is
387  * zero). `cf2_hintmap_insertHint' guarantees no overlap in CS
388  * space. Ensure here that there is no overlap in DS.
389  *
390  * In the first pass, edges are adjusted relative to adjacent hints.
391  * Those that are below have already been adjusted. Those that are
392  * above have not yet been adjusted. If a hint above blocks an
393  * adjustment to an optimal position, we will try again in a second
394  * pass. The second pass is top-down.
395  *
396  */
397 
398  static void
400  {
401  size_t i, j;
402 
403 
404  cf2_arrstack_clear( hintmap->hintMoves ); /* working storage */
405 
406  /*
407  * First pass is bottom-up (font hint order) without look-ahead.
408  * Locked edges are already adjusted.
409  * Unlocked edges begin with dsCoord from `initialHintMap'.
410  * Save edges that are not optimally adjusted in `hintMoves' array,
411  * and process them in second pass.
412  */
413 
414  for ( i = 0; i < hintmap->count; i++ )
415  {
416  FT_Bool isPair = cf2_hint_isPair( &hintmap->edge[i] );
417 
418 
419  /* index of upper edge (same value for ghost hint) */
420  j = isPair ? i + 1 : i;
421 
422  FT_ASSERT( j < hintmap->count );
423  FT_ASSERT( cf2_hint_isValid( &hintmap->edge[i] ) );
424  FT_ASSERT( cf2_hint_isValid( &hintmap->edge[j] ) );
425  FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) ==
426  cf2_hint_isLocked( &hintmap->edge[j] ) );
427 
428  if ( !cf2_hint_isLocked( &hintmap->edge[i] ) )
429  {
430  /* hint edge is not locked, we can adjust it */
431  CF2_Fixed fracDown = cf2_fixedFraction( hintmap->edge[i].dsCoord );
432  CF2_Fixed fracUp = cf2_fixedFraction( hintmap->edge[j].dsCoord );
433 
434  /* calculate all four possibilities; moves down are negative */
435  CF2_Fixed downMoveDown = 0 - fracDown;
436  CF2_Fixed upMoveDown = 0 - fracUp;
437  CF2_Fixed downMoveUp = ( fracDown == 0 )
438  ? 0
439  : cf2_intToFixed( 1 ) - fracDown;
440  CF2_Fixed upMoveUp = ( fracUp == 0 )
441  ? 0
442  : cf2_intToFixed( 1 ) - fracUp;
443 
444  /* smallest move up */
445  CF2_Fixed moveUp = FT_MIN( downMoveUp, upMoveUp );
446  /* smallest move down */
447  CF2_Fixed moveDown = FT_MAX( downMoveDown, upMoveDown );
448 
449  /* final amount to move edge or edge pair */
450  CF2_Fixed move;
451 
452  CF2_Fixed downMinCounter = CF2_MIN_COUNTER;
453  CF2_Fixed upMinCounter = CF2_MIN_COUNTER;
454  FT_Bool saveEdge = FALSE;
455 
456 
457  /* minimum counter constraint doesn't apply when adjacent edges */
458  /* are synthetic */
459  /* TODO: doesn't seem a big effect; for now, reduce the code */
460 #if 0
461  if ( i == 0 ||
462  cf2_hint_isSynthetic( &hintmap->edge[i - 1] ) )
463  downMinCounter = 0;
464 
465  if ( j >= hintmap->count - 1 ||
466  cf2_hint_isSynthetic( &hintmap->edge[j + 1] ) )
467  upMinCounter = 0;
468 #endif
469 
470  /* is there room to move up? */
471  /* there is if we are at top of array or the next edge is at or */
472  /* beyond proposed move up? */
473  if ( j >= hintmap->count - 1 ||
474  hintmap->edge[j + 1].dsCoord >=
475  ADD_INT32( hintmap->edge[j].dsCoord,
476  moveUp + upMinCounter ) )
477  {
478  /* there is room to move up; is there also room to move down? */
479  if ( i == 0 ||
480  hintmap->edge[i - 1].dsCoord <=
481  ADD_INT32( hintmap->edge[i].dsCoord,
482  moveDown - downMinCounter ) )
483  {
484  /* move smaller absolute amount */
485  move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */
486  }
487  else
488  move = moveUp;
489  }
490  else
491  {
492  /* is there room to move down? */
493  if ( i == 0 ||
494  hintmap->edge[i - 1].dsCoord <=
495  ADD_INT32( hintmap->edge[i].dsCoord,
496  moveDown - downMinCounter ) )
497  {
498  move = moveDown;
499  /* true if non-optimum move */
500  saveEdge = (FT_Bool)( moveUp < -moveDown );
501  }
502  else
503  {
504  /* no room to move either way without overlapping or reducing */
505  /* the counter too much */
506  move = 0;
507  saveEdge = TRUE;
508  }
509  }
510 
511  /* Identify non-moves and moves down that aren't optimal, and save */
512  /* them for second pass. */
513  /* Do this only if there is an unlocked edge above (which could */
514  /* possibly move). */
515  if ( saveEdge &&
516  j < hintmap->count - 1 &&
517  !cf2_hint_isLocked( &hintmap->edge[j + 1] ) )
518  {
519  CF2_HintMoveRec savedMove;
520 
521 
522  savedMove.j = j;
523  /* desired adjustment in second pass */
524  savedMove.moveUp = moveUp - move;
525 
526  cf2_arrstack_push( hintmap->hintMoves, &savedMove );
527  }
528 
529  /* move the edge(s) */
530  hintmap->edge[i].dsCoord = ADD_INT32( hintmap->edge[i].dsCoord,
531  move );
532  if ( isPair )
533  hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
534  move );
535  }
536 
537  /* assert there are no overlaps in device space */
538  FT_ASSERT( i == 0 ||
539  hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord );
540  FT_ASSERT( i < j ||
541  hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord );
542 
543  /* adjust the scales, avoiding divide by zero */
544  if ( i > 0 )
545  {
546  if ( hintmap->edge[i].csCoord != hintmap->edge[i - 1].csCoord )
547  hintmap->edge[i - 1].scale =
548  FT_DivFix( SUB_INT32( hintmap->edge[i].dsCoord,
549  hintmap->edge[i - 1].dsCoord ),
550  SUB_INT32( hintmap->edge[i].csCoord,
551  hintmap->edge[i - 1].csCoord ) );
552  }
553 
554  if ( isPair )
555  {
556  if ( hintmap->edge[j].csCoord != hintmap->edge[j - 1].csCoord )
557  hintmap->edge[j - 1].scale =
558  FT_DivFix( SUB_INT32( hintmap->edge[j].dsCoord,
559  hintmap->edge[j - 1].dsCoord ),
560  SUB_INT32( hintmap->edge[j].csCoord,
561  hintmap->edge[j - 1].csCoord ) );
562 
563  i += 1; /* skip upper edge on next loop */
564  }
565  }
566 
567  /* second pass tries to move non-optimal hints up, in case there is */
568  /* room now */
569  for ( i = cf2_arrstack_size( hintmap->hintMoves ); i > 0; i-- )
570  {
571  CF2_HintMove hintMove = (CF2_HintMove)
572  cf2_arrstack_getPointer( hintmap->hintMoves, i - 1 );
573 
574 
575  j = hintMove->j;
576 
577  /* this was tested before the push, above */
578  FT_ASSERT( j < hintmap->count - 1 );
579 
580  /* is there room to move up? */
581  if ( hintmap->edge[j + 1].dsCoord >=
582  ADD_INT32( hintmap->edge[j].dsCoord,
583  hintMove->moveUp + CF2_MIN_COUNTER ) )
584  {
585  /* there is more room now, move edge up */
586  hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
587  hintMove->moveUp );
588 
589  if ( cf2_hint_isPair( &hintmap->edge[j] ) )
590  {
591  FT_ASSERT( j > 0 );
592  hintmap->edge[j - 1].dsCoord =
593  ADD_INT32( hintmap->edge[j - 1].dsCoord, hintMove->moveUp );
594  }
595  }
596  }
597  }
598 
599 
600  /* insert hint edges into map, sorted by csCoord */
601  static void
603  CF2_Hint bottomHintEdge,
604  CF2_Hint topHintEdge )
605  {
606  CF2_UInt indexInsert;
607 
608  /* set default values, then check for edge hints */
609  FT_Bool isPair = TRUE;
610  CF2_Hint firstHintEdge = bottomHintEdge;
611  CF2_Hint secondHintEdge = topHintEdge;
612 
613 
614  /* one or none of the input params may be invalid when dealing with */
615  /* edge hints; at least one edge must be valid */
616  FT_ASSERT( cf2_hint_isValid( bottomHintEdge ) ||
617  cf2_hint_isValid( topHintEdge ) );
618 
619  /* determine how many and which edges to insert */
620  if ( !cf2_hint_isValid( bottomHintEdge ) )
621  {
622  /* insert only the top edge */
623  firstHintEdge = topHintEdge;
624  isPair = FALSE;
625  }
626  else if ( !cf2_hint_isValid( topHintEdge ) )
627  {
628  /* insert only the bottom edge */
629  isPair = FALSE;
630  }
631 
632  /* paired edges must be in proper order */
633  if ( isPair &&
634  topHintEdge->csCoord < bottomHintEdge->csCoord )
635  return;
636 
637  /* linear search to find index value of insertion point */
638  indexInsert = 0;
639  for ( ; indexInsert < hintmap->count; indexInsert++ )
640  {
641  if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord )
642  break;
643  }
644 
645  FT_TRACE7(( " Got hint at %.2f (%.2f)\n",
646  firstHintEdge->csCoord / 65536.0,
647  firstHintEdge->dsCoord / 65536.0 ));
648  if ( isPair )
649  FT_TRACE7(( " Got hint at %.2f (%.2f)\n",
650  secondHintEdge->csCoord / 65536.0,
651  secondHintEdge->dsCoord / 65536.0 ));
652 
653  /*
654  * Discard any hints that overlap in character space. Most often, this
655  * is while building the initial map, where captured hints from all
656  * zones are combined. Define overlap to include hints that `touch'
657  * (overlap zero). Hiragino Sans/Gothic fonts have numerous hints that
658  * touch. Some fonts have non-ideographic glyphs that overlap our
659  * synthetic hints.
660  *
661  * Overlap also occurs when darkening stem hints that are close.
662  *
663  */
664  if ( indexInsert < hintmap->count )
665  {
666  /* we are inserting before an existing edge: */
667  /* verify that an existing edge is not the same */
668  if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord )
669  return; /* ignore overlapping stem hint */
670 
671  /* verify that a new pair does not straddle the next edge */
672  if ( isPair &&
673  hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord )
674  return; /* ignore overlapping stem hint */
675 
676  /* verify that we are not inserting between paired edges */
677  if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) )
678  return; /* ignore overlapping stem hint */
679  }
680 
681  /* recompute device space locations using initial hint map */
682  if ( cf2_hintmap_isValid( hintmap->initialHintMap ) &&
683  !cf2_hint_isLocked( firstHintEdge ) )
684  {
685  if ( isPair )
686  {
687  /* Use hint map to position the center of stem, and nominal scale */
688  /* to position the two edges. This preserves the stem width. */
689  CF2_Fixed midpoint =
691  hintmap->initialHintMap,
692  ADD_INT32( secondHintEdge->csCoord,
693  firstHintEdge->csCoord ) / 2 );
694  CF2_Fixed halfWidth =
695  FT_MulFix( SUB_INT32( secondHintEdge->csCoord,
696  firstHintEdge->csCoord ) / 2,
697  hintmap->scale );
698 
699 
700  firstHintEdge->dsCoord = SUB_INT32( midpoint, halfWidth );
701  secondHintEdge->dsCoord = ADD_INT32( midpoint, halfWidth );
702  }
703  else
704  firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap,
705  firstHintEdge->csCoord );
706  }
707 
708  /*
709  * Discard any hints that overlap in device space; this can occur
710  * because locked hints have been moved to align with blue zones.
711  *
712  * TODO: Although we might correct this later during adjustment, we
713  * don't currently have a way to delete a conflicting hint once it has
714  * been inserted. See v2.030 MinionPro-Regular, 12 ppem darkened,
715  * initial hint map for second path, glyph 945 (the perispomeni (tilde)
716  * in U+1F6E, Greek omega with psili and perispomeni). Darkening is
717  * 25. Pair 667,747 initially conflicts in design space with top edge
718  * 660. This is because 667 maps to 7.87, and the top edge was
719  * captured by a zone at 8.0. The pair is later successfully inserted
720  * in a zone without the top edge. In this zone it is adjusted to 8.0,
721  * and no longer conflicts with the top edge in design space. This
722  * means it can be included in yet a later zone which does have the top
723  * edge hint. This produces a small mismatch between the first and
724  * last points of this path, even though the hint masks are the same.
725  * The density map difference is tiny (1/256).
726  *
727  */
728 
729  if ( indexInsert > 0 )
730  {
731  /* we are inserting after an existing edge */
732  if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord )
733  return;
734  }
735 
736  if ( indexInsert < hintmap->count )
737  {
738  /* we are inserting before an existing edge */
739  if ( isPair )
740  {
741  if ( secondHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
742  return;
743  }
744  else
745  {
746  if ( firstHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
747  return;
748  }
749  }
750 
751  /* make room to insert */
752  {
753  CF2_UInt iSrc = hintmap->count - 1;
754  CF2_UInt iDst = isPair ? hintmap->count + 1 : hintmap->count;
755 
756  CF2_UInt count = hintmap->count - indexInsert;
757 
758 
759  if ( iDst >= CF2_MAX_HINT_EDGES )
760  {
761  FT_TRACE4(( "cf2_hintmap_insertHint: too many hintmaps\n" ));
762  return;
763  }
764 
765  while ( count-- )
766  hintmap->edge[iDst--] = hintmap->edge[iSrc--];
767 
768  /* insert first edge */
769  hintmap->edge[indexInsert] = *firstHintEdge; /* copy struct */
770  hintmap->count += 1;
771 
772  FT_TRACE7(( " Inserting hint %.2f (%.2f)\n",
773  firstHintEdge->csCoord / 65536.0,
774  firstHintEdge->dsCoord / 65536.0 ));
775 
776  if ( isPair )
777  {
778  /* insert second edge */
779  hintmap->edge[indexInsert + 1] = *secondHintEdge; /* copy struct */
780  hintmap->count += 1;
781 
782  FT_TRACE7(( " Inserting hint %.2f (%.2f)\n",
783  secondHintEdge->csCoord / 65536.0,
784  secondHintEdge->dsCoord / 65536.0 ));
785 
786  }
787  }
788 
789  return;
790  }
791 
792 
793  /*
794  * Build a map from hints and mask.
795  *
796  * This function may recur one level if `hintmap->initialHintMap' is not yet
797  * valid.
798  * If `initialMap' is true, simply build initial map.
799  *
800  * Synthetic hints are used in two ways. A hint at zero is inserted, if
801  * needed, in the initial hint map, to prevent translations from
802  * propagating across the origin. If synthetic em box hints are enabled
803  * for ideographic dictionaries, then they are inserted in all hint
804  * maps, including the initial one.
805  *
806  */
807  FT_LOCAL_DEF( void )
809  CF2_ArrStack hStemHintArray,
810  CF2_ArrStack vStemHintArray,
811  CF2_HintMask hintMask,
812  CF2_Fixed hintOrigin,
813  FT_Bool initialMap )
814  {
815  FT_Byte* maskPtr;
816 
817  CF2_Font font = hintmap->font;
818  CF2_HintMaskRec tempHintMask;
819 
820  size_t bitCount, i;
821  FT_Byte maskByte;
822 
823 
824  /* check whether initial map is constructed */
825  if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) )
826  {
827  /* make recursive call with initialHintMap and temporary mask; */
828  /* temporary mask will get all bits set, below */
829  cf2_hintmask_init( &tempHintMask, hintMask->error );
830  cf2_hintmap_build( hintmap->initialHintMap,
831  hStemHintArray,
832  vStemHintArray,
833  &tempHintMask,
834  hintOrigin,
835  TRUE );
836  }
837 
838  if ( !cf2_hintmask_isValid( hintMask ) )
839  {
840  /* without a hint mask, assume all hints are active */
841  cf2_hintmask_setAll( hintMask,
842  cf2_arrstack_size( hStemHintArray ) +
843  cf2_arrstack_size( vStemHintArray ) );
844  if ( !cf2_hintmask_isValid( hintMask ) )
845  {
846  if ( font->isT1 )
847  {
848  /* no error, just continue unhinted */
849  *hintMask->error = FT_Err_Ok;
850  hintmap->hinted = FALSE;
851  }
852  return; /* too many stem hints */
853  }
854  }
855 
856  /* begin by clearing the map */
857  hintmap->count = 0;
858  hintmap->lastIndex = 0;
859 
860  /* make a copy of the hint mask so we can modify it */
861  tempHintMask = *hintMask;
862  maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
863 
864  /* use the hStem hints only, which are first in the mask */
865  bitCount = cf2_arrstack_size( hStemHintArray );
866 
867  /* Defense-in-depth. Should never return here. */
868  if ( bitCount > hintMask->bitCount )
869  return;
870 
871  /* synthetic embox hints get highest priority */
872  if ( font->blues.doEmBoxHints )
873  {
875 
876 
877  cf2_hint_initZero( &dummy ); /* invalid hint map element */
878 
879  /* ghost bottom */
880  cf2_hintmap_insertHint( hintmap,
881  &font->blues.emBoxBottomEdge,
882  &dummy );
883  /* ghost top */
884  cf2_hintmap_insertHint( hintmap,
885  &dummy,
886  &font->blues.emBoxTopEdge );
887  }
888 
889  /* insert hints captured by a blue zone or already locked (higher */
890  /* priority) */
891  for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
892  {
893  if ( maskByte & *maskPtr )
894  {
895  /* expand StemHint into two `CF2_Hint' elements */
896  CF2_HintRec bottomHintEdge, topHintEdge;
897 
898 
899  cf2_hint_init( &bottomHintEdge,
900  hStemHintArray,
901  i,
902  font,
903  hintOrigin,
904  hintmap->scale,
905  TRUE /* bottom */ );
906  cf2_hint_init( &topHintEdge,
907  hStemHintArray,
908  i,
909  font,
910  hintOrigin,
911  hintmap->scale,
912  FALSE /* top */ );
913 
914  if ( cf2_hint_isLocked( &bottomHintEdge ) ||
915  cf2_hint_isLocked( &topHintEdge ) ||
916  cf2_blues_capture( &font->blues,
917  &bottomHintEdge,
918  &topHintEdge ) )
919  {
920  /* insert captured hint into map */
921  cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
922 
923  *maskPtr &= ~maskByte; /* turn off the bit for this hint */
924  }
925  }
926 
927  if ( ( i & 7 ) == 7 )
928  {
929  /* move to next mask byte */
930  maskPtr++;
931  maskByte = 0x80;
932  }
933  else
934  maskByte >>= 1;
935  }
936 
937  /* initial hint map includes only captured hints plus maybe one at 0 */
938 
939  /*
940  * TODO: There is a problem here because we are trying to build a
941  * single hint map containing all captured hints. It is
942  * possible for there to be conflicts between captured hints,
943  * either because of darkening or because the hints are in
944  * separate hint zones (we are ignoring hint zones for the
945  * initial map). An example of the latter is MinionPro-Regular
946  * v2.030 glyph 883 (Greek Capital Alpha with Psili) at 15ppem.
947  * A stem hint for the psili conflicts with the top edge hint
948  * for the base character. The stem hint gets priority because
949  * of its sort order. In glyph 884 (Greek Capital Alpha with
950  * Psili and Oxia), the top of the base character gets a stem
951  * hint, and the psili does not. This creates different initial
952  * maps for the two glyphs resulting in different renderings of
953  * the base character. Will probably defer this either as not
954  * worth the cost or as a font bug. I don't think there is any
955  * good reason for an accent to be captured by an alignment
956  * zone. -darnold 2/12/10
957  */
958 
959  if ( initialMap )
960  {
961  /* Apply a heuristic that inserts a point for (0,0), unless it's */
962  /* already covered by a mapping. This locks the baseline for glyphs */
963  /* that have no baseline hints. */
964 
965  if ( hintmap->count == 0 ||
966  hintmap->edge[0].csCoord > 0 ||
967  hintmap->edge[hintmap->count - 1].csCoord < 0 )
968  {
969  /* all edges are above 0 or all edges are below 0; */
970  /* construct a locked edge hint at 0 */
971 
972  CF2_HintRec edge, invalid;
973 
974 
975  cf2_hint_initZero( &edge );
976 
977  edge.flags = CF2_GhostBottom |
978  CF2_Locked |
980  edge.scale = hintmap->scale;
981 
983  cf2_hintmap_insertHint( hintmap, &edge, &invalid );
984  }
985  }
986  else
987  {
988  /* insert remaining hints */
989 
990  maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
991 
992  for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
993  {
994  if ( maskByte & *maskPtr )
995  {
996  CF2_HintRec bottomHintEdge, topHintEdge;
997 
998 
999  cf2_hint_init( &bottomHintEdge,
1000  hStemHintArray,
1001  i,
1002  font,
1003  hintOrigin,
1004  hintmap->scale,
1005  TRUE /* bottom */ );
1006  cf2_hint_init( &topHintEdge,
1007  hStemHintArray,
1008  i,
1009  font,
1010  hintOrigin,
1011  hintmap->scale,
1012  FALSE /* top */ );
1013 
1014  cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
1015  }
1016 
1017  if ( ( i & 7 ) == 7 )
1018  {
1019  /* move to next mask byte */
1020  maskPtr++;
1021  maskByte = 0x80;
1022  }
1023  else
1024  maskByte >>= 1;
1025  }
1026  }
1027 
1028  FT_TRACE6(( initialMap ? "flags: [p]air [g]host [t]op "
1029  "[b]ottom [L]ocked [S]ynthetic\n"
1030  "Initial hintmap\n"
1031  : "Hints:\n" ));
1032  cf2_hintmap_dump( hintmap );
1033 
1034  /*
1035  * Note: The following line is a convenient place to break when
1036  * debugging hinting. Examine `hintmap->edge' for the list of
1037  * enabled hints, then step over the call to see the effect of
1038  * adjustment. We stop here first on the recursive call that
1039  * creates the initial map, and then on each counter group and
1040  * hint zone.
1041  */
1042 
1043  /* adjust positions of hint edges that are not locked to blue zones */
1044  cf2_hintmap_adjustHints( hintmap );
1045 
1046  FT_TRACE6(( "(adjusted)\n" ));
1047  cf2_hintmap_dump( hintmap );
1048 
1049  /* save the position of all hints that were used in this hint map; */
1050  /* if we use them again, we'll locate them in the same position */
1051  if ( !initialMap )
1052  {
1053  for ( i = 0; i < hintmap->count; i++ )
1054  {
1055  if ( !cf2_hint_isSynthetic( &hintmap->edge[i] ) )
1056  {
1057  /* Note: include both valid and invalid edges */
1058  /* Note: top and bottom edges are copied back separately */
1059  CF2_StemHint stemhint = (CF2_StemHint)
1060  cf2_arrstack_getPointer( hStemHintArray,
1061  hintmap->edge[i].index );
1062 
1063 
1064  if ( cf2_hint_isTop( &hintmap->edge[i] ) )
1065  stemhint->maxDS = hintmap->edge[i].dsCoord;
1066  else
1067  stemhint->minDS = hintmap->edge[i].dsCoord;
1068 
1069  stemhint->used = TRUE;
1070  }
1071  }
1072  }
1073 
1074  /* hint map is ready to use */
1075  hintmap->isValid = TRUE;
1076 
1077  /* remember this mask has been used */
1078  cf2_hintmask_setNew( hintMask, FALSE );
1079  }
1080 
1081 
1082  FT_LOCAL_DEF( void )
1084  CF2_Font font,
1086  CF2_Fixed scaleY,
1087  /* CF2_Fixed hShift, */
1088  CF2_ArrStack hStemHintArray,
1089  CF2_ArrStack vStemHintArray,
1090  CF2_HintMask hintMask,
1091  CF2_Fixed hintOriginY,
1092  const CF2_Blues blues,
1093  const FT_Vector* fractionalTranslation )
1094  {
1095  FT_ZERO( glyphpath );
1096 
1097  glyphpath->font = font;
1098  glyphpath->callbacks = callbacks;
1099 
1100  cf2_arrstack_init( &glyphpath->hintMoves,
1101  font->memory,
1102  &font->error,
1103  sizeof ( CF2_HintMoveRec ) );
1104 
1105  cf2_hintmap_init( &glyphpath->initialHintMap,
1106  font,
1107  &glyphpath->initialHintMap,
1108  &glyphpath->hintMoves,
1109  scaleY );
1110  cf2_hintmap_init( &glyphpath->firstHintMap,
1111  font,
1112  &glyphpath->initialHintMap,
1113  &glyphpath->hintMoves,
1114  scaleY );
1115  cf2_hintmap_init( &glyphpath->hintMap,
1116  font,
1117  &glyphpath->initialHintMap,
1118  &glyphpath->hintMoves,
1119  scaleY );
1120 
1121  glyphpath->scaleX = font->innerTransform.a;
1122  glyphpath->scaleC = font->innerTransform.c;
1123  glyphpath->scaleY = font->innerTransform.d;
1124 
1125  glyphpath->fractionalTranslation = *fractionalTranslation;
1126 
1127 #if 0
1128  glyphpath->hShift = hShift; /* for fauxing */
1129 #endif
1130 
1131  glyphpath->hStemHintArray = hStemHintArray;
1132  glyphpath->vStemHintArray = vStemHintArray;
1133  glyphpath->hintMask = hintMask; /* ptr to current mask */
1134  glyphpath->hintOriginY = hintOriginY;
1135  glyphpath->blues = blues;
1136  glyphpath->darken = font->darkened; /* TODO: should we make copies? */
1137  glyphpath->xOffset = font->darkenX;
1138  glyphpath->yOffset = font->darkenY;
1139  glyphpath->miterLimit = 2 * FT_MAX(
1140  cf2_fixedAbs( glyphpath->xOffset ),
1141  cf2_fixedAbs( glyphpath->yOffset ) );
1142 
1143  /* .1 character space unit */
1144  glyphpath->snapThreshold = cf2_doubleToFixed( 0.1 );
1145 
1146  glyphpath->moveIsPending = TRUE;
1147  glyphpath->pathIsOpen = FALSE;
1148  glyphpath->pathIsClosing = FALSE;
1149  glyphpath->elemIsQueued = FALSE;
1150  }
1151 
1152 
1153  FT_LOCAL_DEF( void )
1155  {
1156  cf2_arrstack_finalize( &glyphpath->hintMoves );
1157  }
1158 
1159 
1160  /*
1161  * Hint point in y-direction and apply outerTransform.
1162  * Input `current' hint map (which is actually delayed by one element).
1163  * Input x,y point in Character Space.
1164  * Output x,y point in Device Space, including translation.
1165  */
1166  static void
1168  CF2_HintMap hintmap,
1169  FT_Vector* ppt,
1170  CF2_Fixed x,
1171  CF2_Fixed y )
1172  {
1173  FT_Vector pt; /* hinted point in upright DS */
1174 
1175 
1176  pt.x = ADD_INT32( FT_MulFix( glyphpath->scaleX, x ),
1177  FT_MulFix( glyphpath->scaleC, y ) );
1178  pt.y = cf2_hintmap_map( hintmap, y );
1179 
1180  ppt->x = ADD_INT32(
1181  FT_MulFix( glyphpath->font->outerTransform.a, pt.x ),
1182  ADD_INT32(
1183  FT_MulFix( glyphpath->font->outerTransform.c, pt.y ),
1184  glyphpath->fractionalTranslation.x ) );
1185  ppt->y = ADD_INT32(
1186  FT_MulFix( glyphpath->font->outerTransform.b, pt.x ),
1187  ADD_INT32(
1188  FT_MulFix( glyphpath->font->outerTransform.d, pt.y ),
1189  glyphpath->fractionalTranslation.y ) );
1190  }
1191 
1192 
1193  /*
1194  * From two line segments, (u1,u2) and (v1,v2), compute a point of
1195  * intersection on the corresponding lines.
1196  * Return false if no intersection is found, or if the intersection is
1197  * too far away from the ends of the line segments, u2 and v1.
1198  *
1199  */
1200  static FT_Bool
1202  const FT_Vector* u1,
1203  const FT_Vector* u2,
1204  const FT_Vector* v1,
1205  const FT_Vector* v2,
1206  FT_Vector* intersection )
1207  {
1208  /*
1209  * Let `u' be a zero-based vector from the first segment, `v' from the
1210  * second segment.
1211  * Let `w 'be the zero-based vector from `u1' to `v1'.
1212  * `perp' is the `perpendicular dot product'; see
1213  * https://mathworld.wolfram.com/PerpDotProduct.html.
1214  * `s' is the parameter for the parametric line for the first segment
1215  * (`u').
1216  *
1217  * See notation in
1218  * http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm.
1219  * Calculations are done in 16.16, but must handle the squaring of
1220  * line lengths in character space. We scale all vectors by 1/32 to
1221  * avoid overflow. This allows values up to 4095 to be squared. The
1222  * scale factor cancels in the divide.
1223  *
1224  * TODO: the scale factor could be computed from UnitsPerEm.
1225  *
1226  */
1227 
1228 #define cf2_perp( a, b ) \
1229  ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) )
1230 
1231  /* round and divide by 32 */
1232 #define CF2_CS_SCALE( x ) \
1233  ( ( (x) + 0x10 ) >> 5 )
1234 
1235  FT_Vector u, v, w; /* scaled vectors */
1236  CF2_Fixed denominator, s;
1237 
1238 
1239  u.x = CF2_CS_SCALE( SUB_INT32( u2->x, u1->x ) );
1240  u.y = CF2_CS_SCALE( SUB_INT32( u2->y, u1->y ) );
1241  v.x = CF2_CS_SCALE( SUB_INT32( v2->x, v1->x ) );
1242  v.y = CF2_CS_SCALE( SUB_INT32( v2->y, v1->y ) );
1243  w.x = CF2_CS_SCALE( SUB_INT32( v1->x, u1->x ) );
1244  w.y = CF2_CS_SCALE( SUB_INT32( v1->y, u1->y ) );
1245 
1246  denominator = cf2_perp( u, v );
1247 
1248  if ( denominator == 0 )
1249  return FALSE; /* parallel or coincident lines */
1250 
1251  s = FT_DivFix( cf2_perp( w, v ), denominator );
1252 
1253  intersection->x = ADD_INT32( u1->x,
1254  FT_MulFix( s, SUB_INT32( u2->x, u1->x ) ) );
1255  intersection->y = ADD_INT32( u1->y,
1256  FT_MulFix( s, SUB_INT32( u2->y, u1->y ) ) );
1257 
1258 
1259  /*
1260  * Special case snapping for horizontal and vertical lines.
1261  * This cleans up intersections and reduces problems with winding
1262  * order detection.
1263  * Sample case is sbc cd KozGoPr6N-Medium.otf 20 16685.
1264  * Note: these calculations are in character space.
1265  *
1266  */
1267 
1268  if ( u1->x == u2->x &&
1269  cf2_fixedAbs( SUB_INT32( intersection->x,
1270  u1->x ) ) < glyphpath->snapThreshold )
1271  intersection->x = u1->x;
1272  if ( u1->y == u2->y &&
1273  cf2_fixedAbs( SUB_INT32( intersection->y,
1274  u1->y ) ) < glyphpath->snapThreshold )
1275  intersection->y = u1->y;
1276 
1277  if ( v1->x == v2->x &&
1278  cf2_fixedAbs( SUB_INT32( intersection->x,
1279  v1->x ) ) < glyphpath->snapThreshold )
1280  intersection->x = v1->x;
1281  if ( v1->y == v2->y &&
1282  cf2_fixedAbs( SUB_INT32( intersection->y,
1283  v1->y ) ) < glyphpath->snapThreshold )
1284  intersection->y = v1->y;
1285 
1286  /* limit the intersection distance from midpoint of u2 and v1 */
1287  if ( cf2_fixedAbs( intersection->x - ADD_INT32( u2->x, v1->x ) / 2 ) >
1288  glyphpath->miterLimit ||
1289  cf2_fixedAbs( intersection->y - ADD_INT32( u2->y, v1->y ) / 2 ) >
1290  glyphpath->miterLimit )
1291  return FALSE;
1292 
1293  return TRUE;
1294  }
1295 
1296 
1297  /*
1298  * Push the cached element (glyphpath->prevElem*) to the outline
1299  * consumer. When a darkening offset is used, the end point of the
1300  * cached element may be adjusted to an intersection point or we may
1301  * synthesize a connecting line to the current element. If we are
1302  * closing a subpath, we may also generate a connecting line to the start
1303  * point.
1304  *
1305  * This is where Character Space (CS) is converted to Device Space (DS)
1306  * using a hint map. This calculation must use a HintMap that was valid
1307  * at the time the element was saved. For the first point in a subpath,
1308  * that is a saved HintMap. For most elements, it just means the caller
1309  * has delayed building a HintMap from the current HintMask.
1310  *
1311  * Transform each point with outerTransform and call the outline
1312  * callbacks. This is a general 3x3 transform:
1313  *
1314  * x' = a*x + c*y + tx, y' = b*x + d*y + ty
1315  *
1316  * but it uses 4 elements from CF2_Font and the translation part
1317  * from CF2_GlyphPath.
1318  *
1319  */
1320  static void
1322  CF2_HintMap hintmap,
1323  FT_Vector* nextP0,
1324  FT_Vector nextP1,
1325  FT_Bool close )
1326  {
1328 
1329  FT_Vector* prevP0;
1330  FT_Vector* prevP1;
1331 
1332  FT_Vector intersection = { 0, 0 };
1333  FT_Bool useIntersection = FALSE;
1334 
1335 
1336  FT_ASSERT( glyphpath->prevElemOp == CF2_PathOpLineTo ||
1337  glyphpath->prevElemOp == CF2_PathOpCubeTo );
1338 
1339  if ( glyphpath->prevElemOp == CF2_PathOpLineTo )
1340  {
1341  prevP0 = &glyphpath->prevElemP0;
1342  prevP1 = &glyphpath->prevElemP1;
1343  }
1344  else
1345  {
1346  prevP0 = &glyphpath->prevElemP2;
1347  prevP1 = &glyphpath->prevElemP3;
1348  }
1349 
1350  /* optimization: if previous and next elements are offset by the same */
1351  /* amount, then there will be no gap, and no need to compute an */
1352  /* intersection. */
1353  if ( prevP1->x != nextP0->x || prevP1->y != nextP0->y )
1354  {
1355  /* previous element does not join next element: */
1356  /* adjust end point of previous element to the intersection */
1357  useIntersection = cf2_glyphpath_computeIntersection( glyphpath,
1358  prevP0,
1359  prevP1,
1360  nextP0,
1361  &nextP1,
1362  &intersection );
1363  if ( useIntersection )
1364  {
1365  /* modify the last point of the cached element (either line or */
1366  /* curve) */
1367  *prevP1 = intersection;
1368  }
1369  }
1370 
1371  params.pt0 = glyphpath->currentDS;
1372 
1373  switch( glyphpath->prevElemOp )
1374  {
1375  case CF2_PathOpLineTo:
1376  params.op = CF2_PathOpLineTo;
1377 
1378  /* note: pt2 and pt3 are unused */
1379 
1380  if ( close )
1381  {
1382  /* use first hint map if closing */
1383  cf2_glyphpath_hintPoint( glyphpath,
1384  &glyphpath->firstHintMap,
1385  &params.pt1,
1386  glyphpath->prevElemP1.x,
1387  glyphpath->prevElemP1.y );
1388  }
1389  else
1390  {
1391  cf2_glyphpath_hintPoint( glyphpath,
1392  hintmap,
1393  &params.pt1,
1394  glyphpath->prevElemP1.x,
1395  glyphpath->prevElemP1.y );
1396  }
1397 
1398  /* output only non-zero length lines */
1399  if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y )
1400  {
1401  glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
1402 
1403  glyphpath->currentDS = params.pt1;
1404  }
1405  break;
1406 
1407  case CF2_PathOpCubeTo:
1408  params.op = CF2_PathOpCubeTo;
1409 
1410  /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */
1411  cf2_glyphpath_hintPoint( glyphpath,
1412  hintmap,
1413  &params.pt1,
1414  glyphpath->prevElemP1.x,
1415  glyphpath->prevElemP1.y );
1416  cf2_glyphpath_hintPoint( glyphpath,
1417  hintmap,
1418  &params.pt2,
1419  glyphpath->prevElemP2.x,
1420  glyphpath->prevElemP2.y );
1421  cf2_glyphpath_hintPoint( glyphpath,
1422  hintmap,
1423  &params.pt3,
1424  glyphpath->prevElemP3.x,
1425  glyphpath->prevElemP3.y );
1426 
1427  glyphpath->callbacks->cubeTo( glyphpath->callbacks, &params );
1428 
1429  glyphpath->currentDS = params.pt3;
1430 
1431  break;
1432  }
1433 
1434  if ( !useIntersection || close )
1435  {
1436  /* insert connecting line between end of previous element and start */
1437  /* of current one */
1438  /* note: at the end of a subpath, we might do both, so use `nextP0' */
1439  /* before we change it, below */
1440 
1441  if ( close )
1442  {
1443  /* if we are closing the subpath, then nextP0 is in the first */
1444  /* hint zone */
1445  cf2_glyphpath_hintPoint( glyphpath,
1446  &glyphpath->firstHintMap,
1447  &params.pt1,
1448  nextP0->x,
1449  nextP0->y );
1450  }
1451  else
1452  {
1453  cf2_glyphpath_hintPoint( glyphpath,
1454  hintmap,
1455  &params.pt1,
1456  nextP0->x,
1457  nextP0->y );
1458  }
1459 
1460  if ( params.pt1.x != glyphpath->currentDS.x ||
1461  params.pt1.y != glyphpath->currentDS.y )
1462  {
1463  /* length is nonzero */
1464  params.op = CF2_PathOpLineTo;
1465  params.pt0 = glyphpath->currentDS;
1466 
1467  /* note: pt2 and pt3 are unused */
1468  glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
1469 
1470  glyphpath->currentDS = params.pt1;
1471  }
1472  }
1473 
1474  if ( useIntersection )
1475  {
1476  /* return intersection point to caller */
1477  *nextP0 = intersection;
1478  }
1479  }
1480 
1481 
1482  /* push a MoveTo element based on current point and offset of current */
1483  /* element */
1484  static void
1486  FT_Vector start )
1487  {
1489 
1490 
1491  params.op = CF2_PathOpMoveTo;
1492  params.pt0 = glyphpath->currentDS;
1493 
1494  /* Test if move has really happened yet; it would have called */
1495  /* `cf2_hintmap_build' to set `isValid'. */
1496  if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) )
1497  {
1498  /* we are here iff first subpath is missing a moveto operator: */
1499  /* synthesize first moveTo to finish initialization of hintMap */
1500  cf2_glyphpath_moveTo( glyphpath,
1501  glyphpath->start.x,
1502  glyphpath->start.y );
1503  }
1504 
1505  cf2_glyphpath_hintPoint( glyphpath,
1506  &glyphpath->hintMap,
1507  &params.pt1,
1508  start.x,
1509  start.y );
1510 
1511  /* note: pt2 and pt3 are unused */
1512  glyphpath->callbacks->moveTo( glyphpath->callbacks, &params );
1513 
1514  glyphpath->currentDS = params.pt1;
1515  glyphpath->offsetStart0 = start;
1516  }
1517 
1518 
1519  /*
1520  * All coordinates are in character space.
1521  * On input, (x1, y1) and (x2, y2) give line segment.
1522  * On output, (x, y) give offset vector.
1523  * We use a piecewise approximation to trig functions.
1524  *
1525  * TODO: Offset true perpendicular and proper length
1526  * supply the y-translation for hinting here, too,
1527  * that adds yOffset unconditionally to *y.
1528  */
1529  static void
1531  CF2_Fixed x1,
1532  CF2_Fixed y1,
1533  CF2_Fixed x2,
1534  CF2_Fixed y2,
1535  CF2_Fixed* x,
1536  CF2_Fixed* y )
1537  {
1538  CF2_Fixed dx = SUB_INT32( x2, x1 );
1539  CF2_Fixed dy = SUB_INT32( y2, y1 );
1540 
1541 
1542  /* note: negative offsets don't work here; negate deltas to change */
1543  /* quadrants, below */
1544  if ( glyphpath->font->reverseWinding )
1545  {
1546  dx = NEG_INT32( dx );
1547  dy = NEG_INT32( dy );
1548  }
1549 
1550  *x = *y = 0;
1551 
1552  if ( !glyphpath->darken )
1553  return;
1554 
1555  /* add momentum for this path element */
1556  glyphpath->callbacks->windingMomentum =
1557  ADD_INT32( glyphpath->callbacks->windingMomentum,
1558  cf2_getWindingMomentum( x1, y1, x2, y2 ) );
1559 
1560  /* note: allow mixed integer and fixed multiplication here */
1561  if ( dx >= 0 )
1562  {
1563  if ( dy >= 0 )
1564  {
1565  /* first quadrant, +x +y */
1566 
1567  if ( dx > MUL_INT32( 2, dy ) )
1568  {
1569  /* +x */
1570  *x = 0;
1571  *y = 0;
1572  }
1573  else if ( dy > MUL_INT32( 2, dx ) )
1574  {
1575  /* +y */
1576  *x = glyphpath->xOffset;
1577  *y = glyphpath->yOffset;
1578  }
1579  else
1580  {
1581  /* +x +y */
1582  *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
1583  glyphpath->xOffset );
1584  *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
1585  glyphpath->yOffset );
1586  }
1587  }
1588  else
1589  {
1590  /* fourth quadrant, +x -y */
1591 
1592  if ( dx > MUL_INT32( -2, dy ) )
1593  {
1594  /* +x */
1595  *x = 0;
1596  *y = 0;
1597  }
1598  else if ( NEG_INT32( dy ) > MUL_INT32( 2, dx ) )
1599  {
1600  /* -y */
1601  *x = NEG_INT32( glyphpath->xOffset );
1602  *y = glyphpath->yOffset;
1603  }
1604  else
1605  {
1606  /* +x -y */
1607  *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
1608  glyphpath->xOffset );
1609  *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
1610  glyphpath->yOffset );
1611  }
1612  }
1613  }
1614  else
1615  {
1616  if ( dy >= 0 )
1617  {
1618  /* second quadrant, -x +y */
1619 
1620  if ( NEG_INT32( dx ) > MUL_INT32( 2, dy ) )
1621  {
1622  /* -x */
1623  *x = 0;
1624  *y = MUL_INT32( 2, glyphpath->yOffset );
1625  }
1626  else if ( dy > MUL_INT32( -2, dx ) )
1627  {
1628  /* +y */
1629  *x = glyphpath->xOffset;
1630  *y = glyphpath->yOffset;
1631  }
1632  else
1633  {
1634  /* -x +y */
1635  *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
1636  glyphpath->xOffset );
1637  *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
1638  glyphpath->yOffset );
1639  }
1640  }
1641  else
1642  {
1643  /* third quadrant, -x -y */
1644 
1645  if ( NEG_INT32( dx ) > MUL_INT32( -2, dy ) )
1646  {
1647  /* -x */
1648  *x = 0;
1649  *y = MUL_INT32( 2, glyphpath->yOffset );
1650  }
1651  else if ( NEG_INT32( dy ) > MUL_INT32( -2, dx ) )
1652  {
1653  /* -y */
1654  *x = NEG_INT32( glyphpath->xOffset );
1655  *y = glyphpath->yOffset;
1656  }
1657  else
1658  {
1659  /* -x -y */
1660  *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
1661  glyphpath->xOffset );
1662  *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
1663  glyphpath->yOffset );
1664  }
1665  }
1666  }
1667  }
1668 
1669 
1670  /*
1671  * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are
1672  * called by the interpreter with Character Space (CS) coordinates. Each
1673  * path element is placed into a queue of length one to await the
1674  * calculation of the following element. At that time, the darkening
1675  * offset of the following element is known and joins can be computed,
1676  * including possible modification of this element, before mapping to
1677  * Device Space (DS) and passing it on to the outline consumer.
1678  *
1679  */
1680  FT_LOCAL_DEF( void )
1682  CF2_Fixed x,
1683  CF2_Fixed y )
1684  {
1685  cf2_glyphpath_closeOpenPath( glyphpath );
1686 
1687  /* save the parameters of the move for later, when we'll know how to */
1688  /* offset it; */
1689  /* also save last move point */
1690  glyphpath->currentCS.x = glyphpath->start.x = x;
1691  glyphpath->currentCS.y = glyphpath->start.y = y;
1692 
1693  glyphpath->moveIsPending = TRUE;
1694 
1695  /* ensure we have a valid map with current mask */
1696  if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) ||
1697  cf2_hintmask_isNew( glyphpath->hintMask ) )
1698  cf2_hintmap_build( &glyphpath->hintMap,
1699  glyphpath->hStemHintArray,
1700  glyphpath->vStemHintArray,
1701  glyphpath->hintMask,
1702  glyphpath->hintOriginY,
1703  FALSE );
1704 
1705  /* save a copy of current HintMap to use when drawing initial point */
1706  glyphpath->firstHintMap = glyphpath->hintMap; /* structure copy */
1707  }
1708 
1709 
1710  FT_LOCAL_DEF( void )
1712  CF2_Fixed x,
1713  CF2_Fixed y )
1714  {
1716  FT_Vector P0, P1;
1717  FT_Bool newHintMap;
1718 
1719  /*
1720  * New hints will be applied after cf2_glyphpath_pushPrevElem has run.
1721  * In case this is a synthesized closing line, any new hints should be
1722  * delayed until this path is closed (`cf2_hintmask_isNew' will be
1723  * called again before the next line or curve).
1724  */
1725 
1726  /* true if new hint map not on close */
1727  newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) &&
1728  !glyphpath->pathIsClosing;
1729 
1730  /*
1731  * Zero-length lines may occur in the charstring. Because we cannot
1732  * compute darkening offsets or intersections from zero-length lines,
1733  * it is best to remove them and avoid artifacts. However, zero-length
1734  * lines in CS at the start of a new hint map can generate non-zero
1735  * lines in DS due to hint substitution. We detect a change in hint
1736  * map here and pass those zero-length lines along.
1737  */
1738 
1739  /*
1740  * Note: Find explicitly closed paths here with a conditional
1741  * breakpoint using
1742  *
1743  * !gp->pathIsClosing && gp->start.x == x && gp->start.y == y
1744  *
1745  */
1746 
1747  if ( glyphpath->currentCS.x == x &&
1748  glyphpath->currentCS.y == y &&
1749  !newHintMap )
1750  /*
1751  * Ignore zero-length lines in CS where the hint map is the same
1752  * because the line in DS will also be zero length.
1753  *
1754  * Ignore zero-length lines when we synthesize a closing line because
1755  * the close will be handled in cf2_glyphPath_pushPrevElem.
1756  */
1757  return;
1758 
1759  cf2_glyphpath_computeOffset( glyphpath,
1760  glyphpath->currentCS.x,
1761  glyphpath->currentCS.y,
1762  x,
1763  y,
1764  &xOffset,
1765  &yOffset );
1766 
1767  /* construct offset points */
1768  P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset );
1769  P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset );
1770  P1.x = ADD_INT32( x, xOffset );
1771  P1.y = ADD_INT32( y, yOffset );
1772 
1773  if ( glyphpath->moveIsPending )
1774  {
1775  /* emit offset 1st point as MoveTo */
1776  cf2_glyphpath_pushMove( glyphpath, P0 );
1777 
1778  glyphpath->moveIsPending = FALSE; /* adjust state machine */
1779  glyphpath->pathIsOpen = TRUE;
1780 
1781  glyphpath->offsetStart1 = P1; /* record second point */
1782  }
1783 
1784  if ( glyphpath->elemIsQueued )
1785  {
1786  FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
1787  glyphpath->hintMap.count == 0 );
1788 
1789  cf2_glyphpath_pushPrevElem( glyphpath,
1790  &glyphpath->hintMap,
1791  &P0,
1792  P1,
1793  FALSE );
1794  }
1795 
1796  /* queue the current element with offset points */
1797  glyphpath->elemIsQueued = TRUE;
1798  glyphpath->prevElemOp = CF2_PathOpLineTo;
1799  glyphpath->prevElemP0 = P0;
1800  glyphpath->prevElemP1 = P1;
1801 
1802  /* update current map */
1803  if ( newHintMap )
1804  cf2_hintmap_build( &glyphpath->hintMap,
1805  glyphpath->hStemHintArray,
1806  glyphpath->vStemHintArray,
1807  glyphpath->hintMask,
1808  glyphpath->hintOriginY,
1809  FALSE );
1810 
1811  glyphpath->currentCS.x = x; /* pre-offset current point */
1812  glyphpath->currentCS.y = y;
1813  }
1814 
1815 
1816  FT_LOCAL_DEF( void )
1818  CF2_Fixed x1,
1819  CF2_Fixed y1,
1820  CF2_Fixed x2,
1821  CF2_Fixed y2,
1822  CF2_Fixed x3,
1823  CF2_Fixed y3 )
1824  {
1825  CF2_Fixed xOffset1, yOffset1, xOffset3, yOffset3;
1826  FT_Vector P0, P1, P2, P3;
1827 
1828 
1829  /* TODO: ignore zero length portions of curve?? */
1830  cf2_glyphpath_computeOffset( glyphpath,
1831  glyphpath->currentCS.x,
1832  glyphpath->currentCS.y,
1833  x1,
1834  y1,
1835  &xOffset1,
1836  &yOffset1 );
1837  cf2_glyphpath_computeOffset( glyphpath,
1838  x2,
1839  y2,
1840  x3,
1841  y3,
1842  &xOffset3,
1843  &yOffset3 );
1844 
1845  /* add momentum from the middle segment */
1846  glyphpath->callbacks->windingMomentum =
1847  ADD_INT32( glyphpath->callbacks->windingMomentum,
1848  cf2_getWindingMomentum( x1, y1, x2, y2 ) );
1849 
1850  /* construct offset points */
1851  P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset1 );
1852  P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset1 );
1853  P1.x = ADD_INT32( x1, xOffset1 );
1854  P1.y = ADD_INT32( y1, yOffset1 );
1855  /* note: preserve angle of final segment by using offset3 at both ends */
1856  P2.x = ADD_INT32( x2, xOffset3 );
1857  P2.y = ADD_INT32( y2, yOffset3 );
1858  P3.x = ADD_INT32( x3, xOffset3 );
1859  P3.y = ADD_INT32( y3, yOffset3 );
1860 
1861  if ( glyphpath->moveIsPending )
1862  {
1863  /* emit offset 1st point as MoveTo */
1864  cf2_glyphpath_pushMove( glyphpath, P0 );
1865 
1866  glyphpath->moveIsPending = FALSE;
1867  glyphpath->pathIsOpen = TRUE;
1868 
1869  glyphpath->offsetStart1 = P1; /* record second point */
1870  }
1871 
1872  if ( glyphpath->elemIsQueued )
1873  {
1874  FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
1875  glyphpath->hintMap.count == 0 );
1876 
1877  cf2_glyphpath_pushPrevElem( glyphpath,
1878  &glyphpath->hintMap,
1879  &P0,
1880  P1,
1881  FALSE );
1882  }
1883 
1884  /* queue the current element with offset points */
1885  glyphpath->elemIsQueued = TRUE;
1886  glyphpath->prevElemOp = CF2_PathOpCubeTo;
1887  glyphpath->prevElemP0 = P0;
1888  glyphpath->prevElemP1 = P1;
1889  glyphpath->prevElemP2 = P2;
1890  glyphpath->prevElemP3 = P3;
1891 
1892  /* update current map */
1893  if ( cf2_hintmask_isNew( glyphpath->hintMask ) )
1894  cf2_hintmap_build( &glyphpath->hintMap,
1895  glyphpath->hStemHintArray,
1896  glyphpath->vStemHintArray,
1897  glyphpath->hintMask,
1898  glyphpath->hintOriginY,
1899  FALSE );
1900 
1901  glyphpath->currentCS.x = x3; /* pre-offset current point */
1902  glyphpath->currentCS.y = y3;
1903  }
1904 
1905 
1906  FT_LOCAL_DEF( void )
1908  {
1909  if ( glyphpath->pathIsOpen )
1910  {
1911  /*
1912  * A closing line in Character Space line is always generated below
1913  * with `cf2_glyphPath_lineTo'. It may be ignored later if it turns
1914  * out to be zero length in Device Space.
1915  */
1916  glyphpath->pathIsClosing = TRUE;
1917 
1918  cf2_glyphpath_lineTo( glyphpath,
1919  glyphpath->start.x,
1920  glyphpath->start.y );
1921 
1922  /* empty the final element from the queue and close the path */
1923  if ( glyphpath->elemIsQueued )
1924  cf2_glyphpath_pushPrevElem( glyphpath,
1925  &glyphpath->hintMap,
1926  &glyphpath->offsetStart0,
1927  glyphpath->offsetStart1,
1928  TRUE );
1929 
1930  /* reset state machine */
1931  glyphpath->moveIsPending = TRUE;
1932  glyphpath->pathIsOpen = FALSE;
1933  glyphpath->pathIsClosing = FALSE;
1934  glyphpath->elemIsQueued = FALSE;
1935  }
1936  }
1937 
1938 
1939 /* END */
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
static FT_Bool cf2_hintmap_isValid(const CF2_HintMap hintmap)
Definition: pshints.c:296
#define CF2_UInt
Definition: pstypes.h:64
cf2_glyphpath_init(CF2_GlyphPath glyphpath, CF2_Font font, CF2_OutlineCallbacks callbacks, CF2_Fixed scaleY, CF2_ArrStack hStemHintArray, CF2_ArrStack vStemHintArray, CF2_HintMask hintMask, CF2_Fixed hintOriginY, const CF2_Blues blues, const FT_Vector *fractionalTranslation)
Definition: pshints.c:1083
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG y1
Definition: winddi.h:3706
static void cf2_glyphpath_computeOffset(CF2_GlyphPath glyphpath, CF2_Fixed x1, CF2_Fixed y1, CF2_Fixed x2, CF2_Fixed y2, CF2_Fixed *x, CF2_Fixed *y)
Definition: pshints.c:1530
static void cf2_hint_initZero(CF2_Hint hint)
Definition: pshints.c:211
static const WCHAR invalid[]
Definition: assoc.c:39
CF2_Callback_Type lineTo
Definition: psglue.h:127
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
GLint GLint GLsizei width
Definition: gl.h:1546
cf2_glyphpath_lineTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1711
GLdouble GLdouble u2
Definition: glext.h:8308
FT_Vector fractionalTranslation
Definition: pshints.h:199
FT_Pos y
Definition: ftimage.h:77
#define TRUE
Definition: types.h:120
CF2_F16Dot16 a
Definition: psglue.h:78
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
FT_Vector offsetStart0
Definition: pshints.h:225
CF2_Fixed scale
Definition: pshints.h:139
cf2_hintmask_setNew(CF2_HintMask hintmask, FT_Bool val)
Definition: psintrp.c:90
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
CF2_UInt count
Definition: pshints.h:140
cf2_arrstack_init(CF2_ArrStack arrstack, FT_Memory memory, FT_Error *error, size_t sizeItem)
Definition: psarrst.c:56
Definition: mk_font.cpp:20
struct CF2_HintMoveRec_ CF2_HintMoveRec
FT_Pos x
Definition: ftimage.h:76
#define pt(x, y)
Definition: drawing.c:79
#define SUB_INT32(a, b)
Definition: ftcalc.h:431
#define ADD_INT32(a, b)
Definition: ftcalc.h:429
GLuint GLuint GLsizei count
Definition: gl.h:1545
CF2_Callback_Type moveTo
Definition: psglue.h:126
GLint dy
Definition: linetemp.h:97
FT_Vector prevElemP0
Definition: pshints.h:239
CF2_Fixed maxDS
Definition: pshints.h:93
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
CF2_Fixed scaleC
Definition: pshints.h:196
static void cf2_glyphpath_hintPoint(CF2_GlyphPath glyphpath, CF2_HintMap hintmap, FT_Vector *ppt, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1167
#define MUL_INT32(a, b)
Definition: ftcalc.h:433
static CF2_Int cf2_getWindingMomentum(CF2_Fixed x1, CF2_Fixed y1, CF2_Fixed x2, CF2_Fixed y2)
Definition: pshints.c:69
CF2_HintMapRec firstHintMap
Definition: pshints.h:190
CF2_F16Dot16 b
Definition: psglue.h:79
#define cf2_intToFixed(i)
Definition: psfixed.h:60
static FT_Bool cf2_hint_isLocked(const CF2_Hint hint)
Definition: pshints.c:256
cf2_hintmask_getMaskPtr(CF2_HintMask hintmask)
Definition: psintrp.c:101
#define FT_MIN(a, b)
Definition: ftobjs.h:71
FT_Vector prevElemP3
Definition: pshints.h:242
CF2_Fixed min
Definition: pshints.h:89
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
cf2_hintmask_isValid(const CF2_HintMask hintmask)
Definition: psintrp.c:76
cf2_hintmask_setAll(CF2_HintMask hintmask, size_t bitCount)
Definition: psintrp.c:173
CF2_Fixed miterLimit
Definition: pshints.h:221
cf2_hintmap_init(CF2_HintMap hintmap, CF2_Font font, CF2_HintMap initialMap, CF2_ArrStack hintMoves, CF2_Fixed scale)
Definition: pshints.c:277
CF2_Fixed scale
Definition: psblues.h:125
static FT_Bool cf2_hint_isPair(const CF2_Hint hint)
Definition: pshints.c:225
GLdouble u1
Definition: glext.h:8308
CF2_Fixed snapThreshold
Definition: pshints.h:223
cf2_glyphpath_curveTo(CF2_GlyphPath glyphpath, CF2_Fixed x1, CF2_Fixed y1, CF2_Fixed x2, CF2_Fixed y2, CF2_Fixed x3, CF2_Fixed y3)
Definition: pshints.c:1817
return FT_Err_Ok
Definition: ftbbox.c:511
static void cf2_hint_init(CF2_Hint hint, const CF2_ArrStack stemHintArray, size_t indexStemHint, const CF2_Font font, CF2_Fixed hintOrigin, CF2_Fixed scale, FT_Bool bottom)
Definition: pshints.c:90
CF2_Fixed dsCoord
Definition: psblues.h:124
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
static FT_Bool cf2_hint_isSynthetic(const CF2_Hint hint)
Definition: pshints.c:263
#define CF2_MIN_COUNTER
Definition: psblues.h:114
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
FT_Bool darken
Definition: pshints.h:207
cf2_arrstack_getPointer(const CF2_ArrStack arrstack, size_t idx)
Definition: psarrst.c:187
CF2_Fixed max
Definition: pshints.h:90
GLenum const GLfloat * params
Definition: glext.h:5645
unsigned char FT_Byte
Definition: fttypes.h:154
#define FT_ASSERT(condition)
Definition: ftdebug.h:211
cf2_glyphpath_finalize(CF2_GlyphPath glyphpath)
Definition: pshints.c:1154
FT_Bool isValid
Definition: pshints.h:136
CF2_Font font
Definition: pshints.h:185
#define FT_TRACE4(varformat)
Definition: ftdebug.h:161
FT_Bool reverseWinding
Definition: psfont.h:112
CF2_OutlineCallbacks callbacks
Definition: pshints.h:186
struct CF2_HintMapRec_ * initialHintMap
Definition: pshints.h:131
CF2_Int prevElemOp
Definition: pshints.h:237
CF2_ArrStack hintMoves
Definition: pshints.h:134
CF2_Fixed moveUp
Definition: pshints.c:61
FT_Error * error
Definition: pshints.h:72
GLint GLint bottom
Definition: glext.h:7726
cf2_hint_lock(CF2_Hint hint)
Definition: pshints.c:270
static FT_Bool cf2_glyphpath_computeIntersection(CF2_GlyphPath glyphpath, const FT_Vector *u1, const FT_Vector *u2, const FT_Vector *v1, const FT_Vector *v2, FT_Vector *intersection)
Definition: pshints.c:1201
CF2_Fixed scaleX
Definition: pshints.h:195
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:388
static void cf2_hintmap_dump(CF2_HintMap hintmap)
Definition: pshints.c:303
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static FT_Bool cf2_hint_isPairTop(const CF2_Hint hint)
Definition: pshints.c:233
#define NEG_INT32(a)
Definition: ftcalc.h:435
cf2_arrstack_push(CF2_ArrStack arrstack, const void *ptr)
Definition: psarrst.c:212
CF2_F16Dot16 c
Definition: psglue.h:80
cf2_glyphpath_closeOpenPath(CF2_GlyphPath glyphpath)
Definition: pshints.c:1907
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_MAX(a, b)
Definition: ftobjs.h:72
struct CF2_StemHintRec_ * CF2_StemHint
#define FT_TRACE7(varformat)
Definition: ftdebug.h:164
CF2_Fixed xOffset
Definition: pshints.h:217
cf2_arrstack_finalize(CF2_ArrStack arrstack)
Definition: psarrst.c:76
cf2_glyphpath_moveTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1681
static void cf2_hintmap_adjustHints(CF2_HintMap hintmap)
Definition: pshints.c:399
FT_BEGIN_HEADER struct CF2_ArrStackRec_ * CF2_ArrStack
cf2_hintmask_isNew(const CF2_HintMask hintmask)
Definition: psintrp.c:83
static void cf2_glyphpath_pushMove(CF2_GlyphPath glyphpath, FT_Vector start)
Definition: pshints.c:1485
static void cf2_hintmap_insertHint(CF2_HintMap hintmap, CF2_Hint bottomHintEdge, CF2_Hint topHintEdge)
Definition: pshints.c:602
#define cf2_fixedFraction(x)
Definition: psfixed.h:72
CF2_UInt flags
Definition: psblues.h:120
CF2_Fixed yOffset
Definition: pshints.h:218
FT_Vector start
Definition: pshints.h:233
cf2_hint_isTop(const CF2_Hint hint)
Definition: pshints.c:240
GLdouble s
Definition: gl.h:2039
#define close
Definition: acwin.h:98
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG _In_ LONG y2
Definition: winddi.h:3706
cf2_arrstack_clear(CF2_ArrStack arrstack)
Definition: psarrst.c:158
static void cf2_glyphpath_pushPrevElem(CF2_GlyphPath glyphpath, CF2_HintMap hintmap, FT_Vector *nextP0, FT_Vector nextP1, FT_Bool close)
Definition: pshints.c:1321
#define cf2_doubleToFixed(f)
Definition: psfixed.h:66
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
#define cf2_perp(a, b)
GLfloat GLfloat GLfloat v2
Definition: glext.h:6063
#define CF2_CS_SCALE(x)
#define FT_TRACE6(varformat)
Definition: ftdebug.h:163
DWORD hint
Definition: vfdcmd.c:88
cf2_hint_isBottom(const CF2_Hint hint)
Definition: pshints.c:248
const GLdouble * v
Definition: gl.h:2040
cf2_hintmap_build(CF2_HintMap hintmap, CF2_ArrStack hStemHintArray, CF2_ArrStack vStemHintArray, CF2_HintMask hintMask, CF2_Fixed hintOrigin, FT_Bool initialMap)
Definition: pshints.c:808
CF2_Fixed minDS
Definition: pshints.h:92
GLuint start
Definition: gl.h:1545
unsigned char dummy
Definition: maze.c:118
FT_Vector currentDS
Definition: pshints.h:231
CF2_Fixed csCoord
Definition: psblues.h:123
int xOffset
Definition: appswitch.c:59
CF2_HintRec edge[CF2_MAX_HINT_EDGES]
Definition: pshints.h:145
#define CF2_Int
Definition: pstypes.h:65
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint dx
Definition: linetemp.h:97
cf2_arrstack_size(const CF2_ArrStack arrstack)
Definition: psarrst.c:168
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3706
CF2_UInt lastIndex
Definition: pshints.h:143
struct CF2_HintMoveRec_ * CF2_HintMove
FT_Vector prevElemP1
Definition: pshints.h:240
cf2_blues_capture(const CF2_Blues blues, CF2_Hint bottomHintEdge, CF2_Hint topHintEdge)
Definition: psblues.c:465
CF2_F16Dot16 d
Definition: psglue.h:81
#define const
Definition: zconf.h:230
CF2_HintMapRec hintMap
Definition: pshints.h:189
FT_Vector prevElemP2
Definition: pshints.h:241
int yOffset
Definition: appswitch.c:59
FT_Bool used
Definition: pshints.h:87
CF2_Matrix outerTransform
Definition: psfont.h:78
CF2_Callback_Type cubeTo
Definition: psglue.h:129
static int callbacks
Definition: xmllint.c:873
#define cf2_fixedAbs(x)
Definition: psfixed.h:68
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
GLfloat GLfloat v1
Definition: glext.h:6062
FT_Bool hinted
Definition: pshints.h:137
cf2_hintmask_init(CF2_HintMask hintmask, FT_Error *error)
Definition: psintrp.c:66
cf2_hint_isValid(const CF2_Hint hint)
Definition: pshints.c:218
static CF2_Fixed cf2_hintmap_map(CF2_HintMap hintmap, CF2_Fixed csCoord)
Definition: pshints.c:334
#define CF2_Fixed
Definition: psfixed.h:48