ReactOS 0.4.16-dev-1025-gd3456f5
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 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 );
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 )
276 CF2_HintMap initialMap,
277 CF2_ArrStack hintMoves,
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(( " %3d %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
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
969 CF2_HintRec edge, invalid;
970
971
972 cf2_hint_initZero( &edge );
973
974 edge.flags = CF2_GhostBottom |
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,
1083 CF2_Fixed scaleY,
1084 /* CF2_Fixed hShift, */
1085 CF2_ArrStack hStemHintArray,
1086 CF2_ArrStack vStemHintArray,
1087 CF2_HintMask hintMask,
1088 CF2_Fixed hintOriginY,
1089 const CF2_Blues blues,
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,
1203 FT_Vector* intersection )
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 */
1233 CF2_Fixed denominator, s;
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 &&
1266 cf2_fixedAbs( SUB_INT32( intersection->x,
1267 u1->x ) ) < glyphpath->snapThreshold )
1268 intersection->x = u1->x;
1269 if ( u1->y == u2->y &&
1270 cf2_fixedAbs( SUB_INT32( intersection->y,
1271 u1->y ) ) < glyphpath->snapThreshold )
1272 intersection->y = u1->y;
1273
1274 if ( v1->x == v2->x &&
1275 cf2_fixedAbs( SUB_INT32( intersection->x,
1276 v1->x ) ) < glyphpath->snapThreshold )
1277 intersection->x = v1->x;
1278 if ( v1->y == v2->y &&
1279 cf2_fixedAbs( SUB_INT32( intersection->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:
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:
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 */
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
1484 {
1486
1487
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,
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 {
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,
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 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:527
#define MUL_INT32(a, b)
Definition: ftcalc.h:486
#define NEG_INT32(a)
Definition: ftcalc.h:488
#define SUB_INT32(a, b)
Definition: ftcalc.h:484
#define ADD_INT32(a, b)
Definition: ftcalc.h:482
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:387
#define FT_UNUSED(arg)
Definition: ftconfig.h:100
#define FT_ASSERT(condition)
Definition: ftdebug.h:239
#define FT_TRACE7(varformat)
Definition: ftdebug.h:192
#define FT_TRACE6(varformat)
Definition: ftdebug.h:191
#define FT_TRACE4(varformat)
Definition: ftdebug.h:189
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_MIN(a, b)
Definition: ftobjs.h:70
#define FT_MAX(a, b)
Definition: ftobjs.h:71
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
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
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:253
cf2_hint_isBottom(const CF2_Hint hint)
Definition: pshints.c:246
cf2_glyphpath_moveTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1678
static void cf2_glyphpath_pushMove(CF2_GlyphPath glyphpath, FT_Vector start)
Definition: pshints.c:1482
cf2_hint_isTop(const CF2_Hint hint)
Definition: pshints.c:239
cf2_glyphpath_finalize(CF2_GlyphPath glyphpath)
Definition: pshints.c:1151
static FT_Bool cf2_hint_isSynthetic(const CF2_Hint hint)
Definition: pshints.c:260
cf2_hintmap_build(CF2_HintMap hintmap, CF2_ArrStack hStemHintArray, CF2_ArrStack vStemHintArray, CF2_HintMask hintMask, CF2_Fixed hintOrigin, FT_Bool initialMap)
Definition: pshints.c:805
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:1814
static CF2_Fixed cf2_hintmap_map(CF2_HintMap hintmap, CF2_Fixed csCoord)
Definition: pshints.c:331
static void cf2_hintmap_adjustHints(CF2_HintMap hintmap)
Definition: pshints.c:396
cf2_glyphpath_closeOpenPath(CF2_GlyphPath glyphpath)
Definition: pshints.c:1904
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:1164
cf2_glyphpath_lineTo(CF2_GlyphPath glyphpath, CF2_Fixed x, CF2_Fixed y)
Definition: pshints.c:1708
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:1198
static void cf2_hintmap_dump(CF2_HintMap hintmap)
Definition: pshints.c:300
cf2_hint_lock(CF2_Hint hint)
Definition: pshints.c:267
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
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:274
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:1527
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 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:1318
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:1080
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:78
FT_Pos y
Definition: ftimage.h:79
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