1 /***************************************************************************/
5 /* TrueType Subpixel Hinting. */
7 /* Copyright 2010-2013 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
19 #include FT_INTERNAL_DEBUG_H
20 #include FT_INTERNAL_CALC_H
21 #include FT_INTERNAL_STREAM_H
22 #include FT_INTERNAL_SFNT_H
23 #include FT_TRUETYPE_TAGS_H
25 #include FT_TRUETYPE_DRIVER_H
30 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
32 /*************************************************************************/
34 /* These rules affect how the TT Interpreter does hinting, with the */
35 /* goal of doing subpixel hinting by (in general) ignoring x moves. */
36 /* Some of these rules are fixes that go above and beyond the */
37 /* stated techniques in the MS whitepaper on Cleartype, due to */
38 /* artifacts in many glyphs. So, these rules make some glyphs render */
39 /* better than they do in the MS rasterizer. */
41 /* "" string or 0 int/char indicates to apply to all glyphs. */
42 /* "-" used as dummy placeholders, but any non-matching string works. */
44 /* Some of this could arguably be implemented in fontconfig, however: */
46 /* - Fontconfig can't set things on a glyph-by-glyph basis. */
47 /* - The tweaks that happen here are very low-level, from an average */
48 /* user's point of view and are best implemented in the hinter. */
50 /* The goal is to make the subpixel hinting techniques as generalized */
51 /* as possible across all fonts to prevent the need for extra rules such */
54 /* The rule structure is designed so that entirely new rules can easily */
55 /* be added when a new compatibility feature is discovered. */
57 /* The rule structures could also use some enhancement to handle ranges. */
59 /* ****************** WORK IN PROGRESS ******************* */
62 /* These are `classes' of fonts that can be grouped together and used in */
63 /* rules below. A blank entry "" is required at the end of these! */
64 #define FAMILY_CLASS_RULES_SIZE 7
66 static const SPH_Font_Class FAMILY_CLASS_Rules
67 [FAMILY_CLASS_RULES_SIZE
] =
94 "Fixed Miriam Transparent",
96 "Franklin Gothic Medium",
111 "Lucida Sans Unicode",
117 "Microsoft Sans Serif",
120 "Miriam Transparent",
129 "Simplified Arabic Fixed",
136 "Traditional Arabic",
145 { "Core MS Legacy Fonts",
156 "Lucida Sans Unicode",
157 "Microsoft Sans Serif",
166 { "Apple Legacy Fonts",
183 { "Legacy Sans Fonts",
189 "Franklin Gothic Medium",
193 "Lucida Sans Unicode",
194 "Lucida Sans Typewriter",
195 "Microsoft Sans Serif",
204 { "Misc Legacy Fonts",
205 { "Dark Courier", "", }, },
208 "Bitstream Vera Sans", "", }, },
209 { "Verdana and Clones",
211 "Bitstream Vera Sans",
216 /* Define this to force natural (i.e. not bitmap-compatible) widths. */
217 /* The default leans strongly towards natural widths except for a few */
218 /* legacy fonts where a selective combination produces nicer results. */
219 /* #define FORCE_NATURAL_WIDTHS */
222 /* Define `classes' of styles that can be grouped together and used in */
223 /* rules below. A blank entry "" is required at the end of these! */
224 #define STYLE_CLASS_RULES_SIZE 5
226 const SPH_Font_Class STYLE_CLASS_Rules
227 [STYLE_CLASS_RULES_SIZE
] =
238 { "Regular/Italic Class",
249 { "Bold/BoldItalic Class",
256 { "Bold/Italic/BoldItalic Class",
265 { "Regular/Bold Class",
279 /* Force special legacy fixes for fonts. */
280 #define COMPATIBILITY_MODE_RULES_SIZE 1
282 const SPH_TweakRule COMPATIBILITY_MODE_Rules
283 [COMPATIBILITY_MODE_RULES_SIZE
] =
289 /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */
290 #define PIXEL_HINTING_RULES_SIZE 2
292 const SPH_TweakRule PIXEL_HINTING_Rules
293 [PIXEL_HINTING_RULES_SIZE
] =
295 /* these characters are almost always safe */
296 { "Courier New", 12, "Italic", 'z' },
297 { "Courier New", 11, "Italic", 'z' },
301 /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */
302 #define DO_SHPIX_RULES_SIZE 1
304 const SPH_TweakRule DO_SHPIX_Rules
305 [DO_SHPIX_RULES_SIZE
] =
311 /* Skip Y moves that start with a point that is not on a Y pixel */
312 /* boundary and don't move that point to a Y pixel boundary. */
313 #define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 4
315 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules
316 [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE
] =
318 /* fix vwxyz thinness*/
319 { "Consolas", 0, "", 0 },
320 /* Fix thin middle stems */
321 { "Core MS Legacy Fonts", 0, "Regular", 0 },
322 /* Cyrillic small letter I */
323 { "Legacy Sans Fonts", 0, "", 0 },
324 /* Fix artifacts with some Regular & Bold */
325 { "Verdana Clones", 0, "", 0 },
329 #define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
331 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
332 [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE
] =
335 { "Courier New", 0, "Regular", 0 },
339 /* Skip Y moves that start with a point that is not on a Y pixel */
340 /* boundary and don't move that point to a Y pixel boundary. */
341 #define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2
343 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules
344 [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE
] =
346 /* Maintain thickness of diagonal in 'N' */
347 { "Times New Roman", 0, "Regular/Bold Class", 'N' },
348 { "Georgia", 0, "Regular/Bold Class", 'N' },
352 /* Skip Y moves that move a point off a Y pixel boundary. */
353 #define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1
355 const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules
356 [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE
] =
362 #define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
364 const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
365 [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE
] =
371 /* Round moves that don't move a point to a Y pixel boundary. */
372 #define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2
374 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules
375 [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE
] =
377 /* Droid font instructions don't snap Y to pixels */
378 { "Droid Sans", 0, "Regular/Italic Class", 0 },
379 { "Droid Sans Mono", 0, "", 0 },
383 #define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
385 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
386 [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE
] =
392 /* Allow a Direct_Move along X freedom vector if matched. */
393 #define ALLOW_X_DMOVE_RULES_SIZE 1
395 const SPH_TweakRule ALLOW_X_DMOVE_Rules
396 [ALLOW_X_DMOVE_RULES_SIZE
] =
398 /* Fixes vanishing diagonal in 4 */
399 { "Verdana", 0, "Regular", '4' },
403 /* Return MS rasterizer version 35 if matched. */
404 #define RASTERIZER_35_RULES_SIZE 8
406 const SPH_TweakRule RASTERIZER_35_Rules
407 [RASTERIZER_35_RULES_SIZE
] =
409 /* This seems to be the only way to make these look good */
410 { "Times New Roman", 0, "Regular", 'i' },
411 { "Times New Roman", 0, "Regular", 'j' },
412 { "Times New Roman", 0, "Regular", 'm' },
413 { "Times New Roman", 0, "Regular", 'r' },
414 { "Times New Roman", 0, "Regular", 'a' },
415 { "Times New Roman", 0, "Regular", 'n' },
416 { "Times New Roman", 0, "Regular", 'p' },
417 { "Times", 0, "", 0 },
421 /* Don't round to the subpixel grid. Round to pixel grid. */
422 #define NORMAL_ROUND_RULES_SIZE 1
424 const SPH_TweakRule NORMAL_ROUND_Rules
425 [NORMAL_ROUND_RULES_SIZE
] =
427 /* Fix serif thickness for certain ppems */
428 /* Can probably be generalized somehow */
429 { "Courier New", 0, "", 0 },
433 /* Skip IUP instructions if matched. */
434 #define SKIP_IUP_RULES_SIZE 1
436 const SPH_TweakRule SKIP_IUP_Rules
437 [SKIP_IUP_RULES_SIZE
] =
439 { "Arial", 13, "Regular", 'a' },
443 /* Skip MIAP Twilight hack if matched. */
444 #define MIAP_HACK_RULES_SIZE 1
446 const SPH_TweakRule MIAP_HACK_Rules
447 [MIAP_HACK_RULES_SIZE
] =
449 { "Geneva", 12, "", 0 },
453 /* Skip DELTAP instructions if matched. */
454 #define ALWAYS_SKIP_DELTAP_RULES_SIZE 23
456 const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
457 [ALWAYS_SKIP_DELTAP_RULES_SIZE
] =
459 { "Georgia", 0, "Regular", 'k' },
460 /* fix various problems with e in different versions */
461 { "Trebuchet MS", 14, "Regular", 'e' },
462 { "Trebuchet MS", 13, "Regular", 'e' },
463 { "Trebuchet MS", 15, "Regular", 'e' },
464 { "Trebuchet MS", 0, "Italic", 'v' },
465 { "Trebuchet MS", 0, "Italic", 'w' },
466 { "Trebuchet MS", 0, "Regular", 'Y' },
467 { "Arial", 11, "Regular", 's' },
468 /* prevent problems with '3' and others */
469 { "Verdana", 10, "Regular", 0 },
470 { "Verdana", 9, "Regular", 0 },
471 /* Cyrillic small letter short I */
472 { "Legacy Sans Fonts", 0, "", 0x438 },
473 { "Legacy Sans Fonts", 0, "", 0x439 },
474 { "Arial", 10, "Regular", '6' },
475 { "Arial", 0, "Bold/BoldItalic Class", 'a' },
476 /* Make horizontal stems consistent with the rest */
477 { "Arial", 24, "Bold", 'a' },
478 { "Arial", 25, "Bold", 'a' },
479 { "Arial", 24, "Bold", 's' },
480 { "Arial", 25, "Bold", 's' },
481 { "Arial", 34, "Bold", 's' },
482 { "Arial", 35, "Bold", 's' },
483 { "Arial", 36, "Bold", 's' },
484 { "Arial", 25, "Regular", 's' },
485 { "Arial", 26, "Regular", 's' },
489 /* Always do DELTAP instructions if matched. */
490 #define ALWAYS_DO_DELTAP_RULES_SIZE 1
492 const SPH_TweakRule ALWAYS_DO_DELTAP_Rules
493 [ALWAYS_DO_DELTAP_RULES_SIZE
] =
499 /* Don't allow ALIGNRP after IUP. */
500 #define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1
502 static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules
503 [NO_ALIGNRP_AFTER_IUP_RULES_SIZE
] =
505 /* Prevent creation of dents in outline */
510 /* Don't allow DELTAP after IUP. */
511 #define NO_DELTAP_AFTER_IUP_RULES_SIZE 1
513 static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules
514 [NO_DELTAP_AFTER_IUP_RULES_SIZE
] =
520 /* Don't allow CALL after IUP. */
521 #define NO_CALL_AFTER_IUP_RULES_SIZE 1
523 static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules
524 [NO_CALL_AFTER_IUP_RULES_SIZE
] =
526 /* Prevent creation of dents in outline */
531 /* De-embolden these glyphs slightly. */
532 #define DEEMBOLDEN_RULES_SIZE 9
534 static const SPH_TweakRule DEEMBOLDEN_Rules
535 [DEEMBOLDEN_RULES_SIZE
] =
537 { "Courier New", 0, "Bold", 'A' },
538 { "Courier New", 0, "Bold", 'W' },
539 { "Courier New", 0, "Bold", 'w' },
540 { "Courier New", 0, "Bold", 'M' },
541 { "Courier New", 0, "Bold", 'X' },
542 { "Courier New", 0, "Bold", 'K' },
543 { "Courier New", 0, "Bold", 'x' },
544 { "Courier New", 0, "Bold", 'z' },
545 { "Courier New", 0, "Bold", 'v' },
549 /* Embolden these glyphs slightly. */
550 #define EMBOLDEN_RULES_SIZE 2
552 static const SPH_TweakRule EMBOLDEN_Rules
553 [EMBOLDEN_RULES_SIZE
] =
555 { "Courier New", 0, "Regular", 0 },
556 { "Courier New", 0, "Italic", 0 },
560 /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */
561 /* similar to Windows XP. */
562 #define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
564 static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules
565 [TIMES_NEW_ROMAN_HACK_RULES_SIZE
] =
567 { "Times New Roman", 16, "Italic", '2' },
568 { "Times New Roman", 16, "Italic", '5' },
569 { "Times New Roman", 16, "Italic", '7' },
570 { "Times New Roman", 16, "Regular", '2' },
571 { "Times New Roman", 16, "Regular", '5' },
572 { "Times New Roman", 16, "Regular", '7' },
573 { "Times New Roman", 17, "Italic", '2' },
574 { "Times New Roman", 17, "Italic", '5' },
575 { "Times New Roman", 17, "Italic", '7' },
576 { "Times New Roman", 17, "Regular", '2' },
577 { "Times New Roman", 17, "Regular", '5' },
578 { "Times New Roman", 17, "Regular", '7' },
582 /* This fudges distance on 2 to get rid of the vanishing stem issue. */
583 /* A real solution to this is certainly welcome. */
584 #define COURIER_NEW_2_HACK_RULES_SIZE 15
586 static const SPH_TweakRule COURIER_NEW_2_HACK_Rules
587 [COURIER_NEW_2_HACK_RULES_SIZE
] =
589 { "Courier New", 10, "Regular", '2' },
590 { "Courier New", 11, "Regular", '2' },
591 { "Courier New", 12, "Regular", '2' },
592 { "Courier New", 13, "Regular", '2' },
593 { "Courier New", 14, "Regular", '2' },
594 { "Courier New", 15, "Regular", '2' },
595 { "Courier New", 16, "Regular", '2' },
596 { "Courier New", 17, "Regular", '2' },
597 { "Courier New", 18, "Regular", '2' },
598 { "Courier New", 19, "Regular", '2' },
599 { "Courier New", 20, "Regular", '2' },
600 { "Courier New", 21, "Regular", '2' },
601 { "Courier New", 22, "Regular", '2' },
602 { "Courier New", 23, "Regular", '2' },
603 { "Courier New", 24, "Regular", '2' },
607 #ifndef FORCE_NATURAL_WIDTHS
609 /* Use compatible widths with these glyphs. Compatible widths is always */
610 /* on when doing B/W TrueType instructing, but is used selectively here, */
611 /* typically on glyphs with 3 or more vertical stems. */
612 #define COMPATIBLE_WIDTHS_RULES_SIZE 38
614 static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
615 [COMPATIBLE_WIDTHS_RULES_SIZE
] =
617 { "Arial Unicode MS", 12, "Regular Class", 'm' },
618 { "Arial Unicode MS", 14, "Regular Class", 'm' },
619 /* Cyrillic small letter sha */
620 { "Arial", 10, "Regular Class", 0x448 },
621 { "Arial", 11, "Regular Class", 'm' },
622 { "Arial", 12, "Regular Class", 'm' },
623 /* Cyrillic small letter sha */
624 { "Arial", 12, "Regular Class", 0x448 },
625 { "Arial", 13, "Regular Class", 0x448 },
626 { "Arial", 14, "Regular Class", 'm' },
627 /* Cyrillic small letter sha */
628 { "Arial", 14, "Regular Class", 0x448 },
629 { "Arial", 15, "Regular Class", 0x448 },
630 { "Arial", 17, "Regular Class", 'm' },
631 { "DejaVu Sans", 15, "Regular Class", 0 },
632 { "Microsoft Sans Serif", 11, "Regular Class", 0 },
633 { "Microsoft Sans Serif", 12, "Regular Class", 0 },
634 { "Segoe UI", 11, "Regular Class", 0 },
635 { "Monaco", 0, "Regular Class", 0 },
636 { "Segoe UI", 12, "Regular Class", 'm' },
637 { "Segoe UI", 14, "Regular Class", 'm' },
638 { "Tahoma", 11, "Regular Class", 0 },
639 { "Times New Roman", 16, "Regular Class", 'c' },
640 { "Times New Roman", 16, "Regular Class", 'm' },
641 { "Times New Roman", 16, "Regular Class", 'o' },
642 { "Times New Roman", 16, "Regular Class", 'w' },
643 { "Trebuchet MS", 11, "Regular Class", 0 },
644 { "Trebuchet MS", 12, "Regular Class", 0 },
645 { "Trebuchet MS", 14, "Regular Class", 0 },
646 { "Trebuchet MS", 15, "Regular Class", 0 },
647 { "Ubuntu", 12, "Regular Class", 'm' },
648 /* Cyrillic small letter sha */
649 { "Verdana", 10, "Regular Class", 0x448 },
650 { "Verdana", 11, "Regular Class", 0x448 },
651 { "Verdana and Clones", 12, "Regular Class", 'i' },
652 { "Verdana and Clones", 12, "Regular Class", 'j' },
653 { "Verdana and Clones", 12, "Regular Class", 'l' },
654 { "Verdana and Clones", 12, "Regular Class", 'm' },
655 { "Verdana and Clones", 13, "Regular Class", 'i' },
656 { "Verdana and Clones", 13, "Regular Class", 'j' },
657 { "Verdana and Clones", 13, "Regular Class", 'l' },
658 { "Verdana and Clones", 14, "Regular Class", 'm' },
662 /* Scaling slightly in the x-direction prior to hinting results in */
663 /* more visually pleasing glyphs in certain cases. */
664 /* This sometimes needs to be coordinated with compatible width rules. */
665 /* A value of 1000 corresponds to a scaled value of 1.0. */
667 #define X_SCALING_RULES_SIZE 50
669 static const SPH_ScaleRule X_SCALING_Rules
[X_SCALING_RULES_SIZE
] =
671 { "DejaVu Sans", 12, "Regular Class", 'm', 950 },
672 { "Verdana and Clones", 12, "Regular Class", 'a', 1100 },
673 { "Verdana and Clones", 13, "Regular Class", 'a', 1050 },
674 { "Arial", 11, "Regular Class", 'm', 975 },
675 { "Arial", 12, "Regular Class", 'm', 1050 },
676 /* Cyrillic small letter el */
677 { "Arial", 13, "Regular Class", 0x43B, 950 },
678 { "Arial", 13, "Regular Class", 'o', 950 },
679 { "Arial", 13, "Regular Class", 'e', 950 },
680 { "Arial", 14, "Regular Class", 'm', 950 },
681 /* Cyrillic small letter el */
682 { "Arial", 15, "Regular Class", 0x43B, 925 },
683 { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 },
684 { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 },
685 { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 },
686 { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 },
687 { "DejaVu Sans", 12, "Regular Class", 'l', 975 },
688 { "DejaVu Sans", 12, "Regular Class", 'i', 975 },
689 { "DejaVu Sans", 12, "Regular Class", 'j', 975 },
690 { "DejaVu Sans", 13, "Regular Class", 'l', 950 },
691 { "DejaVu Sans", 13, "Regular Class", 'i', 950 },
692 { "DejaVu Sans", 13, "Regular Class", 'j', 950 },
693 { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 },
694 { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 },
695 { "Georgia", 10, "", 0, 1050 },
696 { "Georgia", 11, "", 0, 1100 },
697 { "Georgia", 12, "", 0, 1025 },
698 { "Georgia", 13, "", 0, 1050 },
699 { "Georgia", 16, "", 0, 1050 },
700 { "Georgia", 17, "", 0, 1030 },
701 { "Liberation Sans", 12, "Regular Class", 'm', 1100 },
702 { "Lucida Grande", 11, "Regular Class", 'm', 1100 },
703 { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 },
704 { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 },
705 { "Segoe UI", 12, "Regular Class", 'H', 1050 },
706 { "Segoe UI", 12, "Regular Class", 'm', 1050 },
707 { "Segoe UI", 14, "Regular Class", 'm', 1050 },
708 { "Tahoma", 11, "Regular Class", 'i', 975 },
709 { "Tahoma", 11, "Regular Class", 'l', 975 },
710 { "Tahoma", 11, "Regular Class", 'j', 900 },
711 { "Tahoma", 11, "Regular Class", 'm', 918 },
712 { "Verdana", 10, "Regular/Italic Class", 0, 1100 },
713 { "Verdana", 12, "Regular Class", 'm', 975 },
714 { "Verdana", 12, "Regular/Italic Class", 0, 1050 },
715 { "Verdana", 13, "Regular/Italic Class", 'i', 950 },
716 { "Verdana", 13, "Regular/Italic Class", 'j', 950 },
717 { "Verdana", 13, "Regular/Italic Class", 'l', 950 },
718 { "Verdana", 16, "Regular Class", 0, 1050 },
719 { "Verdana", 9, "Regular/Italic Class", 0, 1050 },
720 { "Times New Roman", 16, "Regular Class", 'm', 918 },
721 { "Trebuchet MS", 11, "Regular Class", 'm', 800 },
722 { "Trebuchet MS", 12, "Regular Class", 'm', 800 },
727 #define COMPATIBLE_WIDTHS_RULES_SIZE 1
729 static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
730 [COMPATIBLE_WIDTHS_RULES_SIZE
] =
736 #define X_SCALING_RULES_SIZE 1
738 static const SPH_ScaleRule X_SCALING_Rules
739 [X_SCALING_RULES_SIZE
] =
741 { "-", 0, "", 0, 1000 },
744 #endif /* FORCE_NATURAL_WIDTHS */
747 FT_LOCAL_DEF( FT_Bool
)
748 is_member_of_family_class( const FT_String
* detected_font_name
,
749 const FT_String
* rule_font_name
)
754 /* Does font name match rule family? */
755 if ( strcmp( detected_font_name
, rule_font_name
) == 0 )
758 /* Is font name a wildcard ""? */
759 if ( strcmp( rule_font_name
, "" ) == 0 )
762 /* Is font name contained in a class list? */
763 for ( i
= 0; i
< FAMILY_CLASS_RULES_SIZE
; i
++ )
765 if ( strcmp( FAMILY_CLASS_Rules
[i
].name
, rule_font_name
) == 0 )
767 for ( j
= 0; j
< SPH_MAX_CLASS_MEMBERS
; j
++ )
769 if ( strcmp( FAMILY_CLASS_Rules
[i
].member
[j
], "" ) == 0 )
771 if ( strcmp( FAMILY_CLASS_Rules
[i
].member
[j
],
772 detected_font_name
) == 0 )
782 FT_LOCAL_DEF( FT_Bool
)
783 is_member_of_style_class( const FT_String
* detected_font_style
,
784 const FT_String
* rule_font_style
)
789 /* Does font style match rule style? */
790 if ( strcmp( detected_font_style
, rule_font_style
) == 0 )
793 /* Is font style a wildcard ""? */
794 if ( strcmp( rule_font_style
, "" ) == 0 )
797 /* Is font style contained in a class list? */
798 for ( i
= 0; i
< STYLE_CLASS_RULES_SIZE
; i
++ )
800 if ( strcmp( STYLE_CLASS_Rules
[i
].name
, rule_font_style
) == 0 )
802 for ( j
= 0; j
< SPH_MAX_CLASS_MEMBERS
; j
++ )
804 if ( strcmp( STYLE_CLASS_Rules
[i
].member
[j
], "" ) == 0 )
806 if ( strcmp( STYLE_CLASS_Rules
[i
].member
[j
],
807 detected_font_style
) == 0 )
817 FT_LOCAL_DEF( FT_Bool
)
818 sph_test_tweak( TT_Face face
,
819 const FT_String
* family
,
821 const FT_String
* style
,
823 const SPH_TweakRule
* rule
,
829 /* rule checks may be able to be optimized further */
830 for ( i
= 0; i
< num_rules
; i
++ )
833 ( is_member_of_family_class ( family
, rule
[i
].family
) ) )
834 if ( rule
[i
].ppem
== 0 ||
835 rule
[i
].ppem
== ppem
)
837 is_member_of_style_class ( style
, rule
[i
].style
) )
838 if ( rule
[i
].glyph
== 0 ||
839 FT_Get_Char_Index( (FT_Face
)face
,
840 rule
[i
].glyph
) == glyph_index
)
849 scale_test_tweak( TT_Face face
,
850 const FT_String
* family
,
852 const FT_String
* style
,
854 const SPH_ScaleRule
* rule
,
860 /* rule checks may be able to be optimized further */
861 for ( i
= 0; i
< num_rules
; i
++ )
864 ( is_member_of_family_class ( family
, rule
[i
].family
) ) )
865 if ( rule
[i
].ppem
== 0 ||
866 rule
[i
].ppem
== ppem
)
868 is_member_of_style_class( style
, rule
[i
].style
) )
869 if ( rule
[i
].glyph
== 0 ||
870 FT_Get_Char_Index( (FT_Face
)face
,
871 rule
[i
].glyph
) == glyph_index
)
872 return rule
[i
].scale
;
879 FT_LOCAL_DEF( FT_UInt
)
880 sph_test_tweak_x_scaling( TT_Face face
,
881 const FT_String
* family
,
883 const FT_String
* style
,
884 FT_UInt glyph_index
)
886 return scale_test_tweak( face
, family
, ppem
, style
, glyph_index
,
887 X_SCALING_Rules
, X_SCALING_RULES_SIZE
);
891 #define TWEAK_RULES( x ) \
892 if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
893 x##_Rules, x##_RULES_SIZE ) ) \
894 loader->exec->sph_tweak_flags |= SPH_TWEAK_##x;
896 #define TWEAK_RULES_EXCEPTIONS( x ) \
897 if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
898 x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
899 loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x;
903 sph_set_tweaks( TT_Loader loader
,
904 FT_UInt glyph_index
)
906 TT_Face face
= (TT_Face
)loader
->face
;
907 FT_String
* family
= face
->root
.family_name
;
908 int ppem
= loader
->size
->metrics
.x_ppem
;
909 FT_String
* style
= face
->root
.style_name
;
912 /* don't apply rules if style isn't set */
913 if ( !face
->root
.style_name
)
916 #ifdef SPH_DEBUG_MORE_VERBOSE
917 printf( "%s,%d,%s,%c=%d ",
918 family
, ppem
, style
, glyph_index
, glyph_index
);
921 TWEAK_RULES( PIXEL_HINTING
);
923 if ( loader
->exec
->sph_tweak_flags
& SPH_TWEAK_PIXEL_HINTING
)
925 loader
->exec
->ignore_x_mode
= FALSE
;
929 TWEAK_RULES( ALLOW_X_DMOVE
);
930 TWEAK_RULES( ALWAYS_DO_DELTAP
);
931 TWEAK_RULES( ALWAYS_SKIP_DELTAP
);
932 TWEAK_RULES( DEEMBOLDEN
);
933 TWEAK_RULES( DO_SHPIX
);
934 TWEAK_RULES( EMBOLDEN
);
935 TWEAK_RULES( MIAP_HACK
);
936 TWEAK_RULES( NORMAL_ROUND
);
937 TWEAK_RULES( NO_ALIGNRP_AFTER_IUP
);
938 TWEAK_RULES( NO_CALL_AFTER_IUP
);
939 TWEAK_RULES( NO_DELTAP_AFTER_IUP
);
940 TWEAK_RULES( RASTERIZER_35
);
941 TWEAK_RULES( SKIP_IUP
);
943 TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES
);
944 TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES
);
946 TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP
);
948 TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES
);
949 TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES
);
951 TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES
);
952 TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES
);
954 if ( loader
->exec
->sph_tweak_flags
& SPH_TWEAK_RASTERIZER_35
)
956 if ( loader
->exec
->rasterizer_version
!= TT_INTERPRETER_VERSION_35
)
958 loader
->exec
->rasterizer_version
= TT_INTERPRETER_VERSION_35
;
959 loader
->exec
->size
->cvt_ready
= FALSE
;
961 tt_size_ready_bytecode(
963 FT_BOOL( loader
->load_flags
& FT_LOAD_PEDANTIC
) );
966 loader
->exec
->rasterizer_version
= TT_INTERPRETER_VERSION_35
;
970 if ( loader
->exec
->rasterizer_version
!=
971 SPH_OPTION_SET_RASTERIZER_VERSION
)
973 loader
->exec
->rasterizer_version
= SPH_OPTION_SET_RASTERIZER_VERSION
;
974 loader
->exec
->size
->cvt_ready
= FALSE
;
976 tt_size_ready_bytecode(
978 FT_BOOL( loader
->load_flags
& FT_LOAD_PEDANTIC
) );
981 loader
->exec
->rasterizer_version
= SPH_OPTION_SET_RASTERIZER_VERSION
;
984 if ( IS_HINTED( loader
->load_flags
) )
986 TWEAK_RULES( TIMES_NEW_ROMAN_HACK
);
987 TWEAK_RULES( COURIER_NEW_2_HACK
);
990 if ( sph_test_tweak( face
, family
, ppem
, style
, glyph_index
,
991 COMPATIBILITY_MODE_Rules
, COMPATIBILITY_MODE_RULES_SIZE
) )
992 loader
->exec
->face
->sph_compatibility_mode
= TRUE
;
995 if ( IS_HINTED( loader
->load_flags
) )
997 if ( sph_test_tweak( face
, family
, ppem
, style
, glyph_index
,
998 COMPATIBLE_WIDTHS_Rules
, COMPATIBLE_WIDTHS_RULES_SIZE
) )
999 loader
->exec
->compatible_widths
|= TRUE
;
1003 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1005 /* ANSI C doesn't like empty source files */
1006 typedef int _tt_subpix_dummy
;
1008 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */