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