OLD | NEW |
| (Empty) |
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 "../../include/ft2build.h" | |
19 #include "../../include/freetype/internal/ftdebug.h" | |
20 #include "../../include/freetype/internal/ftcalc.h" | |
21 #include "../../include/freetype/internal/ftstream.h" | |
22 #include "../../include/freetype/internal/sfnt.h" | |
23 #include "../../include/freetype/tttags.h" | |
24 #include "../../include/freetype/ftoutln.h" | |
25 #include "../../include/freetype/ftttdrv.h" | |
26 | |
27 #include "ttsubpix.h" | |
28 | |
29 | |
30 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING | |
31 | |
32 /*************************************************************************/ | |
33 /* */ | |
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. */ | |
40 /* */ | |
41 /* "" string or 0 int/char indicates to apply to all glyphs. */ | |
42 /* "-" used as dummy placeholders, but any non-matching string works. */ | |
43 /* */ | |
44 /* Some of this could arguably be implemented in fontconfig, however: */ | |
45 /* */ | |
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. */ | |
49 /* */ | |
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 */ | |
52 /* as these. */ | |
53 /* */ | |
54 /* The rule structure is designed so that entirely new rules can easily */ | |
55 /* be added when a new compatibility feature is discovered. */ | |
56 /* */ | |
57 /* The rule structures could also use some enhancement to handle ranges. */ | |
58 /* */ | |
59 /* ****************** WORK IN PROGRESS ******************* */ | |
60 /* */ | |
61 | |
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 | |
65 | |
66 static const SPH_Font_Class FAMILY_CLASS_Rules | |
67 [FAMILY_CLASS_RULES_SIZE] = | |
68 { | |
69 { "MS Legacy Fonts", | |
70 { "Aharoni", | |
71 "Andale Mono", | |
72 "Andalus", | |
73 "Angsana New", | |
74 "AngsanaUPC", | |
75 "Arabic Transparent", | |
76 "Arial Black", | |
77 "Arial Narrow", | |
78 "Arial Unicode MS", | |
79 "Arial", | |
80 "Batang", | |
81 "Browallia New", | |
82 "BrowalliaUPC", | |
83 "Comic Sans MS", | |
84 "Cordia New", | |
85 "CordiaUPC", | |
86 "Courier New", | |
87 "DFKai-SB", | |
88 "David Transparent", | |
89 "David", | |
90 "DilleniaUPC", | |
91 "Estrangelo Edessa", | |
92 "EucrosiaUPC", | |
93 "FangSong_GB2312", | |
94 "Fixed Miriam Transparent", | |
95 "FrankRuehl", | |
96 "Franklin Gothic Medium", | |
97 "FreesiaUPC", | |
98 "Garamond", | |
99 "Gautami", | |
100 "Georgia", | |
101 "Gulim", | |
102 "Impact", | |
103 "IrisUPC", | |
104 "JasmineUPC", | |
105 "KaiTi_GB2312", | |
106 "KodchiangUPC", | |
107 "Latha", | |
108 "Levenim MT", | |
109 "LilyUPC", | |
110 "Lucida Console", | |
111 "Lucida Sans Unicode", | |
112 "MS Gothic", | |
113 "MS Mincho", | |
114 "MV Boli", | |
115 "Mangal", | |
116 "Marlett", | |
117 "Microsoft Sans Serif", | |
118 "Mingliu", | |
119 "Miriam Fixed", | |
120 "Miriam Transparent", | |
121 "Miriam", | |
122 "Narkisim", | |
123 "Palatino Linotype", | |
124 "Raavi", | |
125 "Rod Transparent", | |
126 "Rod", | |
127 "Shruti", | |
128 "SimHei", | |
129 "Simplified Arabic Fixed", | |
130 "Simplified Arabic", | |
131 "Simsun", | |
132 "Sylfaen", | |
133 "Symbol", | |
134 "Tahoma", | |
135 "Times New Roman", | |
136 "Traditional Arabic", | |
137 "Trebuchet MS", | |
138 "Tunga", | |
139 "Verdana", | |
140 "Webdings", | |
141 "Wingdings", | |
142 "", | |
143 }, | |
144 }, | |
145 { "Core MS Legacy Fonts", | |
146 { "Arial Black", | |
147 "Arial Narrow", | |
148 "Arial Unicode MS", | |
149 "Arial", | |
150 "Comic Sans MS", | |
151 "Courier New", | |
152 "Garamond", | |
153 "Georgia", | |
154 "Impact", | |
155 "Lucida Console", | |
156 "Lucida Sans Unicode", | |
157 "Microsoft Sans Serif", | |
158 "Palatino Linotype", | |
159 "Tahoma", | |
160 "Times New Roman", | |
161 "Trebuchet MS", | |
162 "Verdana", | |
163 "", | |
164 }, | |
165 }, | |
166 { "Apple Legacy Fonts", | |
167 { "Geneva", | |
168 "Times", | |
169 "Monaco", | |
170 "Century", | |
171 "Chalkboard", | |
172 "Lobster", | |
173 "Century Gothic", | |
174 "Optima", | |
175 "Lucida Grande", | |
176 "Gill Sans", | |
177 "Baskerville", | |
178 "Helvetica", | |
179 "Helvetica Neue", | |
180 "", | |
181 }, | |
182 }, | |
183 { "Legacy Sans Fonts", | |
184 { "Andale Mono", | |
185 "Arial Unicode MS", | |
186 "Arial", | |
187 "Century Gothic", | |
188 "Comic Sans MS", | |
189 "Franklin Gothic Medium", | |
190 "Geneva", | |
191 "Lucida Console", | |
192 "Lucida Grande", | |
193 "Lucida Sans Unicode", | |
194 "Lucida Sans Typewriter", | |
195 "Microsoft Sans Serif", | |
196 "Monaco", | |
197 "Tahoma", | |
198 "Trebuchet MS", | |
199 "Verdana", | |
200 "", | |
201 }, | |
202 }, | |
203 | |
204 { "Misc Legacy Fonts", | |
205 { "Dark Courier", "", }, }, | |
206 { "Verdana Clones", | |
207 { "DejaVu Sans", | |
208 "Bitstream Vera Sans", "", }, }, | |
209 { "Verdana and Clones", | |
210 { "DejaVu Sans", | |
211 "Bitstream Vera Sans", | |
212 "Verdana", "", }, }, | |
213 }; | |
214 | |
215 | |
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 */ | |
220 | |
221 | |
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 | |
225 | |
226 const SPH_Font_Class STYLE_CLASS_Rules | |
227 [STYLE_CLASS_RULES_SIZE] = | |
228 { | |
229 { "Regular Class", | |
230 { "Regular", | |
231 "Book", | |
232 "Medium", | |
233 "Roman", | |
234 "Normal", | |
235 "", | |
236 }, | |
237 }, | |
238 { "Regular/Italic Class", | |
239 { "Regular", | |
240 "Book", | |
241 "Medium", | |
242 "Italic", | |
243 "Oblique", | |
244 "Roman", | |
245 "Normal", | |
246 "", | |
247 }, | |
248 }, | |
249 { "Bold/BoldItalic Class", | |
250 { "Bold", | |
251 "Bold Italic", | |
252 "Black", | |
253 "", | |
254 }, | |
255 }, | |
256 { "Bold/Italic/BoldItalic Class", | |
257 { "Bold", | |
258 "Bold Italic", | |
259 "Black", | |
260 "Italic", | |
261 "Oblique", | |
262 "", | |
263 }, | |
264 }, | |
265 { "Regular/Bold Class", | |
266 { "Regular", | |
267 "Book", | |
268 "Medium", | |
269 "Normal", | |
270 "Roman", | |
271 "Bold", | |
272 "Black", | |
273 "", | |
274 }, | |
275 }, | |
276 }; | |
277 | |
278 | |
279 /* Force special legacy fixes for fonts. */ | |
280 #define COMPATIBILITY_MODE_RULES_SIZE 1 | |
281 | |
282 const SPH_TweakRule COMPATIBILITY_MODE_Rules | |
283 [COMPATIBILITY_MODE_RULES_SIZE] = | |
284 { | |
285 { "-", 0, "", 0 }, | |
286 }; | |
287 | |
288 | |
289 /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */ | |
290 #define PIXEL_HINTING_RULES_SIZE 2 | |
291 | |
292 const SPH_TweakRule PIXEL_HINTING_Rules | |
293 [PIXEL_HINTING_RULES_SIZE] = | |
294 { | |
295 /* these characters are almost always safe */ | |
296 { "Courier New", 12, "Italic", 'z' }, | |
297 { "Courier New", 11, "Italic", 'z' }, | |
298 }; | |
299 | |
300 | |
301 /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */ | |
302 #define DO_SHPIX_RULES_SIZE 1 | |
303 | |
304 const SPH_TweakRule DO_SHPIX_Rules | |
305 [DO_SHPIX_RULES_SIZE] = | |
306 { | |
307 { "-", 0, "", 0 }, | |
308 }; | |
309 | |
310 | |
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 | |
314 | |
315 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules | |
316 [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] = | |
317 { | |
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 }, | |
326 }; | |
327 | |
328 | |
329 #define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 | |
330 | |
331 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions | |
332 [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = | |
333 { | |
334 /* Fixes < and > */ | |
335 { "Courier New", 0, "Regular", 0 }, | |
336 }; | |
337 | |
338 | |
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 | |
342 | |
343 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules | |
344 [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] = | |
345 { | |
346 /* Maintain thickness of diagonal in 'N' */ | |
347 { "Times New Roman", 0, "Regular/Bold Class", 'N' }, | |
348 { "Georgia", 0, "Regular/Bold Class", 'N' }, | |
349 }; | |
350 | |
351 | |
352 /* Skip Y moves that move a point off a Y pixel boundary. */ | |
353 #define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1 | |
354 | |
355 const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules | |
356 [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] = | |
357 { | |
358 { "-", 0, "", 0 }, | |
359 }; | |
360 | |
361 | |
362 #define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 | |
363 | |
364 const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions | |
365 [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = | |
366 { | |
367 { "-", 0, "", 0 }, | |
368 }; | |
369 | |
370 | |
371 /* Round moves that don't move a point to a Y pixel boundary. */ | |
372 #define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2 | |
373 | |
374 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules | |
375 [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] = | |
376 { | |
377 /* Droid font instructions don't snap Y to pixels */ | |
378 { "Droid Sans", 0, "Regular/Italic Class", 0 }, | |
379 { "Droid Sans Mono", 0, "", 0 }, | |
380 }; | |
381 | |
382 | |
383 #define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 | |
384 | |
385 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions | |
386 [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = | |
387 { | |
388 { "-", 0, "", 0 }, | |
389 }; | |
390 | |
391 | |
392 /* Allow a Direct_Move along X freedom vector if matched. */ | |
393 #define ALLOW_X_DMOVE_RULES_SIZE 1 | |
394 | |
395 const SPH_TweakRule ALLOW_X_DMOVE_Rules | |
396 [ALLOW_X_DMOVE_RULES_SIZE] = | |
397 { | |
398 /* Fixes vanishing diagonal in 4 */ | |
399 { "Verdana", 0, "Regular", '4' }, | |
400 }; | |
401 | |
402 | |
403 /* Return MS rasterizer version 35 if matched. */ | |
404 #define RASTERIZER_35_RULES_SIZE 8 | |
405 | |
406 const SPH_TweakRule RASTERIZER_35_Rules | |
407 [RASTERIZER_35_RULES_SIZE] = | |
408 { | |
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 }, | |
418 }; | |
419 | |
420 | |
421 /* Don't round to the subpixel grid. Round to pixel grid. */ | |
422 #define NORMAL_ROUND_RULES_SIZE 1 | |
423 | |
424 const SPH_TweakRule NORMAL_ROUND_Rules | |
425 [NORMAL_ROUND_RULES_SIZE] = | |
426 { | |
427 /* Fix serif thickness for certain ppems */ | |
428 /* Can probably be generalized somehow */ | |
429 { "Courier New", 0, "", 0 }, | |
430 }; | |
431 | |
432 | |
433 /* Skip IUP instructions if matched. */ | |
434 #define SKIP_IUP_RULES_SIZE 1 | |
435 | |
436 const SPH_TweakRule SKIP_IUP_Rules | |
437 [SKIP_IUP_RULES_SIZE] = | |
438 { | |
439 { "Arial", 13, "Regular", 'a' }, | |
440 }; | |
441 | |
442 | |
443 /* Skip MIAP Twilight hack if matched. */ | |
444 #define MIAP_HACK_RULES_SIZE 1 | |
445 | |
446 const SPH_TweakRule MIAP_HACK_Rules | |
447 [MIAP_HACK_RULES_SIZE] = | |
448 { | |
449 { "Geneva", 12, "", 0 }, | |
450 }; | |
451 | |
452 | |
453 /* Skip DELTAP instructions if matched. */ | |
454 #define ALWAYS_SKIP_DELTAP_RULES_SIZE 23 | |
455 | |
456 const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules | |
457 [ALWAYS_SKIP_DELTAP_RULES_SIZE] = | |
458 { | |
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' }, | |
486 }; | |
487 | |
488 | |
489 /* Always do DELTAP instructions if matched. */ | |
490 #define ALWAYS_DO_DELTAP_RULES_SIZE 1 | |
491 | |
492 const SPH_TweakRule ALWAYS_DO_DELTAP_Rules | |
493 [ALWAYS_DO_DELTAP_RULES_SIZE] = | |
494 { | |
495 { "-", 0, "", 0 }, | |
496 }; | |
497 | |
498 | |
499 /* Don't allow ALIGNRP after IUP. */ | |
500 #define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1 | |
501 | |
502 static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules | |
503 [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] = | |
504 { | |
505 /* Prevent creation of dents in outline */ | |
506 { "-", 0, "", 0 }, | |
507 }; | |
508 | |
509 | |
510 /* Don't allow DELTAP after IUP. */ | |
511 #define NO_DELTAP_AFTER_IUP_RULES_SIZE 1 | |
512 | |
513 static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules | |
514 [NO_DELTAP_AFTER_IUP_RULES_SIZE] = | |
515 { | |
516 { "-", 0, "", 0 }, | |
517 }; | |
518 | |
519 | |
520 /* Don't allow CALL after IUP. */ | |
521 #define NO_CALL_AFTER_IUP_RULES_SIZE 1 | |
522 | |
523 static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules | |
524 [NO_CALL_AFTER_IUP_RULES_SIZE] = | |
525 { | |
526 /* Prevent creation of dents in outline */ | |
527 { "-", 0, "", 0 }, | |
528 }; | |
529 | |
530 | |
531 /* De-embolden these glyphs slightly. */ | |
532 #define DEEMBOLDEN_RULES_SIZE 9 | |
533 | |
534 static const SPH_TweakRule DEEMBOLDEN_Rules | |
535 [DEEMBOLDEN_RULES_SIZE] = | |
536 { | |
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' }, | |
546 }; | |
547 | |
548 | |
549 /* Embolden these glyphs slightly. */ | |
550 #define EMBOLDEN_RULES_SIZE 2 | |
551 | |
552 static const SPH_TweakRule EMBOLDEN_Rules | |
553 [EMBOLDEN_RULES_SIZE] = | |
554 { | |
555 { "Courier New", 0, "Regular", 0 }, | |
556 { "Courier New", 0, "Italic", 0 }, | |
557 }; | |
558 | |
559 | |
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 | |
563 | |
564 static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules | |
565 [TIMES_NEW_ROMAN_HACK_RULES_SIZE] = | |
566 { | |
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' }, | |
579 }; | |
580 | |
581 | |
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 | |
585 | |
586 static const SPH_TweakRule COURIER_NEW_2_HACK_Rules | |
587 [COURIER_NEW_2_HACK_RULES_SIZE] = | |
588 { | |
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' }, | |
604 }; | |
605 | |
606 | |
607 #ifndef FORCE_NATURAL_WIDTHS | |
608 | |
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 | |
613 | |
614 static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules | |
615 [COMPATIBLE_WIDTHS_RULES_SIZE] = | |
616 { | |
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' }, | |
659 }; | |
660 | |
661 | |
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. */ | |
666 | |
667 #define X_SCALING_RULES_SIZE 50 | |
668 | |
669 static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] = | |
670 { | |
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 }, | |
723 }; | |
724 | |
725 #else | |
726 | |
727 #define COMPATIBLE_WIDTHS_RULES_SIZE 1 | |
728 | |
729 static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules | |
730 [COMPATIBLE_WIDTHS_RULES_SIZE] = | |
731 { | |
732 { "-", 0, "", 0 }, | |
733 }; | |
734 | |
735 | |
736 #define X_SCALING_RULES_SIZE 1 | |
737 | |
738 static const SPH_ScaleRule X_SCALING_Rules | |
739 [X_SCALING_RULES_SIZE] = | |
740 { | |
741 { "-", 0, "", 0, 1000 }, | |
742 }; | |
743 | |
744 #endif /* FORCE_NATURAL_WIDTHS */ | |
745 | |
746 | |
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 ) | |
750 { | |
751 FT_UInt i, j; | |
752 | |
753 | |
754 /* Does font name match rule family? */ | |
755 if ( strcmp( detected_font_name, rule_font_name ) == 0 ) | |
756 return TRUE; | |
757 | |
758 /* Is font name a wildcard ""? */ | |
759 if ( strcmp( rule_font_name, "" ) == 0 ) | |
760 return TRUE; | |
761 | |
762 /* Is font name contained in a class list? */ | |
763 for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ ) | |
764 { | |
765 if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) | |
766 { | |
767 for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) | |
768 { | |
769 if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) | |
770 continue; | |
771 if ( strcmp( FAMILY_CLASS_Rules[i].member[j], | |
772 detected_font_name ) == 0 ) | |
773 return TRUE; | |
774 } | |
775 } | |
776 } | |
777 | |
778 return FALSE; | |
779 } | |
780 | |
781 | |
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 ) | |
785 { | |
786 FT_UInt i, j; | |
787 | |
788 | |
789 /* Does font style match rule style? */ | |
790 if ( strcmp( detected_font_style, rule_font_style ) == 0 ) | |
791 return TRUE; | |
792 | |
793 /* Is font style a wildcard ""? */ | |
794 if ( strcmp( rule_font_style, "" ) == 0 ) | |
795 return TRUE; | |
796 | |
797 /* Is font style contained in a class list? */ | |
798 for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ ) | |
799 { | |
800 if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) | |
801 { | |
802 for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) | |
803 { | |
804 if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) | |
805 continue; | |
806 if ( strcmp( STYLE_CLASS_Rules[i].member[j], | |
807 detected_font_style ) == 0 ) | |
808 return TRUE; | |
809 } | |
810 } | |
811 } | |
812 | |
813 return FALSE; | |
814 } | |
815 | |
816 | |
817 FT_LOCAL_DEF( FT_Bool ) | |
818 sph_test_tweak( TT_Face face, | |
819 const FT_String* family, | |
820 FT_UInt ppem, | |
821 const FT_String* style, | |
822 FT_UInt glyph_index, | |
823 const SPH_TweakRule* rule, | |
824 FT_UInt num_rules ) | |
825 { | |
826 FT_UInt i; | |
827 | |
828 | |
829 /* rule checks may be able to be optimized further */ | |
830 for ( i = 0; i < num_rules; i++ ) | |
831 { | |
832 if ( family && | |
833 ( is_member_of_family_class ( family, rule[i].family ) ) ) | |
834 if ( rule[i].ppem == 0 || | |
835 rule[i].ppem == ppem ) | |
836 if ( style && | |
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 ) | |
841 return TRUE; | |
842 } | |
843 | |
844 return FALSE; | |
845 } | |
846 | |
847 | |
848 static FT_UInt | |
849 scale_test_tweak( TT_Face face, | |
850 const FT_String* family, | |
851 FT_UInt ppem, | |
852 const FT_String* style, | |
853 FT_UInt glyph_index, | |
854 const SPH_ScaleRule* rule, | |
855 FT_UInt num_rules ) | |
856 { | |
857 FT_UInt i; | |
858 | |
859 | |
860 /* rule checks may be able to be optimized further */ | |
861 for ( i = 0; i < num_rules; i++ ) | |
862 { | |
863 if ( family && | |
864 ( is_member_of_family_class ( family, rule[i].family ) ) ) | |
865 if ( rule[i].ppem == 0 || | |
866 rule[i].ppem == ppem ) | |
867 if ( style && | |
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; | |
873 } | |
874 | |
875 return 1000; | |
876 } | |
877 | |
878 | |
879 FT_LOCAL_DEF( FT_UInt ) | |
880 sph_test_tweak_x_scaling( TT_Face face, | |
881 const FT_String* family, | |
882 FT_UInt ppem, | |
883 const FT_String* style, | |
884 FT_UInt glyph_index ) | |
885 { | |
886 return scale_test_tweak( face, family, ppem, style, glyph_index, | |
887 X_SCALING_Rules, X_SCALING_RULES_SIZE ); | |
888 } | |
889 | |
890 | |
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; | |
895 | |
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; | |
900 | |
901 | |
902 FT_LOCAL_DEF( void ) | |
903 sph_set_tweaks( TT_Loader loader, | |
904 FT_UInt glyph_index ) | |
905 { | |
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; | |
910 | |
911 | |
912 /* don't apply rules if style isn't set */ | |
913 if ( !face->root.style_name ) | |
914 return; | |
915 | |
916 #ifdef SPH_DEBUG_MORE_VERBOSE | |
917 printf( "%s,%d,%s,%c=%d ", | |
918 family, ppem, style, glyph_index, glyph_index ); | |
919 #endif | |
920 | |
921 TWEAK_RULES( PIXEL_HINTING ); | |
922 | |
923 if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING ) | |
924 { | |
925 loader->exec->ignore_x_mode = FALSE; | |
926 return; | |
927 } | |
928 | |
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 ); | |
942 | |
943 TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES ); | |
944 TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES ); | |
945 | |
946 TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP ); | |
947 | |
948 TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES ); | |
949 TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES ); | |
950 | |
951 TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES ); | |
952 TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES ); | |
953 | |
954 if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) | |
955 { | |
956 if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 ) | |
957 { | |
958 loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; | |
959 loader->exec->size->cvt_ready = FALSE; | |
960 | |
961 tt_size_ready_bytecode( | |
962 loader->exec->size, | |
963 FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); | |
964 } | |
965 else | |
966 loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; | |
967 } | |
968 else | |
969 { | |
970 if ( loader->exec->rasterizer_version != | |
971 SPH_OPTION_SET_RASTERIZER_VERSION ) | |
972 { | |
973 loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; | |
974 loader->exec->size->cvt_ready = FALSE; | |
975 | |
976 tt_size_ready_bytecode( | |
977 loader->exec->size, | |
978 FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); | |
979 } | |
980 else | |
981 loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; | |
982 } | |
983 | |
984 if ( IS_HINTED( loader->load_flags ) ) | |
985 { | |
986 TWEAK_RULES( TIMES_NEW_ROMAN_HACK ); | |
987 TWEAK_RULES( COURIER_NEW_2_HACK ); | |
988 } | |
989 | |
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; | |
993 | |
994 | |
995 if ( IS_HINTED( loader->load_flags ) ) | |
996 { | |
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; | |
1000 } | |
1001 } | |
1002 | |
1003 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ | |
1004 | |
1005 /* ANSI C doesn't like empty source files */ | |
1006 typedef int _tt_subpix_dummy; | |
1007 | |
1008 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ | |
1009 | |
1010 | |
1011 /* END */ | |
OLD | NEW |