ReactOS 0.4.16-dev-329-g9223134
aflatin.c
Go to the documentation of this file.
1/***************************************************************************/
2/* */
3/* aflatin.c */
4/* */
5/* Auto-fitter hinting routines for latin writing system (body). */
6/* */
7/* Copyright 2003-2018 by */
8/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include FT_ADVANCES_H
21#include FT_INTERNAL_DEBUG_H
22
23#include "afglobal.h"
24#include "afpic.h"
25#include "aflatin.h"
26#include "aferrors.h"
27
28
29#ifdef AF_CONFIG_OPTION_USE_WARPER
30#include "afwarp.h"
31#endif
32
33
34 /*************************************************************************/
35 /* */
36 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
37 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
38 /* messages during execution. */
39 /* */
40#undef FT_COMPONENT
41#define FT_COMPONENT trace_aflatin
42
43
44 /* needed for computation of round vs. flat segments */
45#define FLAT_THRESHOLD( x ) ( x / 14 )
46
47
48 /*************************************************************************/
49 /*************************************************************************/
50 /***** *****/
51 /***** L A T I N G L O B A L M E T R I C S *****/
52 /***** *****/
53 /*************************************************************************/
54 /*************************************************************************/
55
56
57 /* Find segments and links, compute all stem widths, and initialize */
58 /* standard width and height for the glyph with given charcode. */
59
60 FT_LOCAL_DEF( void )
63 {
64 /* scan the array of segments in each direction */
65#ifdef __REACTOS__
67 if (!hints) return;
68#else
70#endif
71
72
73 FT_TRACE5(( "\n"
74 "latin standard widths computation (style `%s')\n"
75 "=====================================================\n"
76 "\n",
77 af_style_names[metrics->root.style_class->style] ));
78
79 af_glyph_hints_init( hints, face->memory );
80
81 metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
82 metrics->axis[AF_DIMENSION_VERT].width_count = 0;
83
84 {
86 FT_ULong glyph_index;
87 int dim;
88#ifdef __REACTOS__
90 if (!dummy)
91 goto Exit;
92 {
93#else
95#endif
96 AF_Scaler scaler = &dummy->root.scaler;
97
98#ifdef FT_CONFIG_OPTION_PIC
99 AF_FaceGlobals globals = metrics->root.globals;
100#endif
101
102 AF_StyleClass style_class = metrics->root.style_class;
104 [style_class->script];
105
106 void* shaper_buf;
107 const char* p;
108
109#ifdef FT_DEBUG_LEVEL_TRACE
110 FT_ULong ch = 0;
111#endif
112
113 p = script_class->standard_charstring;
114 shaper_buf = af_shaper_buf_create( face );
115
116 /*
117 * We check a list of standard characters to catch features like
118 * `c2sc' (small caps from caps) that don't contain lowercase letters
119 * by definition, or other features that mainly operate on numerals.
120 * The first match wins.
121 */
122
123 glyph_index = 0;
124 while ( *p )
125 {
126 unsigned int num_idx;
127
128#ifdef FT_DEBUG_LEVEL_TRACE
129 const char* p_old;
130#endif
131
132
133 while ( *p == ' ' )
134 p++;
135
136#ifdef FT_DEBUG_LEVEL_TRACE
137 p_old = p;
138 GET_UTF8_CHAR( ch, p_old );
139#endif
140
141 /* reject input that maps to more than a single glyph */
142 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
143 if ( num_idx > 1 )
144 continue;
145
146 /* otherwise exit loop if we have a result */
147 glyph_index = af_shaper_get_elem( &metrics->root,
148 shaper_buf,
149 0,
150 NULL,
151 NULL );
152 if ( glyph_index )
153 break;
154 }
155
156 af_shaper_buf_destroy( face, shaper_buf );
157
158 if ( !glyph_index )
159 goto Exit;
160
161 FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
162 ch, glyph_index ));
163
164 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
165 if ( error || face->glyph->outline.n_points <= 0 )
166 goto Exit;
167
168 FT_ZERO( dummy );
169
170 dummy->units_per_em = metrics->units_per_em;
171
172 scaler->x_scale = 0x10000L;
173 scaler->y_scale = 0x10000L;
174 scaler->x_delta = 0;
175 scaler->y_delta = 0;
176
177 scaler->face = face;
179 scaler->flags = 0;
180
182
183 error = af_glyph_hints_reload( hints, &face->glyph->outline );
184 if ( error )
185 goto Exit;
186
187 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
188 {
189 AF_LatinAxis axis = &metrics->axis[dim];
190 AF_AxisHints axhints = &hints->axis[dim];
191 AF_Segment seg, limit, link;
192 FT_UInt num_widths = 0;
193
194
196 (AF_Dimension)dim );
197 if ( error )
198 goto Exit;
199
200 /*
201 * We assume that the glyphs selected for the stem width
202 * computation are `featureless' enough so that the linking
203 * algorithm works fine without adjustments of its scoring
204 * function.
205 */
207 0,
208 NULL,
209 (AF_Dimension)dim );
210
211 seg = axhints->segments;
212 limit = seg + axhints->num_segments;
213
214 for ( ; seg < limit; seg++ )
215 {
216 link = seg->link;
217
218 /* we only consider stem segments there! */
219 if ( link && link->link == seg && link > seg )
220 {
221 FT_Pos dist;
222
223
224 dist = seg->pos - link->pos;
225 if ( dist < 0 )
226 dist = -dist;
227
228 if ( num_widths < AF_LATIN_MAX_WIDTHS )
229 axis->widths[num_widths++].org = dist;
230 }
231 }
232
233 /* this also replaces multiple almost identical stem widths */
234 /* with a single one (the value 100 is heuristic) */
235 af_sort_and_quantize_widths( &num_widths, axis->widths,
236 dummy->units_per_em / 100 );
237 axis->width_count = num_widths;
238 }
239
240 Exit:
241 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
242 {
243 AF_LatinAxis axis = &metrics->axis[dim];
244 FT_Pos stdw;
245
246
247 stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
248 : AF_LATIN_CONSTANT( metrics, 50 );
249
250 /* let's try 20% of the smallest width */
251 axis->edge_distance_threshold = stdw / 5;
252 axis->standard_width = stdw;
253 axis->extra_light = 0;
254
255#ifdef FT_DEBUG_LEVEL_TRACE
256 {
257 FT_UInt i;
258
259
260 FT_TRACE5(( "%s widths:\n",
261 dim == AF_DIMENSION_VERT ? "horizontal"
262 : "vertical" ));
263
264 FT_TRACE5(( " %d (standard)", axis->standard_width ));
265 for ( i = 1; i < axis->width_count; i++ )
266 FT_TRACE5(( " %d", axis->widths[i].org ));
267
268 FT_TRACE5(( "\n" ));
269 }
270#endif
271 }
272#ifdef __REACTOS__
273 free(dummy);
274 }
275#endif
276 }
277
278 FT_TRACE5(( "\n" ));
279
281
282#ifdef __REACTOS__
283 free(hints);
284#endif
285
286 }
287
288
289 static void
292 {
293 FT_UInt i, j;
295
296
297 /* we sort from bottom to top */
298 for ( i = 1; i < count; i++ )
299 {
300 for ( j = i; j > 0; j-- )
301 {
302 FT_Pos a, b;
303
304
305 if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP |
307 a = table[j - 1]->ref.org;
308 else
309 a = table[j - 1]->shoot.org;
310
311 if ( table[j]->flags & ( AF_LATIN_BLUE_TOP |
313 b = table[j]->ref.org;
314 else
315 b = table[j]->shoot.org;
316
317 if ( b >= a )
318 break;
319
320 swap = table[j];
321 table[j] = table[j - 1];
322 table[j - 1] = swap;
323 }
324 }
325 }
326
327
328 /* Find all blue zones. Flat segments give the reference points, */
329 /* round segments the overshoot positions. */
330
331 static void
333 FT_Face face )
334 {
337
338 FT_UInt num_flats;
339 FT_UInt num_rounds;
340
345
346 AF_StyleClass sc = metrics->root.style_class;
347
350
351 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
352
353 void* shaper_buf;
354
355
356 /* we walk over the blue character strings as specified in the */
357 /* style's entry in the `af_blue_stringset' array */
358
359 FT_TRACE5(( "latin blue zones computation\n"
360 "============================\n"
361 "\n" ));
362
363 shaper_buf = af_shaper_buf_create( face );
364
365 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
366 {
367 const char* p = &af_blue_strings[bs->string];
368 FT_Pos* blue_ref;
369 FT_Pos* blue_shoot;
370 FT_Pos ascender;
371 FT_Pos descender;
372
373
374#ifdef FT_DEBUG_LEVEL_TRACE
375 {
376 FT_Bool have_flag = 0;
377
378
379 FT_TRACE5(( "blue zone %d", axis->blue_count ));
380
381 if ( bs->properties )
382 {
383 FT_TRACE5(( " (" ));
384
385 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
386 {
387 FT_TRACE5(( "top" ));
388 have_flag = 1;
389 }
390 else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
391 {
392 FT_TRACE5(( "sub top" ));
393 have_flag = 1;
394 }
395
397 {
398 if ( have_flag )
399 FT_TRACE5(( ", " ));
400 FT_TRACE5(( "neutral" ));
401 have_flag = 1;
402 }
403
405 {
406 if ( have_flag )
407 FT_TRACE5(( ", " ));
408 FT_TRACE5(( "small top" ));
409 have_flag = 1;
410 }
411
412 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
413 {
414 if ( have_flag )
415 FT_TRACE5(( ", " ));
416 FT_TRACE5(( "long" ));
417 }
418
419 FT_TRACE5(( ")" ));
420 }
421
422 FT_TRACE5(( ":\n" ));
423 }
424#endif /* FT_DEBUG_LEVEL_TRACE */
425
426 num_flats = 0;
427 num_rounds = 0;
428 ascender = 0;
429 descender = 0;
430
431 while ( *p )
432 {
433 FT_ULong glyph_index;
434 FT_Long y_offset;
435 FT_Int best_point, best_contour_first, best_contour_last;
437
438 FT_Pos best_y_extremum; /* same as points.y */
439 FT_Bool best_round = 0;
440
441 unsigned int i, num_idx;
442
443#ifdef FT_DEBUG_LEVEL_TRACE
444 const char* p_old;
445 FT_ULong ch;
446#endif
447
448
449 while ( *p == ' ' )
450 p++;
451
452#ifdef FT_DEBUG_LEVEL_TRACE
453 p_old = p;
454 GET_UTF8_CHAR( ch, p_old );
455#endif
456
457 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
458
459 if ( !num_idx )
460 {
461 FT_TRACE5(( " U+%04lX unavailable\n", ch ));
462 continue;
463 }
464
465 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
466 best_y_extremum = FT_INT_MIN;
467 else
468 best_y_extremum = FT_INT_MAX;
469
470 /* iterate over all glyph elements of the character cluster */
471 /* and get the data of the `biggest' one */
472 for ( i = 0; i < num_idx; i++ )
473 {
474 FT_Pos best_y;
475 FT_Bool round = 0;
476
477
478 /* load the character in the face -- skip unknown or empty ones */
479 glyph_index = af_shaper_get_elem( &metrics->root,
480 shaper_buf,
481 i,
482 NULL,
483 &y_offset );
484 if ( glyph_index == 0 )
485 {
486 FT_TRACE5(( " U+%04lX unavailable\n", ch ));
487 continue;
488 }
489
490 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
491 outline = face->glyph->outline;
492 /* reject glyphs that don't produce any rendering */
493 if ( error || outline.n_points <= 2 )
494 {
495#ifdef FT_DEBUG_LEVEL_TRACE
496 if ( num_idx == 1 )
497 FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch ));
498 else
499 FT_TRACE5(( " component %d of cluster starting with U+%04lX"
500 " contains no (usable) outlines\n", i, ch ));
501#endif
502 continue;
503 }
504
505 /* now compute min or max point indices and coordinates */
506 points = outline.points;
507 best_point = -1;
508 best_y = 0; /* make compiler happy */
509 best_contour_first = 0; /* ditto */
510 best_contour_last = 0; /* ditto */
511
512 {
513 FT_Int nn;
514 FT_Int first = 0;
515 FT_Int last = -1;
516
517
518 for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
519 {
520 FT_Int old_best_point = best_point;
521 FT_Int pp;
522
523
524 last = outline.contours[nn];
525
526 /* Avoid single-point contours since they are never */
527 /* rasterized. In some fonts, they correspond to mark */
528 /* attachment points that are way outside of the glyph's */
529 /* real outline. */
530 if ( last <= first )
531 continue;
532
533 if ( AF_LATIN_IS_TOP_BLUE( bs ) ||
535 {
536 for ( pp = first; pp <= last; pp++ )
537 {
538 if ( best_point < 0 || points[pp].y > best_y )
539 {
540 best_point = pp;
541 best_y = points[pp].y;
542 ascender = FT_MAX( ascender, best_y + y_offset );
543 }
544 else
545 descender = FT_MIN( descender, points[pp].y + y_offset );
546 }
547 }
548 else
549 {
550 for ( pp = first; pp <= last; pp++ )
551 {
552 if ( best_point < 0 || points[pp].y < best_y )
553 {
554 best_point = pp;
555 best_y = points[pp].y;
556 descender = FT_MIN( descender, best_y + y_offset );
557 }
558 else
559 ascender = FT_MAX( ascender, points[pp].y + y_offset );
560 }
561 }
562
563 if ( best_point != old_best_point )
564 {
565 best_contour_first = first;
566 best_contour_last = last;
567 }
568 }
569 }
570
571 /* now check whether the point belongs to a straight or round */
572 /* segment; we first need to find in which contour the extremum */
573 /* lies, then inspect its previous and next points */
574 if ( best_point >= 0 )
575 {
576 FT_Pos best_x = points[best_point].x;
577 FT_Int prev, next;
578 FT_Int best_segment_first, best_segment_last;
579 FT_Int best_on_point_first, best_on_point_last;
580 FT_Pos dist;
581
582
583 best_segment_first = best_point;
584 best_segment_last = best_point;
585
586 if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
587 {
588 best_on_point_first = best_point;
589 best_on_point_last = best_point;
590 }
591 else
592 {
593 best_on_point_first = -1;
594 best_on_point_last = -1;
595 }
596
597 /* look for the previous and next points on the contour */
598 /* that are not on the same Y coordinate, then threshold */
599 /* the `closeness'... */
600 prev = best_point;
601 next = prev;
602
603 do
604 {
605 if ( prev > best_contour_first )
606 prev--;
607 else
608 prev = best_contour_last;
609
610 dist = FT_ABS( points[prev].y - best_y );
611 /* accept a small distance or a small angle (both values are */
612 /* heuristic; value 20 corresponds to approx. 2.9 degrees) */
613 if ( dist > 5 )
614 if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
615 break;
616
617 best_segment_first = prev;
618
619 if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
620 {
621 best_on_point_first = prev;
622 if ( best_on_point_last < 0 )
623 best_on_point_last = prev;
624 }
625
626 } while ( prev != best_point );
627
628 do
629 {
630 if ( next < best_contour_last )
631 next++;
632 else
633 next = best_contour_first;
634
635 dist = FT_ABS( points[next].y - best_y );
636 if ( dist > 5 )
637 if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
638 break;
639
640 best_segment_last = next;
641
642 if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
643 {
644 best_on_point_last = next;
645 if ( best_on_point_first < 0 )
646 best_on_point_first = next;
647 }
648
649 } while ( next != best_point );
650
651 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
652 {
653 /* If this flag is set, we have an additional constraint to */
654 /* get the blue zone distance: Find a segment of the topmost */
655 /* (or bottommost) contour that is longer than a heuristic */
656 /* threshold. This ensures that small bumps in the outline */
657 /* are ignored (for example, the `vertical serifs' found in */
658 /* many Hebrew glyph designs). */
659
660 /* If this segment is long enough, we are done. Otherwise, */
661 /* search the segment next to the extremum that is long */
662 /* enough, has the same direction, and a not too large */
663 /* vertical distance from the extremum. Note that the */
664 /* algorithm doesn't check whether the found segment is */
665 /* actually the one (vertically) nearest to the extremum. */
666
667 /* heuristic threshold value */
668 FT_Pos length_threshold = metrics->units_per_em / 25;
669
670
671 dist = FT_ABS( points[best_segment_last].x -
672 points[best_segment_first].x );
673
674 if ( dist < length_threshold &&
675 best_segment_last - best_segment_first + 2 <=
676 best_contour_last - best_contour_first )
677 {
678 /* heuristic threshold value */
679 FT_Pos height_threshold = metrics->units_per_em / 4;
680
682 FT_Int last;
683 FT_Bool hit;
684
685 /* we intentionally declare these two variables */
686 /* outside of the loop since various compilers emit */
687 /* incorrect warning messages otherwise, talking about */
688 /* `possibly uninitialized variables' */
689 FT_Int p_first = 0; /* make compiler happy */
690 FT_Int p_last = 0;
691
692 FT_Bool left2right;
693
694
695 /* compute direction */
696 prev = best_point;
697
698 do
699 {
700 if ( prev > best_contour_first )
701 prev--;
702 else
703 prev = best_contour_last;
704
705 if ( points[prev].x != best_x )
706 break;
707
708 } while ( prev != best_point );
709
710 /* skip glyph for the degenerate case */
711 if ( prev == best_point )
712 continue;
713
714 left2right = FT_BOOL( points[prev].x < points[best_point].x );
715
716 first = best_segment_last;
717 last = first;
718 hit = 0;
719
720 do
721 {
722 FT_Bool l2r;
723 FT_Pos d;
724
725
726 if ( !hit )
727 {
728 /* no hit; adjust first point */
729 first = last;
730
731 /* also adjust first and last on point */
732 if ( FT_CURVE_TAG( outline.tags[first] ) ==
734 {
735 p_first = first;
736 p_last = first;
737 }
738 else
739 {
740 p_first = -1;
741 p_last = -1;
742 }
743
744 hit = 1;
745 }
746
747 if ( last < best_contour_last )
748 last++;
749 else
750 last = best_contour_first;
751
752 if ( FT_ABS( best_y - points[first].y ) > height_threshold )
753 {
754 /* vertical distance too large */
755 hit = 0;
756 continue;
757 }
758
759 /* same test as above */
760 dist = FT_ABS( points[last].y - points[first].y );
761 if ( dist > 5 )
762 if ( FT_ABS( points[last].x - points[first].x ) <=
763 20 * dist )
764 {
765 hit = 0;
766 continue;
767 }
768
769 if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
770 {
771 p_last = last;
772 if ( p_first < 0 )
773 p_first = last;
774 }
775
776 l2r = FT_BOOL( points[first].x < points[last].x );
777 d = FT_ABS( points[last].x - points[first].x );
778
779 if ( l2r == left2right &&
780 d >= length_threshold )
781 {
782 /* all constraints are met; update segment after */
783 /* finding its end */
784 do
785 {
786 if ( last < best_contour_last )
787 last++;
788 else
789 last = best_contour_first;
790
791 d = FT_ABS( points[last].y - points[first].y );
792 if ( d > 5 )
793 if ( FT_ABS( points[next].x - points[first].x ) <=
794 20 * dist )
795 {
796 if ( last > best_contour_first )
797 last--;
798 else
799 last = best_contour_last;
800 break;
801 }
802
803 p_last = last;
804
805 if ( FT_CURVE_TAG( outline.tags[last] ) ==
807 {
808 p_last = last;
809 if ( p_first < 0 )
810 p_first = last;
811 }
812
813 } while ( last != best_segment_first );
814
815 best_y = points[first].y;
816
817 best_segment_first = first;
818 best_segment_last = last;
819
820 best_on_point_first = p_first;
821 best_on_point_last = p_last;
822
823 break;
824 }
825
826 } while ( last != best_segment_first );
827 }
828 }
829
830 /* for computing blue zones, we add the y offset as returned */
831 /* by the currently used OpenType feature -- for example, */
832 /* superscript glyphs might be identical to subscript glyphs */
833 /* with a vertical shift */
834 best_y += y_offset;
835
836#ifdef FT_DEBUG_LEVEL_TRACE
837 if ( num_idx == 1 )
838 FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
839 else
840 FT_TRACE5(( " component %d of cluster starting with U+%04lX:"
841 " best_y = %5ld", i, ch, best_y ));
842#endif
843
844 /* now set the `round' flag depending on the segment's kind: */
845 /* */
846 /* - if the horizontal distance between the first and last */
847 /* `on' point is larger than a heuristic threshold */
848 /* we have a flat segment */
849 /* - if either the first or the last point of the segment is */
850 /* an `off' point, the segment is round, otherwise it is */
851 /* flat */
852 if ( best_on_point_first >= 0 &&
853 best_on_point_last >= 0 &&
854 ( FT_ABS( points[best_on_point_last].x -
855 points[best_on_point_first].x ) ) >
856 flat_threshold )
857 round = 0;
858 else
859 round = FT_BOOL(
860 FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
862 FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
864
866 {
867 /* only use flat segments for a neutral blue zone */
868 FT_TRACE5(( " (round, skipped)\n" ));
869 continue;
870 }
871
872 FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
873 }
874
875 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
876 {
877 if ( best_y > best_y_extremum )
878 {
879 best_y_extremum = best_y;
880 best_round = round;
881 }
882 }
883 else
884 {
885 if ( best_y < best_y_extremum )
886 {
887 best_y_extremum = best_y;
888 best_round = round;
889 }
890 }
891
892 } /* end for loop */
893
894 if ( !( best_y_extremum == FT_INT_MIN ||
895 best_y_extremum == FT_INT_MAX ) )
896 {
897 if ( best_round )
898 rounds[num_rounds++] = best_y_extremum;
899 else
900 flats[num_flats++] = best_y_extremum;
901 }
902
903 } /* end while loop */
904
905 if ( num_flats == 0 && num_rounds == 0 )
906 {
907 /*
908 * we couldn't find a single glyph to compute this blue zone,
909 * we will simply ignore it then
910 */
911 FT_TRACE5(( " empty\n" ));
912 continue;
913 }
914
915 /* we have computed the contents of the `rounds' and `flats' tables, */
916 /* now determine the reference and overshoot position of the blue -- */
917 /* we simply take the median value after a simple sort */
918 af_sort_pos( num_rounds, rounds );
919 af_sort_pos( num_flats, flats );
920
921 blue = &axis->blues[axis->blue_count];
922 blue_ref = &blue->ref.org;
923 blue_shoot = &blue->shoot.org;
924
925 axis->blue_count++;
926
927 if ( num_flats == 0 )
928 {
929 *blue_ref =
930 *blue_shoot = rounds[num_rounds / 2];
931 }
932 else if ( num_rounds == 0 )
933 {
934 *blue_ref =
935 *blue_shoot = flats[num_flats / 2];
936 }
937 else
938 {
939 *blue_ref = flats [num_flats / 2];
940 *blue_shoot = rounds[num_rounds / 2];
941 }
942
943 /* there are sometimes problems: if the overshoot position of top */
944 /* zones is under its reference position, or the opposite for bottom */
945 /* zones. We must thus check everything there and correct the errors */
946 if ( *blue_shoot != *blue_ref )
947 {
948 FT_Pos ref = *blue_ref;
949 FT_Pos shoot = *blue_shoot;
950 FT_Bool over_ref = FT_BOOL( shoot > ref );
951
952
953 if ( ( AF_LATIN_IS_TOP_BLUE( bs ) ||
954 AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
955 {
956 *blue_ref =
957 *blue_shoot = ( shoot + ref ) / 2;
958
959 FT_TRACE5(( " [overshoot smaller than reference,"
960 " taking mean value]\n" ));
961 }
962 }
963
964 blue->ascender = ascender;
965 blue->descender = descender;
966
967 blue->flags = 0;
968 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
969 blue->flags |= AF_LATIN_BLUE_TOP;
971 blue->flags |= AF_LATIN_BLUE_SUB_TOP;
973 blue->flags |= AF_LATIN_BLUE_NEUTRAL;
974
975 /*
976 * The following flag is used later to adjust the y and x scales
977 * in order to optimize the pixel grid alignment of the top of small
978 * letters.
979 */
982
983 FT_TRACE5(( " -> reference = %ld\n"
984 " overshoot = %ld\n",
985 *blue_ref, *blue_shoot ));
986
987 } /* end for loop */
988
989 af_shaper_buf_destroy( face, shaper_buf );
990
991 /* we finally check whether blue zones are ordered; */
992 /* `ref' and `shoot' values of two blue zones must not overlap */
993 if ( axis->blue_count )
994 {
995 FT_UInt i;
997
998
999 for ( i = 0; i < axis->blue_count; i++ )
1000 blue_sorted[i] = &axis->blues[i];
1001
1002 /* sort bottoms of blue zones... */
1003 af_latin_sort_blue( axis->blue_count, blue_sorted );
1004
1005 /* ...and adjust top values if necessary */
1006 for ( i = 0; i < axis->blue_count - 1; i++ )
1007 {
1008 FT_Pos* a;
1009 FT_Pos* b;
1010
1011#ifdef FT_DEBUG_LEVEL_TRACE
1012 FT_Bool a_is_top = 0;
1013#endif
1014
1015
1016 if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP |
1018 {
1019 a = &blue_sorted[i]->shoot.org;
1020#ifdef FT_DEBUG_LEVEL_TRACE
1021 a_is_top = 1;
1022#endif
1023 }
1024 else
1025 a = &blue_sorted[i]->ref.org;
1026
1027 if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP |
1029 b = &blue_sorted[i + 1]->shoot.org;
1030 else
1031 b = &blue_sorted[i + 1]->ref.org;
1032
1033 if ( *a > *b )
1034 {
1035 *a = *b;
1036 FT_TRACE5(( "blue zone overlap:"
1037 " adjusting %s %d to %ld\n",
1038 a_is_top ? "overshoot" : "reference",
1039 blue_sorted[i] - axis->blues,
1040 *a ));
1041 }
1042 }
1043 }
1044
1045 FT_TRACE5(( "\n" ));
1046
1047 return;
1048 }
1049
1050
1051 /* Check whether all ASCII digits have the same advance width. */
1052
1053 FT_LOCAL_DEF( void )
1055 FT_Face face )
1056 {
1057 FT_Bool started = 0, same_width = 1;
1058 FT_Fixed advance = 0, old_advance = 0;
1059
1060 void* shaper_buf;
1061
1062 /* in all supported charmaps, digits have character codes 0x30-0x39 */
1063 const char digits[] = "0 1 2 3 4 5 6 7 8 9";
1064 const char* p;
1065
1066
1067 p = digits;
1068 shaper_buf = af_shaper_buf_create( face );
1069
1070 while ( *p )
1071 {
1072 FT_ULong glyph_index;
1073 unsigned int num_idx;
1074
1075
1076 /* reject input that maps to more than a single glyph */
1077 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1078 if ( num_idx > 1 )
1079 continue;
1080
1081 glyph_index = af_shaper_get_elem( &metrics->root,
1082 shaper_buf,
1083 0,
1084 &advance,
1085 NULL );
1086 if ( !glyph_index )
1087 continue;
1088
1089 if ( started )
1090 {
1091 if ( advance != old_advance )
1092 {
1093 same_width = 0;
1094 break;
1095 }
1096 }
1097 else
1098 {
1099 old_advance = advance;
1100 started = 1;
1101 }
1102 }
1103
1104 af_shaper_buf_destroy( face, shaper_buf );
1105
1106 metrics->root.digits_have_same_width = same_width;
1107 }
1108
1109
1110 /* Initialize global metrics. */
1111
1114 FT_Face face )
1115 {
1116 FT_CharMap oldmap = face->charmap;
1117
1118
1119 metrics->units_per_em = face->units_per_EM;
1120
1121 if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
1122 {
1126 }
1127
1128 FT_Set_Charmap( face, oldmap );
1129 return FT_Err_Ok;
1130 }
1131
1132
1133 /* Adjust scaling value, then scale and shift widths */
1134 /* and blue zones (if applicable) for given dimension. */
1135
1136 static void
1138 AF_Scaler scaler,
1139 AF_Dimension dim )
1140 {
1142 FT_Pos delta;
1143 AF_LatinAxis axis;
1144 FT_UInt nn;
1145
1146
1147 if ( dim == AF_DIMENSION_HORZ )
1148 {
1149 scale = scaler->x_scale;
1150 delta = scaler->x_delta;
1151 }
1152 else
1153 {
1154 scale = scaler->y_scale;
1155 delta = scaler->y_delta;
1156 }
1157
1158 axis = &metrics->axis[dim];
1159
1160 if ( axis->org_scale == scale && axis->org_delta == delta )
1161 return;
1162
1163 axis->org_scale = scale;
1164 axis->org_delta = delta;
1165
1166 /*
1167 * correct X and Y scale to optimize the alignment of the top of small
1168 * letters to the pixel grid
1169 */
1170 {
1171 AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
1173
1174
1175 for ( nn = 0; nn < Axis->blue_count; nn++ )
1176 {
1177 if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
1178 {
1179 blue = &Axis->blues[nn];
1180 break;
1181 }
1182 }
1183
1184 if ( blue )
1185 {
1186 FT_Pos scaled;
1187 FT_Pos threshold;
1188 FT_Pos fitted;
1189 FT_UInt limit;
1190 FT_UInt ppem;
1191
1192
1193 scaled = FT_MulFix( blue->shoot.org, scale );
1194 ppem = metrics->root.scaler.face->size->metrics.x_ppem;
1195 limit = metrics->root.globals->increase_x_height;
1196 threshold = 40;
1197
1198 /* if the `increase-x-height' property is active, */
1199 /* we round up much more often */
1200 if ( limit &&
1201 ppem <= limit &&
1203 threshold = 52;
1204
1205 fitted = ( scaled + threshold ) & ~63;
1206
1207 if ( scaled != fitted )
1208 {
1209#if 0
1210 if ( dim == AF_DIMENSION_HORZ )
1211 {
1212 if ( fitted < scaled )
1213 scale -= scale / 50; /* scale *= 0.98 */
1214 }
1215 else
1216#endif
1217 if ( dim == AF_DIMENSION_VERT )
1218 {
1219 FT_Pos max_height;
1220 FT_Pos dist;
1221 FT_Fixed new_scale;
1222
1223
1224 new_scale = FT_MulDiv( scale, fitted, scaled );
1225
1226 /* the scaling should not change the result by more than two pixels */
1227 max_height = metrics->units_per_em;
1228
1229 for ( nn = 0; nn < Axis->blue_count; nn++ )
1230 {
1231 max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
1232 max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
1233 }
1234
1235 dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
1236 dist &= ~127;
1237
1238 if ( dist == 0 )
1239 {
1240 FT_TRACE5((
1241 "af_latin_metrics_scale_dim:"
1242 " x height alignment (style `%s'):\n"
1243 " "
1244 " vertical scaling changed from %.5f to %.5f (by %d%%)\n"
1245 "\n",
1246 af_style_names[metrics->root.style_class->style],
1247 scale / 65536.0,
1248 new_scale / 65536.0,
1249 ( fitted - scaled ) * 100 / scaled ));
1250
1251 scale = new_scale;
1252 }
1253#ifdef FT_DEBUG_LEVEL_TRACE
1254 else
1255 {
1256 FT_TRACE5((
1257 "af_latin_metrics_scale_dim:"
1258 " x height alignment (style `%s'):\n"
1259 " "
1260 " excessive vertical scaling abandoned\n"
1261 "\n",
1262 af_style_names[metrics->root.style_class->style] ));
1263 }
1264#endif
1265 }
1266 }
1267 }
1268 }
1269
1270 axis->scale = scale;
1271 axis->delta = delta;
1272
1273 if ( dim == AF_DIMENSION_HORZ )
1274 {
1275 metrics->root.scaler.x_scale = scale;
1276 metrics->root.scaler.x_delta = delta;
1277 }
1278 else
1279 {
1280 metrics->root.scaler.y_scale = scale;
1281 metrics->root.scaler.y_delta = delta;
1282 }
1283
1284 FT_TRACE5(( "%s widths (style `%s')\n",
1285 dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
1286 af_style_names[metrics->root.style_class->style] ));
1287
1288 /* scale the widths */
1289 for ( nn = 0; nn < axis->width_count; nn++ )
1290 {
1291 AF_Width width = axis->widths + nn;
1292
1293
1294 width->cur = FT_MulFix( width->org, scale );
1295 width->fit = width->cur;
1296
1297 FT_TRACE5(( " %d scaled to %.2f\n",
1298 width->org,
1299 width->cur / 64.0 ));
1300 }
1301
1302 FT_TRACE5(( "\n" ));
1303
1304 /* an extra-light axis corresponds to a standard width that is */
1305 /* smaller than 5/8 pixels */
1306 axis->extra_light =
1307 (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1308
1309#ifdef FT_DEBUG_LEVEL_TRACE
1310 if ( axis->extra_light )
1311 FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1312 "\n",
1313 af_style_names[metrics->root.style_class->style] ));
1314#endif
1315
1316 if ( dim == AF_DIMENSION_VERT )
1317 {
1318#ifdef FT_DEBUG_LEVEL_TRACE
1319 if ( axis->blue_count )
1320 FT_TRACE5(( "blue zones (style `%s')\n",
1321 af_style_names[metrics->root.style_class->style] ));
1322#endif
1323
1324 /* scale the blue zones */
1325 for ( nn = 0; nn < axis->blue_count; nn++ )
1326 {
1327 AF_LatinBlue blue = &axis->blues[nn];
1328 FT_Pos dist;
1329
1330
1331 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
1332 blue->ref.fit = blue->ref.cur;
1333 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
1334 blue->shoot.fit = blue->shoot.cur;
1335 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1336
1337 /* a blue zone is only active if it is less than 3/4 pixels tall */
1338 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
1339 if ( dist <= 48 && dist >= -48 )
1340 {
1341#if 0
1342 FT_Pos delta1;
1343#endif
1344 FT_Pos delta2;
1345
1346
1347 /* use discrete values for blue zone widths */
1348
1349#if 0
1350
1351 /* generic, original code */
1352 delta1 = blue->shoot.org - blue->ref.org;
1353 delta2 = delta1;
1354 if ( delta1 < 0 )
1355 delta2 = -delta2;
1356
1357 delta2 = FT_MulFix( delta2, scale );
1358
1359 if ( delta2 < 32 )
1360 delta2 = 0;
1361 else if ( delta2 < 64 )
1362 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
1363 else
1364 delta2 = FT_PIX_ROUND( delta2 );
1365
1366 if ( delta1 < 0 )
1367 delta2 = -delta2;
1368
1369 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1370 blue->shoot.fit = blue->ref.fit + delta2;
1371
1372#else
1373
1374 /* simplified version due to abs(dist) <= 48 */
1375 delta2 = dist;
1376 if ( dist < 0 )
1377 delta2 = -delta2;
1378
1379 if ( delta2 < 32 )
1380 delta2 = 0;
1381 else if ( delta2 < 48 )
1382 delta2 = 32;
1383 else
1384 delta2 = 64;
1385
1386 if ( dist < 0 )
1387 delta2 = -delta2;
1388
1389 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1390 blue->shoot.fit = blue->ref.fit - delta2;
1391
1392#endif
1393
1394 blue->flags |= AF_LATIN_BLUE_ACTIVE;
1395 }
1396 }
1397
1398 /* use sub-top blue zone only if it doesn't overlap with */
1399 /* another (non-sup-top) blue zone; otherwise, the */
1400 /* effect would be similar to a neutral blue zone, which */
1401 /* is not desired here */
1402 for ( nn = 0; nn < axis->blue_count; nn++ )
1403 {
1404 AF_LatinBlue blue = &axis->blues[nn];
1405 FT_UInt i;
1406
1407
1408 if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
1409 continue;
1410 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1411 continue;
1412
1413 for ( i = 0; i < axis->blue_count; i++ )
1414 {
1415 AF_LatinBlue b = &axis->blues[i];
1416
1417
1418 if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
1419 continue;
1420 if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
1421 continue;
1422
1423 if ( b->ref.fit <= blue->shoot.fit &&
1424 b->shoot.fit >= blue->ref.fit )
1425 {
1426 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1427 break;
1428 }
1429 }
1430 }
1431
1432#ifdef FT_DEBUG_LEVEL_TRACE
1433 for ( nn = 0; nn < axis->blue_count; nn++ )
1434 {
1435 AF_LatinBlue blue = &axis->blues[nn];
1436
1437
1438 FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n"
1439 " overshoot %d: %d scaled to %.2f%s\n",
1440 nn,
1441 blue->ref.org,
1442 blue->ref.fit / 64.0,
1443 blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1444 : " (inactive)",
1445 nn,
1446 blue->shoot.org,
1447 blue->shoot.fit / 64.0,
1448 blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1449 : " (inactive)" ));
1450 }
1451#endif
1452 }
1453 }
1454
1455
1456 /* Scale global values in both directions. */
1457
1458 FT_LOCAL_DEF( void )
1460 AF_Scaler scaler )
1461 {
1462 metrics->root.scaler.render_mode = scaler->render_mode;
1463 metrics->root.scaler.face = scaler->face;
1464 metrics->root.scaler.flags = scaler->flags;
1465
1468 }
1469
1470
1471 /* Extract standard_width from writing system/script specific */
1472 /* metrics class. */
1473
1474 FT_LOCAL_DEF( void )
1476 FT_Pos* stdHW,
1477 FT_Pos* stdVW )
1478 {
1479 if ( stdHW )
1480 *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
1481
1482 if ( stdVW )
1483 *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
1484 }
1485
1486
1487 /*************************************************************************/
1488 /*************************************************************************/
1489 /***** *****/
1490 /***** L A T I N G L Y P H A N A L Y S I S *****/
1491 /***** *****/
1492 /*************************************************************************/
1493 /*************************************************************************/
1494
1495
1496 /* Walk over all contours and compute its segments. */
1497
1500 AF_Dimension dim )
1501 {
1503 AF_AxisHints axis = &hints->axis[dim];
1504 FT_Memory memory = hints->memory;
1506 AF_Segment segment = NULL;
1507 AF_SegmentRec seg0;
1508 AF_Point* contour = hints->contours;
1509 AF_Point* contour_limit = contour + hints->num_contours;
1510 AF_Direction major_dir, segment_dir;
1511
1512 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
1513
1514
1515 FT_ZERO( &seg0 );
1516 seg0.score = 32000;
1517 seg0.flags = AF_EDGE_NORMAL;
1518
1519 major_dir = (AF_Direction)FT_ABS( axis->major_dir );
1520 segment_dir = major_dir;
1521
1522 axis->num_segments = 0;
1523
1524 /* set up (u,v) in each point */
1525 if ( dim == AF_DIMENSION_HORZ )
1526 {
1527 AF_Point point = hints->points;
1528 AF_Point limit = point + hints->num_points;
1529
1530
1531 for ( ; point < limit; point++ )
1532 {
1533 point->u = point->fx;
1534 point->v = point->fy;
1535 }
1536 }
1537 else
1538 {
1539 AF_Point point = hints->points;
1540 AF_Point limit = point + hints->num_points;
1541
1542
1543 for ( ; point < limit; point++ )
1544 {
1545 point->u = point->fy;
1546 point->v = point->fx;
1547 }
1548 }
1549
1550 /* do each contour separately */
1551 for ( ; contour < contour_limit; contour++ )
1552 {
1553 AF_Point point = contour[0];
1554 AF_Point last = point->prev;
1555 int on_edge = 0;
1556
1557 /* we call values measured along a segment (point->v) */
1558 /* `coordinates', and values orthogonal to it (point->u) */
1559 /* `positions' */
1560 FT_Pos min_pos = 32000;
1561 FT_Pos max_pos = -32000;
1562 FT_Pos min_coord = 32000;
1563 FT_Pos max_coord = -32000;
1564 FT_UShort min_flags = AF_FLAG_NONE;
1565 FT_UShort max_flags = AF_FLAG_NONE;
1566 FT_Pos min_on_coord = 32000;
1567 FT_Pos max_on_coord = -32000;
1568
1569 FT_Bool passed;
1570
1571 AF_Segment prev_segment = NULL;
1572
1573 FT_Pos prev_min_pos = min_pos;
1574 FT_Pos prev_max_pos = max_pos;
1575 FT_Pos prev_min_coord = min_coord;
1576 FT_Pos prev_max_coord = max_coord;
1577 FT_UShort prev_min_flags = min_flags;
1578 FT_UShort prev_max_flags = max_flags;
1579 FT_Pos prev_min_on_coord = min_on_coord;
1580 FT_Pos prev_max_on_coord = max_on_coord;
1581
1582
1583 if ( FT_ABS( last->out_dir ) == major_dir &&
1584 FT_ABS( point->out_dir ) == major_dir )
1585 {
1586 /* we are already on an edge, try to locate its start */
1587 last = point;
1588
1589 for (;;)
1590 {
1591 point = point->prev;
1592 if ( FT_ABS( point->out_dir ) != major_dir )
1593 {
1594 point = point->next;
1595 break;
1596 }
1597 if ( point == last )
1598 break;
1599 }
1600 }
1601
1602 last = point;
1603 passed = 0;
1604
1605 for (;;)
1606 {
1607 FT_Pos u, v;
1608
1609
1610 if ( on_edge )
1611 {
1612 /* get minimum and maximum position */
1613 u = point->u;
1614 if ( u < min_pos )
1615 min_pos = u;
1616 if ( u > max_pos )
1617 max_pos = u;
1618
1619 /* get minimum and maximum coordinate together with flags */
1620 v = point->v;
1621 if ( v < min_coord )
1622 {
1623 min_coord = v;
1624 min_flags = point->flags;
1625 }
1626 if ( v > max_coord )
1627 {
1628 max_coord = v;
1629 max_flags = point->flags;
1630 }
1631
1632 /* get minimum and maximum coordinate of `on' points */
1633 if ( !( point->flags & AF_FLAG_CONTROL ) )
1634 {
1635 v = point->v;
1636 if ( v < min_on_coord )
1637 min_on_coord = v;
1638 if ( v > max_on_coord )
1639 max_on_coord = v;
1640 }
1641
1642 if ( point->out_dir != segment_dir || point == last )
1643 {
1644 /* check whether the new segment's start point is identical to */
1645 /* the previous segment's end point; for example, this might */
1646 /* happen for spikes */
1647
1648 if ( !prev_segment || segment->first != prev_segment->last )
1649 {
1650 /* points are different: we are just leaving an edge, thus */
1651 /* record a new segment */
1652
1653 segment->last = point;
1654 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1655 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1656
1657 /* a segment is round if either its first or last point */
1658 /* is a control point, and the length of the on points */
1659 /* inbetween doesn't exceed a heuristic limit */
1660 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1661 ( max_on_coord - min_on_coord ) < flat_threshold )
1662 segment->flags |= AF_EDGE_ROUND;
1663
1664 segment->min_coord = (FT_Short)min_coord;
1665 segment->max_coord = (FT_Short)max_coord;
1666 segment->height = segment->max_coord - segment->min_coord;
1667
1668 prev_segment = segment;
1669 prev_min_pos = min_pos;
1670 prev_max_pos = max_pos;
1671 prev_min_coord = min_coord;
1672 prev_max_coord = max_coord;
1673 prev_min_flags = min_flags;
1674 prev_max_flags = max_flags;
1675 prev_min_on_coord = min_on_coord;
1676 prev_max_on_coord = max_on_coord;
1677 }
1678 else
1679 {
1680 /* points are the same: we don't create a new segment but */
1681 /* merge the current segment with the previous one */
1682
1683 if ( prev_segment->last->in_dir == point->in_dir )
1684 {
1685 /* we have identical directions (this can happen for */
1686 /* degenerate outlines that move zig-zag along the main */
1687 /* axis without changing the coordinate value of the other */
1688 /* axis, and where the segments have just been merged): */
1689 /* unify segments */
1690
1691 /* update constraints */
1692
1693 if ( prev_min_pos < min_pos )
1694 min_pos = prev_min_pos;
1695 if ( prev_max_pos > max_pos )
1696 max_pos = prev_max_pos;
1697
1698 if ( prev_min_coord < min_coord )
1699 {
1700 min_coord = prev_min_coord;
1701 min_flags = prev_min_flags;
1702 }
1703 if ( prev_max_coord > max_coord )
1704 {
1705 max_coord = prev_max_coord;
1706 max_flags = prev_max_flags;
1707 }
1708
1709 if ( prev_min_on_coord < min_on_coord )
1710 min_on_coord = prev_min_on_coord;
1711 if ( prev_max_on_coord > max_on_coord )
1712 max_on_coord = prev_max_on_coord;
1713
1714 prev_segment->last = point;
1715 prev_segment->pos = (FT_Short)( ( min_pos +
1716 max_pos ) >> 1 );
1717 prev_segment->delta = (FT_Short)( ( max_pos -
1718 min_pos ) >> 1 );
1719
1720 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1721 ( max_on_coord - min_on_coord ) < flat_threshold )
1722 prev_segment->flags |= AF_EDGE_ROUND;
1723 else
1724 prev_segment->flags &= ~AF_EDGE_ROUND;
1725
1726 prev_segment->min_coord = (FT_Short)min_coord;
1727 prev_segment->max_coord = (FT_Short)max_coord;
1728 prev_segment->height = prev_segment->max_coord -
1729 prev_segment->min_coord;
1730 }
1731 else
1732 {
1733 /* we have different directions; use the properties of the */
1734 /* longer segment and discard the other one */
1735
1736 if ( FT_ABS( prev_max_coord - prev_min_coord ) >
1737 FT_ABS( max_coord - min_coord ) )
1738 {
1739 /* discard current segment */
1740
1741 if ( min_pos < prev_min_pos )
1742 prev_min_pos = min_pos;
1743 if ( max_pos > prev_max_pos )
1744 prev_max_pos = max_pos;
1745
1746 prev_segment->last = point;
1747 prev_segment->pos = (FT_Short)( ( prev_min_pos +
1748 prev_max_pos ) >> 1 );
1749 prev_segment->delta = (FT_Short)( ( prev_max_pos -
1750 prev_min_pos ) >> 1 );
1751 }
1752 else
1753 {
1754 /* discard previous segment */
1755
1756 if ( prev_min_pos < min_pos )
1757 min_pos = prev_min_pos;
1758 if ( prev_max_pos > max_pos )
1759 max_pos = prev_max_pos;
1760
1761 segment->last = point;
1762 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1763 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1764
1765 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1766 ( max_on_coord - min_on_coord ) < flat_threshold )
1767 segment->flags |= AF_EDGE_ROUND;
1768
1769 segment->min_coord = (FT_Short)min_coord;
1770 segment->max_coord = (FT_Short)max_coord;
1771 segment->height = segment->max_coord -
1772 segment->min_coord;
1773
1774 *prev_segment = *segment;
1775
1776 prev_min_pos = min_pos;
1777 prev_max_pos = max_pos;
1778 prev_min_coord = min_coord;
1779 prev_max_coord = max_coord;
1780 prev_min_flags = min_flags;
1781 prev_max_flags = max_flags;
1782 prev_min_on_coord = min_on_coord;
1783 prev_max_on_coord = max_on_coord;
1784 }
1785 }
1786
1787 axis->num_segments--;
1788 }
1789
1790 on_edge = 0;
1791 segment = NULL;
1792
1793 /* fall through */
1794 }
1795 }
1796
1797 /* now exit if we are at the start/end point */
1798 if ( point == last )
1799 {
1800 if ( passed )
1801 break;
1802 passed = 1;
1803 }
1804
1805 /* if we are not on an edge, check whether the major direction */
1806 /* coincides with the current point's `out' direction, or */
1807 /* whether we have a single-point contour */
1808 if ( !on_edge &&
1809 ( FT_ABS( point->out_dir ) == major_dir ||
1810 point == point->prev ) )
1811 {
1812 /* this is the start of a new segment! */
1813 segment_dir = (AF_Direction)point->out_dir;
1814
1815 error = af_axis_hints_new_segment( axis, memory, &segment );
1816 if ( error )
1817 goto Exit;
1818
1819 /* clear all segment fields */
1820 segment[0] = seg0;
1821
1822 segment->dir = (FT_Char)segment_dir;
1823 segment->first = point;
1824 segment->last = point;
1825
1826 /* `af_axis_hints_new_segment' reallocates memory, */
1827 /* thus we have to refresh the `prev_segment' pointer */
1828 if ( prev_segment )
1829 prev_segment = segment - 1;
1830
1831 min_pos = max_pos = point->u;
1832 min_coord = max_coord = point->v;
1833 min_flags = max_flags = point->flags;
1834
1835 if ( point->flags & AF_FLAG_CONTROL )
1836 {
1837 min_on_coord = 32000;
1838 max_on_coord = -32000;
1839 }
1840 else
1841 min_on_coord = max_on_coord = point->v;
1842
1843 on_edge = 1;
1844
1845 if ( point == point->prev )
1846 {
1847 /* we have a one-point segment: this is a one-point */
1848 /* contour with `in' and `out' direction set to */
1849 /* AF_DIR_NONE */
1850 segment->pos = (FT_Short)min_pos;
1851
1852 if (point->flags & AF_FLAG_CONTROL)
1853 segment->flags |= AF_EDGE_ROUND;
1854
1855 segment->min_coord = (FT_Short)point->v;
1856 segment->max_coord = (FT_Short)point->v;
1857 segment->height = 0;
1858
1859 on_edge = 0;
1860 segment = NULL;
1861 }
1862 }
1863
1864 point = point->next;
1865 }
1866
1867 } /* contours */
1868
1869
1870 /* now slightly increase the height of segments if this makes */
1871 /* sense -- this is used to better detect and ignore serifs */
1872 {
1873 AF_Segment segments = axis->segments;
1874 AF_Segment segments_end = segments + axis->num_segments;
1875
1876
1877 for ( segment = segments; segment < segments_end; segment++ )
1878 {
1879 AF_Point first = segment->first;
1880 AF_Point last = segment->last;
1881 FT_Pos first_v = first->v;
1882 FT_Pos last_v = last->v;
1883
1884
1885 if ( first_v < last_v )
1886 {
1887 AF_Point p;
1888
1889
1890 p = first->prev;
1891 if ( p->v < first_v )
1892 segment->height = (FT_Short)( segment->height +
1893 ( ( first_v - p->v ) >> 1 ) );
1894
1895 p = last->next;
1896 if ( p->v > last_v )
1897 segment->height = (FT_Short)( segment->height +
1898 ( ( p->v - last_v ) >> 1 ) );
1899 }
1900 else
1901 {
1902 AF_Point p;
1903
1904
1905 p = first->prev;
1906 if ( p->v > first_v )
1907 segment->height = (FT_Short)( segment->height +
1908 ( ( p->v - first_v ) >> 1 ) );
1909
1910 p = last->next;
1911 if ( p->v < last_v )
1912 segment->height = (FT_Short)( segment->height +
1913 ( ( last_v - p->v ) >> 1 ) );
1914 }
1915 }
1916 }
1917
1918 Exit:
1919 return error;
1920 }
1921
1922
1923 /* Link segments to form stems and serifs. If `width_count' and */
1924 /* `widths' are non-zero, use them to fine-tune the scoring function. */
1925
1926 FT_LOCAL_DEF( void )
1928 FT_UInt width_count,
1929 AF_WidthRec* widths,
1930 AF_Dimension dim )
1931 {
1932 AF_AxisHints axis = &hints->axis[dim];
1933 AF_Segment segments = axis->segments;
1934 AF_Segment segment_limit = segments + axis->num_segments;
1935 FT_Pos len_threshold, len_score, dist_score, max_width;
1936 AF_Segment seg1, seg2;
1937
1938
1939 if ( width_count )
1940 max_width = widths[width_count - 1].org;
1941 else
1942 max_width = 0;
1943
1944 /* a heuristic value to set up a minimum value for overlapping */
1945 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
1946 if ( len_threshold == 0 )
1947 len_threshold = 1;
1948
1949 /* a heuristic value to weight lengths */
1950 len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
1951
1952 /* a heuristic value to weight distances (no call to */
1953 /* AF_LATIN_CONSTANT needed, since we work on multiples */
1954 /* of the stem width) */
1955 dist_score = 3000;
1956
1957 /* now compare each segment to the others */
1958 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1959 {
1960 if ( seg1->dir != axis->major_dir )
1961 continue;
1962
1963 /* search for stems having opposite directions, */
1964 /* with seg1 to the `left' of seg2 */
1965 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
1966 {
1967 FT_Pos pos1 = seg1->pos;
1968 FT_Pos pos2 = seg2->pos;
1969
1970
1971 if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
1972 {
1973 /* compute distance between the two segments */
1974 FT_Pos min = seg1->min_coord;
1975 FT_Pos max = seg1->max_coord;
1976 FT_Pos len;
1977
1978
1979 if ( min < seg2->min_coord )
1980 min = seg2->min_coord;
1981
1982 if ( max > seg2->max_coord )
1983 max = seg2->max_coord;
1984
1985 /* compute maximum coordinate difference of the two segments */
1986 /* (this is, how much they overlap) */
1987 len = max - min;
1988 if ( len >= len_threshold )
1989 {
1990 /*
1991 * The score is the sum of two demerits indicating the
1992 * `badness' of a fit, measured along the segments' main axis
1993 * and orthogonal to it, respectively.
1994 *
1995 * o The less overlapping along the main axis, the worse it
1996 * is, causing a larger demerit.
1997 *
1998 * o The nearer the orthogonal distance to a stem width, the
1999 * better it is, causing a smaller demerit. For simplicity,
2000 * however, we only increase the demerit for values that
2001 * exceed the largest stem width.
2002 */
2003
2004 FT_Pos dist = pos2 - pos1;
2005
2006 FT_Pos dist_demerit, score;
2007
2008
2009 if ( max_width )
2010 {
2011 /* distance demerits are based on multiples of `max_width'; */
2012 /* we scale by 1024 for getting more precision */
2013 FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
2014
2015
2016 if ( delta > 10000 )
2017 dist_demerit = 32000;
2018 else if ( delta > 0 )
2019 dist_demerit = delta * delta / dist_score;
2020 else
2021 dist_demerit = 0;
2022 }
2023 else
2024 dist_demerit = dist; /* default if no widths available */
2025
2026 score = dist_demerit + len_score / len;
2027
2028 /* and we search for the smallest score */
2029 if ( score < seg1->score )
2030 {
2031 seg1->score = score;
2032 seg1->link = seg2;
2033 }
2034
2035 if ( score < seg2->score )
2036 {
2037 seg2->score = score;
2038 seg2->link = seg1;
2039 }
2040 }
2041 }
2042 }
2043 }
2044
2045 /* now compute the `serif' segments, cf. explanations in `afhints.h' */
2046 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2047 {
2048 seg2 = seg1->link;
2049
2050 if ( seg2 )
2051 {
2052 if ( seg2->link != seg1 )
2053 {
2054 seg1->link = 0;
2055 seg1->serif = seg2->link;
2056 }
2057 }
2058 }
2059 }
2060
2061
2062 /* Link segments to edges, using feature analysis for selection. */
2063
2066 AF_Dimension dim )
2067 {
2068 AF_AxisHints axis = &hints->axis[dim];
2070 FT_Memory memory = hints->memory;
2071 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2072
2073#ifdef FT_CONFIG_OPTION_PIC
2074 AF_FaceGlobals globals = hints->metrics->globals;
2075#endif
2076
2077 AF_StyleClass style_class = hints->metrics->style_class;
2079 [style_class->script];
2080
2081 FT_Bool top_to_bottom_hinting = 0;
2082
2083 AF_Segment segments = axis->segments;
2084 AF_Segment segment_limit = segments + axis->num_segments;
2085 AF_Segment seg;
2086
2087#if 0
2088 AF_Direction up_dir;
2089#endif
2091 FT_Pos edge_distance_threshold;
2092 FT_Pos segment_length_threshold;
2093 FT_Pos segment_width_threshold;
2094
2095
2096 axis->num_edges = 0;
2097
2098 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2099 : hints->y_scale;
2100
2101#if 0
2102 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
2103 : AF_DIR_RIGHT;
2104#endif
2105
2106 if ( dim == AF_DIMENSION_VERT )
2107 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2108
2109 /*
2110 * We ignore all segments that are less than 1 pixel in length
2111 * to avoid many problems with serif fonts. We compute the
2112 * corresponding threshold in font units.
2113 */
2114 if ( dim == AF_DIMENSION_HORZ )
2115 segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2116 else
2117 segment_length_threshold = 0;
2118
2119 /*
2120 * Similarly, we ignore segments that have a width delta
2121 * larger than 0.5px (i.e., a width larger than 1px).
2122 */
2123 segment_width_threshold = FT_DivFix( 32, scale );
2124
2125 /*********************************************************************/
2126 /* */
2127 /* We begin by generating a sorted table of edges for the current */
2128 /* direction. To do so, we simply scan each segment and try to find */
2129 /* an edge in our table that corresponds to its position. */
2130 /* */
2131 /* If no edge is found, we create and insert a new edge in the */
2132 /* sorted table. Otherwise, we simply add the segment to the edge's */
2133 /* list which gets processed in the second step to compute the */
2134 /* edge's properties. */
2135 /* */
2136 /* Note that the table of edges is sorted along the segment/edge */
2137 /* position. */
2138 /* */
2139 /*********************************************************************/
2140
2141 /* assure that edge distance threshold is at most 0.25px */
2142 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2143 scale );
2144 if ( edge_distance_threshold > 64 / 4 )
2145 edge_distance_threshold = 64 / 4;
2146
2147 edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2148 scale );
2149
2150 for ( seg = segments; seg < segment_limit; seg++ )
2151 {
2152 AF_Edge found = NULL;
2153 FT_Int ee;
2154
2155
2156 /* ignore too short segments, too wide ones, and, in this loop, */
2157 /* one-point segments without a direction */
2158 if ( seg->height < segment_length_threshold ||
2159 seg->delta > segment_width_threshold ||
2160 seg->dir == AF_DIR_NONE )
2161 continue;
2162
2163 /* A special case for serif edges: If they are smaller than */
2164 /* 1.5 pixels we ignore them. */
2165 if ( seg->serif &&
2166 2 * seg->height < 3 * segment_length_threshold )
2167 continue;
2168
2169 /* look for an edge corresponding to the segment */
2170 for ( ee = 0; ee < axis->num_edges; ee++ )
2171 {
2172 AF_Edge edge = axis->edges + ee;
2173 FT_Pos dist;
2174
2175
2176 dist = seg->pos - edge->fpos;
2177 if ( dist < 0 )
2178 dist = -dist;
2179
2180 if ( dist < edge_distance_threshold && edge->dir == seg->dir )
2181 {
2182 found = edge;
2183 break;
2184 }
2185 }
2186
2187 if ( !found )
2188 {
2189 AF_Edge edge;
2190
2191
2192 /* insert a new edge in the list and */
2193 /* sort according to the position */
2194 error = af_axis_hints_new_edge( axis, seg->pos,
2195 (AF_Direction)seg->dir,
2196 top_to_bottom_hinting,
2197 memory, &edge );
2198 if ( error )
2199 goto Exit;
2200
2201 /* add the segment to the new edge's list */
2202 FT_ZERO( edge );
2203
2204 edge->first = seg;
2205 edge->last = seg;
2206 edge->dir = seg->dir;
2207 edge->fpos = seg->pos;
2208 edge->opos = FT_MulFix( seg->pos, scale );
2209 edge->pos = edge->opos;
2210 seg->edge_next = seg;
2211 }
2212 else
2213 {
2214 /* if an edge was found, simply add the segment to the edge's */
2215 /* list */
2216 seg->edge_next = found->first;
2217 found->last->edge_next = seg;
2218 found->last = seg;
2219 }
2220 }
2221
2222 /* we loop again over all segments to catch one-point segments */
2223 /* without a direction: if possible, link them to existing edges */
2224 for ( seg = segments; seg < segment_limit; seg++ )
2225 {
2226 AF_Edge found = NULL;
2227 FT_Int ee;
2228
2229
2230 if ( seg->dir != AF_DIR_NONE )
2231 continue;
2232
2233 /* look for an edge corresponding to the segment */
2234 for ( ee = 0; ee < axis->num_edges; ee++ )
2235 {
2236 AF_Edge edge = axis->edges + ee;
2237 FT_Pos dist;
2238
2239
2240 dist = seg->pos - edge->fpos;
2241 if ( dist < 0 )
2242 dist = -dist;
2243
2244 if ( dist < edge_distance_threshold )
2245 {
2246 found = edge;
2247 break;
2248 }
2249 }
2250
2251 /* one-point segments without a match are ignored */
2252 if ( found )
2253 {
2254 seg->edge_next = found->first;
2255 found->last->edge_next = seg;
2256 found->last = seg;
2257 }
2258 }
2259
2260
2261 /******************************************************************/
2262 /* */
2263 /* Good, we now compute each edge's properties according to the */
2264 /* segments found on its position. Basically, these are */
2265 /* */
2266 /* - the edge's main direction */
2267 /* - stem edge, serif edge or both (which defaults to stem then) */
2268 /* - rounded edge, straight or both (which defaults to straight) */
2269 /* - link for edge */
2270 /* */
2271 /******************************************************************/
2272
2273 /* first of all, set the `edge' field in each segment -- this is */
2274 /* required in order to compute edge links */
2275
2276 /*
2277 * Note that removing this loop and setting the `edge' field of each
2278 * segment directly in the code above slows down execution speed for
2279 * some reasons on platforms like the Sun.
2280 */
2281 {
2282 AF_Edge edges = axis->edges;
2283 AF_Edge edge_limit = edges + axis->num_edges;
2284 AF_Edge edge;
2285
2286
2287 for ( edge = edges; edge < edge_limit; edge++ )
2288 {
2289 seg = edge->first;
2290 if ( seg )
2291 do
2292 {
2293 seg->edge = edge;
2294 seg = seg->edge_next;
2295
2296 } while ( seg != edge->first );
2297 }
2298
2299 /* now compute each edge properties */
2300 for ( edge = edges; edge < edge_limit; edge++ )
2301 {
2302 FT_Int is_round = 0; /* does it contain round segments? */
2303 FT_Int is_straight = 0; /* does it contain straight segments? */
2304#if 0
2305 FT_Pos ups = 0; /* number of upwards segments */
2306 FT_Pos downs = 0; /* number of downwards segments */
2307#endif
2308
2309
2310 seg = edge->first;
2311
2312 do
2313 {
2314 FT_Bool is_serif;
2315
2316
2317 /* check for roundness of segment */
2318 if ( seg->flags & AF_EDGE_ROUND )
2319 is_round++;
2320 else
2321 is_straight++;
2322
2323#if 0
2324 /* check for segment direction */
2325 if ( seg->dir == up_dir )
2326 ups += seg->max_coord - seg->min_coord;
2327 else
2328 downs += seg->max_coord - seg->min_coord;
2329#endif
2330
2331 /* check for links -- if seg->serif is set, then seg->link must */
2332 /* be ignored */
2333 is_serif = (FT_Bool)( seg->serif &&
2334 seg->serif->edge &&
2335 seg->serif->edge != edge );
2336
2337 if ( ( seg->link && seg->link->edge ) || is_serif )
2338 {
2339 AF_Edge edge2;
2340 AF_Segment seg2;
2341
2342
2343 edge2 = edge->link;
2344 seg2 = seg->link;
2345
2346 if ( is_serif )
2347 {
2348 seg2 = seg->serif;
2349 edge2 = edge->serif;
2350 }
2351
2352 if ( edge2 )
2353 {
2354 FT_Pos edge_delta;
2355 FT_Pos seg_delta;
2356
2357
2358 edge_delta = edge->fpos - edge2->fpos;
2359 if ( edge_delta < 0 )
2360 edge_delta = -edge_delta;
2361
2362 seg_delta = seg->pos - seg2->pos;
2363 if ( seg_delta < 0 )
2364 seg_delta = -seg_delta;
2365
2366 if ( seg_delta < edge_delta )
2367 edge2 = seg2->edge;
2368 }
2369 else
2370 edge2 = seg2->edge;
2371
2372 if ( is_serif )
2373 {
2374 edge->serif = edge2;
2375 edge2->flags |= AF_EDGE_SERIF;
2376 }
2377 else
2378 edge->link = edge2;
2379 }
2380
2381 seg = seg->edge_next;
2382
2383 } while ( seg != edge->first );
2384
2385 /* set the round/straight flags */
2386 edge->flags = AF_EDGE_NORMAL;
2387
2388 if ( is_round > 0 && is_round >= is_straight )
2389 edge->flags |= AF_EDGE_ROUND;
2390
2391#if 0
2392 /* set the edge's main direction */
2393 edge->dir = AF_DIR_NONE;
2394
2395 if ( ups > downs )
2396 edge->dir = (FT_Char)up_dir;
2397
2398 else if ( ups < downs )
2399 edge->dir = (FT_Char)-up_dir;
2400
2401 else if ( ups == downs )
2402 edge->dir = 0; /* both up and down! */
2403#endif
2404
2405 /* get rid of serifs if link is set */
2406 /* XXX: This gets rid of many unpleasant artefacts! */
2407 /* Example: the `c' in cour.pfa at size 13 */
2408
2409 if ( edge->serif && edge->link )
2410 edge->serif = NULL;
2411 }
2412 }
2413
2414 Exit:
2415 return error;
2416 }
2417
2418
2419 /* Detect segments and edges for given dimension. */
2420
2423 FT_UInt width_count,
2424 AF_WidthRec* widths,
2425 AF_Dimension dim )
2426 {
2428
2429
2431 if ( !error )
2432 {
2433 af_latin_hints_link_segments( hints, width_count, widths, dim );
2434
2436 }
2437
2438 return error;
2439 }
2440
2441
2442 /* Compute all edges which lie within blue zones. */
2443
2444 static void
2447 {
2448 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
2449 AF_Edge edge = axis->edges;
2450 AF_Edge edge_limit = edge + axis->num_edges;
2451 AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
2452 FT_Fixed scale = latin->scale;
2453
2454
2455 /* compute which blue zones are active, i.e. have their scaled */
2456 /* size < 3/4 pixels */
2457
2458 /* for each horizontal edge search the blue zone which is closest */
2459 for ( ; edge < edge_limit; edge++ )
2460 {
2461 FT_UInt bb;
2462 AF_Width best_blue = NULL;
2463 FT_Bool best_blue_is_neutral = 0;
2464 FT_Pos best_dist; /* initial threshold */
2465
2466
2467 /* compute the initial threshold as a fraction of the EM size */
2468 /* (the value 40 is heuristic) */
2469 best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
2470
2471 /* assure a minimum distance of 0.5px */
2472 if ( best_dist > 64 / 2 )
2473 best_dist = 64 / 2;
2474
2475 for ( bb = 0; bb < latin->blue_count; bb++ )
2476 {
2477 AF_LatinBlue blue = latin->blues + bb;
2478 FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
2479
2480
2481 /* skip inactive blue zones (i.e., those that are too large) */
2482 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
2483 continue;
2484
2485 /* if it is a top zone, check for right edges (against the major */
2486 /* direction); if it is a bottom zone, check for left edges (in */
2487 /* the major direction) -- this assumes the TrueType convention */
2488 /* for the orientation of contours */
2489 is_top_blue =
2490 (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP |
2491 AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
2492 is_neutral_blue =
2493 (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
2494 is_major_dir =
2495 FT_BOOL( edge->dir == axis->major_dir );
2496
2497 /* neutral blue zones are handled for both directions */
2498 if ( is_top_blue ^ is_major_dir || is_neutral_blue )
2499 {
2500 FT_Pos dist;
2501
2502
2503 /* first of all, compare it to the reference position */
2504 dist = edge->fpos - blue->ref.org;
2505 if ( dist < 0 )
2506 dist = -dist;
2507
2508 dist = FT_MulFix( dist, scale );
2509 if ( dist < best_dist )
2510 {
2511 best_dist = dist;
2512 best_blue = &blue->ref;
2513 best_blue_is_neutral = is_neutral_blue;
2514 }
2515
2516 /* now compare it to the overshoot position and check whether */
2517 /* the edge is rounded, and whether the edge is over the */
2518 /* reference position of a top zone, or under the reference */
2519 /* position of a bottom zone (provided we don't have a */
2520 /* neutral blue zone) */
2521 if ( edge->flags & AF_EDGE_ROUND &&
2522 dist != 0 &&
2523 !is_neutral_blue )
2524 {
2525 FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
2526
2527
2528 if ( is_top_blue ^ is_under_ref )
2529 {
2530 dist = edge->fpos - blue->shoot.org;
2531 if ( dist < 0 )
2532 dist = -dist;
2533
2534 dist = FT_MulFix( dist, scale );
2535 if ( dist < best_dist )
2536 {
2537 best_dist = dist;
2538 best_blue = &blue->shoot;
2539 best_blue_is_neutral = is_neutral_blue;
2540 }
2541 }
2542 }
2543 }
2544 }
2545
2546 if ( best_blue )
2547 {
2548 edge->blue_edge = best_blue;
2549 if ( best_blue_is_neutral )
2550 edge->flags |= AF_EDGE_NEUTRAL;
2551 }
2552 }
2553 }
2554
2555
2556 /* Initalize hinting engine. */
2557
2558 static FT_Error
2561 {
2563 FT_UInt32 scaler_flags, other_flags;
2564 FT_Face face = metrics->root.scaler.face;
2565
2566
2568
2569 /*
2570 * correct x_scale and y_scale if needed, since they may have
2571 * been modified by `af_latin_metrics_scale_dim' above
2572 */
2573 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
2574 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
2575 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
2576 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
2577
2578 /* compute flags depending on render mode, etc. */
2579 mode = metrics->root.scaler.render_mode;
2580
2581#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
2583 metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
2584#endif
2585
2586 scaler_flags = hints->scaler_flags;
2587 other_flags = 0;
2588
2589 /*
2590 * We snap the width of vertical stems for the monochrome and
2591 * horizontal LCD rendering targets only.
2592 */
2594 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
2595
2596 /*
2597 * We snap the width of horizontal stems for the monochrome and
2598 * vertical LCD rendering targets only.
2599 */
2601 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
2602
2603 /*
2604 * We adjust stems to full pixels unless in `light' or `lcd' mode.
2605 */
2607 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
2608
2609 if ( mode == FT_RENDER_MODE_MONO )
2610 other_flags |= AF_LATIN_HINTS_MONO;
2611
2612 /*
2613 * In `light' or `lcd' mode we disable horizontal hinting completely.
2614 * We also do it if the face is italic.
2615 *
2616 * However, if warping is enabled (which only works in `light' hinting
2617 * mode), advance widths get adjusted, too.
2618 */
2620 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
2621 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
2622
2623#ifdef AF_CONFIG_OPTION_USE_WARPER
2624 /* get (global) warper flag */
2625 if ( !metrics->root.globals->module->warping )
2626 scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
2627#endif
2628
2629 hints->scaler_flags = scaler_flags;
2630 hints->other_flags = other_flags;
2631
2632 return FT_Err_Ok;
2633 }
2634
2635
2636 /*************************************************************************/
2637 /*************************************************************************/
2638 /***** *****/
2639 /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
2640 /***** *****/
2641 /*************************************************************************/
2642 /*************************************************************************/
2643
2644 /* Snap a given width in scaled coordinates to one of the */
2645 /* current standard widths. */
2646
2647 static FT_Pos
2649 FT_UInt count,
2650 FT_Pos width )
2651 {
2652 FT_UInt n;
2653 FT_Pos best = 64 + 32 + 2;
2655 FT_Pos scaled;
2656
2657
2658 for ( n = 0; n < count; n++ )
2659 {
2660 FT_Pos w;
2661 FT_Pos dist;
2662
2663
2664 w = widths[n].cur;
2665 dist = width - w;
2666 if ( dist < 0 )
2667 dist = -dist;
2668 if ( dist < best )
2669 {
2670 best = dist;
2671 reference = w;
2672 }
2673 }
2674
2675 scaled = FT_PIX_ROUND( reference );
2676
2677 if ( width >= reference )
2678 {
2679 if ( width < scaled + 48 )
2680 width = reference;
2681 }
2682 else
2683 {
2684 if ( width > scaled - 48 )
2685 width = reference;
2686 }
2687
2688 return width;
2689 }
2690
2691
2692 /* Compute the snapped width of a given stem, ignoring very thin ones. */
2693 /* There is a lot of voodoo in this function; changing the hard-coded */
2694 /* parameters influence the whole hinting process. */
2695
2696 static FT_Pos
2698 AF_Dimension dim,
2699 FT_Pos width,
2700 FT_Pos base_delta,
2701 FT_UInt base_flags,
2702 FT_UInt stem_flags )
2703 {
2705 AF_LatinAxis axis = &metrics->axis[dim];
2706 FT_Pos dist = width;
2707 FT_Int sign = 0;
2708 FT_Int vertical = ( dim == AF_DIMENSION_VERT );
2709
2710
2712 axis->extra_light )
2713 return width;
2714
2715 if ( dist < 0 )
2716 {
2717 dist = -width;
2718 sign = 1;
2719 }
2720
2721 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
2722 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
2723 {
2724 /* smooth hinting process: very lightly quantize the stem width */
2725
2726 /* leave the widths of serifs alone */
2727 if ( ( stem_flags & AF_EDGE_SERIF ) &&
2728 vertical &&
2729 ( dist < 3 * 64 ) )
2730 goto Done_Width;
2731
2732 else if ( base_flags & AF_EDGE_ROUND )
2733 {
2734 if ( dist < 80 )
2735 dist = 64;
2736 }
2737 else if ( dist < 56 )
2738 dist = 56;
2739
2740 if ( axis->width_count > 0 )
2741 {
2742 FT_Pos delta;
2743
2744
2745 /* compare to standard width */
2746 delta = dist - axis->widths[0].cur;
2747
2748 if ( delta < 0 )
2749 delta = -delta;
2750
2751 if ( delta < 40 )
2752 {
2753 dist = axis->widths[0].cur;
2754 if ( dist < 48 )
2755 dist = 48;
2756
2757 goto Done_Width;
2758 }
2759
2760 if ( dist < 3 * 64 )
2761 {
2762 delta = dist & 63;
2763 dist &= -64;
2764
2765 if ( delta < 10 )
2766 dist += delta;
2767
2768 else if ( delta < 32 )
2769 dist += 10;
2770
2771 else if ( delta < 54 )
2772 dist += 54;
2773
2774 else
2775 dist += delta;
2776 }
2777 else
2778 {
2779 /* A stem's end position depends on two values: the start */
2780 /* position and the stem length. The former gets usually */
2781 /* rounded to the grid, while the latter gets rounded also if it */
2782 /* exceeds a certain length (see below in this function). This */
2783 /* `double rounding' can lead to a great difference to the */
2784 /* original, unhinted position; this normally doesn't matter for */
2785 /* large PPEM values, but for small sizes it can easily make */
2786 /* outlines collide. For this reason, we adjust the stem length */
2787 /* by a small amount depending on the PPEM value in case the */
2788 /* former and latter rounding both point into the same */
2789 /* direction. */
2790
2791 FT_Pos bdelta = 0;
2792
2793
2794 if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
2795 ( ( width < 0 ) && ( base_delta < 0 ) ) )
2796 {
2797 FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem;
2798
2799
2800 if ( ppem < 10 )
2801 bdelta = base_delta;
2802 else if ( ppem < 30 )
2803 bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
2804
2805 if ( bdelta < 0 )
2806 bdelta = -bdelta;
2807 }
2808
2809 dist = ( dist - bdelta + 32 ) & ~63;
2810 }
2811 }
2812 }
2813 else
2814 {
2815 /* strong hinting process: snap the stem width to integer pixels */
2816
2817 FT_Pos org_dist = dist;
2818
2819
2820 dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
2821
2822 if ( vertical )
2823 {
2824 /* in the case of vertical hinting, always round */
2825 /* the stem heights to integer pixels */
2826
2827 if ( dist >= 64 )
2828 dist = ( dist + 16 ) & ~63;
2829 else
2830 dist = 64;
2831 }
2832 else
2833 {
2835 {
2836 /* monochrome horizontal hinting: snap widths to integer pixels */
2837 /* with a different threshold */
2838
2839 if ( dist < 64 )
2840 dist = 64;
2841 else
2842 dist = ( dist + 32 ) & ~63;
2843 }
2844 else
2845 {
2846 /* for horizontal anti-aliased hinting, we adopt a more subtle */
2847 /* approach: we strengthen small stems, round stems whose size */
2848 /* is between 1 and 2 pixels to an integer, otherwise nothing */
2849
2850 if ( dist < 48 )
2851 dist = ( dist + 64 ) >> 1;
2852
2853 else if ( dist < 128 )
2854 {
2855 /* We only round to an integer width if the corresponding */
2856 /* distortion is less than 1/4 pixel. Otherwise this */
2857 /* makes everything worse since the diagonals, which are */
2858 /* not hinted, appear a lot bolder or thinner than the */
2859 /* vertical stems. */
2860
2861 FT_Pos delta;
2862
2863
2864 dist = ( dist + 22 ) & ~63;
2865 delta = dist - org_dist;
2866 if ( delta < 0 )
2867 delta = -delta;
2868
2869 if ( delta >= 16 )
2870 {
2871 dist = org_dist;
2872 if ( dist < 48 )
2873 dist = ( dist + 64 ) >> 1;
2874 }
2875 }
2876 else
2877 /* round otherwise to prevent color fringes in LCD mode */
2878 dist = ( dist + 32 ) & ~63;
2879 }
2880 }
2881 }
2882
2883 Done_Width:
2884 if ( sign )
2885 dist = -dist;
2886
2887 return dist;
2888 }
2889
2890
2891 /* Align one stem edge relative to the previous stem edge. */
2892
2893 static void
2895 AF_Dimension dim,
2896 AF_Edge base_edge,
2897 AF_Edge stem_edge )
2898 {
2899 FT_Pos dist, base_delta;
2900 FT_Pos fitted_width;
2901
2902
2903 dist = stem_edge->opos - base_edge->opos;
2904 base_delta = base_edge->pos - base_edge->opos;
2905
2906 fitted_width = af_latin_compute_stem_width( hints, dim,
2907 dist, base_delta,
2908 base_edge->flags,
2909 stem_edge->flags );
2910
2911
2912 stem_edge->pos = base_edge->pos + fitted_width;
2913
2914 FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f,"
2915 " dist was %.2f, now %.2f\n",
2916 stem_edge - hints->axis[dim].edges, stem_edge->opos / 64.0,
2917 stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
2918 }
2919
2920
2921 /* Shift the coordinates of the `serif' edge by the same amount */
2922 /* as the corresponding `base' edge has been moved already. */
2923
2924 static void
2926 AF_Edge base,
2927 AF_Edge serif )
2928 {
2929 FT_UNUSED( hints );
2930
2931 serif->pos = base->pos + ( serif->opos - base->opos );
2932 }
2933
2934
2935 /*************************************************************************/
2936 /*************************************************************************/
2937 /*************************************************************************/
2938 /**** ****/
2939 /**** E D G E H I N T I N G ****/
2940 /**** ****/
2941 /*************************************************************************/
2942 /*************************************************************************/
2943 /*************************************************************************/
2944
2945
2946 /* The main grid-fitting routine. */
2947
2948 static void
2950 AF_Dimension dim )
2951 {
2952 AF_AxisHints axis = &hints->axis[dim];
2953 AF_Edge edges = axis->edges;
2954 AF_Edge edge_limit = edges + axis->num_edges;
2955 FT_PtrDist n_edges;
2956 AF_Edge edge;
2957 AF_Edge anchor = NULL;
2958 FT_Int has_serifs = 0;
2959
2960#ifdef FT_CONFIG_OPTION_PIC
2961 AF_FaceGlobals globals = hints->metrics->globals;
2962#endif
2963
2964 AF_StyleClass style_class = hints->metrics->style_class;
2966 [style_class->script];
2967
2968 FT_Bool top_to_bottom_hinting = 0;
2969
2970#ifdef FT_DEBUG_LEVEL_TRACE
2971 FT_UInt num_actions = 0;
2972#endif
2973
2974
2975 FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
2976 dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
2977 af_style_names[hints->metrics->style_class->style] ));
2978
2979 if ( dim == AF_DIMENSION_VERT )
2980 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2981
2982 /* we begin by aligning all stems relative to the blue zone */
2983 /* if needed -- that's only for horizontal edges */
2984
2985 if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
2986 {
2987 for ( edge = edges; edge < edge_limit; edge++ )
2988 {
2989 AF_Width blue;
2990 AF_Edge edge1, edge2; /* these edges form the stem to check */
2991
2992
2993 if ( edge->flags & AF_EDGE_DONE )
2994 continue;
2995
2996 edge1 = NULL;
2997 edge2 = edge->link;
2998
2999 /*
3000 * If a stem contains both a neutral and a non-neutral blue zone,
3001 * skip the neutral one. Otherwise, outlines with different
3002 * directions might be incorrectly aligned at the same vertical
3003 * position.
3004 *
3005 * If we have two neutral blue zones, skip one of them.
3006 *
3007 */
3008 if ( edge->blue_edge && edge2 && edge2->blue_edge )
3009 {
3010 FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
3011 FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
3012
3013
3014 if ( neutral2 )
3015 {
3016 edge2->blue_edge = NULL;
3017 edge2->flags &= ~AF_EDGE_NEUTRAL;
3018 }
3019 else if ( neutral )
3020 {
3021 edge->blue_edge = NULL;
3022 edge->flags &= ~AF_EDGE_NEUTRAL;
3023 }
3024 }
3025
3026 blue = edge->blue_edge;
3027 if ( blue )
3028 edge1 = edge;
3029
3030 /* flip edges if the other edge is aligned to a blue zone */
3031 else if ( edge2 && edge2->blue_edge )
3032 {
3033 blue = edge2->blue_edge;
3034 edge1 = edge2;
3035 edge2 = edge;
3036 }
3037
3038 if ( !edge1 )
3039 continue;
3040
3041#ifdef FT_DEBUG_LEVEL_TRACE
3042 if ( !anchor )
3043 FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f,"
3044 " was %.2f (anchor=edge %d)\n",
3045 edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3046 edge1->pos / 64.0, edge - edges ));
3047 else
3048 FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f,"
3049 " was %.2f\n",
3050 edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3051 edge1->pos / 64.0 ));
3052
3053 num_actions++;
3054#endif
3055
3056 edge1->pos = blue->fit;
3057 edge1->flags |= AF_EDGE_DONE;
3058
3059 if ( edge2 && !edge2->blue_edge )
3060 {
3061 af_latin_align_linked_edge( hints, dim, edge1, edge2 );
3062 edge2->flags |= AF_EDGE_DONE;
3063
3064#ifdef FT_DEBUG_LEVEL_TRACE
3065 num_actions++;
3066#endif
3067 }
3068
3069 if ( !anchor )
3070 anchor = edge;
3071 }
3072 }
3073
3074 /* now we align all other stem edges, trying to maintain the */
3075 /* relative order of stems in the glyph */
3076 for ( edge = edges; edge < edge_limit; edge++ )
3077 {
3078 AF_Edge edge2;
3079
3080
3081 if ( edge->flags & AF_EDGE_DONE )
3082 continue;
3083
3084 /* skip all non-stem edges */
3085 edge2 = edge->link;
3086 if ( !edge2 )
3087 {
3088 has_serifs++;
3089 continue;
3090 }
3091
3092 /* now align the stem */
3093
3094 /* this should not happen, but it's better to be safe */
3095 if ( edge2->blue_edge )
3096 {
3097 FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges ));
3098
3099 af_latin_align_linked_edge( hints, dim, edge2, edge );
3100 edge->flags |= AF_EDGE_DONE;
3101
3102#ifdef FT_DEBUG_LEVEL_TRACE
3103 num_actions++;
3104#endif
3105 continue;
3106 }
3107
3108 if ( !anchor )
3109 {
3110 /* if we reach this if clause, no stem has been aligned yet */
3111
3112 FT_Pos org_len, org_center, cur_len;
3113 FT_Pos cur_pos1, error1, error2, u_off, d_off;
3114
3115
3116 org_len = edge2->opos - edge->opos;
3117 cur_len = af_latin_compute_stem_width( hints, dim,
3118 org_len, 0,
3119 edge->flags,
3120 edge2->flags );
3121
3122 /* some voodoo to specially round edges for small stem widths; */
3123 /* the idea is to align the center of a stem, then shifting */
3124 /* the stem edges to suitable positions */
3125 if ( cur_len <= 64 )
3126 {
3127 /* width <= 1px */
3128 u_off = 32;
3129 d_off = 32;
3130 }
3131 else
3132 {
3133 /* 1px < width < 1.5px */
3134 u_off = 38;
3135 d_off = 26;
3136 }
3137
3138 if ( cur_len < 96 )
3139 {
3140 org_center = edge->opos + ( org_len >> 1 );
3141 cur_pos1 = FT_PIX_ROUND( org_center );
3142
3143 error1 = org_center - ( cur_pos1 - u_off );
3144 if ( error1 < 0 )
3145 error1 = -error1;
3146
3147 error2 = org_center - ( cur_pos1 + d_off );
3148 if ( error2 < 0 )
3149 error2 = -error2;
3150
3151 if ( error1 < error2 )
3152 cur_pos1 -= u_off;
3153 else
3154 cur_pos1 += d_off;
3155
3156 edge->pos = cur_pos1 - cur_len / 2;
3157 edge2->pos = edge->pos + cur_len;
3158 }
3159 else
3160 edge->pos = FT_PIX_ROUND( edge->opos );
3161
3162 anchor = edge;
3163 edge->flags |= AF_EDGE_DONE;
3164
3165 FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
3166 " snapped to %.2f and %.2f\n",
3167 edge - edges, edge->opos / 64.0,
3168 edge2 - edges, edge2->opos / 64.0,
3169 edge->pos / 64.0, edge2->pos / 64.0 ));
3170
3171 af_latin_align_linked_edge( hints, dim, edge, edge2 );
3172
3173#ifdef FT_DEBUG_LEVEL_TRACE
3174 num_actions += 2;
3175#endif
3176 }
3177 else
3178 {
3179 FT_Pos org_pos, org_len, org_center, cur_len;
3180 FT_Pos cur_pos1, cur_pos2, delta1, delta2;
3181
3182
3183 org_pos = anchor->pos + ( edge->opos - anchor->opos );
3184 org_len = edge2->opos - edge->opos;
3185 org_center = org_pos + ( org_len >> 1 );
3186
3187 cur_len = af_latin_compute_stem_width( hints, dim,
3188 org_len, 0,
3189 edge->flags,
3190 edge2->flags );
3191
3192 if ( edge2->flags & AF_EDGE_DONE )
3193 {
3194 FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n",
3195 edge - edges, edge->pos / 64.0,
3196 ( edge2->pos - cur_len ) / 64.0 ));
3197
3198 edge->pos = edge2->pos - cur_len;
3199 }
3200
3201 else if ( cur_len < 96 )
3202 {
3203 FT_Pos u_off, d_off;
3204
3205
3206 cur_pos1 = FT_PIX_ROUND( org_center );
3207
3208 if ( cur_len <= 64 )
3209 {
3210 u_off = 32;
3211 d_off = 32;
3212 }
3213 else
3214 {
3215 u_off = 38;
3216 d_off = 26;
3217 }
3218
3219 delta1 = org_center - ( cur_pos1 - u_off );
3220 if ( delta1 < 0 )
3221 delta1 = -delta1;
3222
3223 delta2 = org_center - ( cur_pos1 + d_off );
3224 if ( delta2 < 0 )
3225 delta2 = -delta2;
3226
3227 if ( delta1 < delta2 )
3228 cur_pos1 -= u_off;
3229 else
3230 cur_pos1 += d_off;
3231
3232 edge->pos = cur_pos1 - cur_len / 2;
3233 edge2->pos = cur_pos1 + cur_len / 2;
3234
3235 FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
3236 " snapped to %.2f and %.2f\n",
3237 edge - edges, edge->opos / 64.0,
3238 edge2 - edges, edge2->opos / 64.0,
3239 edge->pos / 64.0, edge2->pos / 64.0 ));
3240 }
3241
3242 else
3243 {
3244 org_pos = anchor->pos + ( edge->opos - anchor->opos );
3245 org_len = edge2->opos - edge->opos;
3246 org_center = org_pos + ( org_len >> 1 );
3247
3248 cur_len = af_latin_compute_stem_width( hints, dim,
3249 org_len, 0,
3250 edge->flags,
3251 edge2->flags );
3252
3253 cur_pos1 = FT_PIX_ROUND( org_pos );
3254 delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
3255 if ( delta1 < 0 )
3256 delta1 = -delta1;
3257
3258 cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
3259 delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
3260 if ( delta2 < 0 )
3261 delta2 = -delta2;
3262
3263 edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
3264 edge2->pos = edge->pos + cur_len;
3265
3266 FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
3267 " snapped to %.2f and %.2f\n",
3268 edge - edges, edge->opos / 64.0,
3269 edge2 - edges, edge2->opos / 64.0,
3270 edge->pos / 64.0, edge2->pos / 64.0 ));
3271 }
3272
3273#ifdef FT_DEBUG_LEVEL_TRACE
3274 num_actions++;
3275#endif
3276
3277 edge->flags |= AF_EDGE_DONE;
3278 edge2->flags |= AF_EDGE_DONE;
3279
3280 if ( edge > edges &&
3281 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3282 : ( edge->pos < edge[-1].pos ) ) )
3283 {
3284 /* don't move if stem would (almost) disappear otherwise; */
3285 /* the ad-hoc value 16 corresponds to 1/4px */
3286 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3287 {
3288#ifdef FT_DEBUG_LEVEL_TRACE
3289 FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3290 edge - edges,
3291 edge->pos / 64.0,
3292 edge[-1].pos / 64.0 ));
3293
3294 num_actions++;
3295#endif
3296
3297 edge->pos = edge[-1].pos;
3298 }
3299 }
3300 }
3301 }
3302
3303 /* make sure that lowercase m's maintain their symmetry */
3304
3305 /* In general, lowercase m's have six vertical edges if they are sans */
3306 /* serif, or twelve if they are with serifs. This implementation is */
3307 /* based on that assumption, and seems to work very well with most */
3308 /* faces. However, if for a certain face this assumption is not */
3309 /* true, the m is just rendered like before. In addition, any stem */
3310 /* correction will only be applied to symmetrical glyphs (even if the */
3311 /* glyph is not an m), so the potential for unwanted distortion is */
3312 /* relatively low. */
3313
3314 /* We don't handle horizontal edges since we can't easily assure that */
3315 /* the third (lowest) stem aligns with the base line; it might end up */
3316 /* one pixel higher or lower. */
3317
3318 n_edges = edge_limit - edges;
3319 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
3320 {
3321 AF_Edge edge1, edge2, edge3;
3322 FT_Pos dist1, dist2, span, delta;
3323
3324
3325 if ( n_edges == 6 )
3326 {
3327 edge1 = edges;
3328 edge2 = edges + 2;
3329 edge3 = edges + 4;
3330 }
3331 else
3332 {
3333 edge1 = edges + 1;
3334 edge2 = edges + 5;
3335 edge3 = edges + 9;
3336 }
3337
3338 dist1 = edge2->opos - edge1->opos;
3339 dist2 = edge3->opos - edge2->opos;
3340
3341 span = dist1 - dist2;
3342 if ( span < 0 )
3343 span = -span;
3344
3345 if ( span < 8 )
3346 {
3347 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
3348 edge3->pos -= delta;
3349 if ( edge3->link )
3350 edge3->link->pos -= delta;
3351
3352 /* move the serifs along with the stem */
3353 if ( n_edges == 12 )
3354 {
3355 ( edges + 8 )->pos -= delta;
3356 ( edges + 11 )->pos -= delta;
3357 }
3358
3359 edge3->flags |= AF_EDGE_DONE;
3360 if ( edge3->link )
3361 edge3->link->flags |= AF_EDGE_DONE;
3362 }
3363 }
3364
3365 if ( has_serifs || !anchor )
3366 {
3367 /*
3368 * now hint the remaining edges (serifs and single) in order
3369 * to complete our processing
3370 */
3371 for ( edge = edges; edge < edge_limit; edge++ )
3372 {
3373 FT_Pos delta;
3374
3375
3376 if ( edge->flags & AF_EDGE_DONE )
3377 continue;
3378
3379 delta = 1000;
3380
3381 if ( edge->serif )
3382 {
3383 delta = edge->serif->opos - edge->opos;
3384 if ( delta < 0 )
3385 delta = -delta;
3386 }
3387
3388 if ( delta < 64 + 16 )
3389 {
3390 af_latin_align_serif_edge( hints, edge->serif, edge );
3391 FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
3392 " aligned to %.2f\n",
3393 edge - edges, edge->opos / 64.0,
3394 edge->serif - edges, edge->serif->opos / 64.0,
3395 edge->pos / 64.0 ));
3396 }
3397 else if ( !anchor )
3398 {
3399 edge->pos = FT_PIX_ROUND( edge->opos );
3400 anchor = edge;
3401 FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)"
3402 " snapped to %.2f\n",
3403 edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
3404 }
3405 else
3406 {
3408
3409
3410 for ( before = edge - 1; before >= edges; before-- )
3411 if ( before->flags & AF_EDGE_DONE )
3412 break;
3413
3414 for ( after = edge + 1; after < edge_limit; after++ )
3415 if ( after->flags & AF_EDGE_DONE )
3416 break;
3417
3418 if ( before >= edges && before < edge &&
3419 after < edge_limit && after > edge )
3420 {
3421 if ( after->opos == before->opos )
3422 edge->pos = before->pos;
3423 else
3424 edge->pos = before->pos +
3425 FT_MulDiv( edge->opos - before->opos,
3426 after->pos - before->pos,
3427 after->opos - before->opos );
3428
3429 FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f"
3430 " from %d (opos=%.2f)\n",
3431 edge - edges, edge->opos / 64.0,
3432 edge->pos / 64.0,
3433 before - edges, before->opos / 64.0 ));
3434 }
3435 else
3436 {
3437 edge->pos = anchor->pos +
3438 ( ( edge->opos - anchor->opos + 16 ) & ~31 );
3439 FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)"
3440 " snapped to %.2f\n",
3441 edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
3442 }
3443 }
3444
3445#ifdef FT_DEBUG_LEVEL_TRACE
3446 num_actions++;
3447#endif
3448 edge->flags |= AF_EDGE_DONE;
3449
3450 if ( edge > edges &&
3451 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3452 : ( edge->pos < edge[-1].pos ) ) )
3453 {
3454 /* don't move if stem would (almost) disappear otherwise; */
3455 /* the ad-hoc value 16 corresponds to 1/4px */
3456 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3457 {
3458#ifdef FT_DEBUG_LEVEL_TRACE
3459 FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3460 edge - edges,
3461 edge->pos / 64.0,
3462 edge[-1].pos / 64.0 ));
3463
3464 num_actions++;
3465#endif
3466 edge->pos = edge[-1].pos;
3467 }
3468 }
3469
3470 if ( edge + 1 < edge_limit &&
3471 edge[1].flags & AF_EDGE_DONE &&
3472 ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos )
3473 : ( edge->pos > edge[1].pos ) ) )
3474 {
3475 /* don't move if stem would (almost) disappear otherwise; */
3476 /* the ad-hoc value 16 corresponds to 1/4px */
3477 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3478 {
3479#ifdef FT_DEBUG_LEVEL_TRACE
3480 FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3481 edge - edges,
3482 edge->pos / 64.0,
3483 edge[1].pos / 64.0 ));
3484
3485 num_actions++;
3486#endif
3487
3488 edge->pos = edge[1].pos;
3489 }
3490 }
3491 }
3492 }
3493
3494#ifdef FT_DEBUG_LEVEL_TRACE
3495 if ( !num_actions )
3496 FT_TRACE5(( " (none)\n" ));
3497 FT_TRACE5(( "\n" ));
3498#endif
3499 }
3500
3501
3502 /* Apply the complete hinting algorithm to a latin glyph. */
3503
3504 static FT_Error
3509 {
3511 int dim;
3512
3513 AF_LatinAxis axis;
3514
3515
3517 if ( error )
3518 goto Exit;
3519
3520 /* analyze glyph outline */
3522 {
3523 axis = &metrics->axis[AF_DIMENSION_HORZ];
3525 axis->width_count,
3526 axis->widths,
3528 if ( error )
3529 goto Exit;
3530 }
3531
3532 if ( AF_HINTS_DO_VERTICAL( hints ) )
3533 {
3534 axis = &metrics->axis[AF_DIMENSION_VERT];
3536 axis->width_count,
3537 axis->widths,
3539 if ( error )
3540 goto Exit;
3541
3542 /* apply blue zones to base characters only */
3543 if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
3545 }
3546
3547 /* grid-fit the outline */
3548 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
3549 {
3550#ifdef AF_CONFIG_OPTION_USE_WARPER
3551 if ( dim == AF_DIMENSION_HORZ &&
3552 metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL &&
3554 {
3555 AF_WarperRec warper;
3557 FT_Pos delta;
3558
3559
3560 af_warper_compute( &warper, hints, (AF_Dimension)dim,
3561 &scale, &delta );
3562 af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
3563 scale, delta );
3564 continue;
3565 }
3566#endif /* AF_CONFIG_OPTION_USE_WARPER */
3567
3568 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
3570 {
3575 }
3576 }
3577
3579
3580 Exit:
3581 return error;
3582 }
3583
3584
3585 /*************************************************************************/
3586 /*************************************************************************/
3587 /***** *****/
3588 /***** L A T I N S C R I P T C L A S S *****/
3589 /***** *****/
3590 /*************************************************************************/
3591 /*************************************************************************/
3592
3593
3595 af_latin_writing_system_class,
3596
3598
3599 sizeof ( AF_LatinMetricsRec ),
3600
3603 (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
3605
3606 (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */
3608 )
3609
3610
3611/* END */
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
af_sort_pos(FT_UInt count, FT_Pos *table)
Definition: afangles.c:187
af_sort_and_quantize_widths(FT_UInt *count, AF_Width table, FT_Pos threshold)
Definition: afangles.c:210
af_blue_stringsets[]
Definition: afblue.c:439
af_blue_strings[]
Definition: afblue.c:26
@ AF_BLUE_STRING_MAX
Definition: afblue.h:280
#define AF_BLUE_STRING_MAX_LEN
Definition: afblue.h:73
#define GET_UTF8_CHAR(ch, p)
Definition: afblue.h:31
#define AF_BLUE_STRINGSET_MAX_LEN
Definition: afblue.h:314
enum AF_Blue_Stringset_ AF_Blue_Stringset
#define AF_PROP_INCREASE_X_HEIGHT_MIN
Definition: afglobal.h:87
#define AF_NONBASE
Definition: afglobal.h:84
af_axis_hints_new_edge(AF_AxisHints axis, FT_Int fpos, AF_Direction dir, FT_Bool top_to_bottom_hinting, FT_Memory memory, AF_Edge *anedge)
Definition: afhints.c:99
af_glyph_hints_done(AF_GlyphHints hints)
Definition: afhints.c:672
af_glyph_hints_align_edge_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1181
af_glyph_hints_save(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:1146
af_glyph_hints_rescale(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: afhints.c:720
af_axis_hints_new_segment(AF_AxisHints axis, FT_Memory memory, AF_Segment *asegment)
Definition: afhints.c:38
af_glyph_hints_reload(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:732
af_glyph_hints_align_strong_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1256
af_glyph_hints_align_weak_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1507
af_glyph_hints_init(AF_GlyphHints hints, FT_Memory memory)
Definition: afhints.c:662
#define AF_HINTS_DO_BLUES(h)
Definition: afhints.h:397
#define AF_EDGE_ROUND
Definition: afhints.h:230
#define AF_HINTS_DO_WARP(h)
Definition: afhints.h:405
#define AF_HINTS_DO_HORIZONTAL(h)
Definition: afhints.h:391
FT_BEGIN_HEADER enum AF_Dimension_ AF_Dimension
@ AF_DIMENSION_HORZ
Definition: afhints.h:35
@ AF_DIMENSION_MAX
Definition: afhints.h:40
@ AF_DIMENSION_VERT
Definition: afhints.h:37
enum AF_Direction_ AF_Direction
#define AF_EDGE_SERIF
Definition: afhints.h:231
#define AF_FLAG_NONE
Definition: afhints.h:210
#define AF_EDGE_NEUTRAL
Definition: afhints.h:233
#define AF_EDGE_NORMAL
Definition: afhints.h:229
#define AF_EDGE_DONE
Definition: afhints.h:232
@ AF_DIR_RIGHT
Definition: afhints.h:50
@ AF_DIR_UP
Definition: afhints.h:52
@ AF_DIR_NONE
Definition: afhints.h:49
#define AF_FLAG_CONTROL
Definition: afhints.h:215
#define AF_HINTS_DO_VERTICAL(h)
Definition: afhints.h:394
static void af_latin_align_serif_edge(AF_GlyphHints hints, AF_Edge base, AF_Edge serif)
Definition: aflatin.c:2925
af_latin_get_standard_widths(AF_LatinMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
Definition: aflatin.c:1475
af_latin_metrics_init(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:1113
static void af_latin_align_linked_edge(AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge)
Definition: aflatin.c:2894
#define FLAT_THRESHOLD(x)
Definition: aflatin.c:45
static void af_latin_metrics_scale_dim(AF_LatinMetrics metrics, AF_Scaler scaler, AF_Dimension dim)
Definition: aflatin.c:1137
static void af_latin_sort_blue(FT_UInt count, AF_LatinBlue *table)
Definition: aflatin.c:290
static FT_Pos af_latin_compute_stem_width(AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, FT_Pos base_delta, FT_UInt base_flags, FT_UInt stem_flags)
Definition: aflatin.c:2697
static FT_Error af_latin_hints_apply(FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline *outline, AF_LatinMetrics metrics)
Definition: aflatin.c:3505
static void af_latin_hints_compute_blue_edges(AF_GlyphHints hints, AF_LatinMetrics metrics)
Definition: aflatin.c:2445
af_latin_metrics_scale(AF_LatinMetrics metrics, AF_Scaler scaler)
Definition: aflatin.c:1459
static FT_Error af_latin_hints_init(AF_GlyphHints hints, AF_LatinMetrics metrics)
Definition: aflatin.c:2559
static void af_latin_hint_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:2949
static FT_Pos af_latin_snap_width(AF_Width widths, FT_UInt count, FT_Pos width)
Definition: aflatin.c:2648
af_latin_hints_link_segments(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:1927
af_latin_hints_compute_segments(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:1499
af_latin_metrics_init_widths(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:61
af_latin_metrics_check_digits(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:1054
af_latin_hints_compute_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:2065
static void af_latin_metrics_init_blues(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:332
af_latin_hints_detect_features(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:2422
#define AF_LATIN_IS_X_HEIGHT_BLUE(b)
Definition: aflatin.h:60
#define AF_LATIN_IS_TOP_BLUE(b)
Definition: aflatin.h:54
#define AF_LATIN_HINTS_STEM_ADJUST
Definition: aflatin.h:145
#define AF_LATIN_BLUE_SUB_TOP
Definition: aflatin.h:70
#define AF_LATIN_HINTS_DO_MONO(h)
Definition: aflatin.h:159
#define AF_LATIN_MAX_WIDTHS
Definition: aflatin.h:65
#define AF_LATIN_HINTS_VERT_SNAP
Definition: aflatin.h:144
#define AF_LATIN_HINTS_MONO
Definition: aflatin.h:147
#define AF_LATIN_HINTS_DO_VERT_SNAP(h)
Definition: aflatin.h:153
#define AF_LATIN_IS_LONG_BLUE(b)
Definition: aflatin.h:62
#define AF_LATIN_IS_NEUTRAL_BLUE(b)
Definition: aflatin.h:58
#define AF_LATIN_IS_SUB_TOP_BLUE(b)
Definition: aflatin.h:56
#define AF_LATIN_CONSTANT(metrics, c)
Definition: aflatin.h:34
struct AF_LatinMetricsRec_ * AF_LatinMetrics
#define AF_LATIN_BLUE_TOP
Definition: aflatin.h:69
#define AF_LATIN_HINTS_DO_HORZ_SNAP(h)
Definition: aflatin.h:150
#define AF_LATIN_HINTS_DO_STEM_ADJUST(h)
Definition: aflatin.h:156
#define AF_LATIN_BLUE_ACTIVE
Definition: aflatin.h:68
#define AF_LATIN_BLUE_ADJUSTMENT
Definition: aflatin.h:73
#define AF_LATIN_HINTS_HORZ_SNAP
Definition: aflatin.h:143
#define AF_LATIN_BLUE_NEUTRAL
Definition: aflatin.h:72
#define AF_SCRIPT_CLASSES_GET
Definition: afpic.h:32
void * af_shaper_buf_create(FT_Face face)
Definition: afshaper.c:592
const char * af_shaper_get_cluster(const char *p, AF_StyleMetrics metrics, void *buf_, unsigned int *count)
Definition: afshaper.c:617
FT_ULong af_shaper_get_elem(AF_StyleMetrics metrics, void *buf_, unsigned int idx, FT_Long *advance, FT_Long *y_offset)
Definition: afshaper.c:653
void af_shaper_buf_destroy(FT_Face face, void *buf)
Definition: afshaper.c:606
Arabic default AF_WRITING_SYSTEM_LATIN
Definition: afstyles.h:95
#define AF_SCALER_FLAG_NO_WARPER
Definition: aftypes.h:175
FT_Error(* AF_WritingSystem_InitMetricsFunc)(AF_StyleMetrics metrics, FT_Face face)
Definition: aftypes.h:204
void(* AF_WritingSystem_ScaleMetricsFunc)(AF_StyleMetrics metrics, AF_Scaler scaler)
Definition: aftypes.h:208
FT_BEGIN_HEADER struct AF_WidthRec_ AF_WidthRec
FT_BEGIN_HEADER struct AF_WidthRec_ * AF_Width
void(* AF_WritingSystem_DoneMetricsFunc)(AF_StyleMetrics metrics)
Definition: aftypes.h:212
FT_Error(* AF_WritingSystem_InitHintsFunc)(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: aftypes.h:221
#define AF_DEFINE_WRITING_SYSTEM_CLASS( writing_system_class, system, m_size, m_init, m_scale, m_done, m_stdw, h_init, h_apply)
Definition: aftypes.h:495
FT_Error(* AF_WritingSystem_ApplyHintsFunc)(FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline *outline, AF_StyleMetrics metrics)
Definition: aftypes.h:225
#define AF_SCALER_FLAG_NO_HORIZONTAL
Definition: aftypes.h:172
void(* AF_WritingSystem_GetStdWidthsFunc)(AF_StyleMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
Definition: aftypes.h:215
af_warper_compute(AF_Warper warper, AF_GlyphHints hints, AF_Dimension dim, FT_Fixed *a_scale, FT_Fixed *a_delta)
unsigned int dir
Definition: maze.c:112
const WCHAR * link
Definition: db.cpp:997
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
WORD face[3]
Definition: mesh.c:4747
POINTL point
Definition: edittest.c:50
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:760
#define FT_STYLE_FLAG_ITALIC
Definition: freetype.h:1517
#define FT_LOAD_NO_SCALE
Definition: freetype.h:3009
enum FT_Render_Mode_ FT_Render_Mode
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
FT_Select_Charmap(FT_Face face, FT_Encoding encoding)
Definition: ftobjs.c:3457
FT_Set_Charmap(FT_Face face, FT_CharMap charmap)
Definition: ftobjs.c:3499
@ FT_RENDER_MODE_MONO
Definition: freetype.h:3236
@ FT_RENDER_MODE_NORMAL
Definition: freetype.h:3234
@ FT_RENDER_MODE_LIGHT
Definition: freetype.h:3235
@ FT_RENDER_MODE_LCD_V
Definition: freetype.h:3238
@ FT_RENDER_MODE_LCD
Definition: freetype.h:3237
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:416
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
return FT_Err_Ok
Definition: ftbbox.c:511
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:388
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
#define FT_TRACE5(varformat)
Definition: ftdebug.h:162
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:451
#define FT_CURVE_TAG_ON
Definition: ftimage.h:453
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:58
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_ABS(a)
Definition: ftobjs.h:74
#define FT_MIN(a, b)
Definition: ftobjs.h:71
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:93
#define FT_MAX(a, b)
Definition: ftobjs.h:72
#define FT_INT_MIN
Definition: ftstdlib.h:64
#define FT_INT_MAX
Definition: ftstdlib.h:63
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
signed char FT_Char
Definition: fttypes.h:143
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
ft_ptrdiff_t FT_PtrDist
Definition: fttypes.h:337
unsigned long FT_ULong
Definition: fttypes.h:253
unsigned char FT_Byte
Definition: fttypes.h:154
signed long FT_Fixed
Definition: fttypes.h:288
int FT_Error
Definition: fttypes.h:300
signed long FT_Long
Definition: fttypes.h:242
unsigned short FT_UShort
Definition: fttypes.h:209
signed short FT_Short
Definition: fttypes.h:198
unsigned int FT_UInt
Definition: fttypes.h:231
#define FT_BOOL(x)
Definition: fttypes.h:578
signed int FT_Int
Definition: fttypes.h:220
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLclampf GLclampf blue
Definition: gl.h:1740
GLint GLint GLsizei width
Definition: gl.h:1546
GLdouble n
Definition: glext.h:7729
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GLenum GLenum GLvoid GLvoid GLvoid * span
Definition: glext.h:5664
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLsizei GLenum const GLvoid GLuint GLsizei GLfloat * metrics
Definition: glext.h:11745
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLint limit
Definition: glext.h:10326
GLenum mode
Definition: glext.h:6217
GLint reference
Definition: glext.h:11729
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
GLsizei const GLfloat * points
Definition: glext.h:8112
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
static const int digits[]
Definition: decode.c:71
#define d
Definition: ke_i.h:81
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
#define sign(x)
Definition: mapdesc.cc:613
static struct msdos_boot_sector bs
Definition: mkdosfs.c:539
#define error(str)
Definition: mkdosfs.c:1605
static UINT UINT last
Definition: font.c:45
static char memory[1024 *256]
Definition: process.c:116
#define min(a, b)
Definition: monoChain.cc:55
#define round(x)
Definition: opentype.c:47
#define swap(a, b)
Definition: qsort.c:63
static unsigned __int64 next
Definition: rand_nt.c:6
#define error2(s, a, b)
Definition: debug.h:126
#define error1(s, a)
Definition: debug.h:125
namespace GUID const ADDRINFOEXW * hints
Definition: sock.c:80
static void Exit(void)
Definition: sock.c:1330
AF_Segment segments
Definition: afhints.h:309
FT_Int num_edges
Definition: afhints.h:314
AF_Edge edges
Definition: afhints.h:316
AF_Direction major_dir
Definition: afhints.h:318
FT_Int num_segments
Definition: afhints.h:307
FT_Char dir
Definition: afhints.h:289
AF_Edge serif
Definition: afhints.h:294
AF_Width blue_edge
Definition: afhints.h:292
FT_Pos pos
Definition: afhints.h:286
AF_Edge link
Definition: afhints.h:293
AF_Segment first
Definition: afhints.h:297
AF_Segment last
Definition: afhints.h:298
FT_Short fpos
Definition: afhints.h:284
FT_Pos opos
Definition: afhints.h:285
FT_Byte flags
Definition: afhints.h:288
AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]
Definition: aflatin.h:101
FT_Bool extra_light
Definition: aflatin.h:97
AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]
Definition: aflatin.h:94
FT_Pos delta
Definition: aflatin.h:91
FT_Pos edge_distance_threshold
Definition: aflatin.h:95
FT_Pos standard_width
Definition: aflatin.h:96
FT_UInt width_count
Definition: aflatin.h:93
FT_Pos org_delta
Definition: aflatin.h:104
FT_Fixed scale
Definition: aflatin.h:90
FT_Fixed org_scale
Definition: aflatin.h:103
FT_UInt blue_count
Definition: aflatin.h:100
FT_UInt flags
Definition: aflatin.h:83
FT_Pos descender
Definition: aflatin.h:82
FT_Pos ascender
Definition: aflatin.h:81
AF_WidthRec ref
Definition: aflatin.h:79
AF_WidthRec shoot
Definition: aflatin.h:80
FT_Char in_dir
Definition: afhints.h:244
FT_UInt32 flags
Definition: aftypes.h:186
FT_Render_Mode render_mode
Definition: aftypes.h:185
FT_Pos y_delta
Definition: aftypes.h:184
FT_Face face
Definition: aftypes.h:180
FT_Pos x_delta
Definition: aftypes.h:183
FT_Fixed y_scale
Definition: aftypes.h:182
FT_Fixed x_scale
Definition: aftypes.h:181
const char * standard_charstring
Definition: aftypes.h:348
FT_Bool top_to_bottom_hinting
Definition: aftypes.h:346
FT_Byte flags
Definition: afhints.h:260
AF_Point last
Definition: afhints.h:277
FT_Char dir
Definition: afhints.h:261
FT_Short min_coord
Definition: afhints.h:264
FT_Short max_coord
Definition: afhints.h:265
FT_Short height
Definition: afhints.h:266
AF_Segment edge_next
Definition: afhints.h:269
FT_Short delta
Definition: afhints.h:263
AF_Segment link
Definition: afhints.h:271
AF_Point first
Definition: afhints.h:276
FT_Short pos
Definition: afhints.h:262
AF_Edge edge
Definition: afhints.h:268
FT_Pos score
Definition: afhints.h:273
AF_Segment serif
Definition: afhints.h:272
AF_Script script
Definition: aftypes.h:450
AF_Blue_Stringset blue_stringset
Definition: aftypes.h:451
Definition: mesh.c:5330
Definition: send.c:48
#define max(a, b)
Definition: svc.c:63
__inline int before(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2390
__inline int after(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2395