zenilib: zenilib/jni/external/freetype2/src/pshinter/pshalgo.c Source File

zenilib 0.5.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
pshalgo.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* pshalgo.c */
4 /* */
5 /* PostScript hinting algorithm (body). */
6 /* */
7 /* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 */
8 /* by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used */
12 /* modified and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
16 /* */
17 /***************************************************************************/
18
19
20 #include <ft2build.h>
21 #include FT_INTERNAL_OBJECTS_H
22 #include FT_INTERNAL_DEBUG_H
23 #include FT_INTERNAL_CALC_H
24 #include "pshalgo.h"
25
26 #include "pshnterr.h"
27
28
29 #undef FT_COMPONENT
30 #define FT_COMPONENT trace_pshalgo2
31
32
33 #ifdef DEBUG_HINTER
34 PSH_Hint_Table ps_debug_hint_table = 0;
35 PSH_HintFunc ps_debug_hint_func = 0;
36 PSH_Glyph ps_debug_glyph = 0;
37 #endif
38
39
40 #define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */
41 /* and similar glyphs */
42 #define STRONGER /* slightly increase the contrast of smooth */
43 /* hinting */
44
45
46 /*************************************************************************/
47 /*************************************************************************/
48 /***** *****/
49 /***** BASIC HINTS RECORDINGS *****/
50 /***** *****/
51 /*************************************************************************/
52 /*************************************************************************/
53
54 /* return true if two stem hints overlap */
55 static FT_Int
56 psh_hint_overlap( PSH_Hint hint1,
57 PSH_Hint hint2 )
58 {
59 return hint1->org_pos + hint1->org_len >= hint2->org_pos &&
60 hint2->org_pos + hint2->org_len >= hint1->org_pos;
61 }
62
63
64 /* destroy hints table */
65 static void
66 psh_hint_table_done( PSH_Hint_Table table,
67 FT_Memory memory )
68 {
69 FT_FREE( table->zones );
70 table->num_zones = 0;
71 table->zone = 0;
72
73 FT_FREE( table->sort );
74 FT_FREE( table->hints );
75 table->num_hints = 0;
76 table->max_hints = 0;
77 table->sort_global = 0;
78 }
79
80
81 /* deactivate all hints in a table */
82 static void
83 psh_hint_table_deactivate( PSH_Hint_Table table )
84 {
85 FT_UInt count = table->max_hints;
86 PSH_Hint hint = table->hints;
87
88
89 for ( ; count > 0; count--, hint++ )
90 {
91 psh_hint_deactivate( hint );
92 hint->order = -1;
93 }
94 }
95
96
97 /* internal function to record a new hint */
98 static void
99 psh_hint_table_record( PSH_Hint_Table table,
100 FT_UInt idx )
101 {
102 PSH_Hint hint = table->hints + idx;
103
104
105 if ( idx >= table->max_hints )
106 {
107 FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx ));
108 return;
109 }
110
111 /* ignore active hints */
112 if ( psh_hint_is_active( hint ) )
113 return;
114
115 psh_hint_activate( hint );
116
117 /* now scan the current active hint set to check */
118 /* whether `hint' overlaps with another hint */
119 {
120 PSH_Hint* sorted = table->sort_global;
121 FT_UInt count = table->num_hints;
122 PSH_Hint hint2;
123
124
125 hint->parent = 0;
126 for ( ; count > 0; count--, sorted++ )
127 {
128 hint2 = sorted[0];
129
130 if ( psh_hint_overlap( hint, hint2 ) )
131 {
132 hint->parent = hint2;
133 break;
134 }
135 }
136 }
137
138 if ( table->num_hints < table->max_hints )
139 table->sort_global[table->num_hints++] = hint;
140 else
141 FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" ));
142 }
143
144
145 static void
146 psh_hint_table_record_mask( PSH_Hint_Table table,
147 PS_Mask hint_mask )
148 {
149 FT_Int mask = 0, val = 0;
150 FT_Byte* cursor = hint_mask->bytes;
151 FT_UInt idx, limit;
152
153
154 limit = hint_mask->num_bits;
155
156 for ( idx = 0; idx < limit; idx++ )
157 {
158 if ( mask == 0 )
159 {
160 val = *cursor++;
161 mask = 0x80;
162 }
163
164 if ( val & mask )
165 psh_hint_table_record( table, idx );
166
167 mask >>= 1;
168 }
169 }
170
171
172 /* create hints table */
173 static FT_Error
174 psh_hint_table_init( PSH_Hint_Table table,
175 PS_Hint_Table hints,
176 PS_Mask_Table hint_masks,
177 PS_Mask_Table counter_masks,
178 FT_Memory memory )
179 {
180 FT_UInt count;
181 FT_Error error;
182
183 FT_UNUSED( counter_masks );
184
185
186 count = hints->num_hints;
187
188 /* allocate our tables */
189 if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
190 FT_NEW_ARRAY( table->hints, count ) ||
191 FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
192 goto Exit;
193
194 table->max_hints = count;
195 table->sort_global = table->sort + count;
196 table->num_hints = 0;
197 table->num_zones = 0;
198 table->zone = 0;
199
200 /* initialize the `table->hints' array */
201 {
202 PSH_Hint write = table->hints;
203 PS_Hint read = hints->hints;
204
205
206 for ( ; count > 0; count--, write++, read++ )
207 {
208 write->org_pos = read->pos;
209 write->org_len = read->len;
210 write->flags = read->flags;
211 }
212 }
213
214 /* we now need to determine the initial `parent' stems; first */
215 /* activate the hints that are given by the initial hint masks */
216 if ( hint_masks )
217 {
218 PS_Mask mask = hint_masks->masks;
219
220
221 count = hint_masks->num_masks;
222 table->hint_masks = hint_masks;
223
224 for ( ; count > 0; count--, mask++ )
225 psh_hint_table_record_mask( table, mask );
226 }
227
228 /* finally, do a linear parse in case some hints were left alone */
229 if ( table->num_hints != table->max_hints )
230 {
231 FT_UInt idx;
232
233
234 FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" ));
235
236 count = table->max_hints;
237 for ( idx = 0; idx < count; idx++ )
238 psh_hint_table_record( table, idx );
239 }
240
241 Exit:
242 return error;
243 }
244
245
246 static void
247 psh_hint_table_activate_mask( PSH_Hint_Table table,
248 PS_Mask hint_mask )
249 {
250 FT_Int mask = 0, val = 0;
251 FT_Byte* cursor = hint_mask->bytes;
252 FT_UInt idx, limit, count;
253
254
255 limit = hint_mask->num_bits;
256 count = 0;
257
258 psh_hint_table_deactivate( table );
259
260 for ( idx = 0; idx < limit; idx++ )
261 {
262 if ( mask == 0 )
263 {
264 val = *cursor++;
265 mask = 0x80;
266 }
267
268 if ( val & mask )
269 {
270 PSH_Hint hint = &table->hints[idx];
271
272
273 if ( !psh_hint_is_active( hint ) )
274 {
275 FT_UInt count2;
276
277 #if 0
278 PSH_Hint* sort = table->sort;
279 PSH_Hint hint2;
280
281
282 for ( count2 = count; count2 > 0; count2--, sort++ )
283 {
284 hint2 = sort[0];
285 if ( psh_hint_overlap( hint, hint2 ) )
286 FT_TRACE0(( "psh_hint_table_activate_mask:"
287 " found overlapping hints\n" ))
288 }
289 #else
290 count2 = 0;
291 #endif
292
293 if ( count2 == 0 )
294 {
295 psh_hint_activate( hint );
296 if ( count < table->max_hints )
297 table->sort[count++] = hint;
298 else
299 FT_TRACE0(( "psh_hint_tableactivate_mask:"
300 " too many active hints\n" ));
301 }
302 }
303 }
304
305 mask >>= 1;
306 }
307 table->num_hints = count;
308
309 /* now, sort the hints; they are guaranteed to not overlap */
310 /* so we can compare their "org_pos" field directly */
311 {
312 FT_Int i1, i2;
313 PSH_Hint hint1, hint2;
314 PSH_Hint* sort = table->sort;
315
316
317 /* a simple bubble sort will do, since in 99% of cases, the hints */
318 /* will be already sorted -- and the sort will be linear */
319 for ( i1 = 1; i1 < (FT_Int)count; i1++ )
320 {
321 hint1 = sort[i1];
322 for ( i2 = i1 - 1; i2 >= 0; i2-- )
323 {
324 hint2 = sort[i2];
325
326 if ( hint2->org_pos < hint1->org_pos )
327 break;
328
329 sort[i2 + 1] = hint2;
330 sort[i2] = hint1;
331 }
332 }
333 }
334 }
335
336
337 /*************************************************************************/
338 /*************************************************************************/
339 /***** *****/
340 /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
341 /***** *****/
342 /*************************************************************************/
343 /*************************************************************************/
344
345 #if 1
346 static FT_Pos
347 psh_dimension_quantize_len( PSH_Dimension dim,
348 FT_Pos len,
349 FT_Bool do_snapping )
350 {
351 if ( len <= 64 )
352 len = 64;
353 else
354 {
355 FT_Pos delta = len - dim->stdw.widths[0].cur;
356
357
358 if ( delta < 0 )
359 delta = -delta;
360
361 if ( delta < 40 )
362 {
363 len = dim->stdw.widths[0].cur;
364 if ( len < 48 )
365 len = 48;
366 }
367
368 if ( len < 3 * 64 )
369 {
370 delta = ( len & 63 );
371 len &= -64;
372
373 if ( delta < 10 )
374 len += delta;
375
376 else if ( delta < 32 )
377 len += 10;
378
379 else if ( delta < 54 )
380 len += 54;
381
382 else
383 len += delta;
384 }
385 else
386 len = FT_PIX_ROUND( len );
387 }
388
389 if ( do_snapping )
390 len = FT_PIX_ROUND( len );
391
392 return len;
393 }
394 #endif /* 0 */
395
396
397 #ifdef DEBUG_HINTER
398
399 static void
400 ps_simple_scale( PSH_Hint_Table table,
401 FT_Fixed scale,
402 FT_Fixed delta,
403 FT_Int dimension )
404 {
405 PSH_Hint hint;
406 FT_UInt count;
407
408
409 for ( count = 0; count < table->max_hints; count++ )
410 {
411 hint = table->hints + count;
412
413 hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
414 hint->cur_len = FT_MulFix( hint->org_len, scale );
415
416 if ( ps_debug_hint_func )
417 ps_debug_hint_func( hint, dimension );
418 }
419 }
420
421 #endif /* DEBUG_HINTER */
422
423
424 static FT_Fixed
425 psh_hint_snap_stem_side_delta( FT_Fixed pos,
426 FT_Fixed len )
427 {
428 FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos;
429 FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len;
430
431
432 if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) )
433 return delta1;
434 else
435 return delta2;
436 }
437
438
439 static void
440 psh_hint_align( PSH_Hint hint,
441 PSH_Globals globals,
442 FT_Int dimension,
443 PSH_Glyph glyph )
444 {
445 PSH_Dimension dim = &globals->dimension[dimension];
446 FT_Fixed scale = dim->scale_mult;
447 FT_Fixed delta = dim->scale_delta;
448
449
450 if ( !psh_hint_is_fitted( hint ) )
451 {
452 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
453 FT_Pos len = FT_MulFix( hint->org_len, scale );
454
455 FT_Int do_snapping;
456 FT_Pos fit_len;
457 PSH_AlignmentRec align;
458
459
460 /* ignore stem alignments when requested through the hint flags */
461 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
462 ( dimension == 1 && !glyph->do_vert_hints ) )
463 {
464 hint->cur_pos = pos;
465 hint->cur_len = len;
466
467 psh_hint_set_fitted( hint );
468 return;
469 }
470
471 /* perform stem snapping when requested - this is necessary
472 * for monochrome and LCD hinting modes only
473 */
474 do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
475 ( dimension == 1 && glyph->do_vert_snapping );
476
477 hint->cur_len = fit_len = len;
478
479 /* check blue zones for horizontal stems */
480 align.align = PSH_BLUE_ALIGN_NONE;
481 align.align_bot = align.align_top = 0;
482
483 if ( dimension == 1 )
484 psh_blues_snap_stem( &globals->blues,
485 hint->org_pos + hint->org_len,
486 hint->org_pos,
487 &align );
488
489 switch ( align.align )
490 {
491 case PSH_BLUE_ALIGN_TOP:
492 /* the top of the stem is aligned against a blue zone */
493 hint->cur_pos = align.align_top - fit_len;
494 break;
495
496 case PSH_BLUE_ALIGN_BOT:
497 /* the bottom of the stem is aligned against a blue zone */
498 hint->cur_pos = align.align_bot;
499 break;
500
501 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
502 /* both edges of the stem are aligned against blue zones */
503 hint->cur_pos = align.align_bot;
504 hint->cur_len = align.align_top - align.align_bot;
505 break;
506
507 default:
508 {
509 PSH_Hint parent = hint->parent;
510
511
512 if ( parent )
513 {
514 FT_Pos par_org_center, par_cur_center;
515 FT_Pos cur_org_center, cur_delta;
516
517
518 /* ensure that parent is already fitted */
519 if ( !psh_hint_is_fitted( parent ) )
520 psh_hint_align( parent, globals, dimension, glyph );
521
522 /* keep original relation between hints, this is, use the */
523 /* scaled distance between the centers of the hints to */
524 /* compute the new position */
525 par_org_center = parent->org_pos + ( parent->org_len >> 1 );
526 par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
527 cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
528
529 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
530 pos = par_cur_center + cur_delta - ( len >> 1 );
531 }
532
533 hint->cur_pos = pos;
534 hint->cur_len = fit_len;
535
536 /* Stem adjustment tries to snap stem widths to standard
537 * ones. This is important to prevent unpleasant rounding
538 * artefacts.
539 */
540 if ( glyph->do_stem_adjust )
541 {
542 if ( len <= 64 )
543 {
544 /* the stem is less than one pixel; we will center it
545 * around the nearest pixel center
546 */
547 if ( len >= 32 )
548 {
549 /* This is a special case where we also widen the stem
550 * and align it to the pixel grid.
551 *
552 * stem_center = pos + (len/2)
553 * nearest_pixel_center = FT_ROUND(stem_center-32)+32
554 * new_pos = nearest_pixel_center-32
555 * = FT_ROUND(stem_center-32)
556 * = FT_FLOOR(stem_center-32+32)
557 * = FT_FLOOR(stem_center)
558 * new_len = 64
559 */
560 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) );
561 len = 64;
562 }
563 else if ( len > 0 )
564 {
565 /* This is a very small stem; we simply align it to the
566 * pixel grid, trying to find the minimal displacement.
567 *
568 * left = pos
569 * right = pos + len
570 * left_nearest_edge = ROUND(pos)
571 * right_nearest_edge = ROUND(right)
572 *
573 * if ( ABS(left_nearest_edge - left) <=
574 * ABS(right_nearest_edge - right) )
575 * new_pos = left
576 * else
577 * new_pos = right
578 */
579 FT_Pos left_nearest = FT_PIX_ROUND( pos );
580 FT_Pos right_nearest = FT_PIX_ROUND( pos + len );
581 FT_Pos left_disp = left_nearest - pos;
582 FT_Pos right_disp = right_nearest - ( pos + len );
583
584
585 if ( left_disp < 0 )
586 left_disp = -left_disp;
587 if ( right_disp < 0 )
588 right_disp = -right_disp;
589 if ( left_disp <= right_disp )
590 pos = left_nearest;
591 else
592 pos = right_nearest;
593 }
594 else
595 {
596 /* this is a ghost stem; we simply round it */
597 pos = FT_PIX_ROUND( pos );
598 }
599 }
600 else
601 {
602 len = psh_dimension_quantize_len( dim, len, 0 );
603 }
604 }
605
606 /* now that we have a good hinted stem width, try to position */
607 /* the stem along a pixel grid integer coordinate */
608 hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len );
609 hint->cur_len = len;
610 }
611 }
612
613 if ( do_snapping )
614 {
615 pos = hint->cur_pos;
616 len = hint->cur_len;
617
618 if ( len < 64 )
619 len = 64;
620 else
621 len = FT_PIX_ROUND( len );
622
623 switch ( align.align )
624 {
625 case PSH_BLUE_ALIGN_TOP:
626 hint->cur_pos = align.align_top - len;
627 hint->cur_len = len;
628 break;
629
630 case PSH_BLUE_ALIGN_BOT:
631 hint->cur_len = len;
632 break;
633
634 case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
635 /* don't touch */
636 break;
637
638
639 default:
640 hint->cur_len = len;
641 if ( len & 64 )
642 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32;
643 else
644 pos = FT_PIX_ROUND( pos + ( len >> 1 ) );
645
646 hint->cur_pos = pos - ( len >> 1 );
647 hint->cur_len = len;
648 }
649 }
650
651 psh_hint_set_fitted( hint );
652
653 #ifdef DEBUG_HINTER
654 if ( ps_debug_hint_func )
655 ps_debug_hint_func( hint, dimension );
656 #endif
657 }
658 }
659
660
661 #if 0 /* not used for now, experimental */
662
663 /*
664 * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
665 * of stems
666 */
667 static void
668 psh_hint_align_light( PSH_Hint hint,
669 PSH_Globals globals,
670 FT_Int dimension,
671 PSH_Glyph glyph )
672 {
673 PSH_Dimension dim = &globals->dimension[dimension];
674 FT_Fixed scale = dim->scale_mult;
675 FT_Fixed delta = dim->scale_delta;
676
677
678 if ( !psh_hint_is_fitted( hint ) )
679 {
680 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
681 FT_Pos len = FT_MulFix( hint->org_len, scale );
682
683 FT_Pos fit_len;
684
685 PSH_AlignmentRec align;
686
687
688 /* ignore stem alignments when requested through the hint flags */
689 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
690 ( dimension == 1 && !glyph->do_vert_hints ) )
691 {
692 hint->cur_pos = pos;
693 hint->cur_len = len;
694
695 psh_hint_set_fitted( hint );
696 return;
697 }
698
699 fit_len = len;
700
701 hint->cur_len = fit_len;
702
703 /* check blue zones for horizontal stems */
704 align.align = PSH_BLUE_ALIGN_NONE;
705 align.align_bot = align.align_top = 0;
706
707 if ( dimension == 1 )
708 psh_blues_snap_stem( &globals->blues,
709 hint->org_pos + hint->org_len,
710 hint->org_pos,
711 &align );
712
713 switch ( align.align )
714 {
715 case PSH_BLUE_ALIGN_TOP:
716 /* the top of the stem is aligned against a blue zone */
717 hint->cur_pos = align.align_top - fit_len;
718 break;
719
720 case PSH_BLUE_ALIGN_BOT:
721 /* the bottom of the stem is aligned against a blue zone */
722 hint->cur_pos = align.align_bot;
723 break;
724
725 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
726 /* both edges of the stem are aligned against blue zones */
727 hint->cur_pos = align.align_bot;
728 hint->cur_len = align.align_top - align.align_bot;
729 break;
730
731 default:
732 {
733 PSH_Hint parent = hint->parent;
734
735
736 if ( parent )
737 {
738 FT_Pos par_org_center, par_cur_center;
739 FT_Pos cur_org_center, cur_delta;
740
741
742 /* ensure that parent is already fitted */
743 if ( !psh_hint_is_fitted( parent ) )
744 psh_hint_align_light( parent, globals, dimension, glyph );
745
746 par_org_center = parent->org_pos + ( parent->org_len / 2 );
747 par_cur_center = parent->cur_pos + ( parent->cur_len / 2 );
748 cur_org_center = hint->org_pos + ( hint->org_len / 2 );
749
750 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
751 pos = par_cur_center + cur_delta - ( len >> 1 );
752 }
753
754 /* Stems less than one pixel wide are easy -- we want to
755 * make them as dark as possible, so they must fall within
756 * one pixel. If the stem is split between two pixels
757 * then snap the edge that is nearer to the pixel boundary
758 * to the pixel boundary.
759 */
760 if ( len <= 64 )
761 {
762 if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
763 pos += psh_hint_snap_stem_side_delta ( pos, len );
764 }
765
766 /* Position stems other to minimize the amount of mid-grays.
767 * There are, in general, two positions that do this,
768 * illustrated as A) and B) below.
769 *
770 * + + + +
771 *
772 * A) |--------------------------------|
773 * B) |--------------------------------|
774 * C) |--------------------------------|
775 *
776 * Position A) (split the excess stem equally) should be better
777 * for stems of width N + f where f < 0.5.
778 *
779 * Position B) (split the deficiency equally) should be better
780 * for stems of width N + f where f > 0.5.
781 *
782 * It turns out though that minimizing the total number of lit
783 * pixels is also important, so position C), with one edge
784 * aligned with a pixel boundary is actually preferable
785 * to A). There are also more possibile positions for C) than
786 * for A) or B), so it involves less distortion of the overall
787 * character shape.
788 */
789 else /* len > 64 */
790 {
791 FT_Fixed frac_len = len & 63;
792 FT_Fixed center = pos + ( len >> 1 );
793 FT_Fixed delta_a, delta_b;
794
795
796 if ( ( len / 64 ) & 1 )
797 {
798 delta_a = FT_PIX_FLOOR( center ) + 32 - center;
799 delta_b = FT_PIX_ROUND( center ) - center;
800 }
801 else
802 {
803 delta_a = FT_PIX_ROUND( center ) - center;
804 delta_b = FT_PIX_FLOOR( center ) + 32 - center;
805 }
806
807 /* We choose between B) and C) above based on the amount
808 * of fractinal stem width; for small amounts, choose
809 * C) always, for large amounts, B) always, and inbetween,
810 * pick whichever one involves less stem movement.
811 */
812 if ( frac_len < 32 )
813 {
814 pos += psh_hint_snap_stem_side_delta ( pos, len );
815 }
816 else if ( frac_len < 48 )
817 {
818 FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos,
819 len );
820
821 if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) )
822 pos += side_delta;
823 else
824 pos += delta_b;
825 }
826 else
827 {
828 pos += delta_b;
829 }
830 }
831
832 hint->cur_pos = pos;
833 }
834 } /* switch */
835
836 psh_hint_set_fitted( hint );
837
838 #ifdef DEBUG_HINTER
839 if ( ps_debug_hint_func )
840 ps_debug_hint_func( hint, dimension );
841 #endif
842 }
843 }
844
845 #endif /* 0 */
846
847
848 static void
849 psh_hint_table_align_hints( PSH_Hint_Table table,
850 PSH_Globals globals,
851 FT_Int dimension,
852 PSH_Glyph glyph )
853 {
854 PSH_Hint hint;
855 FT_UInt count;
856
857 #ifdef DEBUG_HINTER
858
859 PSH_Dimension dim = &globals->dimension[dimension];
860 FT_Fixed scale = dim->scale_mult;
861 FT_Fixed delta = dim->scale_delta;
862
863
864 if ( ps_debug_no_vert_hints && dimension == 0 )
865 {
866 ps_simple_scale( table, scale, delta, dimension );
867 return;
868 }
869
870 if ( ps_debug_no_horz_hints && dimension == 1 )
871 {
872 ps_simple_scale( table, scale, delta, dimension );
873 return;
874 }
875
876 #endif /* DEBUG_HINTER*/
877
878 hint = table->hints;
879 count = table->max_hints;
880
881 for ( ; count > 0; count--, hint++ )
882 psh_hint_align( hint, globals, dimension, glyph );
883 }
884
885
886 /*************************************************************************/
887 /*************************************************************************/
888 /***** *****/
889 /***** POINTS INTERPOLATION ROUTINES *****/
890 /***** *****/
891 /*************************************************************************/
892 /*************************************************************************/
893
894 #define PSH_ZONE_MIN -3200000L
895 #define PSH_ZONE_MAX +3200000L
896
897 #define xxDEBUG_ZONES
898
899
900 #ifdef DEBUG_ZONES
901
902 #include FT_CONFIG_STANDARD_LIBRARY_H
903
904 static void
905 psh_print_zone( PSH_Zone zone )
906 {
907 printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
908 zone->scale / 65536.0,
909 zone->delta / 64.0,
910 zone->min,
911 zone->max );
912 }
913
914 #else
915
916 #define psh_print_zone( x ) do { } while ( 0 )
917
918 #endif /* DEBUG_ZONES */
919
920
921 /*************************************************************************/
922 /*************************************************************************/
923 /***** *****/
924 /***** HINTER GLYPH MANAGEMENT *****/
925 /***** *****/
926 /*************************************************************************/
927 /*************************************************************************/
928
929 #if 1
930
931 #define psh_corner_is_flat ft_corner_is_flat
932 #define psh_corner_orientation ft_corner_orientation
933
934 #else
935
936 FT_LOCAL_DEF( FT_Int )
937 psh_corner_is_flat( FT_Pos x_in,
938 FT_Pos y_in,
939 FT_Pos x_out,
940 FT_Pos y_out )
941 {
942 FT_Pos ax = x_in;
943 FT_Pos ay = y_in;
944
945 FT_Pos d_in, d_out, d_corner;
946
947
948 if ( ax < 0 )
949 ax = -ax;
950 if ( ay < 0 )
951 ay = -ay;
952 d_in = ax + ay;
953
954 ax = x_out;
955 if ( ax < 0 )
956 ax = -ax;
957 ay = y_out;
958 if ( ay < 0 )
959 ay = -ay;
960 d_out = ax + ay;
961
962 ax = x_out + x_in;
963 if ( ax < 0 )
964 ax = -ax;
965 ay = y_out + y_in;
966 if ( ay < 0 )
967 ay = -ay;
968 d_corner = ax + ay;
969
970 return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
971 }
972
973 static FT_Int
974 psh_corner_orientation( FT_Pos in_x,
975 FT_Pos in_y,
976 FT_Pos out_x,
977 FT_Pos out_y )
978 {
979 FT_Int result;
980
981
982 /* deal with the trivial cases quickly */
983 if ( in_y == 0 )
984 {
985 if ( in_x >= 0 )
986 result = out_y;
987 else
988 result = -out_y;
989 }
990 else if ( in_x == 0 )
991 {
992 if ( in_y >= 0 )
993 result = -out_x;
994 else
995 result = out_x;
996 }
997 else if ( out_y == 0 )
998 {
999 if ( out_x >= 0 )
1000 result = in_y;
1001 else
1002 result = -in_y;
1003 }
1004 else if ( out_x == 0 )
1005 {
1006 if ( out_y >= 0 )
1007 result = -in_x;
1008 else
1009 result = in_x;
1010 }
1011 else /* general case */
1012 {
1013 long long delta = (long long)in_x * out_y - (long long)in_y * out_x;
1014
1015 if ( delta == 0 )
1016 result = 0;
1017 else
1018 result = 1 - 2 * ( delta < 0 );
1019 }
1020
1021 return result;
1022 }
1023
1024 #endif /* !1 */
1025
1026
1027 #ifdef COMPUTE_INFLEXS
1028
1029 /* compute all inflex points in a given glyph */
1030 static void
1031 psh_glyph_compute_inflections( PSH_Glyph glyph )
1032 {
1033 FT_UInt n;
1034
1035
1036 for ( n = 0; n < glyph->num_contours; n++ )
1037 {
1038 PSH_Point first, start, end, before, after;
1039 FT_Pos in_x, in_y, out_x, out_y;
1040 FT_Int orient_prev, orient_cur;
1041 FT_Int finished = 0;
1042
1043
1044 /* we need at least 4 points to create an inflection point */
1045 if ( glyph->contours[n].count < 4 )
1046 continue;
1047
1048 /* compute first segment in contour */
1049 first = glyph->contours[n].start;
1050
1051 start = end = first;
1052 do
1053 {
1054 end = end->next;
1055 if ( end == first )
1056 goto Skip;
1057
1058 in_x = end->org_u - start->org_u;
1059 in_y = end->org_v - start->org_v;
1060
1061 } while ( in_x == 0 && in_y == 0 );
1062
1063 /* extend the segment start whenever possible */
1064 before = start;
1065 do
1066 {
1067 do
1068 {
1069 start = before;
1070 before = before->prev;
1071 if ( before == first )
1072 goto Skip;
1073
1074 out_x = start->org_u - before->org_u;
1075 out_y = start->org_v - before->org_v;
1076
1077 } while ( out_x == 0 && out_y == 0 );
1078
1079 orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
1080
1081 } while ( orient_prev == 0 );
1082
1083 first = start;
1084 in_x = out_x;
1085 in_y = out_y;
1086
1087 /* now, process all segments in the contour */
1088 do
1089 {
1090 /* first, extend current segment's end whenever possible */
1091 after = end;
1092 do
1093 {
1094 do
1095 {
1096 end = after;
1097 after = after->next;
1098 if ( after == first )
1099 finished = 1;
1100
1101 out_x = after->org_u - end->org_u;
1102 out_y = after->org_v - end->org_v;
1103
1104 } while ( out_x == 0 && out_y == 0 );
1105
1106 orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
1107
1108 } while ( orient_cur == 0 );
1109
1110 if ( ( orient_cur ^ orient_prev ) < 0 )
1111 {
1112 do
1113 {
1114 psh_point_set_inflex( start );
1115 start = start->next;
1116 }
1117 while ( start != end );
1118
1119 psh_point_set_inflex( start );
1120 }
1121
1122 start = end;
1123 end = after;
1124 orient_prev = orient_cur;
1125 in_x = out_x;
1126 in_y = out_y;
1127
1128 } while ( !finished );
1129
1130 Skip:
1131 ;
1132 }
1133 }
1134
1135 #endif /* COMPUTE_INFLEXS */
1136
1137
1138 static void
1139 psh_glyph_done( PSH_Glyph glyph )
1140 {
1141 FT_Memory memory = glyph->memory;
1142
1143
1144 psh_hint_table_done( &glyph->hint_tables[1], memory );
1145 psh_hint_table_done( &glyph->hint_tables[0], memory );
1146
1147 FT_FREE( glyph->points );
1148 FT_FREE( glyph->contours );
1149
1150 glyph->num_points = 0;
1151 glyph->num_contours = 0;
1152
1153 glyph->memory = 0;
1154 }
1155
1156
1157 static int
1158 psh_compute_dir( FT_Pos dx,
1159 FT_Pos dy )
1160 {
1161 FT_Pos ax, ay;
1162 int result = PSH_DIR_NONE;
1163
1164
1165 ax = ( dx >= 0 ) ? dx : -dx;
1166 ay = ( dy >= 0 ) ? dy : -dy;
1167
1168 if ( ay * 12 < ax )
1169 {
1170 /* |dy| <<< |dx| means a near-horizontal segment */
1171 result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT;
1172 }
1173 else if ( ax * 12 < ay )
1174 {
1175 /* |dx| <<< |dy| means a near-vertical segment */
1176 result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN;
1177 }
1178
1179 return result;
1180 }
1181
1182
1183 /* load outline point coordinates into hinter glyph */
1184 static void
1185 psh_glyph_load_points( PSH_Glyph glyph,
1186 FT_Int dimension )
1187 {
1188 FT_Vector* vec = glyph->outline->points;
1189 PSH_Point point = glyph->points;
1190 FT_UInt count = glyph->num_points;
1191
1192
1193 for ( ; count > 0; count--, point++, vec++ )
1194 {
1195 point->flags2 = 0;
1196 point->hint = NULL;
1197 if ( dimension == 0 )
1198 {
1199 point->org_u = vec->x;
1200 point->org_v = vec->y;
1201 }
1202 else
1203 {
1204 point->org_u = vec->y;
1205 point->org_v = vec->x;
1206 }
1207
1208 #ifdef DEBUG_HINTER
1209 point->org_x = vec->x;
1210 point->org_y = vec->y;
1211 #endif
1212
1213 }
1214 }
1215
1216
1217 /* save hinted point coordinates back to outline */
1218 static void
1219 psh_glyph_save_points( PSH_Glyph glyph,
1220 FT_Int dimension )
1221 {
1222 FT_UInt n;
1223 PSH_Point point = glyph->points;
1224 FT_Vector* vec = glyph->outline->points;
1225 char* tags = glyph->outline->tags;
1226
1227
1228 for ( n = 0; n < glyph->num_points; n++ )
1229 {
1230 if ( dimension == 0 )
1231 vec[n].x = point->cur_u;
1232 else
1233 vec[n].y = point->cur_u;
1234
1235 if ( psh_point_is_strong( point ) )
1236 tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
1237
1238 #ifdef DEBUG_HINTER
1239
1240 if ( dimension == 0 )
1241 {
1242 point->cur_x = point->cur_u;
1243 point->flags_x = point->flags2 | point->flags;
1244 }
1245 else
1246 {
1247 point->cur_y = point->cur_u;
1248 point->flags_y = point->flags2 | point->flags;
1249 }
1250
1251 #endif
1252
1253 point++;
1254 }
1255 }
1256
1257
1258 static FT_Error
1259 psh_glyph_init( PSH_Glyph glyph,
1260 FT_Outline* outline,
1261 PS_Hints ps_hints,
1262 PSH_Globals globals )
1263 {
1264 FT_Error error;
1265 FT_Memory memory;
1266
1267
1268 /* clear all fields */
1269 FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
1270
1271 memory = glyph->memory = globals->memory;
1272
1273 /* allocate and setup points + contours arrays */
1274 if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
1275 FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
1276 goto Exit;
1277
1278 glyph->num_points = outline->n_points;
1279 glyph->num_contours = outline->n_contours;
1280
1281 {
1282 FT_UInt first = 0, next, n;
1283 PSH_Point points = glyph->points;
1284 PSH_Contour contour = glyph->contours;
1285
1286
1287 for ( n = 0; n < glyph->num_contours; n++ )
1288 {
1289 FT_Int count;
1290 PSH_Point point;
1291
1292
1293 next = outline->contours[n] + 1;
1294 count = next - first;
1295
1296 contour->start = points + first;
1297 contour->count = (FT_UInt)count;
1298
1299 if ( count > 0 )
1300 {
1301 point = points + first;
1302
1303 point->prev = points + next - 1;
1304 point->contour = contour;
1305
1306 for ( ; count > 1; count-- )
1307 {
1308 point[0].next = point + 1;
1309 point[1].prev = point;
1310 point++;
1311 point->contour = contour;
1312 }
1313 point->next = points + first;
1314 }
1315
1316 contour++;
1317 first = next;
1318 }
1319 }
1320
1321 {
1322 PSH_Point points = glyph->points;
1323 PSH_Point point = points;
1324 FT_Vector* vec = outline->points;
1325 FT_UInt n;
1326
1327
1328 for ( n = 0; n < glyph->num_points; n++, point++ )
1329 {
1330 FT_Int n_prev = (FT_Int)( point->prev - points );
1331 FT_Int n_next = (FT_Int)( point->next - points );
1332 FT_Pos dxi, dyi, dxo, dyo;
1333
1334
1335 if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
1336 point->flags = PSH_POINT_OFF;
1337
1338 dxi = vec[n].x - vec[n_prev].x;
1339 dyi = vec[n].y - vec[n_prev].y;
1340
1341 point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi );
1342
1343 dxo = vec[n_next].x - vec[n].x;
1344 dyo = vec[n_next].y - vec[n].y;
1345
1346 point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo );
1347
1348 /* detect smooth points */
1349 if ( point->flags & PSH_POINT_OFF )
1350 point->flags |= PSH_POINT_SMOOTH;
1351
1352 else if ( point->dir_in == point->dir_out )
1353 {
1354 if ( point->dir_out != PSH_DIR_NONE ||
1355 psh_corner_is_flat( dxi, dyi, dxo, dyo ) )
1356 point->flags |= PSH_POINT_SMOOTH;
1357 }
1358 }
1359 }
1360
1361 glyph->outline = outline;
1362 glyph->globals = globals;
1363
1364 #ifdef COMPUTE_INFLEXS
1365 psh_glyph_load_points( glyph, 0 );
1366 psh_glyph_compute_inflections( glyph );
1367 #endif /* COMPUTE_INFLEXS */
1368
1369 /* now deal with hints tables */
1370 error = psh_hint_table_init( &glyph->hint_tables [0],
1371 &ps_hints->dimension[0].hints,
1372 &ps_hints->dimension[0].masks,
1373 &ps_hints->dimension[0].counters,
1374 memory );
1375 if ( error )
1376 goto Exit;
1377
1378 error = psh_hint_table_init( &glyph->hint_tables [1],
1379 &ps_hints->dimension[1].hints,
1380 &ps_hints->dimension[1].masks,
1381 &ps_hints->dimension[1].counters,
1382 memory );
1383 if ( error )
1384 goto Exit;
1385
1386 Exit:
1387 return error;
1388 }
1389
1390
1391 /* compute all extrema in a glyph for a given dimension */
1392 static void
1393 psh_glyph_compute_extrema( PSH_Glyph glyph )
1394 {
1395 FT_UInt n;
1396
1397
1398 /* first of all, compute all local extrema */
1399 for ( n = 0; n < glyph->num_contours; n++ )
1400 {
1401 PSH_Point first = glyph->contours[n].start;
1402 PSH_Point point, before, after;
1403
1404
1405 if ( glyph->contours[n].count == 0 )
1406 continue;
1407
1408 point = first;
1409 before = point;
1410 after = point;
1411
1412 do
1413 {
1414 before = before->prev;
1415 if ( before == first )
1416 goto Skip;
1417
1418 } while ( before->org_u == point->org_u );
1419
1420 first = point = before->next;
1421
1422 for (;;)
1423 {
1424 after = point;
1425 do
1426 {
1427 after = after->next;
1428 if ( after == first )
1429 goto Next;
1430
1431 } while ( after->org_u == point->org_u );
1432
1433 if ( before->org_u < point->org_u )
1434 {
1435 if ( after->org_u < point->org_u )
1436 {
1437 /* local maximum */
1438 goto Extremum;
1439 }
1440 }
1441 else /* before->org_u > point->org_u */
1442 {
1443 if ( after->org_u > point->org_u )
1444 {
1445 /* local minimum */
1446 Extremum:
1447 do
1448 {
1449 psh_point_set_extremum( point );
1450 point = point->next;
1451
1452 } while ( point != after );
1453 }
1454 }
1455
1456 before = after->prev;
1457 point = after;
1458
1459 } /* for */
1460
1461 Next:
1462 ;
1463 }
1464
1465 /* for each extremum, determine its direction along the */
1466 /* orthogonal axis */
1467 for ( n = 0; n < glyph->num_points; n++ )
1468 {
1469 PSH_Point point, before, after;
1470
1471
1472 point = &glyph->points[n];
1473 before = point;
1474 after = point;
1475
1476 if ( psh_point_is_extremum( point ) )
1477 {
1478 do
1479 {
1480 before = before->prev;
1481 if ( before == point )
1482 goto Skip;
1483
1484 } while ( before->org_v == point->org_v );
1485
1486 do
1487 {
1488 after = after->next;
1489 if ( after == point )
1490 goto Skip;
1491
1492 } while ( after->org_v == point->org_v );
1493 }
1494
1495 if ( before->org_v < point->org_v &&
1496 after->org_v > point->org_v )
1497 {
1498 psh_point_set_positive( point );
1499 }
1500 else if ( before->org_v > point->org_v &&
1501 after->org_v < point->org_v )
1502 {
1503 psh_point_set_negative( point );
1504 }
1505
1506 Skip:
1507 ;
1508 }
1509 }
1510
1511
1512 /* major_dir is the direction for points on the bottom/left of the stem; */
1513 /* Points on the top/right of the stem will have a direction of */
1514 /* -major_dir. */
1515
1516 static void
1517 psh_hint_table_find_strong_points( PSH_Hint_Table table,
1518 PSH_Point point,
1519 FT_UInt count,
1520 FT_Int threshold,
1521 FT_Int major_dir )
1522 {
1523 PSH_Hint* sort = table->sort;
1524 FT_UInt num_hints = table->num_hints;
1525
1526
1527 for ( ; count > 0; count--, point++ )
1528 {
1529 FT_Int point_dir = 0;
1530 FT_Pos org_u = point->org_u;
1531
1532
1533 if ( psh_point_is_strong( point ) )
1534 continue;
1535
1536 if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) )
1537 point_dir = point->dir_in;
1538
1539 else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) )
1540 point_dir = point->dir_out;
1541
1542 if ( point_dir )
1543 {
1544 if ( point_dir == major_dir )
1545 {
1546 FT_UInt nn;
1547
1548
1549 for ( nn = 0; nn < num_hints; nn++ )
1550 {
1551 PSH_Hint hint = sort[nn];
1552 FT_Pos d = org_u - hint->org_pos;
1553
1554
1555 if ( d < threshold && -d < threshold )
1556 {
1557 psh_point_set_strong( point );
1558 point->flags2 |= PSH_POINT_EDGE_MIN;
1559 point->hint = hint;
1560 break;
1561 }
1562 }
1563 }
1564 else if ( point_dir == -major_dir )
1565 {
1566 FT_UInt nn;
1567
1568
1569 for ( nn = 0; nn < num_hints; nn++ )
1570 {
1571 PSH_Hint hint = sort[nn];
1572 FT_Pos d = org_u - hint->org_pos - hint->org_len;
1573
1574
1575 if ( d < threshold && -d < threshold )
1576 {
1577 psh_point_set_strong( point );
1578 point->flags2 |= PSH_POINT_EDGE_MAX;
1579 point->hint = hint;
1580 break;
1581 }
1582 }
1583 }
1584 }
1585
1586 #if 1
1587 else if ( psh_point_is_extremum( point ) )
1588 {
1589 /* treat extrema as special cases for stem edge alignment */
1590 FT_UInt nn, min_flag, max_flag;
1591
1592
1593 if ( major_dir == PSH_DIR_HORIZONTAL )
1594 {
1595 min_flag = PSH_POINT_POSITIVE;
1596 max_flag = PSH_POINT_NEGATIVE;
1597 }
1598 else
1599 {
1600 min_flag = PSH_POINT_NEGATIVE;
1601 max_flag = PSH_POINT_POSITIVE;
1602 }
1603
1604 if ( point->flags2 & min_flag )
1605 {
1606 for ( nn = 0; nn < num_hints; nn++ )
1607 {
1608 PSH_Hint hint = sort[nn];
1609 FT_Pos d = org_u - hint->org_pos;
1610
1611
1612 if ( d < threshold && -d < threshold )
1613 {
1614 point->flags2 |= PSH_POINT_EDGE_MIN;
1615 point->hint = hint;
1616 psh_point_set_strong( point );
1617 break;
1618 }
1619 }
1620 }
1621 else if ( point->flags2 & max_flag )
1622 {
1623 for ( nn = 0; nn < num_hints; nn++ )
1624 {
1625 PSH_Hint hint = sort[nn];
1626 FT_Pos d = org_u - hint->org_pos - hint->org_len;
1627
1628
1629 if ( d < threshold && -d < threshold )
1630 {
1631 point->flags2 |= PSH_POINT_EDGE_MAX;
1632 point->hint = hint;
1633 psh_point_set_strong( point );
1634 break;
1635 }
1636 }
1637 }
1638
1639 if ( point->hint == NULL )
1640 {
1641 for ( nn = 0; nn < num_hints; nn++ )
1642 {
1643 PSH_Hint hint = sort[nn];
1644
1645
1646 if ( org_u >= hint->org_pos &&
1647 org_u <= hint->org_pos + hint->org_len )
1648 {
1649 point->hint = hint;
1650 break;
1651 }
1652 }
1653 }
1654 }
1655
1656 #endif /* 1 */
1657 }
1658 }
1659
1660
1661 /* the accepted shift for strong points in fractional pixels */
1662 #define PSH_STRONG_THRESHOLD 32
1663
1664 /* the maximum shift value in font units */
1665 #define PSH_STRONG_THRESHOLD_MAXIMUM 30
1666
1667
1668 /* find strong points in a glyph */
1669 static void
1670 psh_glyph_find_strong_points( PSH_Glyph glyph,
1671 FT_Int dimension )
1672 {
1673 /* a point is `strong' if it is located on a stem edge and */
1674 /* has an `in' or `out' tangent parallel to the hint's direction */
1675
1676 PSH_Hint_Table table = &glyph->hint_tables[dimension];
1677 PS_Mask mask = table->hint_masks->masks;
1678 FT_UInt num_masks = table->hint_masks->num_masks;
1679 FT_UInt first = 0;
1680 FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL
1681 : PSH_DIR_HORIZONTAL;
1682 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1683 FT_Fixed scale = dim->scale_mult;
1684 FT_Int threshold;
1685
1686
1687 threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale );
1688 if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM )
1689 threshold = PSH_STRONG_THRESHOLD_MAXIMUM;
1690
1691 /* process secondary hints to `selected' points */
1692 if ( num_masks > 1 && glyph->num_points > 0 )
1693 {
1694 /* the `endchar' op can reduce the number of points */
1695 first = mask->end_point > glyph->num_points
1696 ? glyph->num_points
1697 : mask->end_point;
1698 mask++;
1699 for ( ; num_masks > 1; num_masks--, mask++ )
1700 {
1701 FT_UInt next;
1702 FT_Int count;
1703
1704
1705 next = mask->end_point > glyph->num_points
1706 ? glyph->num_points
1707 : mask->end_point;
1708 count = next - first;
1709 if ( count > 0 )
1710 {
1711 PSH_Point point = glyph->points + first;
1712
1713
1714 psh_hint_table_activate_mask( table, mask );
1715
1716 psh_hint_table_find_strong_points( table, point, count,
1717 threshold, major_dir );
1718 }
1719 first = next;
1720 }
1721 }
1722
1723 /* process primary hints for all points */
1724 if ( num_masks == 1 )
1725 {
1726 FT_UInt count = glyph->num_points;
1727 PSH_Point point = glyph->points;
1728
1729
1730 psh_hint_table_activate_mask( table, table->hint_masks->masks );
1731
1732 psh_hint_table_find_strong_points( table, point, count,
1733 threshold, major_dir );
1734 }
1735
1736 /* now, certain points may have been attached to a hint and */
1737 /* not marked as strong; update their flags then */
1738 {
1739 FT_UInt count = glyph->num_points;
1740 PSH_Point point = glyph->points;
1741
1742
1743 for ( ; count > 0; count--, point++ )
1744 if ( point->hint && !psh_point_is_strong( point ) )
1745 psh_point_set_strong( point );
1746 }
1747 }
1748
1749
1750 /* find points in a glyph which are in a blue zone and have `in' or */
1751 /* `out' tangents parallel to the horizontal axis */
1752 static void
1753 psh_glyph_find_blue_points( PSH_Blues blues,
1754 PSH_Glyph glyph )
1755 {
1756 PSH_Blue_Table table;
1757 PSH_Blue_Zone zone;
1758 FT_UInt glyph_count = glyph->num_points;
1759 FT_UInt blue_count;
1760 PSH_Point point = glyph->points;
1761
1762
1763 for ( ; glyph_count > 0; glyph_count--, point++ )
1764 {
1765 FT_Pos y;
1766
1767
1768 /* check tangents */
1769 if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) &&
1770 !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) )
1771 continue;
1772
1773 /* skip strong points */
1774 if ( psh_point_is_strong( point ) )
1775 continue;
1776
1777 y = point->org_u;
1778
1779 /* look up top zones */
1780 table = &blues->normal_top;
1781 blue_count = table->count;
1782 zone = table->zones;
1783
1784 for ( ; blue_count > 0; blue_count--, zone++ )
1785 {
1786 FT_Pos delta = y - zone->org_bottom;
1787
1788
1789 if ( delta < -blues->blue_fuzz )
1790 break;
1791
1792 if ( y <= zone->org_top + blues->blue_fuzz )
1793 if ( blues->no_overshoots || delta <= blues->blue_threshold )
1794 {
1795 point->cur_u = zone->cur_bottom;
1796 psh_point_set_strong( point );
1797 psh_point_set_fitted( point );
1798 }
1799 }
1800
1801 /* look up bottom zones */
1802 table = &blues->normal_bottom;
1803 blue_count = table->count;
1804 zone = table->zones + blue_count - 1;
1805
1806 for ( ; blue_count > 0; blue_count--, zone-- )
1807 {
1808 FT_Pos delta = zone->org_top - y;
1809
1810
1811 if ( delta < -blues->blue_fuzz )
1812 break;
1813
1814 if ( y >= zone->org_bottom - blues->blue_fuzz )
1815 if ( blues->no_overshoots || delta < blues->blue_threshold )
1816 {
1817 point->cur_u = zone->cur_top;
1818 psh_point_set_strong( point );
1819 psh_point_set_fitted( point );
1820 }
1821 }
1822 }
1823 }
1824
1825
1826 /* interpolate strong points with the help of hinted coordinates */
1827 static void
1828 psh_glyph_interpolate_strong_points( PSH_Glyph glyph,
1829 FT_Int dimension )
1830 {
1831 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1832 FT_Fixed scale = dim->scale_mult;
1833
1834 FT_UInt count = glyph->num_points;
1835 PSH_Point point = glyph->points;
1836
1837
1838 for ( ; count > 0; count--, point++ )
1839 {
1840 PSH_Hint hint = point->hint;
1841
1842
1843 if ( hint )
1844 {
1845 FT_Pos delta;
1846
1847
1848 if ( psh_point_is_edge_min( point ) )
1849 point->cur_u = hint->cur_pos;
1850
1851 else if ( psh_point_is_edge_max( point ) )
1852 point->cur_u = hint->cur_pos + hint->cur_len;
1853
1854 else
1855 {
1856 delta = point->org_u - hint->org_pos;
1857
1858 if ( delta <= 0 )
1859 point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
1860
1861 else if ( delta >= hint->org_len )
1862 point->cur_u = hint->cur_pos + hint->cur_len +
1863 FT_MulFix( delta - hint->org_len, scale );
1864
1865 else /* hint->org_len > 0 */
1866 point->cur_u = hint->cur_pos +
1867 FT_MulDiv( delta, hint->cur_len,
1868 hint->org_len );
1869 }
1870 psh_point_set_fitted( point );
1871 }
1872 }
1873 }
1874
1875
1876 #define PSH_MAX_STRONG_INTERNAL 16
1877
1878 static void
1879 psh_glyph_interpolate_normal_points( PSH_Glyph glyph,
1880 FT_Int dimension )
1881 {
1882
1883 #if 1
1884 /* first technique: a point is strong if it is a local extremum */
1885
1886 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1887 FT_Fixed scale = dim->scale_mult;
1888 FT_Memory memory = glyph->memory;
1889
1890 PSH_Point* strongs = NULL;
1891 PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL];
1892 FT_UInt num_strongs = 0;
1893
1894 PSH_Point points = glyph->points;
1895 PSH_Point points_end = points + glyph->num_points;
1896 PSH_Point point;
1897
1898
1899 /* first count the number of strong points */
1900 for ( point = points; point < points_end; point++ )
1901 {
1902 if ( psh_point_is_strong( point ) )
1903 num_strongs++;
1904 }
1905
1906 if ( num_strongs == 0 ) /* nothing to do here */
1907 return;
1908
1909 /* allocate an array to store a list of points, */
1910 /* stored in increasing org_u order */
1911 if ( num_strongs <= PSH_MAX_STRONG_INTERNAL )
1912 strongs = strongs_0;
1913 else
1914 {
1915 FT_Error error;
1916
1917
1918 if ( FT_NEW_ARRAY( strongs, num_strongs ) )
1919 return;
1920 }
1921
1922 num_strongs = 0;
1923 for ( point = points; point < points_end; point++ )
1924 {
1925 PSH_Point* insert;
1926
1927
1928 if ( !psh_point_is_strong( point ) )
1929 continue;
1930
1931 for ( insert = strongs + num_strongs; insert > strongs; insert-- )
1932 {
1933 if ( insert[-1]->org_u <= point->org_u )
1934 break;
1935
1936 insert[0] = insert[-1];
1937 }
1938 insert[0] = point;
1939 num_strongs++;
1940 }
1941
1942 /* now try to interpolate all normal points */
1943 for ( point = points; point < points_end; point++ )
1944 {
1945 if ( psh_point_is_strong( point ) )
1946 continue;
1947
1948 /* sometimes, some local extrema are smooth points */
1949 if ( psh_point_is_smooth( point ) )
1950 {
1951 if ( point->dir_in == PSH_DIR_NONE ||
1952 point->dir_in != point->dir_out )
1953 continue;
1954
1955 if ( !psh_point_is_extremum( point ) &&
1956 !psh_point_is_inflex( point ) )
1957 continue;
1958
1959 point->flags &= ~PSH_POINT_SMOOTH;
1960 }
1961
1962 /* find best enclosing point coordinates then interpolate */
1963 {
1964 PSH_Point before, after;
1965 FT_UInt nn;
1966
1967
1968 for ( nn = 0; nn < num_strongs; nn++ )
1969 if ( strongs[nn]->org_u > point->org_u )
1970 break;
1971
1972 if ( nn == 0 ) /* point before the first strong point */
1973 {
1974 after = strongs[0];
1975
1976 point->cur_u = after->cur_u +
1977 FT_MulFix( point->org_u - after->org_u,
1978 scale );
1979 }
1980 else
1981 {
1982 before = strongs[nn - 1];
1983
1984 for ( nn = num_strongs; nn > 0; nn-- )
1985 if ( strongs[nn - 1]->org_u < point->org_u )
1986 break;
1987
1988 if ( nn == num_strongs ) /* point is after last strong point */
1989 {
1990 before = strongs[nn - 1];
1991
1992 point->cur_u = before->cur_u +
1993 FT_MulFix( point->org_u - before->org_u,
1994 scale );
1995 }
1996 else
1997 {
1998 FT_Pos u;
1999
2000
2001 after = strongs[nn];
2002
2003 /* now interpolate point between before and after */
2004 u = point->org_u;
2005
2006 if ( u == before->org_u )
2007 point->cur_u = before->cur_u;
2008
2009 else if ( u == after->org_u )
2010 point->cur_u = after->cur_u;
2011
2012 else
2013 point->cur_u = before->cur_u +
2014 FT_MulDiv( u - before->org_u,
2015 after->cur_u - before->cur_u,
2016 after->org_u - before->org_u );
2017 }
2018 }
2019 psh_point_set_fitted( point );
2020 }
2021 }
2022
2023 if ( strongs != strongs_0 )
2024 FT_FREE( strongs );
2025
2026 #endif /* 1 */
2027
2028 }
2029
2030
2031 /* interpolate other points */
2032 static void
2033 psh_glyph_interpolate_other_points( PSH_Glyph glyph,
2034 FT_Int dimension )
2035 {
2036 PSH_Dimension dim = &glyph->globals->dimension[dimension];
2037 FT_Fixed scale = dim->scale_mult;
2038 FT_Fixed delta = dim->scale_delta;
2039 PSH_Contour contour = glyph->contours;
2040 FT_UInt num_contours = glyph->num_contours;
2041
2042
2043 for ( ; num_contours > 0; num_contours--, contour++ )
2044 {
2045 PSH_Point start = contour->start;
2046 PSH_Point first, next, point;
2047 FT_UInt fit_count;
2048
2049
2050 /* count the number of strong points in this contour */
2051 next = start + contour->count;
2052 fit_count = 0;
2053 first = 0;
2054
2055 for ( point = start; point < next; point++ )
2056 if ( psh_point_is_fitted( point ) )
2057 {
2058 if ( !first )
2059 first = point;
2060
2061 fit_count++;
2062 }
2063
2064 /* if there are less than 2 fitted points in the contour, we */
2065 /* simply scale and eventually translate the contour points */
2066 if ( fit_count < 2 )
2067 {
2068 if ( fit_count == 1 )
2069 delta = first->cur_u - FT_MulFix( first->org_u, scale );
2070
2071 for ( point = start; point < next; point++ )
2072 if ( point != first )
2073 point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
2074
2075 goto Next_Contour;
2076 }
2077
2078 /* there are more than 2 strong points in this contour; we */
2079 /* need to interpolate weak points between them */
2080 start = first;
2081 do
2082 {
2083 point = first;
2084
2085 /* skip consecutive fitted points */
2086 for (;;)
2087 {
2088 next = first->next;
2089 if ( next == start )
2090 goto Next_Contour;
2091
2092 if ( !psh_point_is_fitted( next ) )
2093 break;
2094
2095 first = next;
2096 }
2097
2098 /* find next fitted point after unfitted one */
2099 for (;;)
2100 {
2101 next = next->next;
2102 if ( psh_point_is_fitted( next ) )
2103 break;
2104 }
2105
2106 /* now interpolate between them */
2107 {
2108 FT_Pos org_a, org_ab, cur_a, cur_ab;
2109 FT_Pos org_c, org_ac, cur_c;
2110 FT_Fixed scale_ab;
2111
2112
2113 if ( first->org_u <= next->org_u )
2114 {
2115 org_a = first->org_u;
2116 cur_a = first->cur_u;
2117 org_ab = next->org_u - org_a;
2118 cur_ab = next->cur_u - cur_a;
2119 }
2120 else
2121 {
2122 org_a = next->org_u;
2123 cur_a = next->cur_u;
2124 org_ab = first->org_u - org_a;
2125 cur_ab = first->cur_u - cur_a;
2126 }
2127
2128 scale_ab = 0x10000L;
2129 if ( org_ab > 0 )
2130 scale_ab = FT_DivFix( cur_ab, org_ab );
2131
2132 point = first->next;
2133 do
2134 {
2135 org_c = point->org_u;
2136 org_ac = org_c - org_a;
2137
2138 if ( org_ac <= 0 )
2139 {
2140 /* on the left of the interpolation zone */
2141 cur_c = cur_a + FT_MulFix( org_ac, scale );
2142 }
2143 else if ( org_ac >= org_ab )
2144 {
2145 /* on the right on the interpolation zone */
2146 cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
2147 }
2148 else
2149 {
2150 /* within the interpolation zone */
2151 cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
2152 }
2153
2154 point->cur_u = cur_c;
2155
2156 point = point->next;
2157
2158 } while ( point != next );
2159 }
2160
2161 /* keep going until all points in the contours have been processed */
2162 first = next;
2163
2164 } while ( first != start );
2165
2166 Next_Contour:
2167 ;
2168 }
2169 }
2170
2171
2172 /*************************************************************************/
2173 /*************************************************************************/
2174 /***** *****/
2175 /***** HIGH-LEVEL INTERFACE *****/
2176 /***** *****/
2177 /*************************************************************************/
2178 /*************************************************************************/
2179
2180 FT_Error
2181 ps_hints_apply( PS_Hints ps_hints,
2182 FT_Outline* outline,
2183 PSH_Globals globals,
2184 FT_Render_Mode hint_mode )
2185 {
2186 PSH_GlyphRec glyphrec;
2187 PSH_Glyph glyph = &glyphrec;
2188 FT_Error error;
2189 #ifdef DEBUG_HINTER
2190 FT_Memory memory;
2191 #endif
2192 FT_Int dimension;
2193
2194
2195 /* something to do? */
2196 if ( outline->n_points == 0 || outline->n_contours == 0 )
2197 return PSH_Err_Ok;
2198
2199 #ifdef DEBUG_HINTER
2200
2201 memory = globals->memory;
2202
2203 if ( ps_debug_glyph )
2204 {
2205 psh_glyph_done( ps_debug_glyph );
2206 FT_FREE( ps_debug_glyph );
2207 }
2208
2209 if ( FT_NEW( glyph ) )
2210 return error;
2211
2212 ps_debug_glyph = glyph;
2213
2214 #endif /* DEBUG_HINTER */
2215
2216 error = psh_glyph_init( glyph, outline, ps_hints, globals );
2217 if ( error )
2218 goto Exit;
2219
2220 /* try to optimize the y_scale so that the top of non-capital letters
2221 * is aligned on a pixel boundary whenever possible
2222 */
2223 {
2224 PSH_Dimension dim_x = &glyph->globals->dimension[0];
2225 PSH_Dimension dim_y = &glyph->globals->dimension[1];
2226
2227 FT_Fixed x_scale = dim_x->scale_mult;
2228 FT_Fixed y_scale = dim_y->scale_mult;
2229
2230 FT_Fixed old_x_scale = x_scale;
2231 FT_Fixed old_y_scale = y_scale;
2232
2233 FT_Fixed scaled;
2234 FT_Fixed fitted;
2235
2236 FT_Bool rescale = FALSE;
2237
2238
2239 scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale );
2240 fitted = FT_PIX_ROUND( scaled );
2241
2242 if ( fitted != 0 && scaled != fitted )
2243 {
2244 rescale = TRUE;
2245
2246 y_scale = FT_MulDiv( y_scale, fitted, scaled );
2247
2248 if ( fitted < scaled )
2249 x_scale -= x_scale / 50;
2250
2251 psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 );
2252 }
2253
2254 glyph->do_horz_hints = 1;
2255 glyph->do_vert_hints = 1;
2256
2257 glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
2258 hint_mode == FT_RENDER_MODE_LCD );
2259
2260 glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
2261 hint_mode == FT_RENDER_MODE_LCD_V );
2262
2263 glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
2264
2265 for ( dimension = 0; dimension < 2; dimension++ )
2266 {
2267 /* load outline coordinates into glyph */
2268 psh_glyph_load_points( glyph, dimension );
2269
2270 /* compute local extrema */
2271 psh_glyph_compute_extrema( glyph );
2272
2273 /* compute aligned stem/hints positions */
2274 psh_hint_table_align_hints( &glyph->hint_tables[dimension],
2275 glyph->globals,
2276 dimension,
2277 glyph );
2278
2279 /* find strong points, align them, then interpolate others */
2280 psh_glyph_find_strong_points( glyph, dimension );
2281 if ( dimension == 1 )
2282 psh_glyph_find_blue_points( &globals->blues, glyph );
2283 psh_glyph_interpolate_strong_points( glyph, dimension );
2284 psh_glyph_interpolate_normal_points( glyph, dimension );
2285 psh_glyph_interpolate_other_points( glyph, dimension );
2286
2287 /* save hinted coordinates back to outline */
2288 psh_glyph_save_points( glyph, dimension );
2289
2290 if ( rescale )
2291 psh_globals_set_scale( glyph->globals,
2292 old_x_scale, old_y_scale, 0, 0 );
2293 }
2294 }
2295
2296 Exit:
2297
2298 #ifndef DEBUG_HINTER
2299 psh_glyph_done( glyph );
2300 #endif
2301
2302 return error;
2303 }
2304
2305
2306 /* END */
FT_RENDER_MODE_MONO
Definition: freetype.h:2713
PSH_POINT_OFF
Definition: pshalgo.h:120
PSH_Hint_TableRec_::sort
PSH_Hint * sort
Definition: pshalgo.h:85
PSH_Globals
typedefFT_BEGIN_HEADER struct PSH_GlobalsRec_ * PSH_Globals
Definition: pshints.h:41
table
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glew.h:4422
PSH_ZoneRec_::delta
FT_Fixed delta
Definition: pshalgo.h:73
psh_hint_table_record_mask
static void psh_hint_table_record_mask(PSH_Hint_Table table, PS_Mask hint_mask)
Definition: pshalgo.c:146
psh_glyph_find_blue_points
static void psh_glyph_find_blue_points(PSH_Blues blues, PSH_Glyph glyph)
Definition: pshalgo.c:1753
FT_Error
int FT_Error
Definition: fttypes.h:296
psh_point_is_extremum
#define psh_point_is_extremum(p)
Definition: pshalgo.h:147
FT_DivFix
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:536
PS_Hint
typedefFT_BEGIN_HEADER struct PS_HintRec_ * PS_Hint
Definition: pshrec.h:52
PS_Mask_TableRec_::masks
PS_Mask masks
Definition: pshrec.h:113
PSH_PointRec_::dir_in
FT_Char dir_in
Definition: pshalgo.h:169
val
GLuint const GLfloat * val
Definition: glew.h:2715
psh_hint_is_active
#define psh_hint_is_active(x)
Definition: pshalgo.h:45
PSH_GlyphRec_::outline
FT_Outline * outline
Definition: pshalgo.h:212
PSH_Hint_TableRec_::hint_masks
PS_Mask_Table hint_masks
Definition: pshalgo.h:90
PSH_BluesRec_
Definition: pshglob.h:116
PSH_POINT_SMOOTH
Definition: pshalgo.h:121
FT_Pos
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:59
PSH_GlyphRec_::contours
PSH_Contour contours
Definition: pshalgo.h:209
FT_RENDER_MODE_LCD
Definition: freetype.h:2714
psh_glyph_interpolate_strong_points
static void psh_glyph_interpolate_strong_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:1828
PSH_PointRec_::prev
PSH_Point prev
Definition: pshalgo.h:164
PSH_DIR_NONE
Definition: pshalgo.h:101
PSH_DimensionRec_::stdw
PSH_WidthsRec stdw
Definition: pshglob.h:84
PSH_WidthRec_::cur
FT_Pos cur
Definition: pshglob.h:67
PSH_PointRec_::hint
PSH_Hint hint
Definition: pshalgo.h:173
PSH_BluesRec_::normal_bottom
PSH_Blue_TableRec normal_bottom
Definition: pshglob.h:119
PS_HintsRec_
Definition: pshrec.h:131
FT_MEM_ZERO
#define FT_MEM_ZERO(dest, count)
Definition: ftmemory.h:208
psh_compute_dir
static int psh_compute_dir(FT_Pos dx, FT_Pos dy)
Definition: pshalgo.c:1158
psh_point_set_fitted
#define psh_point_set_fitted(p)
Definition: pshalgo.h:154
NULL
#define NULL
Definition: ftobjs.h:61
FT_Int
signed int FT_Int
Definition: fttypes.h:216
start
GLuint start
Definition: glew.h:1239
PSH_BluesRec_::blue_fuzz
FT_Int blue_fuzz
Definition: pshglob.h:126
FT_Outline_::n_contours
short n_contours
Definition: ftimage.h:385
PSH_DIR_RIGHT
Definition: pshalgo.h:105
PS_MaskRec_
Definition: pshrec.h:98
PSH_GlyphRec_::num_points
FT_UInt num_points
Definition: pshalgo.h:205
PSH_Hint_TableRec_::hints
PSH_Hint hints
Definition: pshalgo.h:84
FT_ABS
#define FT_ABS(a)
Definition: ftobjs.h:73
FT_Render_Mode
enum FT_Render_Mode_ FT_Render_Mode
PSH_DimensionRec_::scale_mult
FT_Fixed scale_mult
Definition: pshglob.h:85
PSH_STRONG_THRESHOLD_MAXIMUM
#define PSH_STRONG_THRESHOLD_MAXIMUM
Definition: pshalgo.c:1665
n
GLclampd n
Definition: glew.h:7287
PSH_GlyphRec_::globals
PSH_Globals globals
Definition: pshalgo.h:213
FT_Outline_::contours
short * contours
Definition: ftimage.h:390
PSH_GlyphRec_::points
PSH_Point points
Definition: pshalgo.h:208
psh_hint_activate
#define psh_hint_activate(x)
Definition: pshalgo.h:49
psh_point_set_inflex
#define psh_point_set_inflex(p)
Definition: pshalgo.h:131
FT_Outline_::tags
char * tags
Definition: ftimage.h:389
PSH_DIR_VERTICAL
#define PSH_DIR_VERTICAL
Definition: pshalgo.h:109
FT_Char
signed char FT_Char
Definition: fttypes.h:139
FT_Outline_
Definition: ftimage.h:383
PSH_PointRec_::flags2
FT_UInt flags2
Definition: pshalgo.h:168
PSH_AlignmentRec_::align
int align
Definition: pshglob.h:151
PSH_GlyphRec_::do_horz_snapping
FT_Bool do_horz_snapping
Definition: pshalgo.h:222
PS_MaskRec_::end_point
FT_UInt end_point
Definition: pshrec.h:103
PSH_DIR_LEFT
Definition: pshalgo.h:104
psh_hint_table_done
static void psh_hint_table_done(PSH_Hint_Table table, FT_Memory memory)
Definition: pshalgo.c:66
PSH_BluesRec_::no_overshoots
FT_Bool no_overshoots
Definition: pshglob.h:127
PS_MaskRec_::num_bits
FT_UInt num_bits
Definition: pshrec.h:100
PSH_AlignmentRec_::align_bot
FT_Pos align_bot
Definition: pshglob.h:153
d
return Display return Display Bool Bool int d
Definition: SDL_x11sym.h:30
len
GLenum GLsizei len
Definition: glew.h:7035
psh_hint_snap_stem_side_delta
static FT_Fixed psh_hint_snap_stem_side_delta(FT_Fixed pos, FT_Fixed len)
Definition: pshalgo.c:425
PSH_BLUE_ALIGN_BOT
#define PSH_BLUE_ALIGN_BOT
Definition: pshglob.h:146
i2
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint GLint i2
Definition: SDL_glfuncs.h:118
PSH_PointRec_::org_u
FT_Pos org_u
Definition: pshalgo.h:174
psh_point_set_negative
#define psh_point_set_negative(p)
Definition: pshalgo.h:157
FT_Bool
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
PSH_GlyphRec_::memory
FT_Memory memory
Definition: pshalgo.h:211
PSH_POINT_EDGE_MAX
Definition: pshalgo.h:142
PSH_GlyphRec_::do_vert_snapping
FT_Bool do_vert_snapping
Definition: pshalgo.h:223
PSH_DIR_DOWN
Definition: pshalgo.h:103
PS_DimensionRec_::hints
PS_Hint_TableRec hints
Definition: pshrec.h:121
PSH_ZoneRec_::min
FT_Pos min
Definition: pshalgo.h:74
PSH_PointRec_::contour
PSH_Contour contour
Definition: pshalgo.h:166
PSH_GlyphRec_::hint_tables
PSH_Hint_TableRec hint_tables[2]
Definition: pshalgo.h:214
psh_hint_table_align_hints
static void psh_hint_table_align_hints(PSH_Hint_Table table, PSH_Globals globals, FT_Int dimension, PSH_Glyph glyph)
Definition: pshalgo.c:849
FT_Byte
unsigned char FT_Byte
Definition: fttypes.h:150
PSH_ContourRec_
Definition: pshalgo.h:195
psh_glyph_done
static void psh_glyph_done(PSH_Glyph glyph)
Definition: pshalgo.c:1139
PSH_Blue_ZoneRec_::org_bottom
FT_Int org_bottom
Definition: pshglob.h:97
PSH_ZoneRec_::scale
FT_Fixed scale
Definition: pshalgo.h:72
PSH_BluesRec_::normal_top
PSH_Blue_TableRec normal_top
Definition: pshglob.h:118
PSH_Hint
typedefFT_BEGIN_HEADER struct PSH_HintRec_ * PSH_Hint
Definition: pshalgo.h:32
psh_glyph_interpolate_normal_points
static void psh_glyph_interpolate_normal_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:1879
PS_HintsRec_::dimension
PS_DimensionRec dimension[2]
Definition: pshrec.h:137
PSH_PointRec_::org_v
FT_Pos org_v
Definition: pshalgo.h:175
FT_PIX_FLOOR
#define FT_PIX_FLOOR(x)
Definition: ftobjs.h:80
PS_Hint_TableRec_::num_hints
FT_UInt num_hints
Definition: pshrec.h:90
FT_FREE
#define FT_FREE(ptr)
Definition: ftmemory.h:286
u
ALuint u
Definition: alMain.h:58
PSH_PointRec_::cur_u
FT_Pos cur_u
Definition: pshalgo.h:176
first
GLint first
Definition: gl2ext.h:1011
result
GLuint64EXT * result
Definition: glew.h:12708
FT_LOCAL_DEF
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:467
idx
FT_UInt idx
Definition: cffcmap.c:125
PSH_ContourRec_::count
FT_UInt count
Definition: pshalgo.h:198
FT_MulDiv
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:358
error
FT_Error error
Definition: cffdrivr.c:407
FT_Vector_::x
FT_Pos x
Definition: ftimage.h:77
FT_TRACE0
#define FT_TRACE0(varformat)
Definition: ftdebug.h:157
PSH_Blue_ZoneRec_::cur_top
FT_Pos cur_top
Definition: pshglob.h:102
PSH_Hint_TableRec_::max_hints
FT_UInt max_hints
Definition: pshalgo.h:82
count
GLint GLsizei count
Definition: gl2ext.h:1011
PSH_PointRec_::flags
FT_UInt flags
Definition: pshalgo.h:167
psh_glyph_compute_inflections
static void psh_glyph_compute_inflections(PSH_Glyph glyph)
Definition: pshalgo.c:1031
psh_hint_set_fitted
#define psh_hint_set_fitted(x)
Definition: pshalgo.h:51
FT_Vector_::y
FT_Pos y
Definition: ftimage.h:78
PSH_Hint_TableRec_
Definition: pshalgo.h:80
PSH_Blue_TableRec_
Definition: pshglob.h:107
psh_point_is_strong
#define psh_point_is_strong(p)
Definition: pshalgo.h:145
PSH_DIR_UP
Definition: pshalgo.h:102
PSH_PointRec_::next
PSH_Point next
Definition: pshalgo.h:165
PSH_MAX_STRONG_INTERNAL
#define PSH_MAX_STRONG_INTERNAL
Definition: pshalgo.c:1876
PSH_BLUE_ALIGN_TOP
#define PSH_BLUE_ALIGN_TOP
Definition: pshglob.h:145
limit
GLint limit
Definition: glew.h:11829
pshnterr.h
PSH_ZoneRec_::max
FT_Pos max
Definition: pshalgo.h:75
FT_Vector_
Definition: ftimage.h:75
pshalgo.h
psh_hint_deactivate
#define psh_hint_deactivate(x)
Definition: pshalgo.h:50
PSH_DIR_COMPARE
#define PSH_DIR_COMPARE(d1, d2)
Definition: pshalgo.h:111
PSH_Hint_TableRec_::num_hints
FT_UInt num_hints
Definition: pshalgo.h:83
vec
FT_Vector * vec
Definition: ftbbox.c:579
psh_glyph_interpolate_other_points
static void psh_glyph_interpolate_other_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:2033
psh_glyph_find_strong_points
static void psh_glyph_find_strong_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:1670
PSH_Hint_TableRec_::zones
PSH_ZoneRec * zones
Definition: pshalgo.h:88
PSH_BLUE_ALIGN_NONE
#define PSH_BLUE_ALIGN_NONE
Definition: pshglob.h:144
FALSE
#define FALSE
Definition: ftobjs.h:57
PSH_Blue_ZoneRec_::org_top
FT_Int org_top
Definition: pshglob.h:96
FT_Outline_::n_points
short n_points
Definition: ftimage.h:386
psh_hint_table_find_strong_points
static void psh_hint_table_find_strong_points(PSH_Hint_Table table, PSH_Point point, FT_UInt count, FT_Int threshold, FT_Int major_dir)
Definition: pshalgo.c:1517
scale
GLenum GLenum GLenum GLenum GLenum scale
Definition: glew.h:12632
PSH_PointRec_::dir_out
FT_Char dir_out
Definition: pshalgo.h:170
PS_Mask_TableRec_
Definition: pshrec.h:109
PSH_Hint_TableRec_::sort_global
PSH_Hint * sort_global
Definition: pshalgo.h:86
PS_DimensionRec_::counters
PS_Mask_TableRec counters
Definition: pshrec.h:123
FT_Memory
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
psh_point_is_fitted
#define psh_point_is_fitted(p)
Definition: pshalgo.h:146
FT_BOOL
#define FT_BOOL(x)
Definition: fttypes.h:581
i1
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint i1
Definition: SDL_glfuncs.h:118
PSH_Blue_TableRec_::count
FT_UInt count
Definition: pshglob.h:109
PSH_ZoneRec_
Definition: pshalgo.h:70
ps_hints_apply
FT_Error ps_hints_apply(PS_Hints ps_hints, FT_Outline *outline, PSH_Globals globals, FT_Render_Mode hint_mode)
Definition: pshalgo.c:2181
FT_NEW_ARRAY
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:290
y
EGLSurface EGLint EGLint y
Definition: eglext.h:293
FT_MulFix
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:435
PSH_GlyphRec_
Definition: pshalgo.h:203
PSH_AlignmentRec_::align_top
FT_Pos align_top
Definition: pshglob.h:152
PSH_Blue_ZoneRec_::cur_bottom
FT_Pos cur_bottom
Definition: pshglob.h:101
PSH_POINT_POSITIVE
Definition: pshalgo.h:139
psh_hint_overlap
static FT_Int psh_hint_overlap(PSH_Hint hint1, PSH_Hint hint2)
Definition: pshalgo.c:56
PSH_DimensionRec_
Definition: pshglob.h:82
psh_glyph_load_points
static void psh_glyph_load_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:1185
PSH_STRONG_THRESHOLD
#define PSH_STRONG_THRESHOLD
Definition: pshalgo.c:1662
FT_RENDER_MODE_LCD_V
Definition: freetype.h:2715
PSH_POINT_EDGE_MIN
Definition: pshalgo.h:141
PSH_ContourRec_::start
PSH_Point start
Definition: pshalgo.h:197
PSH_PointRec_
Definition: pshalgo.h:162
ft2build.h
FT_Fixed
signed long FT_Fixed
Definition: fttypes.h:284
PSH_WidthsRec_::widths
PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS]
Definition: pshglob.h:77
PS_DimensionRec_::masks
PS_Mask_TableRec masks
Definition: pshrec.h:122
PSH_Hint_TableRec_::zone
PSH_Zone zone
Definition: pshalgo.h:89
PSH_Blue_TableRec_::zones
PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES]
Definition: pshglob.h:110
FT_UInt
unsigned int FT_UInt
Definition: fttypes.h:227
psh_point_is_edge_min
#define psh_point_is_edge_min(p)
Definition: pshalgo.h:150
psh_hint_is_fitted
#define psh_hint_is_fitted(x)
Definition: pshalgo.h:47
PSH_POINT_NEGATIVE
Definition: pshalgo.h:140
mask
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition: gl2ext.h:961
PSH_GlyphRec_::do_stem_adjust
FT_Bool do_stem_adjust
Definition: pshalgo.h:224
psh_point_is_smooth
#define psh_point_is_smooth(p)
Definition: pshalgo.h:125
FT_RENDER_MODE_LIGHT
Definition: freetype.h:2712
end
GLuint GLuint end
Definition: glew.h:1239
PSH_DIR_HORIZONTAL
#define PSH_DIR_HORIZONTAL
Definition: pshalgo.h:108
PSH_GlyphRec_::num_contours
FT_UInt num_contours
Definition: pshalgo.h:206
PSH_AlignmentRec_
Definition: pshglob.h:149
psh_dimension_quantize_len
static FT_Pos psh_dimension_quantize_len(PSH_Dimension dim, FT_Pos len, FT_Bool do_snapping)
Definition: pshalgo.c:347
PSH_Hint_TableRec_::num_zones
FT_UInt num_zones
Definition: pshalgo.h:87
FT_CURVE_TAG_ON
#define FT_CURVE_TAG_ON
Definition: ftimage.h:516
points
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3337
psh_hint_table_init
static FT_Error psh_hint_table_init(PSH_Hint_Table table, PS_Hint_Table hints, PS_Mask_Table hint_masks, PS_Mask_Table counter_masks, FT_Memory memory)
Definition: pshalgo.c:174
psh_glyph_save_points
static void psh_glyph_save_points(PSH_Glyph glyph, FT_Int dimension)
Definition: pshalgo.c:1219
PS_Hint_TableRec_
Definition: pshrec.h:88
FT_NEW
#define FT_NEW(ptr)
Definition: ftmemory.h:288
psh_hint_table_deactivate
static void psh_hint_table_deactivate(PSH_Hint_Table table)
Definition: pshalgo.c:83
psh_glyph_compute_extrema
static void psh_glyph_compute_extrema(PSH_Glyph glyph)
Definition: pshalgo.c:1393
psh_point_is_edge_max
#define psh_point_is_edge_max(p)
Definition: pshalgo.h:151
psh_corner_orientation
#define psh_corner_orientation
Definition: pshalgo.c:932
psh_point_set_strong
#define psh_point_set_strong(p)
Definition: pshalgo.h:153
psh_point_set_positive
#define psh_point_set_positive(p)
Definition: pshalgo.h:156
psh_hint_align
static void psh_hint_align(PSH_Hint hint, PSH_Globals globals, FT_Int dimension, PSH_Glyph glyph)
Definition: pshalgo.c:440
psh_print_zone
#define psh_print_zone(x)
Definition: pshalgo.c:916
PS_Hint_TableRec_::hints
PS_Hint hints
Definition: pshrec.h:92
PSH_DimensionRec_::scale_delta
FT_Fixed scale_delta
Definition: pshglob.h:86
psh_point_set_extremum
#define psh_point_set_extremum(p)
Definition: pshalgo.h:155
FT_UNUSED
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
psh_blues_snap_stem
psh_blues_snap_stem(PSH_Blues blues, FT_Int stem_top, FT_Int stem_bot, PSH_Alignment alignment)
Definition: pshglob.c:526
psh_hint_table_record
static void psh_hint_table_record(PSH_Hint_Table table, FT_UInt idx)
Definition: pshalgo.c:99
psh_hint_table_activate_mask
static void psh_hint_table_activate_mask(PSH_Hint_Table table, PS_Mask hint_mask)
Definition: pshalgo.c:247
TRUE
#define TRUE
Definition: ftobjs.h:53
PS_Mask_TableRec_::num_masks
FT_UInt num_masks
Definition: pshrec.h:111
FT_Outline_::points
FT_Vector * points
Definition: ftimage.h:388
PS_MaskRec_::bytes
FT_Byte * bytes
Definition: pshrec.h:102
PSH_Blue_ZoneRec_
Definition: pshglob.h:92
psh_glyph_init
static FT_Error psh_glyph_init(PSH_Glyph glyph, FT_Outline *outline, PS_Hints ps_hints, PSH_Globals globals)
Definition: pshalgo.c:1259
FT_PIX_ROUND
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:81
PSH_GlyphRec_::do_vert_hints
FT_Bool do_vert_hints
Definition: pshalgo.h:221
psh_globals_set_scale
psh_globals_set_scale(PSH_Globals globals, FT_Fixed x_scale, FT_Fixed y_scale, FT_Fixed x_delta, FT_Fixed y_delta)
Definition: pshglob.c:707
psh_corner_is_flat
#define psh_corner_is_flat
Definition: pshalgo.c:931
psh_point_is_inflex
#define psh_point_is_inflex(p)
Definition: pshalgo.h:127
PSH_GlyphRec_::do_horz_hints
FT_Bool do_horz_hints
Definition: pshalgo.h:220