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