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