w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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