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