ReactOS 0.4.16-dev-1059-gb1cf981
aflatin2.c
Go to the documentation of this file.
1/* ATTENTION: This file doesn't compile. It is only here as a reference */
2/* of an alternative latin hinting algorithm that was always */
3/* marked as experimental. */
4
5
6/****************************************************************************
7 *
8 * aflatin2.c
9 *
10 * Auto-fitter hinting routines for latin writing system (body).
11 *
12 * Copyright (C) 2003-2019 by
13 * David Turner, Robert Wilhelm, and Werner Lemberg.
14 *
15 * This file is part of the FreeType project, and may only be used,
16 * modified, and distributed under the terms of the FreeType project
17 * license, LICENSE.TXT. By continuing to use, modify, or distribute
18 * this file you indicate that you have read the license and
19 * understand and accept it fully.
20 *
21 */
22
23
24#include FT_ADVANCES_H
25
26
27#ifdef FT_OPTION_AUTOFIT2
28
29#include "afglobal.h"
30#include "aflatin.h"
31#include "aflatin2.h"
32#include "aferrors.h"
33
34
35#ifdef AF_CONFIG_OPTION_USE_WARPER
36#include "afwarp.h"
37#endif
38
39
40 /**************************************************************************
41 *
42 * The macro FT_COMPONENT is used in trace mode. It is an implicit
43 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
44 * messages during execution.
45 */
46#undef FT_COMPONENT
47#define FT_COMPONENT aflatin2
48
49
51 af_latin2_hints_compute_segments( AF_GlyphHints hints,
52 AF_Dimension dim );
53
54 FT_LOCAL_DEF( void )
55 af_latin2_hints_link_segments( AF_GlyphHints hints,
56 AF_Dimension dim );
57
58 /*************************************************************************/
59 /*************************************************************************/
60 /***** *****/
61 /***** L A T I N G L O B A L M E T R I C S *****/
62 /***** *****/
63 /*************************************************************************/
64 /*************************************************************************/
65
66 FT_LOCAL_DEF( void )
67 af_latin2_metrics_init_widths( AF_LatinMetrics metrics,
69 {
70 /* scan the array of segments in each direction */
71#ifdef __REACTOS__
73 if (!hints) return;
74#else
76#endif
77
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_UInt glyph_index;
87 int dim;
88#ifdef __REACTOS__
90 if (dummy) goto Exit;
91 {
92#else
94#endif
95 AF_Scaler scaler = &dummy->root.scaler;
96
97
98 glyph_index = FT_Get_Char_Index(
99 face,
100 metrics->root.style_class->standard_char );
101 if ( glyph_index == 0 )
102 goto Exit;
103
104 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
105 if ( error || face->glyph->outline.n_points <= 0 )
106 goto Exit;
107
108 FT_ZERO( dummy );
109
110 dummy->units_per_em = metrics->units_per_em;
111 scaler->x_scale = scaler->y_scale = 0x10000L;
112 scaler->x_delta = scaler->y_delta = 0;
113 scaler->face = face;
115 scaler->flags = 0;
116
118
119 error = af_glyph_hints_reload( hints, &face->glyph->outline );
120 if ( error )
121 goto Exit;
122
123 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
124 {
125 AF_LatinAxis axis = &metrics->axis[dim];
126 AF_AxisHints axhints = &hints->axis[dim];
127 AF_Segment seg, limit, link;
128 FT_UInt num_widths = 0;
129
130
131 error = af_latin2_hints_compute_segments( hints,
132 (AF_Dimension)dim );
133 if ( error )
134 goto Exit;
135
136 af_latin2_hints_link_segments( hints,
137 (AF_Dimension)dim );
138
139 seg = axhints->segments;
140 limit = seg + axhints->num_segments;
141
142 for ( ; seg < limit; seg++ )
143 {
144 link = seg->link;
145
146 /* we only consider stem segments there! */
147 if ( link && link->link == seg && link > seg )
148 {
149 FT_Pos dist;
150
151
152 dist = seg->pos - link->pos;
153 if ( dist < 0 )
154 dist = -dist;
155
156 if ( num_widths < AF_LATIN_MAX_WIDTHS )
157 axis->widths[num_widths++].org = dist;
158 }
159 }
160
161 af_sort_widths( num_widths, axis->widths );
162 axis->width_count = num_widths;
163 }
164
165 Exit:
166 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
167 {
168 AF_LatinAxis axis = &metrics->axis[dim];
169 FT_Pos stdw;
170
171
172 stdw = ( axis->width_count > 0 )
173 ? axis->widths[0].org
174 : AF_LATIN_CONSTANT( metrics, 50 );
175
176 /* let's try 20% of the smallest width */
177 axis->edge_distance_threshold = stdw / 5;
178 axis->standard_width = stdw;
179 axis->extra_light = 0;
180 }
181#ifdef __REACTOS__
182 free(dummy);
183 }
184#endif
185 }
186
188#ifdef __REACTOS__
189 free(hints);
190#endif
191 }
192
193
194
195#define AF_LATIN_MAX_TEST_CHARACTERS 12
196
197
198 static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES]
199 [AF_LATIN_MAX_TEST_CHARACTERS+1] =
200 {
201 "THEZOCQS",
202 "HEZLOCUS",
203 "fijkdbh",
204 "xzroesc",
205 "xzroesc",
206 "pqgjy"
207 };
208
209
210 static void
211 af_latin2_metrics_init_blues( AF_LatinMetrics metrics,
212 FT_Face face )
213 {
214 FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS];
215 FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS];
216 FT_Int num_flats;
217 FT_Int num_rounds;
218 FT_Int bb;
222 FT_GlyphSlot glyph = face->glyph;
223
224
225 /* we compute the blues simply by loading each character from the */
226 /* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */
227 /* bottom-most points (depending on `AF_IS_TOP_BLUE') */
228
229 FT_TRACE5(( "blue zones computation\n"
230 "======================\n\n" ));
231
232 for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
233 {
234 const char* p = af_latin2_blue_chars[bb];
235 const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
236 FT_Pos* blue_ref;
237 FT_Pos* blue_shoot;
238
239
240 FT_TRACE5(( "blue zone %d:\n", bb ));
241
242 num_flats = 0;
243 num_rounds = 0;
244
245 for ( ; p < limit && *p; p++ )
246 {
247 FT_UInt glyph_index;
248 FT_Int best_point, best_y, best_first, best_last;
251
252
253 /* load the character in the face -- skip unknown or empty ones */
254 glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
255 if ( glyph_index == 0 )
256 continue;
257
258 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
259 if ( error || glyph->outline.n_points <= 0 )
260 continue;
261
262 /* now compute min or max point indices and coordinates */
263 points = glyph->outline.points;
264 best_point = -1;
265 best_y = 0; /* make compiler happy */
266 best_first = 0; /* ditto */
267 best_last = 0; /* ditto */
268
269 {
270 FT_Int nn;
271 FT_Int first = 0;
272 FT_Int last = -1;
273
274
275 for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
276 {
277 FT_Int old_best_point = best_point;
278 FT_Int pp;
279
280
281 last = glyph->outline.contours[nn];
282
283 /* Avoid single-point contours since they are never rasterized. */
284 /* In some fonts, they correspond to mark attachment points */
285 /* which are way outside of the glyph's real outline. */
286 if ( last <= first )
287 continue;
288
289 if ( AF_LATIN_IS_TOP_BLUE( bb ) )
290 {
291 for ( pp = first; pp <= last; pp++ )
292 if ( best_point < 0 || points[pp].y > best_y )
293 {
294 best_point = pp;
295 best_y = points[pp].y;
296 }
297 }
298 else
299 {
300 for ( pp = first; pp <= last; pp++ )
301 if ( best_point < 0 || points[pp].y < best_y )
302 {
303 best_point = pp;
304 best_y = points[pp].y;
305 }
306 }
307
308 if ( best_point != old_best_point )
309 {
310 best_first = first;
311 best_last = last;
312 }
313 }
314 FT_TRACE5(( " %c %d", *p, best_y ));
315 }
316
317 /* now check whether the point belongs to a straight or round */
318 /* segment; we first need to find in which contour the extremum */
319 /* lies, then inspect its previous and next points */
320 if ( best_point >= 0 )
321 {
322 FT_Pos best_x = points[best_point].x;
323 FT_Int start, end, prev, next;
324 FT_Pos dist;
325
326
327 /* now look for the previous and next points that are not on the */
328 /* same Y coordinate. Threshold the `closeness'... */
329 start = end = best_point;
330
331 do
332 {
333 prev = start - 1;
334 if ( prev < best_first )
335 prev = best_last;
336
337 dist = FT_ABS( points[prev].y - best_y );
338 /* accept a small distance or a small angle (both values are */
339 /* heuristic; value 20 corresponds to approx. 2.9 degrees) */
340 if ( dist > 5 )
341 if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
342 break;
343
344 start = prev;
345
346 } while ( start != best_point );
347
348 do
349 {
350 next = end + 1;
351 if ( next > best_last )
352 next = best_first;
353
354 dist = FT_ABS( points[next].y - best_y );
355 if ( dist > 5 )
356 if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
357 break;
358
359 end = next;
360
361 } while ( end != best_point );
362
363 /* now, set the `round' flag depending on the segment's kind */
364 round = FT_BOOL(
366 FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON );
367
368 FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
369 }
370
371 if ( round )
372 rounds[num_rounds++] = best_y;
373 else
374 flats[num_flats++] = best_y;
375 }
376
377 if ( num_flats == 0 && num_rounds == 0 )
378 {
379 /*
380 * we couldn't find a single glyph to compute this blue zone,
381 * we will simply ignore it then
382 */
383 FT_TRACE5(( " empty\n" ));
384 continue;
385 }
386
387 /* we have computed the contents of the `rounds' and `flats' tables, */
388 /* now determine the reference and overshoot position of the blue -- */
389 /* we simply take the median value after a simple sort */
390 af_sort_pos( num_rounds, rounds );
391 af_sort_pos( num_flats, flats );
392
393 blue = & axis->blues[axis->blue_count];
394 blue_ref = & blue->ref.org;
395 blue_shoot = & blue->shoot.org;
396
397 axis->blue_count++;
398
399 if ( num_flats == 0 )
400 {
401 *blue_ref =
402 *blue_shoot = rounds[num_rounds / 2];
403 }
404 else if ( num_rounds == 0 )
405 {
406 *blue_ref =
407 *blue_shoot = flats[num_flats / 2];
408 }
409 else
410 {
411 *blue_ref = flats[num_flats / 2];
412 *blue_shoot = rounds[num_rounds / 2];
413 }
414
415 /* there are sometimes problems: if the overshoot position of top */
416 /* zones is under its reference position, or the opposite for bottom */
417 /* zones. We must thus check everything there and correct the errors */
418 if ( *blue_shoot != *blue_ref )
419 {
420 FT_Pos ref = *blue_ref;
421 FT_Pos shoot = *blue_shoot;
422 FT_Bool over_ref = FT_BOOL( shoot > ref );
423
424
425 if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
426 {
427 *blue_ref =
428 *blue_shoot = ( shoot + ref ) / 2;
429
430 FT_TRACE5(( " [overshoot smaller than reference,"
431 " taking mean value]\n" ));
432 }
433 }
434
435 blue->flags = 0;
436 if ( AF_LATIN_IS_TOP_BLUE( bb ) )
437 blue->flags |= AF_LATIN_BLUE_TOP;
438
439 /*
440 * The following flag is used later to adjust the y and x scales
441 * in order to optimize the pixel grid alignment of the top of small
442 * letters.
443 */
444 if ( AF_LATIN_IS_X_HEIGHT_BLUE( bb ) )
446
447 FT_TRACE5(( " -> reference = %ld\n"
448 " overshoot = %ld\n",
449 *blue_ref, *blue_shoot ));
450 }
451
452 return;
453 }
454
455
456 FT_LOCAL_DEF( void )
457 af_latin2_metrics_check_digits( AF_LatinMetrics metrics,
458 FT_Face face )
459 {
460 FT_UInt i;
461 FT_Bool started = 0, same_width = 1;
462 FT_Fixed advance, old_advance = 0;
463
464
465 /* check whether all ASCII digits have the same advance width; */
466 /* digit `0' is 0x30 in all supported charmaps */
467 for ( i = 0x30; i <= 0x39; i++ )
468 {
469 FT_UInt glyph_index;
470
471
472 glyph_index = FT_Get_Char_Index( face, i );
473 if ( glyph_index == 0 )
474 continue;
475
476 if ( FT_Get_Advance( face, glyph_index,
480 &advance ) )
481 continue;
482
483 if ( started )
484 {
485 if ( advance != old_advance )
486 {
487 same_width = 0;
488 break;
489 }
490 }
491 else
492 {
493 old_advance = advance;
494 started = 1;
495 }
496 }
497
498 metrics->root.digits_have_same_width = same_width;
499 }
500
501
503 af_latin2_metrics_init( AF_LatinMetrics metrics,
504 FT_Face face )
505 {
507 FT_CharMap oldmap = face->charmap;
508 FT_UInt ee;
509
510 static const FT_Encoding latin_encodings[] =
511 {
512 FT_ENCODING_UNICODE,
513 FT_ENCODING_APPLE_ROMAN,
514 FT_ENCODING_ADOBE_STANDARD,
515 FT_ENCODING_ADOBE_LATIN_1,
516 FT_ENCODING_NONE /* end of list */
517 };
518
519
520 metrics->units_per_em = face->units_per_EM;
521
522 /* do we have a latin charmap in there? */
523 for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
524 {
525 error = FT_Select_Charmap( face, latin_encodings[ee] );
526 if ( !error )
527 break;
528 }
529
530 if ( !error )
531 {
532 af_latin2_metrics_init_widths( metrics, face );
533 af_latin2_metrics_init_blues( metrics, face );
534 af_latin2_metrics_check_digits( metrics, face );
535 }
536
537 FT_Set_Charmap( face, oldmap );
538 return FT_Err_Ok;
539 }
540
541
542 static void
543 af_latin2_metrics_scale_dim( AF_LatinMetrics metrics,
544 AF_Scaler scaler,
545 AF_Dimension dim )
546 {
548 FT_Pos delta;
549 AF_LatinAxis axis;
550 FT_UInt nn;
551
552
553 if ( dim == AF_DIMENSION_HORZ )
554 {
555 scale = scaler->x_scale;
556 delta = scaler->x_delta;
557 }
558 else
559 {
560 scale = scaler->y_scale;
561 delta = scaler->y_delta;
562 }
563
564 axis = &metrics->axis[dim];
565
566 if ( axis->org_scale == scale && axis->org_delta == delta )
567 return;
568
569 axis->org_scale = scale;
570 axis->org_delta = delta;
571
572 /*
573 * correct Y scale to optimize the alignment of the top of small
574 * letters to the pixel grid
575 */
576 if ( dim == AF_DIMENSION_VERT )
577 {
578 AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT];
580
581
582 for ( nn = 0; nn < vaxis->blue_count; nn++ )
583 {
584 if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
585 {
586 blue = &vaxis->blues[nn];
587 break;
588 }
589 }
590
591 if ( blue )
592 {
593 FT_Pos scaled;
594 FT_Pos threshold;
595 FT_Pos fitted;
597 FT_UInt ppem;
598
599
600 scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
601 ppem = metrics->root.scaler.face->size->metrics.x_ppem;
602 limit = metrics->root.globals->increase_x_height;
603 threshold = 40;
604
605 /* if the `increase-x-height' property is active, */
606 /* we round up much more often */
607 if ( limit &&
608 ppem <= limit &&
610 threshold = 52;
611
612 fitted = ( scaled + threshold ) & ~63;
613
614#if 1
615 if ( scaled != fitted )
616 {
617 scale = FT_MulDiv( scale, fitted, scaled );
618 FT_TRACE5(( "== scaled x-top = %.2g"
619 " fitted = %.2g, scaling = %.4g\n",
620 scaled / 64.0, fitted / 64.0,
621 ( fitted * 1.0 ) / scaled ));
622 }
623#endif
624 }
625 }
626
627 axis->scale = scale;
628 axis->delta = delta;
629
630 if ( dim == AF_DIMENSION_HORZ )
631 {
632 metrics->root.scaler.x_scale = scale;
633 metrics->root.scaler.x_delta = delta;
634 }
635 else
636 {
637 metrics->root.scaler.y_scale = scale;
638 metrics->root.scaler.y_delta = delta;
639 }
640
641 /* scale the standard widths */
642 for ( nn = 0; nn < axis->width_count; nn++ )
643 {
644 AF_Width width = axis->widths + nn;
645
646
647 width->cur = FT_MulFix( width->org, scale );
648 width->fit = width->cur;
649 }
650
651 /* an extra-light axis corresponds to a standard width that is */
652 /* smaller than 5/8 pixels */
653 axis->extra_light =
654 FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
655
656 if ( dim == AF_DIMENSION_VERT )
657 {
658 /* scale the blue zones */
659 for ( nn = 0; nn < axis->blue_count; nn++ )
660 {
661 AF_LatinBlue blue = &axis->blues[nn];
662 FT_Pos dist;
663
664
665 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
666 blue->ref.fit = blue->ref.cur;
667 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
668 blue->shoot.fit = blue->shoot.cur;
669 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
670
671 /* a blue zone is only active if it is less than 3/4 pixels tall */
672 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
673 if ( dist <= 48 && dist >= -48 )
674 {
675 FT_Pos delta1, delta2;
676
677 delta1 = blue->shoot.org - blue->ref.org;
678 delta2 = delta1;
679 if ( delta1 < 0 )
680 delta2 = -delta2;
681
682 delta2 = FT_MulFix( delta2, scale );
683
684 if ( delta2 < 32 )
685 delta2 = 0;
686 else if ( delta2 < 64 )
687 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
688 else
689 delta2 = FT_PIX_ROUND( delta2 );
690
691 if ( delta1 < 0 )
692 delta2 = -delta2;
693
694 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
695 blue->shoot.fit = blue->ref.fit + delta2;
696
697 FT_TRACE5(( ">> activating blue zone %d:"
698 " ref.cur=%.2g ref.fit=%.2g"
699 " shoot.cur=%.2g shoot.fit=%.2g\n",
700 nn, blue->ref.cur / 64.0, blue->ref.fit / 64.0,
701 blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 ));
702
703 blue->flags |= AF_LATIN_BLUE_ACTIVE;
704 }
705 }
706 }
707 }
708
709
710 FT_LOCAL_DEF( void )
711 af_latin2_metrics_scale( AF_LatinMetrics metrics,
712 AF_Scaler scaler )
713 {
714 metrics->root.scaler.render_mode = scaler->render_mode;
715 metrics->root.scaler.face = scaler->face;
716 metrics->root.scaler.flags = scaler->flags;
717
718 af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
719 af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
720 }
721
722
723 /* Extract standard_width from writing system/script specific */
724 /* metrics class. */
725
726 FT_LOCAL_DEF( void )
727 af_latin2_get_standard_widths( AF_LatinMetrics metrics,
728 FT_Pos* stdHW,
729 FT_Pos* stdVW )
730 {
731 if ( stdHW )
732 *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
733
734 if ( stdVW )
735 *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
736 }
737
738
739 /*************************************************************************/
740 /*************************************************************************/
741 /***** *****/
742 /***** L A T I N G L Y P H A N A L Y S I S *****/
743 /***** *****/
744 /*************************************************************************/
745 /*************************************************************************/
746
747#define SORT_SEGMENTS
748
750 af_latin2_hints_compute_segments( AF_GlyphHints hints,
751 AF_Dimension dim )
752 {
753 AF_AxisHints axis = &hints->axis[dim];
754 FT_Memory memory = hints->memory;
756 AF_Segment segment = NULL;
757 AF_SegmentRec seg0;
758 AF_Point* contour = hints->contours;
759 AF_Point* contour_limit = contour + hints->num_contours;
760 AF_Direction major_dir, segment_dir;
761
762
763 FT_ZERO( &seg0 );
764 seg0.score = 32000;
765 seg0.flags = AF_EDGE_NORMAL;
766
767 major_dir = (AF_Direction)FT_ABS( axis->major_dir );
768 segment_dir = major_dir;
769
770 axis->num_segments = 0;
771
772 /* set up (u,v) in each point */
773 if ( dim == AF_DIMENSION_HORZ )
774 {
775 AF_Point point = hints->points;
776 AF_Point limit = point + hints->num_points;
777
778
779 for ( ; point < limit; point++ )
780 {
781 point->u = point->fx;
782 point->v = point->fy;
783 }
784 }
785 else
786 {
787 AF_Point point = hints->points;
788 AF_Point limit = point + hints->num_points;
789
790
791 for ( ; point < limit; point++ )
792 {
793 point->u = point->fy;
794 point->v = point->fx;
795 }
796 }
797
798 /* do each contour separately */
799 for ( ; contour < contour_limit; contour++ )
800 {
801 AF_Point point = contour[0];
803 AF_Point last = point->prev;
804
805
806 if ( point == last ) /* skip singletons -- just in case */
807 continue;
808
809 /* already on an edge ?, backtrack to find its start */
810 if ( FT_ABS( point->in_dir ) == major_dir )
811 {
812 point = point->prev;
813
814 while ( point->in_dir == start->in_dir )
815 point = point->prev;
816 }
817 else /* otherwise, find first segment start, if any */
818 {
819 while ( FT_ABS( point->out_dir ) != major_dir )
820 {
821 point = point->next;
822
823 if ( point == start )
824 goto NextContour;
825 }
826 }
827
828 start = point;
829
830 for (;;)
831 {
833 FT_Pos min_u, min_v, max_u, max_v;
834
835 /* we're at the start of a new segment */
836 FT_ASSERT( FT_ABS( point->out_dir ) == major_dir &&
837 point->in_dir != point->out_dir );
838 first = point;
839
840 min_u = max_u = point->u;
841 min_v = max_v = point->v;
842
843 point = point->next;
844
845 while ( point->out_dir == first->out_dir )
846 {
847 point = point->next;
848
849 if ( point->u < min_u )
850 min_u = point->u;
851
852 if ( point->u > max_u )
853 max_u = point->u;
854 }
855
856 if ( point->v < min_v )
857 min_v = point->v;
858
859 if ( point->v > max_v )
860 max_v = point->v;
861
862 /* record new segment */
863 error = af_axis_hints_new_segment( axis, memory, &segment );
864 if ( error )
865 goto Exit;
866
867 segment[0] = seg0;
868 segment->dir = first->out_dir;
869 segment->first = first;
870 segment->last = point;
871 segment->pos = (FT_Short)( ( min_u + max_u ) >> 1 );
872 segment->min_coord = (FT_Short) min_v;
873 segment->max_coord = (FT_Short) max_v;
874 segment->height = (FT_Short)( max_v - min_v );
875
876 /* a segment is round if it doesn't have successive */
877 /* on-curve points. */
878 {
879 AF_Point pt = first;
881 FT_UInt f0 = pt->flags & AF_FLAG_CONTROL;
882 FT_UInt f1;
883
884
885 segment->flags &= ~AF_EDGE_ROUND;
886
887 for ( ; pt != last; f0 = f1 )
888 {
889 pt = pt->next;
890 f1 = pt->flags & AF_FLAG_CONTROL;
891
892 if ( !f0 && !f1 )
893 break;
894
895 if ( pt == last )
896 segment->flags |= AF_EDGE_ROUND;
897 }
898 }
899
900 /* this can happen in the case of a degenerate contour
901 * e.g. a 2-point vertical contour
902 */
903 if ( point == start )
904 break;
905
906 /* jump to the start of the next segment, if any */
907 while ( FT_ABS( point->out_dir ) != major_dir )
908 {
909 point = point->next;
910
911 if ( point == start )
912 goto NextContour;
913 }
914 }
915
916 NextContour:
917 ;
918 } /* contours */
919
920 /* now slightly increase the height of segments when this makes */
921 /* sense -- this is used to better detect and ignore serifs */
922 {
923 AF_Segment segments = axis->segments;
924 AF_Segment segments_end = segments + axis->num_segments;
925
926
927 for ( segment = segments; segment < segments_end; segment++ )
928 {
929 AF_Point first = segment->first;
930 AF_Point last = segment->last;
931 AF_Point p;
932 FT_Pos first_v = first->v;
933 FT_Pos last_v = last->v;
934
935
936 if ( first_v < last_v )
937 {
938 p = first->prev;
939 if ( p->v < first_v )
940 segment->height = (FT_Short)( segment->height +
941 ( ( first_v - p->v ) >> 1 ) );
942
943 p = last->next;
944 if ( p->v > last_v )
945 segment->height = (FT_Short)( segment->height +
946 ( ( p->v - last_v ) >> 1 ) );
947 }
948 else
949 {
950 p = first->prev;
951 if ( p->v > first_v )
952 segment->height = (FT_Short)( segment->height +
953 ( ( p->v - first_v ) >> 1 ) );
954
955 p = last->next;
956 if ( p->v < last_v )
957 segment->height = (FT_Short)( segment->height +
958 ( ( last_v - p->v ) >> 1 ) );
959 }
960 }
961 }
962
963#ifdef AF_SORT_SEGMENTS
964 /* place all segments with a negative direction to the start
965 * of the array, used to speed up segment linking later...
966 */
967 {
968 AF_Segment segments = axis->segments;
969 FT_UInt count = axis->num_segments;
970 FT_UInt ii, jj;
971
972 for ( ii = 0; ii < count; ii++ )
973 {
974 if ( segments[ii].dir > 0 )
975 {
976 for ( jj = ii + 1; jj < count; jj++ )
977 {
978 if ( segments[jj].dir < 0 )
979 {
980 AF_SegmentRec tmp;
981
982
983 tmp = segments[ii];
984 segments[ii] = segments[jj];
985 segments[jj] = tmp;
986
987 break;
988 }
989 }
990
991 if ( jj == count )
992 break;
993 }
994 }
995 axis->mid_segments = ii;
996 }
997#endif
998
999 Exit:
1000 return error;
1001 }
1002
1003
1004 FT_LOCAL_DEF( void )
1005 af_latin2_hints_link_segments( AF_GlyphHints hints,
1006 AF_Dimension dim )
1007 {
1008 AF_AxisHints axis = &hints->axis[dim];
1009 AF_Segment segments = axis->segments;
1010 AF_Segment segment_limit = segments + axis->num_segments;
1011#ifdef AF_SORT_SEGMENTS
1012 AF_Segment segment_mid = segments + axis->mid_segments;
1013#endif
1014 FT_Pos len_threshold, len_score;
1015 AF_Segment seg1, seg2;
1016
1017
1018 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
1019 if ( len_threshold == 0 )
1020 len_threshold = 1;
1021
1022 len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
1023
1024#ifdef AF_SORT_SEGMENTS
1025 for ( seg1 = segments; seg1 < segment_mid; seg1++ )
1026 {
1027 if ( seg1->dir != axis->major_dir )
1028 continue;
1029
1030 for ( seg2 = segment_mid; seg2 < segment_limit; seg2++ )
1031#else
1032 /* now compare each segment to the others */
1033 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1034 {
1035 if ( seg1->dir != axis->major_dir )
1036 continue;
1037
1038 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
1039 if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
1040#endif
1041 {
1042 FT_Pos pos1 = seg1->pos;
1043 FT_Pos pos2 = seg2->pos;
1044 FT_Pos dist = pos2 - pos1;
1045
1046
1047 if ( dist < 0 )
1048 continue;
1049
1050 {
1051 FT_Pos min = seg1->min_coord;
1052 FT_Pos max = seg1->max_coord;
1053 FT_Pos len, score;
1054
1055
1056 if ( min < seg2->min_coord )
1057 min = seg2->min_coord;
1058
1059 if ( max > seg2->max_coord )
1060 max = seg2->max_coord;
1061
1062 len = max - min;
1063 if ( len >= len_threshold )
1064 {
1065 score = dist + len_score / len;
1066 if ( score < seg1->score )
1067 {
1068 seg1->score = score;
1069 seg1->link = seg2;
1070 }
1071
1072 if ( score < seg2->score )
1073 {
1074 seg2->score = score;
1075 seg2->link = seg1;
1076 }
1077 }
1078 }
1079 }
1080 }
1081#if 0
1082 }
1083#endif
1084
1085 /* now, compute the `serif' segments */
1086 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1087 {
1088 seg2 = seg1->link;
1089
1090 if ( seg2 )
1091 {
1092 if ( seg2->link != seg1 )
1093 {
1094 seg1->link = NULL;
1095 seg1->serif = seg2->link;
1096 }
1097 }
1098 }
1099 }
1100
1101
1103 af_latin2_hints_compute_edges( AF_GlyphHints hints,
1104 AF_Dimension dim )
1105 {
1106 AF_AxisHints axis = &hints->axis[dim];
1108 FT_Memory memory = hints->memory;
1109 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
1110
1111 AF_Segment segments = axis->segments;
1112 AF_Segment segment_limit = segments + axis->num_segments;
1113 AF_Segment seg;
1114
1115 AF_Direction up_dir;
1117 FT_Pos edge_distance_threshold;
1118 FT_Pos segment_length_threshold;
1119
1120
1121 axis->num_edges = 0;
1122
1123 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
1124 : hints->y_scale;
1125
1126 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
1127 : AF_DIR_RIGHT;
1128
1129 /*
1130 * We want to ignore very small (mostly serif) segments, we do that
1131 * by ignoring those that whose length is less than a given fraction
1132 * of the standard width. If there is no standard width, we ignore
1133 * those that are less than a given size in pixels
1134 *
1135 * also, unlink serif segments that are linked to segments farther
1136 * than 50% of the standard width
1137 */
1138 if ( dim == AF_DIMENSION_HORZ )
1139 {
1140 if ( laxis->width_count > 0 )
1141 segment_length_threshold = ( laxis->standard_width * 10 ) >> 4;
1142 else
1143 segment_length_threshold = FT_DivFix( 64, hints->y_scale );
1144 }
1145 else
1146 segment_length_threshold = 0;
1147
1148 /**********************************************************************
1149 *
1150 * We will begin by generating a sorted table of edges for the
1151 * current direction. To do so, we simply scan each segment and try
1152 * to find an edge in our table that corresponds to its position.
1153 *
1154 * If no edge is found, we create and insert a new edge in the
1155 * sorted table. Otherwise, we simply add the segment to the edge's
1156 * list which will be processed in the second step to compute the
1157 * edge's properties.
1158 *
1159 * Note that the edges table is sorted along the segment/edge
1160 * position.
1161 *
1162 */
1163
1164 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
1165 scale );
1166 if ( edge_distance_threshold > 64 / 4 )
1167 edge_distance_threshold = 64 / 4;
1168
1169 edge_distance_threshold = FT_DivFix( edge_distance_threshold,
1170 scale );
1171
1172 for ( seg = segments; seg < segment_limit; seg++ )
1173 {
1174 AF_Edge found = NULL;
1175 FT_Int ee;
1176
1177
1178 if ( seg->height < segment_length_threshold )
1179 continue;
1180
1181 /* A special case for serif edges: If they are smaller than */
1182 /* 1.5 pixels we ignore them. */
1183 if ( seg->serif )
1184 {
1185 FT_Pos dist = seg->serif->pos - seg->pos;
1186
1187
1188 if ( dist < 0 )
1189 dist = -dist;
1190
1191 if ( dist >= laxis->standard_width >> 1 )
1192 {
1193 /* unlink this serif, it is too distant from its reference stem */
1194 seg->serif = NULL;
1195 }
1196 else if ( 2*seg->height < 3 * segment_length_threshold )
1197 continue;
1198 }
1199
1200 /* look for an edge corresponding to the segment */
1201 for ( ee = 0; ee < axis->num_edges; ee++ )
1202 {
1203 AF_Edge edge = axis->edges + ee;
1204 FT_Pos dist;
1205
1206
1207 dist = seg->pos - edge->fpos;
1208 if ( dist < 0 )
1209 dist = -dist;
1210
1211 if ( dist < edge_distance_threshold && edge->dir == seg->dir )
1212 {
1213 found = edge;
1214 break;
1215 }
1216 }
1217
1218 if ( !found )
1219 {
1220 AF_Edge edge;
1221
1222
1223 /* insert a new edge in the list and */
1224 /* sort according to the position */
1225 error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, 0,
1226 memory, &edge );
1227 if ( error )
1228 goto Exit;
1229
1230 /* add the segment to the new edge's list */
1231 FT_ZERO( edge );
1232
1233 edge->first = seg;
1234 edge->last = seg;
1235 edge->dir = seg->dir;
1236 edge->fpos = seg->pos;
1237 edge->opos = FT_MulFix( seg->pos, scale );
1238 edge->pos = edge->opos;
1239 seg->edge_next = seg;
1240 }
1241 else
1242 {
1243 /* if an edge was found, simply add the segment to the edge's */
1244 /* list */
1245 seg->edge_next = found->first;
1246 found->last->edge_next = seg;
1247 found->last = seg;
1248 }
1249 }
1250
1251
1252 /**********************************************************************
1253 *
1254 * Good, we will now compute each edge's properties according to
1255 * segments found on its position. Basically, these are:
1256 *
1257 * - edge's main direction
1258 * - stem edge, serif edge or both (which defaults to stem then)
1259 * - rounded edge, straight or both (which defaults to straight)
1260 * - link for edge
1261 *
1262 */
1263
1264 /* first of all, set the `edge' field in each segment -- this is */
1265 /* required in order to compute edge links */
1266
1267 /*
1268 * Note that removing this loop and setting the `edge' field of each
1269 * segment directly in the code above slows down execution speed for
1270 * some reasons on platforms like the Sun.
1271 */
1272 {
1273 AF_Edge edges = axis->edges;
1274 AF_Edge edge_limit = edges + axis->num_edges;
1275 AF_Edge edge;
1276
1277
1278 for ( edge = edges; edge < edge_limit; edge++ )
1279 {
1280 seg = edge->first;
1281 if ( seg )
1282 do
1283 {
1284 seg->edge = edge;
1285 seg = seg->edge_next;
1286
1287 } while ( seg != edge->first );
1288 }
1289
1290 /* now, compute each edge properties */
1291 for ( edge = edges; edge < edge_limit; edge++ )
1292 {
1293 FT_Int is_round = 0; /* does it contain round segments? */
1294 FT_Int is_straight = 0; /* does it contain straight segments? */
1295#if 0
1296 FT_Pos ups = 0; /* number of upwards segments */
1297 FT_Pos downs = 0; /* number of downwards segments */
1298#endif
1299
1300
1301 seg = edge->first;
1302
1303 do
1304 {
1305 FT_Bool is_serif;
1306
1307
1308 /* check for roundness of segment */
1309 if ( seg->flags & AF_EDGE_ROUND )
1310 is_round++;
1311 else
1312 is_straight++;
1313
1314#if 0
1315 /* check for segment direction */
1316 if ( seg->dir == up_dir )
1317 ups += seg->max_coord-seg->min_coord;
1318 else
1319 downs += seg->max_coord-seg->min_coord;
1320#endif
1321
1322 /* check for links -- if seg->serif is set, then seg->link must */
1323 /* be ignored */
1324 is_serif = FT_BOOL( seg->serif &&
1325 seg->serif->edge &&
1326 seg->serif->edge != edge );
1327
1328 if ( ( seg->link && seg->link->edge ) || is_serif )
1329 {
1330 AF_Edge edge2;
1331 AF_Segment seg2;
1332
1333
1334 edge2 = edge->link;
1335 seg2 = seg->link;
1336
1337 if ( is_serif )
1338 {
1339 seg2 = seg->serif;
1340 edge2 = edge->serif;
1341 }
1342
1343 if ( edge2 )
1344 {
1345 FT_Pos edge_delta;
1346 FT_Pos seg_delta;
1347
1348
1349 edge_delta = edge->fpos - edge2->fpos;
1350 if ( edge_delta < 0 )
1351 edge_delta = -edge_delta;
1352
1353 seg_delta = seg->pos - seg2->pos;
1354 if ( seg_delta < 0 )
1355 seg_delta = -seg_delta;
1356
1357 if ( seg_delta < edge_delta )
1358 edge2 = seg2->edge;
1359 }
1360 else
1361 edge2 = seg2->edge;
1362
1363 if ( is_serif )
1364 {
1365 edge->serif = edge2;
1366 edge2->flags |= AF_EDGE_SERIF;
1367 }
1368 else
1369 edge->link = edge2;
1370 }
1371
1372 seg = seg->edge_next;
1373
1374 } while ( seg != edge->first );
1375
1376 /* set the round/straight flags */
1377 edge->flags = AF_EDGE_NORMAL;
1378
1379 if ( is_round > 0 && is_round >= is_straight )
1380 edge->flags |= AF_EDGE_ROUND;
1381
1382#if 0
1383 /* set the edge's main direction */
1384 edge->dir = AF_DIR_NONE;
1385
1386 if ( ups > downs )
1387 edge->dir = (FT_Char)up_dir;
1388
1389 else if ( ups < downs )
1390 edge->dir = (FT_Char)-up_dir;
1391
1392 else if ( ups == downs )
1393 edge->dir = 0; /* both up and down! */
1394#endif
1395
1396 /* gets rid of serifs if link is set */
1397 /* XXX: This gets rid of many unpleasant artefacts! */
1398 /* Example: the `c' in cour.pfa at size 13 */
1399
1400 if ( edge->serif && edge->link )
1401 edge->serif = NULL;
1402 }
1403 }
1404
1405 Exit:
1406 return error;
1407 }
1408
1409
1411 af_latin2_hints_detect_features( AF_GlyphHints hints,
1412 AF_Dimension dim )
1413 {
1415
1416
1417 error = af_latin2_hints_compute_segments( hints, dim );
1418 if ( !error )
1419 {
1420 af_latin2_hints_link_segments( hints, dim );
1421
1422 error = af_latin2_hints_compute_edges( hints, dim );
1423 }
1424 return error;
1425 }
1426
1427
1428 static void
1429 af_latin2_hints_compute_blue_edges( AF_GlyphHints hints,
1431 {
1432 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
1433 AF_Edge edge = axis->edges;
1434 AF_Edge edge_limit = edge + axis->num_edges;
1435 AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
1436 FT_Fixed scale = latin->scale;
1437 FT_Pos best_dist0; /* initial threshold */
1438
1439
1440 /* compute the initial threshold as a fraction of the EM size */
1441 best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
1442
1443 if ( best_dist0 > 64 / 2 )
1444 best_dist0 = 64 / 2;
1445
1446 /* compute which blue zones are active, i.e. have their scaled */
1447 /* size < 3/4 pixels */
1448
1449 /* for each horizontal edge search the blue zone which is closest */
1450 for ( ; edge < edge_limit; edge++ )
1451 {
1452 FT_Int bb;
1453 AF_Width best_blue = NULL;
1454 FT_Pos best_dist = best_dist0;
1455
1456 for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
1457 {
1458 AF_LatinBlue blue = latin->blues + bb;
1459 FT_Bool is_top_blue, is_major_dir;
1460
1461
1462 /* skip inactive blue zones (i.e., those that are too small) */
1463 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1464 continue;
1465
1466 /* if it is a top zone, check for right edges -- if it is a bottom */
1467 /* zone, check for left edges */
1468 /* */
1469 /* of course, that's for TrueType */
1470 is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
1471 is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
1472
1473 /* if it is a top zone, the edge must be against the major */
1474 /* direction; if it is a bottom zone, it must be in the major */
1475 /* direction */
1476 if ( is_top_blue ^ is_major_dir )
1477 {
1478 FT_Pos dist;
1480
1481
1482 /* if it's a rounded edge, compare it to the overshoot position */
1483 /* if it's a flat edge, compare it to the reference position */
1484 if ( edge->flags & AF_EDGE_ROUND )
1485 compare = &blue->shoot;
1486 else
1487 compare = &blue->ref;
1488
1489 dist = edge->fpos - compare->org;
1490 if ( dist < 0 )
1491 dist = -dist;
1492
1493 dist = FT_MulFix( dist, scale );
1494 if ( dist < best_dist )
1495 {
1496 best_dist = dist;
1497 best_blue = compare;
1498 }
1499
1500#if 0
1501 /* now, compare it to the overshoot position if the edge is */
1502 /* rounded, and if the edge is over the reference position of a */
1503 /* top zone, or under the reference position of a bottom zone */
1504 if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
1505 {
1506 FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
1507
1508
1509 if ( is_top_blue ^ is_under_ref )
1510 {
1511 blue = latin->blues + bb;
1512 dist = edge->fpos - blue->shoot.org;
1513 if ( dist < 0 )
1514 dist = -dist;
1515
1516 dist = FT_MulFix( dist, scale );
1517 if ( dist < best_dist )
1518 {
1519 best_dist = dist;
1520 best_blue = & blue->shoot;
1521 }
1522 }
1523 }
1524#endif
1525 }
1526 }
1527
1528 if ( best_blue )
1529 edge->blue_edge = best_blue;
1530 }
1531 }
1532
1533
1534 static FT_Error
1535 af_latin2_hints_init( AF_GlyphHints hints,
1537 {
1539 FT_UInt32 scaler_flags, other_flags;
1540 FT_Face face = metrics->root.scaler.face;
1541
1542
1544
1545 /*
1546 * correct x_scale and y_scale if needed, since they may have
1547 * been modified `af_latin2_metrics_scale_dim' above
1548 */
1549 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
1550 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
1551 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
1552 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
1553
1554 /* compute flags depending on render mode, etc. */
1555 mode = metrics->root.scaler.render_mode;
1556
1557#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
1559 metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
1560#endif
1561
1562 scaler_flags = hints->scaler_flags;
1563 other_flags = 0;
1564
1565 /*
1566 * We snap the width of vertical stems for the monochrome and
1567 * horizontal LCD rendering targets only.
1568 */
1570 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
1571
1572 /*
1573 * We snap the width of horizontal stems for the monochrome and
1574 * vertical LCD rendering targets only.
1575 */
1577 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
1578
1579 /*
1580 * We adjust stems to full pixels unless in `light' or `lcd' mode.
1581 */
1583 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
1584
1585 if ( mode == FT_RENDER_MODE_MONO )
1586 other_flags |= AF_LATIN_HINTS_MONO;
1587
1588 /*
1589 * In `light' or `lcd' mode we disable horizontal hinting completely.
1590 * We also do it if the face is italic.
1591 */
1593 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
1594 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
1595
1596#ifdef AF_CONFIG_OPTION_USE_WARPER
1597 /* get (global) warper flag */
1598 if ( !metrics->root.globals->module->warping )
1599 scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
1600#endif
1601
1602 hints->scaler_flags = scaler_flags;
1603 hints->other_flags = other_flags;
1604
1605 return 0;
1606 }
1607
1608
1609 /*************************************************************************/
1610 /*************************************************************************/
1611 /***** *****/
1612 /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
1613 /***** *****/
1614 /*************************************************************************/
1615 /*************************************************************************/
1616
1617 /* snap a given width in scaled coordinates to one of the */
1618 /* current standard widths */
1619
1620 static FT_Pos
1621 af_latin2_snap_width( AF_Width widths,
1622 FT_UInt count,
1623 FT_Pos width )
1624 {
1625 FT_UInt n;
1626 FT_Pos best = 64 + 32 + 2;
1628 FT_Pos scaled;
1629
1630
1631 for ( n = 0; n < count; n++ )
1632 {
1633 FT_Pos w;
1634 FT_Pos dist;
1635
1636
1637 w = widths[n].cur;
1638 dist = width - w;
1639 if ( dist < 0 )
1640 dist = -dist;
1641 if ( dist < best )
1642 {
1643 best = dist;
1644 reference = w;
1645 }
1646 }
1647
1648 scaled = FT_PIX_ROUND( reference );
1649
1650 if ( width >= reference )
1651 {
1652 if ( width < scaled + 48 )
1653 width = reference;
1654 }
1655 else
1656 {
1657 if ( width > scaled - 48 )
1658 width = reference;
1659 }
1660
1661 return width;
1662 }
1663
1664
1665 /* compute the snapped width of a given stem */
1666
1667 static FT_Pos
1668 af_latin2_compute_stem_width( AF_GlyphHints hints,
1669 AF_Dimension dim,
1670 FT_Pos width,
1671 FT_UInt base_flags,
1672 FT_UInt stem_flags )
1673 {
1675 AF_LatinAxis axis = & metrics->axis[dim];
1676 FT_Pos dist = width;
1677 FT_Int sign = 0;
1678 FT_Int vertical = ( dim == AF_DIMENSION_VERT );
1679
1680 FT_UNUSED( base_flags );
1681
1682
1684 axis->extra_light )
1685 return width;
1686
1687 if ( dist < 0 )
1688 {
1689 dist = -width;
1690 sign = 1;
1691 }
1692
1693 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
1694 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
1695 {
1696 /* smooth hinting process: very lightly quantize the stem width */
1697
1698 /* leave the widths of serifs alone */
1699
1700 if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
1701 goto Done_Width;
1702
1703#if 0
1704 else if ( ( base_flags & AF_EDGE_ROUND ) )
1705 {
1706 if ( dist < 80 )
1707 dist = 64;
1708 }
1709 else if ( dist < 56 )
1710 dist = 56;
1711#endif
1712 if ( axis->width_count > 0 )
1713 {
1714 FT_Pos delta;
1715
1716
1717 /* compare to standard width */
1718 if ( axis->width_count > 0 )
1719 {
1720 delta = dist - axis->widths[0].cur;
1721
1722 if ( delta < 0 )
1723 delta = -delta;
1724
1725 if ( delta < 40 )
1726 {
1727 dist = axis->widths[0].cur;
1728 if ( dist < 48 )
1729 dist = 48;
1730
1731 goto Done_Width;
1732 }
1733 }
1734
1735 if ( dist < 3 * 64 )
1736 {
1737 delta = dist & 63;
1738 dist &= -64;
1739
1740 if ( delta < 10 )
1741 dist += delta;
1742
1743 else if ( delta < 32 )
1744 dist += 10;
1745
1746 else if ( delta < 54 )
1747 dist += 54;
1748
1749 else
1750 dist += delta;
1751 }
1752 else
1753 dist = ( dist + 32 ) & ~63;
1754 }
1755 }
1756 else
1757 {
1758 /* strong hinting process: snap the stem width to integer pixels */
1759 FT_Pos org_dist = dist;
1760
1761
1762 dist = af_latin2_snap_width( axis->widths, axis->width_count, dist );
1763
1764 if ( vertical )
1765 {
1766 /* in the case of vertical hinting, always round */
1767 /* the stem heights to integer pixels */
1768
1769 if ( dist >= 64 )
1770 dist = ( dist + 16 ) & ~63;
1771 else
1772 dist = 64;
1773 }
1774 else
1775 {
1777 {
1778 /* monochrome horizontal hinting: snap widths to integer pixels */
1779 /* with a different threshold */
1780
1781 if ( dist < 64 )
1782 dist = 64;
1783 else
1784 dist = ( dist + 32 ) & ~63;
1785 }
1786 else
1787 {
1788 /* for horizontal anti-aliased hinting, we adopt a more subtle */
1789 /* approach: we strengthen small stems, round stems whose size */
1790 /* is between 1 and 2 pixels to an integer, otherwise nothing */
1791
1792 if ( dist < 48 )
1793 dist = ( dist + 64 ) >> 1;
1794
1795 else if ( dist < 128 )
1796 {
1797 /* We only round to an integer width if the corresponding */
1798 /* distortion is less than 1/4 pixel. Otherwise this */
1799 /* makes everything worse since the diagonals, which are */
1800 /* not hinted, appear a lot bolder or thinner than the */
1801 /* vertical stems. */
1802
1803 FT_Int delta;
1804
1805
1806 dist = ( dist + 22 ) & ~63;
1807 delta = dist - org_dist;
1808 if ( delta < 0 )
1809 delta = -delta;
1810
1811 if ( delta >= 16 )
1812 {
1813 dist = org_dist;
1814 if ( dist < 48 )
1815 dist = ( dist + 64 ) >> 1;
1816 }
1817 }
1818 else
1819 /* round otherwise to prevent color fringes in LCD mode */
1820 dist = ( dist + 32 ) & ~63;
1821 }
1822 }
1823 }
1824
1825 Done_Width:
1826 if ( sign )
1827 dist = -dist;
1828
1829 return dist;
1830 }
1831
1832
1833 /* align one stem edge relative to the previous stem edge */
1834
1835 static void
1836 af_latin2_align_linked_edge( AF_GlyphHints hints,
1837 AF_Dimension dim,
1838 AF_Edge base_edge,
1839 AF_Edge stem_edge )
1840 {
1841 FT_Pos dist = stem_edge->opos - base_edge->opos;
1842
1843 FT_Pos fitted_width = af_latin2_compute_stem_width( hints, dim, dist,
1844 base_edge->flags,
1845 stem_edge->flags );
1846
1847
1848 stem_edge->pos = base_edge->pos + fitted_width;
1849
1850 FT_TRACE5(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
1851 "dist was %.2f, now %.2f\n",
1852 stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
1853 stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
1854 }
1855
1856
1857 static void
1858 af_latin2_align_serif_edge( AF_GlyphHints hints,
1859 AF_Edge base,
1860 AF_Edge serif )
1861 {
1862 FT_UNUSED( hints );
1863
1864 serif->pos = base->pos + ( serif->opos - base->opos );
1865 }
1866
1867
1868 /*************************************************************************/
1869 /*************************************************************************/
1870 /*************************************************************************/
1871 /**** ****/
1872 /**** E D G E H I N T I N G ****/
1873 /**** ****/
1874 /*************************************************************************/
1875 /*************************************************************************/
1876 /*************************************************************************/
1877
1878
1879 static void
1880 af_latin2_hint_edges( AF_GlyphHints hints,
1881 AF_Dimension dim )
1882 {
1883 AF_AxisHints axis = &hints->axis[dim];
1884 AF_Edge edges = axis->edges;
1885 AF_Edge edge_limit = edges + axis->num_edges;
1886 AF_Edge edge;
1887 AF_Edge anchor = NULL;
1888 FT_Int has_serifs = 0;
1889 FT_Pos anchor_drift = 0;
1890
1891
1892
1893 FT_TRACE5(( "==== hinting %s edges =====\n",
1894 dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ));
1895
1896 /* we begin by aligning all stems relative to the blue zone */
1897 /* if needed -- that's only for horizontal edges */
1898
1899 if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
1900 {
1901 for ( edge = edges; edge < edge_limit; edge++ )
1902 {
1903 AF_Width blue;
1904 AF_Edge edge1, edge2;
1905
1906
1907 if ( edge->flags & AF_EDGE_DONE )
1908 continue;
1909
1910 blue = edge->blue_edge;
1911 edge1 = NULL;
1912 edge2 = edge->link;
1913
1914 if ( blue )
1915 {
1916 edge1 = edge;
1917 }
1918 else if ( edge2 && edge2->blue_edge )
1919 {
1920 blue = edge2->blue_edge;
1921 edge1 = edge2;
1922 edge2 = edge;
1923 }
1924
1925 if ( !edge1 )
1926 continue;
1927
1928 FT_TRACE5(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
1929 "was (%.2f)\n",
1930 edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
1931 edge1->pos / 64.0 ));
1932
1933 edge1->pos = blue->fit;
1934 edge1->flags |= AF_EDGE_DONE;
1935
1936 if ( edge2 && !edge2->blue_edge )
1937 {
1938 af_latin2_align_linked_edge( hints, dim, edge1, edge2 );
1939 edge2->flags |= AF_EDGE_DONE;
1940 }
1941
1942 if ( !anchor )
1943 {
1944 anchor = edge;
1945
1946 anchor_drift = ( anchor->pos - anchor->opos );
1947 if ( edge2 )
1948 anchor_drift = ( anchor_drift +
1949 ( edge2->pos - edge2->opos ) ) >> 1;
1950 }
1951 }
1952 }
1953
1954 /* now we will align all stem edges, trying to maintain the */
1955 /* relative order of stems in the glyph */
1956 for ( edge = edges; edge < edge_limit; edge++ )
1957 {
1958 AF_Edge edge2;
1959
1960
1961 if ( edge->flags & AF_EDGE_DONE )
1962 continue;
1963
1964 /* skip all non-stem edges */
1965 edge2 = edge->link;
1966 if ( !edge2 )
1967 {
1968 has_serifs++;
1969 continue;
1970 }
1971
1972 /* now align the stem */
1973
1974 /* this should not happen, but it's better to be safe */
1975 if ( edge2->blue_edge )
1976 {
1977 FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
1978
1979 af_latin2_align_linked_edge( hints, dim, edge2, edge );
1980 edge->flags |= AF_EDGE_DONE;
1981 continue;
1982 }
1983
1984 if ( !anchor )
1985 {
1986 FT_Pos org_len, org_center, cur_len;
1987 FT_Pos cur_pos1, error1, error2, u_off, d_off;
1988
1989
1990 org_len = edge2->opos - edge->opos;
1991 cur_len = af_latin2_compute_stem_width( hints, dim, org_len,
1992 edge->flags,
1993 edge2->flags );
1994 if ( cur_len <= 64 )
1995 u_off = d_off = 32;
1996 else
1997 {
1998 u_off = 38;
1999 d_off = 26;
2000 }
2001
2002 if ( cur_len < 96 )
2003 {
2004 org_center = edge->opos + ( org_len >> 1 );
2005
2006 cur_pos1 = FT_PIX_ROUND( org_center );
2007
2008 error1 = org_center - ( cur_pos1 - u_off );
2009 if ( error1 < 0 )
2010 error1 = -error1;
2011
2012 error2 = org_center - ( cur_pos1 + d_off );
2013 if ( error2 < 0 )
2014 error2 = -error2;
2015
2016 if ( error1 < error2 )
2017 cur_pos1 -= u_off;
2018 else
2019 cur_pos1 += d_off;
2020
2021 edge->pos = cur_pos1 - cur_len / 2;
2022 edge2->pos = edge->pos + cur_len;
2023 }
2024 else
2025 edge->pos = FT_PIX_ROUND( edge->opos );
2026
2027 FT_TRACE5(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
2028 " snapped to (%.2f) (%.2f)\n",
2029 edge-edges, edge->opos / 64.0,
2030 edge2-edges, edge2->opos / 64.0,
2031 edge->pos / 64.0, edge2->pos / 64.0 ));
2032 anchor = edge;
2033
2034 edge->flags |= AF_EDGE_DONE;
2035
2036 af_latin2_align_linked_edge( hints, dim, edge, edge2 );
2037
2038 edge2->flags |= AF_EDGE_DONE;
2039
2040 anchor_drift = ( ( anchor->pos - anchor->opos ) +
2041 ( edge2->pos - edge2->opos ) ) >> 1;
2042
2043 FT_TRACE5(( "DRIFT: %.2f\n", anchor_drift/64.0 ));
2044 }
2045 else
2046 {
2047 FT_Pos org_pos, org_len, org_center, cur_center, cur_len;
2048 FT_Pos org_left, org_right;
2049
2050
2051 org_pos = edge->opos + anchor_drift;
2052 org_len = edge2->opos - edge->opos;
2053 org_center = org_pos + ( org_len >> 1 );
2054
2055 cur_len = af_latin2_compute_stem_width( hints, dim, org_len,
2056 edge->flags,
2057 edge2->flags );
2058
2059 org_left = org_pos + ( ( org_len - cur_len ) >> 1 );
2060 org_right = org_pos + ( ( org_len + cur_len ) >> 1 );
2061
2062 FT_TRACE5(( "ALIGN: left=%.2f right=%.2f ",
2063 org_left / 64.0, org_right / 64.0 ));
2064 cur_center = org_center;
2065
2066 if ( edge2->flags & AF_EDGE_DONE )
2067 {
2068 FT_TRACE5(( "\n" ));
2069 edge->pos = edge2->pos - cur_len;
2070 }
2071 else
2072 {
2073 /* we want to compare several displacement, and choose
2074 * the one that increases fitness while minimizing
2075 * distortion as well
2076 */
2077 FT_Pos displacements[6], scores[6], org, fit, delta;
2078 FT_UInt count = 0;
2079
2080 /* note: don't even try to fit tiny stems */
2081 if ( cur_len < 32 )
2082 {
2083 FT_TRACE5(( "tiny stem\n" ));
2084 goto AlignStem;
2085 }
2086
2087 /* if the span is within a single pixel, don't touch it */
2088 if ( FT_PIX_FLOOR( org_left ) == FT_PIX_CEIL( org_right ) )
2089 {
2090 FT_TRACE5(( "single pixel stem\n" ));
2091 goto AlignStem;
2092 }
2093
2094 if ( cur_len <= 96 )
2095 {
2096 /* we want to avoid the absolute worst case which is
2097 * when the left and right edges of the span each represent
2098 * about 50% of the gray. we'd better want to change this
2099 * to 25/75%, since this is much more pleasant to the eye with
2100 * very acceptable distortion
2101 */
2102 FT_Pos frac_left = org_left & 63;
2103 FT_Pos frac_right = org_right & 63;
2104
2105 if ( frac_left >= 22 && frac_left <= 42 &&
2106 frac_right >= 22 && frac_right <= 42 )
2107 {
2108 org = frac_left;
2109 fit = ( org <= 32 ) ? 16 : 48;
2110 delta = FT_ABS( fit - org );
2111 displacements[count] = fit - org;
2112 scores[count++] = delta;
2113 FT_TRACE5(( "dispA=%.2f (%d) ", ( fit - org ) / 64.0, delta ));
2114
2115 org = frac_right;
2116 fit = ( org <= 32 ) ? 16 : 48;
2117 delta = FT_ABS( fit - org );
2118 displacements[count] = fit - org;
2119 scores[count++] = delta;
2120 FT_TRACE5(( "dispB=%.2f (%d) ", ( fit - org ) / 64.0, delta ));
2121 }
2122 }
2123
2124 /* snapping the left edge to the grid */
2125 org = org_left;
2126 fit = FT_PIX_ROUND( org );
2127 delta = FT_ABS( fit - org );
2128 displacements[count] = fit - org;
2129 scores[count++] = delta;
2130 FT_TRACE5(( "dispC=%.2f (%d) ", ( fit - org ) / 64.0, delta ));
2131
2132 /* snapping the right edge to the grid */
2133 org = org_right;
2134 fit = FT_PIX_ROUND( org );
2135 delta = FT_ABS( fit - org );
2136 displacements[count] = fit - org;
2137 scores[count++] = delta;
2138 FT_TRACE5(( "dispD=%.2f (%d) ", ( fit - org ) / 64.0, delta ));
2139
2140 /* now find the best displacement */
2141 {
2142 FT_Pos best_score = scores[0];
2143 FT_Pos best_disp = displacements[0];
2144 FT_UInt nn;
2145
2146 for ( nn = 1; nn < count; nn++ )
2147 {
2148 if ( scores[nn] < best_score )
2149 {
2150 best_score = scores[nn];
2151 best_disp = displacements[nn];
2152 }
2153 }
2154
2155 cur_center = org_center + best_disp;
2156 }
2157 FT_TRACE5(( "\n" ));
2158 }
2159
2160 AlignStem:
2161 edge->pos = cur_center - ( cur_len >> 1 );
2162 edge2->pos = edge->pos + cur_len;
2163
2164 FT_TRACE5(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f)"
2165 " snapped to (%.2f) and (%.2f),"
2166 " org_len=%.2f cur_len=%.2f\n",
2167 edge-edges, edge->opos / 64.0,
2168 edge2-edges, edge2->opos / 64.0,
2169 edge->pos / 64.0, edge2->pos / 64.0,
2170 org_len / 64.0, cur_len / 64.0 ));
2171
2172 edge->flags |= AF_EDGE_DONE;
2173 edge2->flags |= AF_EDGE_DONE;
2174
2175 if ( edge > edges && edge->pos < edge[-1].pos )
2176 {
2177 FT_TRACE5(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
2178 edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
2179 edge->pos = edge[-1].pos;
2180 }
2181 }
2182 }
2183
2184 /* make sure that lowercase m's maintain their symmetry */
2185
2186 /* In general, lowercase m's have six vertical edges if they are sans */
2187 /* serif, or twelve if they are with serifs. This implementation is */
2188 /* based on that assumption, and seems to work very well with most */
2189 /* faces. However, if for a certain face this assumption is not */
2190 /* true, the m is just rendered like before. In addition, any stem */
2191 /* correction will only be applied to symmetrical glyphs (even if the */
2192 /* glyph is not an m), so the potential for unwanted distortion is */
2193 /* relatively low. */
2194
2195 /* We don't handle horizontal edges since we can't easily assure that */
2196 /* the third (lowest) stem aligns with the base line; it might end up */
2197 /* one pixel higher or lower. */
2198
2199#if 0
2200 {
2201 FT_Int n_edges = edge_limit - edges;
2202
2203
2204 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
2205 {
2206 AF_Edge edge1, edge2, edge3;
2207 FT_Pos dist1, dist2, span, delta;
2208
2209
2210 if ( n_edges == 6 )
2211 {
2212 edge1 = edges;
2213 edge2 = edges + 2;
2214 edge3 = edges + 4;
2215 }
2216 else
2217 {
2218 edge1 = edges + 1;
2219 edge2 = edges + 5;
2220 edge3 = edges + 9;
2221 }
2222
2223 dist1 = edge2->opos - edge1->opos;
2224 dist2 = edge3->opos - edge2->opos;
2225
2226 span = dist1 - dist2;
2227 if ( span < 0 )
2228 span = -span;
2229
2230 if ( span < 8 )
2231 {
2232 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
2233 edge3->pos -= delta;
2234 if ( edge3->link )
2235 edge3->link->pos -= delta;
2236
2237 /* move the serifs along with the stem */
2238 if ( n_edges == 12 )
2239 {
2240 ( edges + 8 )->pos -= delta;
2241 ( edges + 11 )->pos -= delta;
2242 }
2243
2244 edge3->flags |= AF_EDGE_DONE;
2245 if ( edge3->link )
2246 edge3->link->flags |= AF_EDGE_DONE;
2247 }
2248 }
2249 }
2250#endif
2251
2252 if ( has_serifs || !anchor )
2253 {
2254 /*
2255 * now hint the remaining edges (serifs and single) in order
2256 * to complete our processing
2257 */
2258 for ( edge = edges; edge < edge_limit; edge++ )
2259 {
2260 FT_Pos delta;
2261
2262
2263 if ( edge->flags & AF_EDGE_DONE )
2264 continue;
2265
2266 delta = 1000;
2267
2268 if ( edge->serif )
2269 {
2270 delta = edge->serif->opos - edge->opos;
2271 if ( delta < 0 )
2272 delta = -delta;
2273 }
2274
2275 if ( delta < 64 + 16 )
2276 {
2277 af_latin2_align_serif_edge( hints, edge->serif, edge );
2278 FT_TRACE5(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
2279 " aligned to (%.2f)\n",
2280 edge-edges, edge->opos / 64.0,
2281 edge->serif - edges, edge->serif->opos / 64.0,
2282 edge->pos / 64.0 ));
2283 }
2284 else if ( !anchor )
2285 {
2286 FT_TRACE5(( "SERIF_ANCHOR: edge %d (opos=%.2f)"
2287 " snapped to (%.2f)\n",
2288 edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
2289 edge->pos = FT_PIX_ROUND( edge->opos );
2290 anchor = edge;
2291 }
2292 else
2293 {
2295
2296
2297 for ( before = edge - 1; before >= edges; before-- )
2298 if ( before->flags & AF_EDGE_DONE )
2299 break;
2300
2301 for ( after = edge + 1; after < edge_limit; after++ )
2302 if ( after->flags & AF_EDGE_DONE )
2303 break;
2304
2305 if ( before >= edges && before < edge &&
2306 after < edge_limit && after > edge )
2307 {
2308 if ( after->opos == before->opos )
2309 edge->pos = before->pos;
2310 else
2311 edge->pos = before->pos +
2312 FT_MulDiv( edge->opos - before->opos,
2313 after->pos - before->pos,
2314 after->opos - before->opos );
2315 FT_TRACE5(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f)"
2316 " from %d (opos=%.2f)\n",
2317 edge-edges, edge->opos / 64.0, edge->pos / 64.0,
2318 before - edges, before->opos / 64.0 ));
2319 }
2320 else
2321 {
2322 edge->pos = anchor->pos +
2323 ( ( edge->opos - anchor->opos + 16 ) & ~31 );
2324
2325 FT_TRACE5(( "SERIF_LINK2: edge %d (opos=%.2f)"
2326 " snapped to (%.2f)\n",
2327 edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
2328 }
2329 }
2330
2331 edge->flags |= AF_EDGE_DONE;
2332
2333 if ( edge > edges && edge->pos < edge[-1].pos )
2334 edge->pos = edge[-1].pos;
2335
2336 if ( edge + 1 < edge_limit &&
2337 edge[1].flags & AF_EDGE_DONE &&
2338 edge->pos > edge[1].pos )
2339 edge->pos = edge[1].pos;
2340 }
2341 }
2342 }
2343
2344
2345 static FT_Error
2346 af_latin2_hints_apply( FT_UInt glyph_index,
2350 {
2352 int dim;
2353
2354 FT_UNUSED( glyph_index );
2355
2356
2358 if ( error )
2359 goto Exit;
2360
2361 /* analyze glyph outline */
2363 {
2364 error = af_latin2_hints_detect_features( hints, AF_DIMENSION_HORZ );
2365 if ( error )
2366 goto Exit;
2367 }
2368
2369 if ( AF_HINTS_DO_VERTICAL( hints ) )
2370 {
2371 error = af_latin2_hints_detect_features( hints, AF_DIMENSION_VERT );
2372 if ( error )
2373 goto Exit;
2374
2375 af_latin2_hints_compute_blue_edges( hints, metrics );
2376 }
2377
2378 /* grid-fit the outline */
2379 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
2380 {
2381#ifdef AF_CONFIG_OPTION_USE_WARPER
2382 if ( dim == AF_DIMENSION_HORZ &&
2383 metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL &&
2385 {
2386 AF_WarperRec warper;
2388 FT_Pos delta;
2389
2390
2391 af_warper_compute( &warper, hints, dim, &scale, &delta );
2392 af_glyph_hints_scale_dim( hints, dim, scale, delta );
2393 continue;
2394 }
2395#endif /* AF_CONFIG_OPTION_USE_WARPER */
2396
2397 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
2399 {
2400 af_latin2_hint_edges( hints, (AF_Dimension)dim );
2404 }
2405 }
2407
2408 Exit:
2409 return error;
2410 }
2411
2412
2413 /*************************************************************************/
2414 /*************************************************************************/
2415 /***** *****/
2416 /***** L A T I N S C R I P T C L A S S *****/
2417 /***** *****/
2418 /*************************************************************************/
2419 /*************************************************************************/
2420
2421
2423 af_latin2_writing_system_class,
2424
2425 AF_WRITING_SYSTEM_LATIN2,
2426
2427 sizeof ( AF_LatinMetricsRec ),
2428
2429 (AF_WritingSystem_InitMetricsFunc) af_latin2_metrics_init, /* style_metrics_init */
2430 (AF_WritingSystem_ScaleMetricsFunc)af_latin2_metrics_scale, /* style_metrics_scale */
2431 (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
2432 (AF_WritingSystem_GetStdWidthsFunc)af_latin2_get_standard_widths, /* style_metrics_getstdw */
2433
2434 (AF_WritingSystem_InitHintsFunc) af_latin2_hints_init, /* style_hints_init */
2435 (AF_WritingSystem_ApplyHintsFunc) af_latin2_hints_apply /* style_hints_apply */
2436 )
2437
2438#else /* !FT_OPTION_AUTOFIT2 */
2439
2440 /* ANSI C doesn't like empty source files */
2441 typedef int _af_latin2_dummy;
2442
2443#endif /* !FT_OPTION_AUTOFIT2 */
2444
2445
2446/* END */
#define compare
_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
#define AF_PROP_INCREASE_X_HEIGHT_MIN
Definition: afglobal.h:87
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:702
af_glyph_hints_align_edge_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1219
af_glyph_hints_save(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:1184
af_glyph_hints_rescale(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: afhints.c:750
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:762
af_glyph_hints_align_strong_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1294
af_glyph_hints_align_weak_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1568
af_glyph_hints_init(AF_GlyphHints hints, FT_Memory memory)
Definition: afhints.c:692
#define AF_HINTS_DO_BLUES(h)
Definition: afhints.h:403
#define AF_EDGE_ROUND
Definition: afhints.h:230
#define AF_HINTS_DO_WARP(h)
Definition: afhints.h:411
#define AF_HINTS_DO_HORIZONTAL(h)
Definition: afhints.h:397
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_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:400
int _af_latin2_dummy
Definition: aflatin2.c:2441
#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_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_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_SCALER_FLAG_NO_WARPER
Definition: aftypes.h:176
FT_Error(* AF_WritingSystem_InitMetricsFunc)(AF_StyleMetrics metrics, FT_Face face)
Definition: aftypes.h:206
void(* AF_WritingSystem_ScaleMetricsFunc)(AF_StyleMetrics metrics, AF_Scaler scaler)
Definition: aftypes.h:210
FT_BEGIN_HEADER struct AF_WidthRec_ * AF_Width
void(* AF_WritingSystem_DoneMetricsFunc)(AF_StyleMetrics metrics)
Definition: aftypes.h:214
FT_Error(* AF_WritingSystem_InitHintsFunc)(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: aftypes.h:223
#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:227
#define AF_SCALER_FLAG_NO_HORIZONTAL
Definition: aftypes.h:173
void(* AF_WritingSystem_GetStdWidthsFunc)(AF_StyleMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
Definition: aftypes.h:217
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
#define pt(x, y)
Definition: drawing.c:79
POINTL point
Definition: edittest.c:50
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:797
#define FT_STYLE_FLAG_ITALIC
Definition: freetype.h:1488
#define FT_LOAD_IGNORE_TRANSFORM
Definition: freetype.h:3037
#define FT_LOAD_NO_SCALE
Definition: freetype.h:3027
enum FT_Render_Mode_ FT_Render_Mode
#define FT_LOAD_NO_HINTING
Definition: freetype.h:3028
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
FT_Get_Char_Index(FT_Face face, FT_ULong charcode)
Definition: ftobjs.c:3711
FT_Select_Charmap(FT_Face face, FT_Encoding encoding)
Definition: ftobjs.c:3501
FT_Set_Charmap(FT_Face face, FT_CharMap charmap)
Definition: ftobjs.c:3544
enum FT_Encoding_ FT_Encoding
@ FT_RENDER_MODE_MONO
Definition: freetype.h:3258
@ FT_RENDER_MODE_NORMAL
Definition: freetype.h:3256
@ FT_RENDER_MODE_LIGHT
Definition: freetype.h:3257
@ FT_RENDER_MODE_LCD_V
Definition: freetype.h:3260
@ FT_RENDER_MODE_LCD
Definition: freetype.h:3259
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
FT_Get_Advance(FT_Face face, FT_UInt gindex, FT_Int32 load_flags, FT_Fixed *padvance)
Definition: ftadvanc.c:75
return FT_Err_Ok
Definition: ftbbox.c:527
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:387
#define FT_UNUSED(arg)
Definition: ftconfig.h:100
#define FT_ASSERT(condition)
Definition: ftdebug.h:239
#define FT_TRACE5(varformat)
Definition: ftdebug.h:190
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:452
#define FT_CURVE_TAG_ON
Definition: ftimage.h:455
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:58
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define FT_PIX_CEIL(x)
Definition: ftobjs.h:93
#define FT_ABS(a)
Definition: ftobjs.h:73
#define FT_PIX_FLOOR(x)
Definition: ftobjs.h:91
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:92
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:65
signed char FT_Char
Definition: fttypes.h:143
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
unsigned char FT_Byte
Definition: fttypes.h:154
signed long FT_Fixed
Definition: fttypes.h:287
int FT_Error
Definition: fttypes.h:299
signed short FT_Short
Definition: fttypes.h:198
unsigned int FT_UInt
Definition: fttypes.h:231
#define FT_BOOL(x)
Definition: fttypes.h:591
signed int FT_Int
Definition: fttypes.h:220
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
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
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
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
#define sign(x)
Definition: mapdesc.cc:613
#define error(str)
Definition: mkdosfs.c:1605
static char org[]
Definition: encode.c:7456
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
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
#define f1(x, y, z)
Definition: sha1.c:30
namespace GUID const ADDRINFOEXW * hints
Definition: sock.c:80
static void Exit(void)
Definition: sock.c:1330
AF_Segment segments
Definition: afhints.h:315
FT_Int num_edges
Definition: afhints.h:320
AF_Edge edges
Definition: afhints.h:322
AF_Direction major_dir
Definition: afhints.h:324
FT_Int num_segments
Definition: afhints.h:313
FT_Char dir
Definition: afhints.h:295
AF_Edge serif
Definition: afhints.h:300
AF_Width blue_edge
Definition: afhints.h:298
FT_Pos pos
Definition: afhints.h:292
AF_Edge link
Definition: afhints.h:299
AF_Segment first
Definition: afhints.h:303
AF_Segment last
Definition: afhints.h:304
FT_Short fpos
Definition: afhints.h:290
FT_Pos opos
Definition: afhints.h:291
FT_Byte flags
Definition: afhints.h:294
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
AF_WidthRec ref
Definition: aflatin.h:79
FT_UInt32 flags
Definition: aftypes.h:187
FT_Render_Mode render_mode
Definition: aftypes.h:186
FT_Pos y_delta
Definition: aftypes.h:185
FT_Face face
Definition: aftypes.h:181
FT_Pos x_delta
Definition: aftypes.h:184
FT_Fixed y_scale
Definition: aftypes.h:183
FT_Fixed x_scale
Definition: aftypes.h:182
FT_Byte flags
Definition: afhints.h:266
AF_Point last
Definition: afhints.h:283
FT_Char dir
Definition: afhints.h:267
FT_Short min_coord
Definition: afhints.h:270
FT_Short max_coord
Definition: afhints.h:271
FT_Short height
Definition: afhints.h:272
AF_Segment edge_next
Definition: afhints.h:275
AF_Segment link
Definition: afhints.h:277
AF_Point first
Definition: afhints.h:282
FT_Short pos
Definition: afhints.h:268
AF_Edge edge
Definition: afhints.h:274
FT_Pos score
Definition: afhints.h:279
AF_Segment serif
Definition: afhints.h:278
FT_Outline outline
Definition: freetype.h:1896
short n_contours
Definition: ftimage.h:339
short * contours
Definition: ftimage.h:344
FT_Vector * points
Definition: ftimage.h:342
short n_points
Definition: ftimage.h:340
char * tags
Definition: ftimage.h:343
Definition: bug.cpp:8
struct define * next
Definition: compiler.c:65
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