Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ttsubpix.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* ttsubpix.c */
4 /* */
5 /* TrueType Subpixel Hinting. */
6 /* */
7 /* Copyright 2010-2013 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 #include <ft2build.h>
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
24 #include FT_OUTLINE_H
25 
26 #include "ttsubpix.h"
27 
28 
29 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
30 
31  /*************************************************************************/
32  /* */
33  /* These rules affect how the TT Interpreter does hinting, with the */
34  /* goal of doing subpixel hinting by (in general) ignoring x moves. */
35  /* Some of these rules are fixes that go above and beyond the */
36  /* stated techniques in the MS whitepaper on Cleartype, due to */
37  /* artifacts in many glyphs. So, these rules make some glyphs render */
38  /* better than they do in the MS rasterizer. */
39  /* */
40  /* "" string or 0 int/char indicates to apply to all glyphs. */
41  /* "-" used as dummy placeholders, but any non-matching string works. */
42  /* */
43  /* Some of this could arguably be implemented in fontconfig, however: */
44  /* */
45  /* - Fontconfig can't set things on a glyph-by-glyph basis. */
46  /* - The tweaks that happen here are very low-level, from an average */
47  /* user's point of view and are best implemented in the hinter. */
48  /* */
49  /* The goal is to make the subpixel hinting techniques as generalized */
50  /* as possible across all fonts to prevent the need for extra rules such */
51  /* as these. */
52  /* */
53  /* The rule structure is designed so that entirely new rules can easily */
54  /* be added when a new compatibility feature is discovered. */
55  /* */
56  /* The rule structures could also use some enhancement to handle ranges. */
57  /* */
58  /* ****************** WORK IN PROGRESS ******************* */
59  /* */
60 
61  /* These are `classes' of fonts that can be grouped together and used in */
62  /* rules below. A blank entry "" is required at the end of these! */
63 #define FAMILY_CLASS_RULES_SIZE 7
64 
65  static const SPH_Font_Class FAMILY_CLASS_Rules
66  [FAMILY_CLASS_RULES_SIZE] =
67  {
68  { "MS Legacy Fonts",
69  { "Aharoni",
70  "Andale Mono",
71  "Andalus",
72  "Angsana New",
73  "AngsanaUPC",
74  "Arabic Transparent",
75  "Arial Black",
76  "Arial Narrow",
77  "Arial Unicode MS",
78  "Arial",
79  "Batang",
80  "Browallia New",
81  "BrowalliaUPC",
82  "Comic Sans MS",
83  "Cordia New",
84  "CordiaUPC",
85  "Courier New",
86  "DFKai-SB",
87  "David Transparent",
88  "David",
89  "DilleniaUPC",
90  "Estrangelo Edessa",
91  "EucrosiaUPC",
92  "FangSong_GB2312",
93  "Fixed Miriam Transparent",
94  "FrankRuehl",
95  "Franklin Gothic Medium",
96  "FreesiaUPC",
97  "Garamond",
98  "Gautami",
99  "Georgia",
100  "Gulim",
101  "Impact",
102  "IrisUPC",
103  "JasmineUPC",
104  "KaiTi_GB2312",
105  "KodchiangUPC",
106  "Latha",
107  "Levenim MT",
108  "LilyUPC",
109  "Lucida Console",
110  "Lucida Sans Unicode",
111  "MS Gothic",
112  "MS Mincho",
113  "MV Boli",
114  "Mangal",
115  "Marlett",
116  "Microsoft Sans Serif",
117  "Mingliu",
118  "Miriam Fixed",
119  "Miriam Transparent",
120  "Miriam",
121  "Narkisim",
122  "Palatino Linotype",
123  "Raavi",
124  "Rod Transparent",
125  "Rod",
126  "Shruti",
127  "SimHei",
128  "Simplified Arabic Fixed",
129  "Simplified Arabic",
130  "Simsun",
131  "Sylfaen",
132  "Symbol",
133  "Tahoma",
134  "Times New Roman",
135  "Traditional Arabic",
136  "Trebuchet MS",
137  "Tunga",
138  "Verdana",
139  "Webdings",
140  "Wingdings",
141  "",
142  },
143  },
144  { "Core MS Legacy Fonts",
145  { "Arial Black",
146  "Arial Narrow",
147  "Arial Unicode MS",
148  "Arial",
149  "Comic Sans MS",
150  "Courier New",
151  "Garamond",
152  "Georgia",
153  "Impact",
154  "Lucida Console",
155  "Lucida Sans Unicode",
156  "Microsoft Sans Serif",
157  "Palatino Linotype",
158  "Tahoma",
159  "Times New Roman",
160  "Trebuchet MS",
161  "Verdana",
162  "",
163  },
164  },
165  { "Apple Legacy Fonts",
166  { "Geneva",
167  "Times",
168  "Monaco",
169  "Century",
170  "Chalkboard",
171  "Lobster",
172  "Century Gothic",
173  "Optima",
174  "Lucida Grande",
175  "Gill Sans",
176  "Baskerville",
177  "Helvetica",
178  "Helvetica Neue",
179  "",
180  },
181  },
182  { "Legacy Sans Fonts",
183  { "Andale Mono",
184  "Arial Unicode MS",
185  "Arial",
186  "Century Gothic",
187  "Comic Sans MS",
188  "Franklin Gothic Medium",
189  "Geneva",
190  "Lucida Console",
191  "Lucida Grande",
192  "Lucida Sans Unicode",
193  "Lucida Sans Typewriter",
194  "Microsoft Sans Serif",
195  "Monaco",
196  "Tahoma",
197  "Trebuchet MS",
198  "Verdana",
199  "",
200  },
201  },
202 
203  { "Misc Legacy Fonts",
204  { "Dark Courier", "", }, },
205  { "Verdana Clones",
206  { "DejaVu Sans",
207  "Bitstream Vera Sans", "", }, },
208  { "Verdana and Clones",
209  { "DejaVu Sans",
210  "Bitstream Vera Sans",
211  "Verdana", "", }, },
212  };
213 
214 
215  /* Define this to force natural (i.e. not bitmap-compatible) widths. */
216  /* The default leans strongly towards natural widths except for a few */
217  /* legacy fonts where a selective combination produces nicer results. */
218 /* #define FORCE_NATURAL_WIDTHS */
219 
220 
221  /* Define `classes' of styles that can be grouped together and used in */
222  /* rules below. A blank entry "" is required at the end of these! */
223 #define STYLE_CLASS_RULES_SIZE 5
224 
225  const SPH_Font_Class STYLE_CLASS_Rules
226  [STYLE_CLASS_RULES_SIZE] =
227  {
228  { "Regular Class",
229  { "Regular",
230  "Book",
231  "Medium",
232  "Roman",
233  "Normal",
234  "",
235  },
236  },
237  { "Regular/Italic Class",
238  { "Regular",
239  "Book",
240  "Medium",
241  "Italic",
242  "Oblique",
243  "Roman",
244  "Normal",
245  "",
246  },
247  },
248  { "Bold/BoldItalic Class",
249  { "Bold",
250  "Bold Italic",
251  "Black",
252  "",
253  },
254  },
255  { "Bold/Italic/BoldItalic Class",
256  { "Bold",
257  "Bold Italic",
258  "Black",
259  "Italic",
260  "Oblique",
261  "",
262  },
263  },
264  { "Regular/Bold Class",
265  { "Regular",
266  "Book",
267  "Medium",
268  "Normal",
269  "Roman",
270  "Bold",
271  "Black",
272  "",
273  },
274  },
275  };
276 
277 
278  /* Force special legacy fixes for fonts. */
279 #define COMPATIBILITY_MODE_RULES_SIZE 1
280 
281  const SPH_TweakRule COMPATIBILITY_MODE_Rules
282  [COMPATIBILITY_MODE_RULES_SIZE] =
283  {
284  { "-", 0, "", 0 },
285  };
286 
287 
288  /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */
289 #define PIXEL_HINTING_RULES_SIZE 1
290 
291  const SPH_TweakRule PIXEL_HINTING_Rules
292  [PIXEL_HINTING_RULES_SIZE] =
293  {
294  /* these characters are almost always safe */
295  { "-", 0, "", 0 },
296  };
297 
298 
299  /* According to Greg Hitchcock and the MS whitepaper, this should work */
300  /* on all legacy MS fonts, but creates artifacts with some. Only using */
301  /* where absolutely necessary. */
302 #define SKIP_INLINE_DELTAS_RULES_SIZE 1
303 
304  const SPH_TweakRule SKIP_INLINE_DELTAS_Rules
305  [SKIP_INLINE_DELTAS_RULES_SIZE] =
306  {
307  { "-", 0, "", 0 },
308  };
309 
310 
311  /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */
312 #define DO_SHPIX_RULES_SIZE 1
313 
314  const SPH_TweakRule DO_SHPIX_Rules
315  [DO_SHPIX_RULES_SIZE] =
316  {
317  { "-", 0, "", 0 },
318  };
319 
320 
321  /* Skip Y moves that start with a point that is not on a Y pixel */
322  /* boundary and don't move that point to a Y pixel boundary. */
323 #define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 9
324 
325  const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules
326  [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
327  {
328  /* fix vwxyz thinness*/
329  { "Consolas", 0, "Regular", 0 },
330  /* fix tiny gap at top of m */
331  { "Arial", 0, "Regular", 'm' },
332  /* Fix thin middle stems */
333  { "Core MS Legacy Fonts", 0, "Regular/Bold Class", 'N' },
334  { "Lucida Grande", 0, "", 'N' },
335  { "Lucida Grande", 0, "Bold", 'y' },
336  /* Cyrillic small letter I */
337  { "Legacy Sans Fonts", 0, "", 0x438 },
338  { "Verdana Clones", 0, "",'N' },
339  /* Fix misshapen x */
340  { "Verdana", 0, "Bold", 'x' },
341  /* Fix misshapen s */
342  { "Tahoma", 0, "", 's' },
343  };
344 
345 
346 #define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 7
347 
348  const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
349  [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
350  {
351  { "Tahoma", 0, "", 'N' },
352  { "Comic Sans MS", 0, "", 'N' },
353  { "Verdana", 0, "Regular/Bold Class", 'N' },
354  { "Verdana", 11, "Bold", 'x' },
355  /* Cyrillic small letter I */
356  { "Arial", 0, "", 0x438 },
357  { "Arial", 11, "Bold", 'N' },
358  { "Trebuchet MS", 0, "Bold", 0 },
359  };
360 
361 
362  /* Skip Y moves that move a point off a Y pixel boundary. */
363 #define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1
364 
365  const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules
366  [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
367  {
368  { "-", 0, "", 0 },
369  };
370 
371 
372 #define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
373 
374  const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
375  [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
376  {
377  { "-", 0, "", 0 },
378  };
379 
380 
381  /* Round moves that don't move a point to a Y pixel boundary. */
382 #define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2
383 
384  const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules
385  [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
386  {
387  /* Droid font instructions don't snap Y to pixels */
388  { "Droid Sans", 0, "Regular/Italic Class", 0 },
389  { "Droid Sans Mono", 0, "", 0 },
390  };
391 
392 
393 #define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
394 
395  const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
396  [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
397  {
398  { "-", 0, "", 0 },
399  };
400 
401 
402  /* Allow a Direct_Move_X along X freedom vector if matched. */
403 #define ALLOW_X_DMOVEX_RULES_SIZE 1
404 
405  const SPH_TweakRule ALLOW_X_DMOVEX_Rules
406  [ALLOW_X_DMOVEX_RULES_SIZE] =
407  {
408  { "-", 0, "Regular", 0 },
409  };
410 
411 
412  /* Allow a Direct_Move along X freedom vector if matched. */
413 #define ALLOW_X_DMOVE_RULES_SIZE 1
414 
415  const SPH_TweakRule ALLOW_X_DMOVE_Rules
416  [ALLOW_X_DMOVE_RULES_SIZE] =
417  {
418  /* Fixes vanishing diagonal in 4 */
419  { "Verdana", 0, "Regular", '4' },
420  };
421 
422 
423  /* Allow a ZP2 move along freedom vector if matched; */
424  /* This is called from SHP, SHPIX, SHC, SHZ. */
425 #define ALLOW_X_MOVE_ZP2_RULES_SIZE 1
426 
427  const SPH_TweakRule ALLOW_X_MOVE_ZP2_Rules
428  [ALLOW_X_MOVE_ZP2_RULES_SIZE] =
429  {
430  { "-", 0, "", 0 },
431  };
432 
433 
434  /* Return MS rasterizer version 35 if matched. */
435 #define RASTERIZER_35_RULES_SIZE 8
436 
437  const SPH_TweakRule RASTERIZER_35_Rules
438  [RASTERIZER_35_RULES_SIZE] =
439  {
440  /* This seems to be the only way to make these look good */
441  { "Times New Roman", 0, "Regular", 'i' },
442  { "Times New Roman", 0, "Regular", 'j' },
443  { "Times New Roman", 0, "Regular", 'm' },
444  { "Times New Roman", 0, "Regular", 'r' },
445  { "Times New Roman", 0, "Regular", 'a' },
446  { "Times New Roman", 0, "Regular", 'n' },
447  { "Times New Roman", 0, "Regular", 'p' },
448  { "Times", 0, "", 0 },
449  };
450 
451 
452  /* Don't round to the subpixel grid. Round to pixel grid. */
453 #define NORMAL_ROUND_RULES_SIZE 1
454 
455  const SPH_TweakRule NORMAL_ROUND_Rules
456  [NORMAL_ROUND_RULES_SIZE] =
457  {
458  /* Fix serif thickness */
459  { "Courier New", 0, "", 0 },
460  };
461 
462 
463  /* Skip IUP instructions if matched. */
464 #define SKIP_IUP_RULES_SIZE 1
465 
466  const SPH_TweakRule SKIP_IUP_Rules
467  [SKIP_IUP_RULES_SIZE] =
468  {
469  { "Arial", 13, "Regular", 'a' },
470  };
471 
472 
473  /* Skip MIAP Twilight hack if matched. */
474 #define MIAP_HACK_RULES_SIZE 1
475 
476  const SPH_TweakRule MIAP_HACK_Rules
477  [MIAP_HACK_RULES_SIZE] =
478  {
479  { "Geneva", 12, "", 0 },
480  };
481 
482 
483  /* Skip DELTAP instructions if matched. */
484 #define ALWAYS_SKIP_DELTAP_RULES_SIZE 15
485 
486  const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
487  [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
488  {
489  { "Georgia", 0, "Regular", 'k' },
490  /* fix various problems with e in different versions */
491  { "Trebuchet MS", 14, "Regular", 'e' },
492  { "Trebuchet MS", 13, "Regular", 'e' },
493  { "Trebuchet MS", 15, "Regular", 'e' },
494  { "Arial", 11, "Regular", 's' },
495  { "Verdana", 10, "Regular", 0 },
496  { "Verdana", 9, "Regular", 0 },
497  /* Cyrillic small letter short I */
498  { "Legacy Sans Fonts", 0, "", 0x438 },
499  { "Legacy Sans Fonts", 0, "", 0x439 },
500  { "Arial", 10, "Regular", '6' },
501  { "Arial", 0, "Bold/BoldItalic Class", 'a' },
502  /* Make horizontal stems consistent with the rest */
503  { "Arial", 24, "Bold", 's' },
504  { "Arial", 25, "Bold", 's' },
505  { "Arial", 24, "Bold", 'a' },
506  { "Arial", 25, "Bold", 'a' },
507  };
508 
509 
510  /* Always do DELTAP instructions if matched. */
511 #define ALWAYS_DO_DELTAP_RULES_SIZE 2
512 
513  const SPH_TweakRule ALWAYS_DO_DELTAP_Rules
514  [ALWAYS_DO_DELTAP_RULES_SIZE] =
515  {
516  { "Verdana Clones", 17, "Regular Class", 'K' },
517  { "Verdana Clones", 17, "Regular Class", 'k' },
518  };
519 
520 
521  /* Do an extra RTG instruction in DELTAP if matched. */
522 #define DELTAP_RTG_RULES_SIZE 1
523 
524  static const SPH_TweakRule DELTAP_RTG_Rules
525  [DELTAP_RTG_RULES_SIZE] =
526  {
527  { "-", 0, "", 0 },
528  };
529 
530 
531  /* Force CVT distance to zero in MIRP. */
532 #define MIRP_CVT_ZERO_RULES_SIZE 1
533 
534  static const SPH_TweakRule MIRP_CVT_ZERO_Rules
535  [MIRP_CVT_ZERO_RULES_SIZE] =
536  {
537  { "-", 0, "", 0 },
538  };
539 
540 
541  /* Skip moves that meet or exceed 1 pixel. */
542 #define DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE 1
543 
544  static const SPH_TweakRule DELTAP_SKIP_EXAGGERATED_VALUES_Rules
545  [DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE] =
546  {
547  { "-", 0, "", 0 },
548  };
549 
550 
551  /* Don't allow ALIGNRP after IUP. */
552 #define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 4
553 
554  static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules
555  [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] =
556  {
557  /* Prevent creation of dents in outline */
558  { "Courier New", 0, "Bold", 'C' },
559  { "Courier New", 0, "Bold", 'D' },
560  { "Courier New", 0, "Bold", 'Q' },
561  { "Courier New", 0, "Bold", '0' },
562  };
563 
564 
565  /* Don't allow DELTAP after IUP. */
566 #define NO_DELTAP_AFTER_IUP_RULES_SIZE 1
567 
568  static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules
569  [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
570  {
571  { "-", 0, "", 0 },
572  };
573 
574 
575  /* Don't allow CALL after IUP. */
576 #define NO_CALL_AFTER_IUP_RULES_SIZE 4
577 
578  static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules
579  [NO_CALL_AFTER_IUP_RULES_SIZE] =
580  {
581  /* Prevent creation of dents in outline */
582  { "Courier New", 0, "Bold", 'O' },
583  { "Courier New", 0, "Bold", 'Q' },
584  { "Courier New", 0, "Bold", 'k' },
585  { "Courier New", 0, "Bold Italic", 'M' },
586  };
587 
588 
589  /* De-embolden these glyphs slightly. */
590 #define DEEMBOLDEN_RULES_SIZE 9
591 
592  static const SPH_TweakRule DEEMBOLDEN_Rules
593  [DEEMBOLDEN_RULES_SIZE] =
594  {
595  { "Courier New", 0, "Bold", 'A' },
596  { "Courier New", 0, "Bold", 'W' },
597  { "Courier New", 0, "Bold", 'w' },
598  { "Courier New", 0, "Bold", 'M' },
599  { "Courier New", 0, "Bold", 'X' },
600  { "Courier New", 0, "Bold", 'K' },
601  { "Courier New", 0, "Bold", 'x' },
602  { "Courier New", 0, "Bold", 'z' },
603  { "Courier New", 0, "Bold", 'v' },
604  };
605 
606 
607  /* Embolden these glyphs slightly. */
608 #define EMBOLDEN_RULES_SIZE 5
609 
610  static const SPH_TweakRule EMBOLDEN_Rules
611  [EMBOLDEN_RULES_SIZE] =
612  {
613  { "Courier New", 12, "Italic", 'z' },
614  { "Courier New", 11, "Italic", 'z' },
615  { "Courier New", 10, "Italic", 'z' },
616  { "Courier New", 0, "Regular", 0 },
617  { "Courier New", 0, "Italic", 0 },
618  };
619 
620 
621  /* Do an extra RDTG instruction in DELTAP if matched. */
622 #define DELTAP_RDTG_RULES_SIZE 1
623 
624  static const SPH_TweakRule DELTAP_RDTG_Rules
625  [DELTAP_RDTG_RULES_SIZE] =
626  {
627  { "-", 0, "", 0 },
628  };
629 
630 
631  /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */
632  /* similar to Windows XP. */
633 #define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
634 
635  static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules
636  [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
637  {
638  { "Times New Roman", 16, "Italic", '2' },
639  { "Times New Roman", 16, "Italic", '5' },
640  { "Times New Roman", 16, "Italic", '7' },
641  { "Times New Roman", 16, "Regular", '2' },
642  { "Times New Roman", 16, "Regular", '5' },
643  { "Times New Roman", 16, "Regular", '7' },
644  { "Times New Roman", 17, "Italic", '2' },
645  { "Times New Roman", 17, "Italic", '5' },
646  { "Times New Roman", 17, "Italic", '7' },
647  { "Times New Roman", 17, "Regular", '2' },
648  { "Times New Roman", 17, "Regular", '5' },
649  { "Times New Roman", 17, "Regular", '7' },
650  };
651 
652 
653  /* This fudges distance on 2 to get rid of the vanishing stem issue. */
654  /* A real solution to this is certainly welcome. */
655 #define COURIER_NEW_2_HACK_RULES_SIZE 15
656 
657  static const SPH_TweakRule COURIER_NEW_2_HACK_Rules
658  [COURIER_NEW_2_HACK_RULES_SIZE] =
659  {
660  { "Courier New", 10, "Regular", '2' },
661  { "Courier New", 11, "Regular", '2' },
662  { "Courier New", 12, "Regular", '2' },
663  { "Courier New", 13, "Regular", '2' },
664  { "Courier New", 14, "Regular", '2' },
665  { "Courier New", 15, "Regular", '2' },
666  { "Courier New", 16, "Regular", '2' },
667  { "Courier New", 17, "Regular", '2' },
668  { "Courier New", 18, "Regular", '2' },
669  { "Courier New", 19, "Regular", '2' },
670  { "Courier New", 20, "Regular", '2' },
671  { "Courier New", 21, "Regular", '2' },
672  { "Courier New", 22, "Regular", '2' },
673  { "Courier New", 23, "Regular", '2' },
674  { "Courier New", 24, "Regular", '2' },
675  };
676 
677 
678 #ifndef FORCE_NATURAL_WIDTHS
679 
680  /* Use compatible widths with these glyphs. Compatible widths is always */
681  /* on when doing B/W TrueType instructing, but is used selectively here, */
682  /* typically on glyphs with 3 or more vertical stems. */
683 #define COMPATIBLE_WIDTHS_RULES_SIZE 38
684 
685  static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
686  [COMPATIBLE_WIDTHS_RULES_SIZE] =
687  {
688  { "Arial Unicode MS", 12, "Regular Class", 'm' },
689  { "Arial Unicode MS", 14, "Regular Class", 'm' },
690  /* Cyrillic small letter sha */
691  { "Arial", 10, "Regular Class", 0x448 },
692  { "Arial", 11, "Regular Class", 'm' },
693  { "Arial", 12, "Regular Class", 'm' },
694  /* Cyrillic small letter sha */
695  { "Arial", 12, "Regular Class", 0x448 },
696  { "Arial", 13, "Regular Class", 0x448 },
697  { "Arial", 14, "Regular Class", 'm' },
698  /* Cyrillic small letter sha */
699  { "Arial", 14, "Regular Class", 0x448 },
700  { "Arial", 15, "Regular Class", 0x448 },
701  { "Arial", 17, "Regular Class", 'm' },
702  { "DejaVu Sans", 15, "Regular Class", 0 },
703  { "Microsoft Sans Serif", 11, "Regular Class", 0 },
704  { "Microsoft Sans Serif", 12, "Regular Class", 0 },
705  { "Segoe UI", 11, "Regular Class", 0 },
706  { "Monaco", 0, "Regular Class", 0 },
707  { "Segoe UI", 12, "Regular Class", 'm' },
708  { "Segoe UI", 14, "Regular Class", 'm' },
709  { "Tahoma", 11, "Regular Class", 0 },
710  { "Times New Roman", 16, "Regular Class", 'c' },
711  { "Times New Roman", 16, "Regular Class", 'm' },
712  { "Times New Roman", 16, "Regular Class", 'o' },
713  { "Times New Roman", 16, "Regular Class", 'w' },
714  { "Trebuchet MS", 11, "Regular Class", 0 },
715  { "Trebuchet MS", 12, "Regular Class", 0 },
716  { "Trebuchet MS", 14, "Regular Class", 0 },
717  { "Trebuchet MS", 15, "Regular Class", 0 },
718  { "Ubuntu", 12, "Regular Class", 'm' },
719  /* Cyrillic small letter sha */
720  { "Verdana", 10, "Regular Class", 0x448 },
721  { "Verdana", 11, "Regular Class", 0x448 },
722  { "Verdana and Clones", 12, "Regular Class", 'i' },
723  { "Verdana and Clones", 12, "Regular Class", 'j' },
724  { "Verdana and Clones", 12, "Regular Class", 'l' },
725  { "Verdana and Clones", 12, "Regular Class", 'm' },
726  { "Verdana and Clones", 13, "Regular Class", 'i' },
727  { "Verdana and Clones", 13, "Regular Class", 'j' },
728  { "Verdana and Clones", 13, "Regular Class", 'l' },
729  { "Verdana and Clones", 14, "Regular Class", 'm' },
730  };
731 
732 
733  /* Scaling slightly in the x-direction prior to hinting results in */
734  /* more visually pleasing glyphs in certain cases. */
735  /* This sometimes needs to be coordinated with compatible width rules. */
736  /* A value of 1000 corresponds to a scaled value of 1.0. */
737 
738 #define X_SCALING_RULES_SIZE 50
739 
740  static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] =
741  {
742  { "DejaVu Sans", 12, "Regular Class", 'm', 950 },
743  { "Verdana and Clones", 12, "Regular Class", 'a', 1100 },
744  { "Verdana and Clones", 13, "Regular Class", 'a', 1050 },
745  { "Arial", 11, "Regular Class", 'm', 975 },
746  { "Arial", 12, "Regular Class", 'm', 1050 },
747  /* Cyrillic small letter el */
748  { "Arial", 13, "Regular Class", 0x43B, 950 },
749  { "Arial", 13, "Regular Class", 'o', 950 },
750  { "Arial", 13, "Regular Class", 'e', 950 },
751  { "Arial", 14, "Regular Class", 'm', 950 },
752  /* Cyrillic small letter el */
753  { "Arial", 15, "Regular Class", 0x43B, 925 },
754  { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 },
755  { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 },
756  { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 },
757  { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 },
758  { "DejaVu Sans", 12, "Regular Class", 'l', 975 },
759  { "DejaVu Sans", 12, "Regular Class", 'i', 975 },
760  { "DejaVu Sans", 12, "Regular Class", 'j', 975 },
761  { "DejaVu Sans", 13, "Regular Class", 'l', 950 },
762  { "DejaVu Sans", 13, "Regular Class", 'i', 950 },
763  { "DejaVu Sans", 13, "Regular Class", 'j', 950 },
764  { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 },
765  { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 },
766  { "Georgia", 10, "", 0, 1050 },
767  { "Georgia", 11, "", 0, 1100 },
768  { "Georgia", 12, "", 0, 1025 },
769  { "Georgia", 13, "", 0, 1050 },
770  { "Georgia", 16, "", 0, 1050 },
771  { "Georgia", 17, "", 0, 1030 },
772  { "Liberation Sans", 12, "Regular Class", 'm', 1100 },
773  { "Lucida Grande", 11, "Regular Class", 'm', 1100 },
774  { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 },
775  { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 },
776  { "Segoe UI", 12, "Regular Class", 'H', 1050 },
777  { "Segoe UI", 12, "Regular Class", 'm', 1050 },
778  { "Segoe UI", 14, "Regular Class", 'm', 1050 },
779  { "Tahoma", 11, "Regular Class", 'i', 975 },
780  { "Tahoma", 11, "Regular Class", 'l', 975 },
781  { "Tahoma", 11, "Regular Class", 'j', 900 },
782  { "Tahoma", 11, "Regular Class", 'm', 918 },
783  { "Verdana", 10, "Regular/Italic Class", 0, 1100 },
784  { "Verdana", 12, "Regular Class", 'm', 975 },
785  { "Verdana", 12, "Regular/Italic Class", 0, 1050 },
786  { "Verdana", 13, "Regular/Italic Class", 'i', 950 },
787  { "Verdana", 13, "Regular/Italic Class", 'j', 950 },
788  { "Verdana", 13, "Regular/Italic Class", 'l', 950 },
789  { "Verdana", 16, "Regular Class", 0, 1050 },
790  { "Verdana", 9, "Regular/Italic Class", 0, 1050 },
791  { "Times New Roman", 16, "Regular Class", 'm', 918 },
792  { "Trebuchet MS", 11, "Regular Class", 'm', 800 },
793  { "Trebuchet MS", 12, "Regular Class", 'm', 800 },
794  };
795 
796 #else
797 
798 #define COMPATIBLE_WIDTHS_RULES_SIZE 1
799 
800  static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
801  [COMPATIBLE_WIDTHS_RULES_SIZE] =
802  {
803  { "-", 0, "", 0 },
804  };
805 
806 
807 #define X_SCALING_RULES_SIZE 1
808 
809  static const SPH_ScaleRule X_SCALING_Rules
810  [X_SCALING_RULES_SIZE] =
811  {
812  { "-", 0, "", 0, 1000 },
813  };
814 
815 #endif /* FORCE_NATURAL_WIDTHS */
816 
817 
819  is_member_of_family_class( const FT_String* detected_font_name,
820  const FT_String* rule_font_name )
821  {
822  FT_UInt i, j;
823 
824 
825  /* Does font name match rule family? */
826  if ( strcmp( detected_font_name, rule_font_name ) == 0 )
827  return TRUE;
828 
829  /* Is font name a wildcard ""? */
830  if ( strcmp( rule_font_name, "" ) == 0 )
831  return TRUE;
832 
833  /* Is font name contained in a class list? */
834  for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ )
835  {
836  if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 )
837  {
838  for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
839  {
840  if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 )
841  continue;
842  if ( strcmp( FAMILY_CLASS_Rules[i].member[j],
843  detected_font_name ) == 0 )
844  return TRUE;
845  }
846  }
847  }
848 
849  return FALSE;
850  }
851 
852 
854  is_member_of_style_class( const FT_String* detected_font_style,
855  const FT_String* rule_font_style )
856  {
857  FT_UInt i, j;
858 
859 
860  /* Does font style match rule style? */
861  if ( strcmp( detected_font_style, rule_font_style ) == 0 )
862  return TRUE;
863 
864  /* Is font style a wildcard ""? */
865  if ( strcmp( rule_font_style, "" ) == 0 )
866  return TRUE;
867 
868  /* Is font style contained in a class list? */
869  for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ )
870  {
871  if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 )
872  {
873  for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
874  {
875  if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 )
876  continue;
877  if ( strcmp( STYLE_CLASS_Rules[i].member[j],
878  detected_font_style ) == 0 )
879  return TRUE;
880  }
881  }
882  }
883 
884  return FALSE;
885  }
886 
887 
889  sph_test_tweak( TT_Face face,
890  const FT_String* family,
891  FT_UInt ppem,
892  const FT_String* style,
893  FT_UInt glyph_index,
894  const SPH_TweakRule* rule,
895  FT_UInt num_rules )
896  {
897  FT_UInt i;
898 
899 
900  /* rule checks may be able to be optimized further */
901  for ( i = 0; i < num_rules; i++ )
902  {
903  if ( family &&
904  ( is_member_of_family_class ( family, rule[i].family ) ) )
905  if ( rule[i].ppem == 0 ||
906  rule[i].ppem == ppem )
907  if ( style &&
908  is_member_of_style_class ( style, rule[i].style ) )
909  if ( rule[i].glyph == 0 ||
910  FT_Get_Char_Index( (FT_Face)face,
911  rule[i].glyph ) == glyph_index )
912  return TRUE;
913  }
914 
915  return FALSE;
916  }
917 
918 
919  static FT_UInt
920  scale_test_tweak( TT_Face face,
921  const FT_String* family,
922  FT_UInt ppem,
923  const FT_String* style,
924  FT_UInt glyph_index,
925  const SPH_ScaleRule* rule,
926  FT_UInt num_rules )
927  {
928  FT_UInt i;
929 
930 
931  /* rule checks may be able to be optimized further */
932  for ( i = 0; i < num_rules; i++ )
933  {
934  if ( family &&
935  ( is_member_of_family_class ( family, rule[i].family ) ) )
936  if ( rule[i].ppem == 0 ||
937  rule[i].ppem == ppem )
938  if ( style &&
939  is_member_of_style_class( style, rule[i].style ) )
940  if ( rule[i].glyph == 0 ||
941  FT_Get_Char_Index( (FT_Face)face,
942  rule[i].glyph ) == glyph_index )
943  return rule[i].scale;
944  }
945 
946  return 1000;
947  }
948 
949 
951  sph_test_tweak_x_scaling( TT_Face face,
952  const FT_String* family,
953  FT_UInt ppem,
954  const FT_String* style,
955  FT_UInt glyph_index )
956  {
957  return scale_test_tweak( face, family, ppem, style, glyph_index,
958  X_SCALING_Rules, X_SCALING_RULES_SIZE );
959  }
960 
961 
962 #define TWEAK_RULES( x ) \
963  if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
964  x##_Rules, x##_RULES_SIZE ) ) \
965  loader->exec->sph_tweak_flags |= SPH_TWEAK_##x;
966 
967 #define TWEAK_RULES_EXCEPTIONS( x ) \
968  if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
969  x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
970  loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x;
971 
972 
973  FT_LOCAL_DEF( void )
974  sph_set_tweaks( TT_Loader loader,
975  FT_UInt glyph_index )
976  {
977  TT_Face face = (TT_Face)loader->face;
978  FT_String* family = face->root.family_name;
979  int ppem = loader->size->metrics.x_ppem;
980  FT_String* style = face->root.style_name;
981 
982 
983  /* don't apply rules if style isn't set */
984  if ( !face->root.style_name )
985  return;
986 
987 #ifdef SPH_DEBUG_MORE_VERBOSE
988  printf( "%s,%d,%s,%c=%d ",
989  family, ppem, style, glyph_index, glyph_index );
990 #endif
991 
992  TWEAK_RULES( PIXEL_HINTING );
993 
994  if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING )
995  {
996  loader->exec->ignore_x_mode = FALSE;
997  return;
998  }
999 
1000  TWEAK_RULES( ALLOW_X_DMOVE );
1001  TWEAK_RULES( ALLOW_X_DMOVEX );
1002  TWEAK_RULES( ALLOW_X_MOVE_ZP2 );
1003  TWEAK_RULES( ALWAYS_DO_DELTAP );
1004  TWEAK_RULES( ALWAYS_SKIP_DELTAP );
1005  TWEAK_RULES( DEEMBOLDEN );
1006  TWEAK_RULES( DELTAP_SKIP_EXAGGERATED_VALUES );
1007  TWEAK_RULES( DO_SHPIX );
1008  TWEAK_RULES( EMBOLDEN );
1009  TWEAK_RULES( MIAP_HACK );
1010  TWEAK_RULES( NORMAL_ROUND );
1011  TWEAK_RULES( NO_ALIGNRP_AFTER_IUP );
1012  TWEAK_RULES( NO_CALL_AFTER_IUP );
1013  TWEAK_RULES( NO_DELTAP_AFTER_IUP );
1014  TWEAK_RULES( RASTERIZER_35 );
1015  TWEAK_RULES( SKIP_INLINE_DELTAS );
1016  TWEAK_RULES( SKIP_IUP );
1017  TWEAK_RULES( MIRP_CVT_ZERO );
1018 
1019  TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES );
1020  TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES );
1021 
1022  TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES );
1023  TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
1024 
1025  TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
1026  TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
1027 
1028  if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
1029  {
1030  if ( loader->exec->rasterizer_version != 35 )
1031  {
1032  loader->exec->rasterizer_version = 35;
1033  loader->exec->size->cvt_ready = FALSE;
1034 
1035  tt_size_ready_bytecode(
1036  loader->exec->size,
1037  FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
1038  }
1039  else
1040  loader->exec->rasterizer_version = 35;
1041  }
1042  else
1043  {
1044  if ( loader->exec->rasterizer_version !=
1045  SPH_OPTION_SET_RASTERIZER_VERSION )
1046  {
1047  loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
1048  loader->exec->size->cvt_ready = FALSE;
1049 
1050  tt_size_ready_bytecode(
1051  loader->exec->size,
1052  FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
1053  }
1054  else
1055  loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
1056  }
1057 
1058  if ( IS_HINTED( loader->load_flags ) )
1059  {
1060  TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
1061  TWEAK_RULES( COURIER_NEW_2_HACK );
1062  }
1063 
1064  if ( sph_test_tweak( face, family, ppem, style, glyph_index,
1065  COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
1066  loader->exec->face->sph_compatibility_mode = TRUE;
1067 
1068 
1069  if ( IS_HINTED( loader->load_flags ) )
1070  {
1071  if ( sph_test_tweak( face, family, ppem, style, glyph_index,
1072  COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
1073  loader->exec->compatible_widths |= TRUE;
1074  }
1075  }
1076 
1077 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1078 
1079 
1080 /* END */
TT_ExecContext exec
Definition: tttypes.h:1525
FT_String * family_name
Definition: freetype.h:929
#define FT_LOAD_PEDANTIC
Definition: freetype.h:2556
FT_String * style_name
Definition: freetype.h:930
png_uint_32 i
Definition: png.h:2640
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
GLenum GLuint GLint GLenum face
struct TT_FaceRec_ * TT_Face
Definition: tttypes.h:951
FT_Get_Char_Index(FT_Face face, FT_ULong charcode)
Definition: ftobjs.c:3302
FT_Size size
Definition: tttypes.h:1499
char FT_String
Definition: fttypes.h:183
FT_UShort x_ppem
Definition: freetype.h:1369
#define FALSE
Definition: ftobjs.h:57
#define FT_BOOL(x)
Definition: fttypes.h:574
FT_FaceRec root
Definition: tttypes.h:1260
GLuint const GLchar * name
if(!abbox) return FT_THROW(Invalid_Argument)
unsigned int FT_UInt
Definition: fttypes.h:227
FT_ULong load_flags
Definition: tttypes.h:1503
#define TRUE
Definition: ftobjs.h:53
FT_Size_Metrics metrics
Definition: freetype.h:1406
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:236
FT_Face face
Definition: tttypes.h:1498
#define IS_HINTED(flags)
Definition: ttobjs.h:433