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