ReactOS 0.4.15-dev-7934-g1dc8d80
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
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,
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
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 )
279 CF2_HintMap initialMap,
280 CF2_ArrStack hintMoves,
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
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:
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:
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 */
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
1487 {
1489
1490
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,
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,
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 */
#define close
Definition: acwin.h:98
int yOffset
Definition: appswitch.c:59
int xOffset
Definition: appswitch.c:59
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define pt(x, y)
Definition: drawing.c:79
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
return FT_Err_Ok
Definition: ftbbox.c:511
#define MUL_INT32(a, b)
Definition: ftcalc.h:433
#define NEG_INT32(a)
Definition: ftcalc.h:435
#define SUB_INT32(a, b)
Definition: ftcalc.h:431
#define ADD_INT32(a, b)
Definition: ftcalc.h:429
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:388
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
#define FT_ASSERT(condition)
Definition: ftdebug.h:211
#define FT_TRACE7(varformat)
Definition: ftdebug.h:164
#define FT_TRACE6(varformat)
Definition: ftdebug.h:163
#define FT_TRACE4(varformat)
Definition: ftdebug.h:161
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_MIN(a, b)
Definition: ftobjs.h:71
#define FT_MAX(a, b)
Definition: ftobjs.h:72
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
unsigned char FT_Byte
Definition: fttypes.h:154
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLdouble s
Definition: gl.h:2039
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLsizei width
Definition: gl.h:1546
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GLenum const GLfloat * params
Definition: glext.h:5645
GLint GLint bottom
Definition: glext.h:7726
GLdouble GLdouble u2
Definition: glext.h:8308
GLfloat GLfloat v1
Definition: glext.h:6062
GLfloat GLfloat GLfloat v2
Definition: glext.h:6063
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
GLdouble u1
Definition: glext.h:8308
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
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
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
#define CF2_UInt
Definition: pstypes.h:64
#define CF2_Int
Definition: pstypes.h:65
GLint dy
Definition: linetemp.h:97
GLint dx
Definition: linetemp.h:97
static const WCHAR invalid[]
Definition: assoc.c:39
Definition: mk_font.cpp:20
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
static FT_Bool cf2_hint_isLocked(const CF2_Hint hint)
Definition: pshints.c:256
cf2_hint_isBottom(const CF2_Hint hint)
Definition: pshints.c:248
cf2_glyphpath_moveTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1681
static void cf2_glyphpath_pushMove(CF2_GlyphPath glyphpath, FT_Vector start)
Definition: pshints.c:1485
cf2_hint_isTop(const CF2_Hint hint)
Definition: pshints.c:240
cf2_glyphpath_finalize(CF2_GlyphPath glyphpath)
Definition: pshints.c:1154
static FT_Bool cf2_hint_isSynthetic(const CF2_Hint hint)
Definition: pshints.c:263
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_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
static CF2_Fixed cf2_hintmap_map(CF2_HintMap hintmap, CF2_Fixed csCoord)
Definition: pshints.c:334
static void cf2_hintmap_adjustHints(CF2_HintMap hintmap)
Definition: pshints.c:399
cf2_glyphpath_closeOpenPath(CF2_GlyphPath glyphpath)
Definition: pshints.c:1907
struct CF2_HintMoveRec_ CF2_HintMoveRec
struct CF2_HintMoveRec_ * CF2_HintMove
static void cf2_glyphpath_hintPoint(CF2_GlyphPath glyphpath, CF2_HintMap hintmap, FT_Vector *ppt, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1167
cf2_glyphpath_lineTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1711
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
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
static void cf2_hintmap_dump(CF2_HintMap hintmap)
Definition: pshints.c:303
cf2_hint_lock(CF2_Hint hint)
Definition: pshints.c:270
static FT_Bool cf2_hintmap_isValid(const CF2_HintMap hintmap)
Definition: pshints.c:296
static FT_Bool cf2_hint_isPairTop(const CF2_Hint hint)
Definition: pshints.c:233
cf2_hint_isValid(const CF2_Hint hint)
Definition: pshints.c:218
#define cf2_perp(a, b)
static void cf2_hint_initZero(CF2_Hint hint)
Definition: pshints.c:211
#define CF2_CS_SCALE(x)
cf2_hintmap_init(CF2_HintMap hintmap, CF2_Font font, CF2_HintMap initialMap, CF2_ArrStack hintMoves, CF2_Fixed scale)
Definition: pshints.c:277
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_hintmap_insertHint(CF2_HintMap hintmap, CF2_Hint bottomHintEdge, CF2_Hint topHintEdge)
Definition: pshints.c:602
static FT_Bool cf2_hint_isPair(const CF2_Hint hint)
Definition: pshints.c:225
static CF2_Int cf2_getWindingMomentum(CF2_Fixed x1, CF2_Fixed y1, CF2_Fixed x2, CF2_Fixed y2)
Definition: pshints.c:69
static void cf2_glyphpath_pushPrevElem(CF2_GlyphPath glyphpath, CF2_HintMap hintmap, FT_Vector *nextP0, FT_Vector nextP1, FT_Bool close)
Definition: pshints.c:1321
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
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
struct CF2_StemHintRec_ * CF2_StemHint
@ CF2_MAX_HINT_EDGES
Definition: pshints.h:122
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
CF2_ArrStack hintMoves
Definition: pshints.h:134
CF2_UInt lastIndex
Definition: pshints.h:143
struct CF2_HintMapRec_ * initialHintMap
Definition: pshints.h:131
FT_Bool hinted
Definition: pshints.h:137
CF2_Fixed scale
Definition: pshints.h:139
CF2_HintRec edge[CF2_MAX_HINT_EDGES]
Definition: pshints.h:145
FT_Error * error
Definition: pshints.h:72
CF2_Fixed moveUp
Definition: pshints.c:61
CF2_Fixed scale
Definition: psblues.h:125
CF2_Fixed csCoord
Definition: psblues.h:123
CF2_UInt flags
Definition: psblues.h:120
CF2_Fixed 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:76
FT_Pos y
Definition: ftimage.h:77
DWORD hint
Definition: vfdcmd.c:88
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3710
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG y1
Definition: winddi.h:3709
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3708
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG _In_ LONG y2
Definition: winddi.h:3711
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
static int callbacks
Definition: xmllint.c:838
#define const
Definition: zconf.h:233