Werner Lemberg pushed to branch adjust at FreeType / FreeType
Commits:
-
546237e1
by Werner Lemberg at 2024-02-23T11:55:53+01:00
-
2a790a9f
by Ben Wanger at 2024-02-29T07:06:46+01:00
-
2cc58904
by Jordan Williams at 2024-03-04T12:46:19-06:00
-
660a7017
by Alexei Podtelezhnikov (Алексей Подтележников) at 2024-03-06T20:08:04+00:00
-
17545d4b
by Ben Wagner at 2024-03-08T17:47:43+01:00
-
f42ce255
by Ben Wanger at 2024-03-08T14:55:12-05:00
-
813e081e
by Craig White at 2024-04-14T14:00:00+02:00
-
ab648b2d
by Craig White at 2024-04-14T14:00:00+02:00
-
2d84675f
by Craig White at 2024-04-14T14:00:00+02:00
-
34c1acfc
by Craig White at 2024-04-14T14:00:00+02:00
-
48491c67
by Craig White at 2024-04-14T14:55:53+02:00
-
74d9a996
by Craig White at 2024-04-14T14:55:57+02:00
-
7724a854
by Werner Lemberg at 2024-04-14T14:55:58+02:00
17 changed files:
- CMakeLists.txt
- docs/CHANGES
- include/freetype/internal/ftobjs.h
- include/freetype/internal/fttrace.h
- meson.build
- + src/autofit/afadjust.c
- + src/autofit/afadjust.h
- src/autofit/aflatin.c
- src/autofit/aftypes.h
- src/autofit/autofit.c
- src/autofit/rules.mk
- src/base/ftobjs.c
- src/cff/cffobjs.c
- src/cid/cidparse.c
- src/sfnt/ttcolr.c
- src/truetype/ttgxvar.c
- src/truetype/ttobjs.c
Changes:
... | ... | @@ -110,7 +110,7 @@ |
110 | 110 | |
111 | 111 | # To minimize the number of cmake_policy() workarounds,
|
112 | 112 | # CMake >= 3 is requested.
|
113 | -cmake_minimum_required(VERSION 3.0)
|
|
113 | +cmake_minimum_required(VERSION 3.0...3.5)
|
|
114 | 114 | |
115 | 115 | if (NOT CMAKE_VERSION VERSION_LESS 3.3)
|
116 | 116 | # Allow symbol visibility settings also on static libraries. CMake < 3.3
|
... | ... | @@ -5,7 +5,25 @@ CHANGES BETWEEN 2.13.2 and 2.13.3 (202Y-Mmm-DD) |
5 | 5 | - Excessive stack allocation in the autohinter has been fixed.
|
6 | 6 | |
7 | 7 | |
8 | - II. MISCELLANEOUS
|
|
8 | + II. IMPORTANT CHANGES
|
|
9 | + |
|
10 | + - The auto-hinter got new abilities.
|
|
11 | + |
|
12 | + . It can now better separate accents from base characters at small
|
|
13 | + sizes by artificially moving accents up if necessary.
|
|
14 | + |
|
15 | + . Tilde characters get vertically stretched at small sizes so that
|
|
16 | + they don't degenerate to horizontal lines.
|
|
17 | + |
|
18 | + Both features use a database, which currently has entries for
|
|
19 | + Unicode characters lower than U+0180. FreeType needs to access or
|
|
20 | + construct a proper Unicode character map from a given font to make
|
|
21 | + this work.
|
|
22 | + |
|
23 | + This was Craig White's GSoC 2023 project.
|
|
24 | + |
|
25 | + |
|
26 | + III. MISCELLANEOUS
|
|
9 | 27 | |
10 | 28 | - The B/W rasterizer has received a major upkeep that resulted in
|
11 | 29 | large performance improvement. The rendering speed has increased
|
... | ... | @@ -275,6 +275,28 @@ FT_BEGIN_HEADER |
275 | 275 | FT_GlyphSlot slot,
|
276 | 276 | FT_Render_Mode mode );
|
277 | 277 | |
278 | + |
|
279 | + /**************************************************************************
|
|
280 | + *
|
|
281 | + * @Function:
|
|
282 | + * find_unicode_charmap
|
|
283 | + *
|
|
284 | + * @Description:
|
|
285 | + * This function finds a Unicode charmap, if there is one. And if there
|
|
286 | + * is more than one, it tries to favour the more extensive one, i.e., one
|
|
287 | + * that supports UCS-4 against those which are limited to the BMP (UCS-2
|
|
288 | + * encoding.)
|
|
289 | + *
|
|
290 | + * If a unicode charmap is found, `face->charmap` is set to it.
|
|
291 | + *
|
|
292 | + * This function is called from `open_face`, from `FT_Select_Charmap(...,
|
|
293 | + * FT_ENCODING_UNICODE)`, and also from `afadjust.c` in the 'autofit'
|
|
294 | + * module.
|
|
295 | + */
|
|
296 | + FT_BASE( FT_Error )
|
|
297 | + find_unicode_charmap( FT_Face face );
|
|
298 | + |
|
299 | + |
|
278 | 300 | #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
279 | 301 | |
280 | 302 | typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
|
... | ... | @@ -159,6 +159,7 @@ FT_TRACE_DEF( gxvprop ) |
159 | 159 | FT_TRACE_DEF( gxvtrak )
|
160 | 160 | |
161 | 161 | /* autofit components */
|
162 | +FT_TRACE_DEF( afadjust )
|
|
162 | 163 | FT_TRACE_DEF( afcjk )
|
163 | 164 | FT_TRACE_DEF( afglobal )
|
164 | 165 | FT_TRACE_DEF( afhints )
|
... | ... | @@ -316,8 +316,10 @@ else |
316 | 316 | endif
|
317 | 317 | |
318 | 318 | # BZip2 support
|
319 | -bzip2_dep = cc.find_library('bz2',
|
|
320 | - required: get_option('bzip2'))
|
|
319 | +bzip2_dep = dependency('bzip2', required: false)
|
|
320 | +if not bzip2_dep.found()
|
|
321 | + bzip2_dep = cc.find_library('bz2', has_headers: ['bzlib.h'], required: get_option('bzip2'))
|
|
322 | +endif
|
|
321 | 323 | |
322 | 324 | if bzip2_dep.found()
|
323 | 325 | ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2']
|
1 | +/****************************************************************************
|
|
2 | + *
|
|
3 | + * afadjust.c
|
|
4 | + *
|
|
5 | + * Auto-fitter routines to adjust components based on charcode (body).
|
|
6 | + *
|
|
7 | + * Copyright (C) 2023-2024 by
|
|
8 | + * David Turner, Robert Wilhelm, and Werner Lemberg.
|
|
9 | + *
|
|
10 | + * Written by Craig White <gerzytet@gmail.com>.
|
|
11 | + *
|
|
12 | + * This file is part of the FreeType project, and may only be used,
|
|
13 | + * modified, and distributed under the terms of the FreeType project
|
|
14 | + * license, LICENSE.TXT. By continuing to use, modify, or distribute
|
|
15 | + * this file you indicate that you have read the license and
|
|
16 | + * understand and accept it fully.
|
|
17 | + *
|
|
18 | + */
|
|
19 | + |
|
20 | +#include "afadjust.h"
|
|
21 | + |
|
22 | +#include <freetype/freetype.h>
|
|
23 | +#include <freetype/internal/ftobjs.h>
|
|
24 | +#include <freetype/internal/ftmemory.h>
|
|
25 | +#include <freetype/internal/ftdebug.h>
|
|
26 | + |
|
27 | +#define AF_ADJUSTMENT_DATABASE_LENGTH \
|
|
28 | + ( sizeof ( adjustment_database ) / \
|
|
29 | + sizeof ( adjustment_database[0] ) )
|
|
30 | + |
|
31 | +#undef FT_COMPONENT
|
|
32 | +#define FT_COMPONENT afadjust
|
|
33 | + |
|
34 | + |
|
35 | + /*
|
|
36 | + All entries in this list must be sorted by ascending Unicode code
|
|
37 | + points. The table entries are 3 numbers consisting of:
|
|
38 | + |
|
39 | + - Unicode code point.
|
|
40 | + - The vertical adjustment type. This should be one of the enum
|
|
41 | + constants in `AF_VerticalSeparationAdjustmentType`.
|
|
42 | + - Value 1 if the topmost contour is a tilde and should be prevented from
|
|
43 | + flattening, and 0 otherwise.
|
|
44 | + */
|
|
45 | + FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry )
|
|
46 | + adjustment_database[] =
|
|
47 | + {
|
|
48 | + { 0x21, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ! */
|
|
49 | + { 0x69, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* i */
|
|
50 | + { 0x6A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* j */
|
|
51 | + |
|
52 | + { 0xA1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ¡ */
|
|
53 | + { 0xBF, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ¿ */
|
|
54 | + |
|
55 | + { 0xC0, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* À */
|
|
56 | + { 0xC1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Á */
|
|
57 | + { 0xC2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Â */
|
|
58 | + { 0xC3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ã */
|
|
59 | + { 0xC8, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* È */
|
|
60 | + { 0xC9, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* É */
|
|
61 | + { 0xCA, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ê */
|
|
62 | + { 0xCC, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ì */
|
|
63 | + { 0xCD, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Í */
|
|
64 | + { 0xCE, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Î */
|
|
65 | + |
|
66 | + { 0xD1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ñ */
|
|
67 | + { 0xD2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ò */
|
|
68 | + { 0xD3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ó */
|
|
69 | + { 0xD4, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ô */
|
|
70 | + { 0xD5, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Õ */
|
|
71 | + { 0xD9, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ù */
|
|
72 | + { 0xDA, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ú */
|
|
73 | + { 0xDB, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Û */
|
|
74 | + { 0xDD, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ý */
|
|
75 | + |
|
76 | + { 0xE0, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* à */
|
|
77 | + { 0xE1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* á */
|
|
78 | + { 0xE2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* â */
|
|
79 | + { 0xE3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ã */
|
|
80 | + { 0xE8, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* è */
|
|
81 | + { 0xE9, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* é */
|
|
82 | + { 0xEA, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ê */
|
|
83 | + { 0xEC, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ì */
|
|
84 | + { 0xED, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* í */
|
|
85 | + { 0xEE, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* î */
|
|
86 | + |
|
87 | + { 0xF1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ñ */
|
|
88 | + { 0xF2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ò */
|
|
89 | + { 0xF3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ó */
|
|
90 | + { 0xF4, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ô */
|
|
91 | + { 0xF5, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* õ */
|
|
92 | + { 0xF9, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ù */
|
|
93 | + { 0xFA, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ú */
|
|
94 | + { 0xFB, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* û */
|
|
95 | + { 0xFD, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ý */
|
|
96 | + |
|
97 | + { 0x100, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ā */
|
|
98 | + { 0x101, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ā */
|
|
99 | + { 0x102, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ă */
|
|
100 | + { 0x103, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ă */
|
|
101 | + { 0x106, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ć */
|
|
102 | + { 0x107, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ć */
|
|
103 | + { 0x108, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĉ */
|
|
104 | + { 0x109, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĉ */
|
|
105 | + { 0x10A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ċ */
|
|
106 | + { 0x10B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ċ */
|
|
107 | + { 0x10C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Č */
|
|
108 | + { 0x10D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* č */
|
|
109 | + { 0x10E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ď */
|
|
110 | + |
|
111 | + { 0x112, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ē */
|
|
112 | + { 0x113, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ē */
|
|
113 | + { 0x114, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĕ */
|
|
114 | + { 0x115, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĕ */
|
|
115 | + { 0x116, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ė */
|
|
116 | + { 0x117, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ė */
|
|
117 | + { 0x11A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ě */
|
|
118 | + { 0x11B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ě */
|
|
119 | + { 0x11C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĝ */
|
|
120 | + { 0x11D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĝ */
|
|
121 | + { 0x11E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ğ */
|
|
122 | + { 0x11F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ğ */
|
|
123 | + |
|
124 | + { 0x120, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ġ */
|
|
125 | + { 0x121, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ġ */
|
|
126 | + { 0x123, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ģ */
|
|
127 | + { 0x124, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĥ */
|
|
128 | + { 0x125, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĥ */
|
|
129 | + { 0x128, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ĩ */
|
|
130 | + { 0x129, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ĩ */
|
|
131 | + { 0x12A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ī */
|
|
132 | + { 0x12B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ī */
|
|
133 | + { 0x12C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĭ */
|
|
134 | + { 0x12D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĭ */
|
|
135 | + { 0x12F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* į */
|
|
136 | + |
|
137 | + { 0x130, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* İ */
|
|
138 | + { 0x133, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ij */
|
|
139 | + { 0x134, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĵ */
|
|
140 | + { 0x135, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĵ */
|
|
141 | + { 0x139, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĺ */
|
|
142 | + { 0x13A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĺ */
|
|
143 | + |
|
144 | + { 0x143, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ń */
|
|
145 | + { 0x144, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ń */
|
|
146 | + { 0x147, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ň */
|
|
147 | + { 0x148, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ň */
|
|
148 | + { 0x14C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ō */
|
|
149 | + { 0x14D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ō */
|
|
150 | + { 0x14E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŏ */
|
|
151 | + { 0x14F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŏ */
|
|
152 | + |
|
153 | + { 0x154, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŕ */
|
|
154 | + { 0x155, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŕ */
|
|
155 | + { 0x158, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ř */
|
|
156 | + { 0x159, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ř */
|
|
157 | + { 0x15A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ś */
|
|
158 | + { 0x15B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ś */
|
|
159 | + { 0x15C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŝ */
|
|
160 | + { 0x15D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŝ */
|
|
161 | + |
|
162 | + { 0x160, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Š */
|
|
163 | + { 0x161, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* š */
|
|
164 | + { 0x164, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ť */
|
|
165 | + { 0x168, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ũ */
|
|
166 | + { 0x169, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ũ */
|
|
167 | + { 0x16A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ū */
|
|
168 | + { 0x16B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ū */
|
|
169 | + { 0x16C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŭ */
|
|
170 | + { 0x16D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŭ */
|
|
171 | + |
|
172 | + { 0x174, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŵ */
|
|
173 | + { 0x175, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŵ */
|
|
174 | + { 0x176, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŷ */
|
|
175 | + { 0x177, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŷ */
|
|
176 | + { 0x179, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ź */
|
|
177 | + { 0x17A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ź */
|
|
178 | + { 0x17B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ż */
|
|
179 | + { 0x17C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ż */
|
|
180 | + { 0x17D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ž */
|
|
181 | + { 0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 } /* ž */
|
|
182 | + };
|
|
183 | + |
|
184 | + |
|
185 | + /* Helper function: get the adjustment database entry for a codepoint. */
|
|
186 | + static const AF_AdjustmentDatabaseEntry*
|
|
187 | + af_adjustment_database_lookup( FT_UInt32 codepoint )
|
|
188 | + {
|
|
189 | + /* Binary search for database entry */
|
|
190 | + FT_Int low = 0;
|
|
191 | + FT_Int high = AF_ADJUSTMENT_DATABASE_LENGTH - 1;
|
|
192 | + |
|
193 | + |
|
194 | + while ( high >= low )
|
|
195 | + {
|
|
196 | + FT_Int mid = ( low + high ) / 2;
|
|
197 | + FT_UInt32 mid_codepoint = adjustment_database[mid].codepoint;
|
|
198 | + |
|
199 | + |
|
200 | + if ( mid_codepoint < codepoint )
|
|
201 | + low = mid + 1;
|
|
202 | + else if ( mid_codepoint > codepoint )
|
|
203 | + high = mid - 1;
|
|
204 | + else
|
|
205 | + return &adjustment_database[mid];
|
|
206 | + }
|
|
207 | + |
|
208 | + return NULL;
|
|
209 | + }
|
|
210 | + |
|
211 | + |
|
212 | + /* `qsort` compare function for reverse character map. */
|
|
213 | + FT_COMPARE_DEF( FT_Int )
|
|
214 | + af_reverse_character_map_entry_compare( const void *a,
|
|
215 | + const void *b )
|
|
216 | + {
|
|
217 | + const AF_ReverseMapEntry entry_a = *((const AF_ReverseMapEntry *)a);
|
|
218 | + const AF_ReverseMapEntry entry_b = *((const AF_ReverseMapEntry *)b);
|
|
219 | + |
|
220 | + |
|
221 | + return entry_a.glyph_index < entry_b.glyph_index
|
|
222 | + ? -1
|
|
223 | + : entry_a.glyph_index > entry_b.glyph_index
|
|
224 | + ? 1
|
|
225 | + : 0;
|
|
226 | + }
|
|
227 | + |
|
228 | + |
|
229 | + static FT_UInt32
|
|
230 | + af_reverse_character_map_lookup( AF_ReverseCharacterMap map,
|
|
231 | + FT_Int glyph_index )
|
|
232 | + {
|
|
233 | + FT_Int low, high;
|
|
234 | + FT_Long length;
|
|
235 | + |
|
236 | + |
|
237 | + if ( !map )
|
|
238 | + return 0;
|
|
239 | + |
|
240 | + length = map->length;
|
|
241 | + |
|
242 | + /* Binary search for reverse character map entry. */
|
|
243 | + low = 0;
|
|
244 | + high = length - 1;
|
|
245 | + |
|
246 | + while ( high >= low )
|
|
247 | + {
|
|
248 | + FT_Int mid = ( high + low ) / 2;
|
|
249 | + FT_Int mid_glyph_index = map->entries[mid].glyph_index;
|
|
250 | + |
|
251 | + |
|
252 | + if ( glyph_index < mid_glyph_index )
|
|
253 | + high = mid - 1;
|
|
254 | + else if ( glyph_index > mid_glyph_index )
|
|
255 | + low = mid + 1;
|
|
256 | + else
|
|
257 | + return map->entries[mid].codepoint;
|
|
258 | + }
|
|
259 | + |
|
260 | + return 0;
|
|
261 | + }
|
|
262 | + |
|
263 | + |
|
264 | + FT_LOCAL_DEF( AF_VerticalSeparationAdjustmentType )
|
|
265 | + af_lookup_vertical_separation_type( AF_ReverseCharacterMap map,
|
|
266 | + FT_Int glyph_index )
|
|
267 | + {
|
|
268 | + FT_UInt32 codepoint = af_reverse_character_map_lookup( map,
|
|
269 | + glyph_index );
|
|
270 | + |
|
271 | + const AF_AdjustmentDatabaseEntry *entry =
|
|
272 | + af_adjustment_database_lookup( codepoint );
|
|
273 | + |
|
274 | + |
|
275 | + if ( !entry )
|
|
276 | + return AF_VERTICAL_ADJUSTMENT_NONE;
|
|
277 | + |
|
278 | + return entry->vertical_separation_adjustment_type;
|
|
279 | + }
|
|
280 | + |
|
281 | + |
|
282 | + /* Return 1 if tilde correction should be applied to the topmost */
|
|
283 | + /* contour, else 0. */
|
|
284 | + FT_LOCAL_DEF( FT_Bool )
|
|
285 | + af_lookup_tilde_correction_type( AF_ReverseCharacterMap map,
|
|
286 | + FT_Int glyph_index )
|
|
287 | + {
|
|
288 | + FT_UInt32 codepoint = af_reverse_character_map_lookup( map,
|
|
289 | + glyph_index );
|
|
290 | + |
|
291 | + const AF_AdjustmentDatabaseEntry *entry =
|
|
292 | + af_adjustment_database_lookup( codepoint );
|
|
293 | + |
|
294 | + |
|
295 | + if ( !entry )
|
|
296 | + return 0;
|
|
297 | + |
|
298 | + return entry->apply_tilde;
|
|
299 | + }
|
|
300 | + |
|
301 | + |
|
302 | + /* Prepare to add one more entry to the reverse character map. */
|
|
303 | + /* This is a helper function for `af_reverse_character_map_new`. */
|
|
304 | + static FT_Error
|
|
305 | + af_reverse_character_map_expand( AF_ReverseCharacterMap map,
|
|
306 | + FT_Long *capacity,
|
|
307 | + FT_Memory memory )
|
|
308 | + {
|
|
309 | + FT_Error error;
|
|
310 | + |
|
311 | + |
|
312 | + if ( map->length < *capacity )
|
|
313 | + return FT_Err_Ok;
|
|
314 | + |
|
315 | + if ( map->length == *capacity )
|
|
316 | + {
|
|
317 | + FT_Long new_capacity = *capacity + *capacity / 2;
|
|
318 | + |
|
319 | + |
|
320 | + if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) )
|
|
321 | + return error;
|
|
322 | + |
|
323 | + *capacity = new_capacity;
|
|
324 | + }
|
|
325 | + |
|
326 | + return FT_Err_Ok;
|
|
327 | + }
|
|
328 | + |
|
329 | + |
|
330 | +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
|
|
331 | + |
|
332 | + /*
|
|
333 | + Recursive algorithm to find all glyphs that a code point could turn into
|
|
334 | + from the 'GSUB' table.
|
|
335 | + |
|
336 | + buffer: a buffer containing only the input code point
|
|
337 | + feature_tag_pool: the current list of features under consideration
|
|
338 | + current_features: the current list of features being applied
|
|
339 | + num_features: length of current_features
|
|
340 | + result: the set of glyphs that the input code point can map to
|
|
341 | + |
|
342 | + The algorithm works by running the `hb_ot_shape_glyphs_closure` function
|
|
343 | + on different lists of features to check which features map the glyph onto
|
|
344 | + something different. This function returns the result of transforming a
|
|
345 | + glyph using a list of features as well as all intermediate forms if the
|
|
346 | + glyph was transformed multiple times.
|
|
347 | + |
|
348 | + With no features enabled, `hb_ot_shape_glyphs_closure` only returns the
|
|
349 | + glyph given by the cmap. This character is the first to be placed into
|
|
350 | + the result set.
|
|
351 | + |
|
352 | + Next, the algorithm tests the same lookup enabling one feature at a time
|
|
353 | + and check whether any of those features change the result.
|
|
354 | + |
|
355 | + If any new glyph variants are found this way, they are added to the
|
|
356 | + result set and the algorithm recurses, trying that feature in combination
|
|
357 | + with every other feature to look for further glyph variants.
|
|
358 | + |
|
359 | + Example:
|
|
360 | + |
|
361 | + suppose we have the following features in the GSUB table:
|
|
362 | + |
|
363 | + f1: a -> b
|
|
364 | + f2: b -> c
|
|
365 | + f3: d -> e
|
|
366 | + |
|
367 | + The algorithm takes the following steps to find all variants of 'a'.
|
|
368 | + |
|
369 | + - Add 'a' to the result.
|
|
370 | + - Look up with feature list {f1}, yielding {a, b}.
|
|
371 | + => Add 'b' to the result list, recurse.
|
|
372 | + - Look up with feature list {f1, f2}, yielding {a, b, c}.
|
|
373 | + => Add 'c' to the result list, recurse.
|
|
374 | + - Look up with feature list {f1, f2, f3}, yielding {a, b, c}.
|
|
375 | + => No new glyphs.
|
|
376 | + - Look up with feature list {f1, f3}, yielding {a, b}.
|
|
377 | + => No new glyphs.
|
|
378 | + - Look up with feature list {f2}, yielding {a}.
|
|
379 | + => No new glyphs.
|
|
380 | + - Look up with feature list {f3}, yielding {a}.
|
|
381 | + => No new glyphs.
|
|
382 | + */
|
|
383 | + static FT_Error
|
|
384 | + af_all_glyph_variants_helper( hb_font_t *font,
|
|
385 | + hb_buffer_t *buffer,
|
|
386 | + hb_set_t *feature_tag_pool,
|
|
387 | + hb_feature_t *current_features,
|
|
388 | + FT_UInt32 num_features,
|
|
389 | + hb_set_t* result )
|
|
390 | + {
|
|
391 | + FT_Error error;
|
|
392 | + |
|
393 | + hb_set_t *baseline_glyphs = NULL;
|
|
394 | + hb_set_t *new_glyphs = NULL;
|
|
395 | + |
|
396 | + hb_tag_t feature_tag;
|
|
397 | + |
|
398 | + |
|
399 | + /* Get the list of glyphs that are created by only transforming, */
|
|
400 | + /* based on the features in `current_features`. */
|
|
401 | + baseline_glyphs = hb_set_create();
|
|
402 | + if ( !hb_set_allocation_successful( baseline_glyphs ) )
|
|
403 | + {
|
|
404 | + error = FT_Err_Out_Of_Memory;
|
|
405 | + goto Exit;
|
|
406 | + }
|
|
407 | + |
|
408 | + hb_ot_shape_glyphs_closure( font,
|
|
409 | + buffer,
|
|
410 | + current_features,
|
|
411 | + num_features,
|
|
412 | + baseline_glyphs );
|
|
413 | + if ( !hb_set_allocation_successful( baseline_glyphs ) )
|
|
414 | + {
|
|
415 | + error = FT_Err_Out_Of_Memory;
|
|
416 | + goto Exit;
|
|
417 | + }
|
|
418 | + |
|
419 | + /* Add these baseline glyphs to the result. The baseline glyph set */
|
|
420 | + /* contains at least the glyph specified by the cmap. */
|
|
421 | + hb_set_union( result, baseline_glyphs );
|
|
422 | + if ( !hb_set_allocation_successful( result ) )
|
|
423 | + {
|
|
424 | + error = FT_Err_Out_Of_Memory;
|
|
425 | + goto Exit;
|
|
426 | + }
|
|
427 | + |
|
428 | + if ( !hb_set_get_population( feature_tag_pool ) )
|
|
429 | + {
|
|
430 | + error = FT_Err_Out_Of_Memory;
|
|
431 | + goto Exit;
|
|
432 | + }
|
|
433 | + |
|
434 | + /* Prepare for adding different features to `current_features` to */
|
|
435 | + /* check whether any of them have an effect of the glyphs we get from */
|
|
436 | + /* `hb_ot_shape_glyphs_closure`. */
|
|
437 | + current_features[num_features].start = HB_FEATURE_GLOBAL_START;
|
|
438 | + current_features[num_features].end = HB_FEATURE_GLOBAL_END;
|
|
439 | + current_features[num_features].value = 1; /* enable the feature */
|
|
440 | + |
|
441 | + /*
|
|
442 | + Quote from the HarfBuzz documentation about the `value` attribute:
|
|
443 | + |
|
444 | + 0 disables the feature, non-zero (usually 1) enables the feature.
|
|
445 | + For features implemented as lookup type 3 (like 'salt') the value is
|
|
446 | + a one-based index into the alternates. This algorithm does not
|
|
447 | + handle these lookup type 3 cases fully.
|
|
448 | + */
|
|
449 | + |
|
450 | + new_glyphs = hb_set_create();
|
|
451 | + if ( !hb_set_allocation_successful( new_glyphs ) )
|
|
452 | + {
|
|
453 | + error = FT_Err_Out_Of_Memory;
|
|
454 | + goto Exit;
|
|
455 | + }
|
|
456 | + |
|
457 | + feature_tag = HB_SET_VALUE_INVALID;
|
|
458 | + |
|
459 | + while ( hb_set_next( feature_tag_pool, &feature_tag ) )
|
|
460 | + {
|
|
461 | + hb_set_clear( new_glyphs );
|
|
462 | + |
|
463 | + current_features[num_features].tag = feature_tag;
|
|
464 | + |
|
465 | + hb_ot_shape_glyphs_closure ( font,
|
|
466 | + buffer,
|
|
467 | + current_features,
|
|
468 | + num_features + 1,
|
|
469 | + new_glyphs );
|
|
470 | + if ( !hb_set_allocation_successful( new_glyphs ) )
|
|
471 | + {
|
|
472 | + error = FT_Err_Out_Of_Memory;
|
|
473 | + goto Exit;
|
|
474 | + }
|
|
475 | + |
|
476 | + hb_set_subtract( new_glyphs, result );
|
|
477 | + |
|
478 | + /* `new_glyphs` now contains all glyphs that appeared in the result */
|
|
479 | + /* of `hb_ot_shape_glyphs_closure` that haven't already been */
|
|
480 | + /* accounted for in the result. If this contains any glyphs, we */
|
|
481 | + /* also need to try this feature in combination with other features */
|
|
482 | + /* by recursing. */
|
|
483 | + if ( hb_set_get_population( new_glyphs ) != 0 )
|
|
484 | + {
|
|
485 | + /* Remove this feature from the feature pool temporarily so that */
|
|
486 | + /* a later recursion won't try it. */
|
|
487 | + hb_set_del( feature_tag_pool, feature_tag );
|
|
488 | + |
|
489 | + error = af_all_glyph_variants_helper( font,
|
|
490 | + buffer,
|
|
491 | + feature_tag_pool,
|
|
492 | + current_features,
|
|
493 | + num_features + 1,
|
|
494 | + result );
|
|
495 | + if ( error )
|
|
496 | + goto Exit;
|
|
497 | + |
|
498 | + /* Add back the feature we removed. */
|
|
499 | + hb_set_add( feature_tag_pool, feature_tag );
|
|
500 | + if ( !hb_set_allocation_successful( feature_tag_pool ) )
|
|
501 | + return FT_Err_Out_Of_Memory;
|
|
502 | + }
|
|
503 | + }
|
|
504 | + |
|
505 | + Exit:
|
|
506 | + hb_set_destroy( baseline_glyphs );
|
|
507 | + hb_set_destroy( new_glyphs );
|
|
508 | + return FT_Err_Ok;
|
|
509 | + }
|
|
510 | + |
|
511 | + |
|
512 | + static FT_Error
|
|
513 | + af_all_glyph_variants( FT_Face face,
|
|
514 | + hb_font_t *hb_font,
|
|
515 | + FT_UInt32 codepoint,
|
|
516 | + hb_set_t* result )
|
|
517 | + {
|
|
518 | + FT_Error error;
|
|
519 | + |
|
520 | + FT_Memory memory = face->memory;
|
|
521 | + hb_face_t *hb_face = hb_font_get_face( hb_font );
|
|
522 | + |
|
523 | + FT_Bool feature_list_done;
|
|
524 | + unsigned int start_offset;
|
|
525 | + |
|
526 | + /* The set of all feature tags in the font. */
|
|
527 | + hb_set_t *feature_tags = hb_set_create();
|
|
528 | + hb_set_t *type_3_lookup_indices = hb_set_create();
|
|
529 | + hb_buffer_t *codepoint_buffer = hb_buffer_create();
|
|
530 | + hb_codepoint_t *type_3_alternate_glyphs_buffer;
|
|
531 | + |
|
532 | + hb_feature_t *feature_buffer;
|
|
533 | + |
|
534 | + /* List of features containing type 3 lookups. */
|
|
535 | + hb_tag_t feature_list[] =
|
|
536 | + {
|
|
537 | + HB_TAG( 's', 'a', 'l', 't' ),
|
|
538 | + HB_TAG( 's', 'w', 's', 'h' ),
|
|
539 | + HB_TAG( 'n', 'a', 'l', 't' ),
|
|
540 | + HB_TAG_NONE
|
|
541 | + };
|
|
542 | + |
|
543 | + hb_codepoint_t lookup_index;
|
|
544 | + FT_UInt base_glyph_index;
|
|
545 | + |
|
546 | + |
|
547 | + if ( !hb_set_allocation_successful( feature_tags ) ||
|
|
548 | + !hb_buffer_allocation_successful( codepoint_buffer ) ||
|
|
549 | + !hb_set_allocation_successful ( type_3_lookup_indices ) )
|
|
550 | + {
|
|
551 | + error = FT_Err_Out_Of_Memory;
|
|
552 | + goto Exit;
|
|
553 | + }
|
|
554 | + |
|
555 | + /* Populate `feature_tags` using the output of */
|
|
556 | + /* `hb_ot_layout_table_get_feature_tags`. */
|
|
557 | + feature_list_done = 0;
|
|
558 | + start_offset = 0;
|
|
559 | + |
|
560 | + while ( !feature_list_done )
|
|
561 | + {
|
|
562 | + unsigned int feature_count = 20;
|
|
563 | + hb_tag_t tags[20];
|
|
564 | + |
|
565 | + unsigned int i;
|
|
566 | + |
|
567 | + |
|
568 | + hb_ot_layout_table_get_feature_tags( hb_face,
|
|
569 | + HB_OT_TAG_GSUB,
|
|
570 | + start_offset,
|
|
571 | + &feature_count,
|
|
572 | + tags );
|
|
573 | + start_offset += 20;
|
|
574 | + if ( feature_count < 20 )
|
|
575 | + feature_list_done = 1;
|
|
576 | + |
|
577 | + for ( i = 0; i < feature_count; i++ )
|
|
578 | + hb_set_add( feature_tags, tags[i] );
|
|
579 | + |
|
580 | + if ( !hb_set_allocation_successful( feature_tags ) )
|
|
581 | + {
|
|
582 | + error = FT_Err_Out_Of_Memory;
|
|
583 | + goto Exit;
|
|
584 | + }
|
|
585 | + }
|
|
586 | + |
|
587 | + /* Make a buffer only consisting of the given code point. */
|
|
588 | + if ( !hb_buffer_pre_allocate( codepoint_buffer, 1 ) )
|
|
589 | + {
|
|
590 | + error = FT_Err_Out_Of_Memory;
|
|
591 | + goto Exit;
|
|
592 | + }
|
|
593 | + hb_buffer_set_direction( codepoint_buffer, HB_DIRECTION_LTR );
|
|
594 | + hb_buffer_add( codepoint_buffer, codepoint, 0 );
|
|
595 | + |
|
596 | + /* The array of features that is used by the recursive part has at */
|
|
597 | + /* most as many entries as there are features, so make the length */
|
|
598 | + /* equal to the length of `feature_tags`. */
|
|
599 | + if ( ( error = FT_NEW_ARRAY( feature_buffer,
|
|
600 | + hb_set_get_population( feature_tags ) ) ) )
|
|
601 | + goto Exit;
|
|
602 | + |
|
603 | + error = af_all_glyph_variants_helper( hb_font,
|
|
604 | + codepoint_buffer,
|
|
605 | + feature_tags,
|
|
606 | + feature_buffer,
|
|
607 | + 0,
|
|
608 | + result );
|
|
609 | + if ( error )
|
|
610 | + goto Exit;
|
|
611 | + |
|
612 | + /* Add the alternative glyph forms that come from features using
|
|
613 | + type 3 lookups.
|
|
614 | + |
|
615 | + This file from gtk was very useful in figuring out my approach:
|
|
616 | + |
|
617 | + https://gitlab.gnome.org/GNOME/gtk/-/blob/40f20fee3d8468749dfb233a6f95921c765c1163/gtk/gtkfontchooserwidget.c#L2100
|
|
618 | + */
|
|
619 | + hb_ot_layout_collect_lookups( hb_face,
|
|
620 | + HB_OT_TAG_GSUB,
|
|
621 | + NULL,
|
|
622 | + NULL,
|
|
623 | + feature_list,
|
|
624 | + type_3_lookup_indices );
|
|
625 | + if ( !hb_set_allocation_successful( type_3_lookup_indices ) )
|
|
626 | + {
|
|
627 | + error = FT_Err_Out_Of_Memory;
|
|
628 | + goto Exit;
|
|
629 | + }
|
|
630 | + |
|
631 | +#define MAX_ALTERNATES 100 /* ad-hoc value */
|
|
632 | + |
|
633 | + if ( ( error = FT_NEW_ARRAY( type_3_alternate_glyphs_buffer,
|
|
634 | + MAX_ALTERNATES ) ) )
|
|
635 | + goto Exit;
|
|
636 | + |
|
637 | + lookup_index = HB_SET_VALUE_INVALID;
|
|
638 | + base_glyph_index = FT_Get_Char_Index( face, codepoint );
|
|
639 | + |
|
640 | + if ( base_glyph_index )
|
|
641 | + {
|
|
642 | + while ( hb_set_next( type_3_lookup_indices, &lookup_index ) )
|
|
643 | + {
|
|
644 | + unsigned alternate_count = MAX_ALTERNATES;
|
|
645 | + unsigned i;
|
|
646 | + |
|
647 | + |
|
648 | + hb_ot_layout_lookup_get_glyph_alternates(
|
|
649 | + hb_face,
|
|
650 | + lookup_index,
|
|
651 | + base_glyph_index,
|
|
652 | + 0,
|
|
653 | + &alternate_count,
|
|
654 | + type_3_alternate_glyphs_buffer );
|
|
655 | + |
|
656 | + for ( i = 0; i < alternate_count; i++ )
|
|
657 | + hb_set_add( result, type_3_alternate_glyphs_buffer[i] );
|
|
658 | + }
|
|
659 | + }
|
|
660 | + |
|
661 | + Exit:
|
|
662 | + hb_set_destroy( feature_tags );
|
|
663 | + hb_buffer_destroy( codepoint_buffer );
|
|
664 | + FT_FREE( feature_buffer );
|
|
665 | + FT_FREE( type_3_alternate_glyphs_buffer );
|
|
666 | + |
|
667 | + return error;
|
|
668 | + }
|
|
669 | + |
|
670 | +#endif /*FT_CONFIG_OPTION_USE_HARFBUZZ*/
|
|
671 | + |
|
672 | + |
|
673 | + FT_LOCAL_DEF( FT_Error )
|
|
674 | + af_reverse_character_map_new( AF_ReverseCharacterMap *map,
|
|
675 | + AF_FaceGlobals globals )
|
|
676 | + {
|
|
677 | + FT_Error error;
|
|
678 | + |
|
679 | + FT_Face face = globals->face;
|
|
680 | + FT_Memory memory = face->memory;
|
|
681 | + |
|
682 | + FT_CharMap old_charmap;
|
|
683 | + |
|
684 | + FT_Long capacity;
|
|
685 | + |
|
686 | + |
|
687 | + /* Search for a unicode charmap. */
|
|
688 | + /* If there isn't one, create a blank map. */
|
|
689 | + |
|
690 | + FT_TRACE4(( "af_reverse_character_map_new:"
|
|
691 | + " building reverse character map\n" ));
|
|
692 | + |
|
693 | + /* Back up `face->charmap` because `find_unicode_charmap` sets it. */
|
|
694 | + old_charmap = face->charmap;
|
|
695 | + |
|
696 | + if ( ( error = find_unicode_charmap( face ) ) )
|
|
697 | + goto Exit;
|
|
698 | + |
|
699 | + *map = NULL;
|
|
700 | + if ( FT_NEW( *map ) )
|
|
701 | + goto Exit;
|
|
702 | + |
|
703 | + /* Start with a capacity of 10 entries. */
|
|
704 | + capacity = 10;
|
|
705 | + ( *map )->length = 0;
|
|
706 | + |
|
707 | + if ( FT_NEW_ARRAY( ( *map )->entries, capacity ) )
|
|
708 | + goto Exit;
|
|
709 | + |
|
710 | +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
|
|
711 | + |
|
712 | + {
|
|
713 | + hb_font_t *hb_font = globals->hb_font;
|
|
714 | + hb_set_t *result_set = hb_set_create();
|
|
715 | + |
|
716 | + FT_ULong i;
|
|
717 | + |
|
718 | + |
|
719 | + if ( !hb_set_allocation_successful( result_set ) )
|
|
720 | + {
|
|
721 | + error = FT_Err_Out_Of_Memory;
|
|
722 | + goto harfbuzz_path_Exit;
|
|
723 | + }
|
|
724 | + |
|
725 | + /* Find all glyph variants of the code points, then make an entry */
|
|
726 | + /* from the glyph to the code point for each one. */
|
|
727 | + for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
|
|
728 | + {
|
|
729 | + FT_UInt32 codepoint = adjustment_database[i].codepoint;
|
|
730 | + |
|
731 | + hb_codepoint_t glyph;
|
|
732 | + |
|
733 | + |
|
734 | + error = af_all_glyph_variants( face,
|
|
735 | + hb_font,
|
|
736 | + codepoint,
|
|
737 | + result_set );
|
|
738 | + if ( error )
|
|
739 | + goto harfbuzz_path_Exit;
|
|
740 | + |
|
741 | + glyph = HB_SET_VALUE_INVALID;
|
|
742 | + |
|
743 | + while ( hb_set_next( result_set, &glyph ) )
|
|
744 | + {
|
|
745 | + FT_Long insert_point;
|
|
746 | + |
|
747 | + |
|
748 | + error = af_reverse_character_map_expand( *map, &capacity, memory );
|
|
749 | + if ( error )
|
|
750 | + goto harfbuzz_path_Exit;
|
|
751 | + |
|
752 | + insert_point = ( *map )->length;
|
|
753 | + |
|
754 | + ( *map )->length++;
|
|
755 | + ( *map )->entries[insert_point].glyph_index = glyph;
|
|
756 | + ( *map )->entries[insert_point].codepoint = codepoint;
|
|
757 | + }
|
|
758 | + |
|
759 | + hb_set_clear( result_set );
|
|
760 | + }
|
|
761 | + |
|
762 | + harfbuzz_path_Exit:
|
|
763 | + hb_set_destroy( result_set );
|
|
764 | + if ( error )
|
|
765 | + goto Exit;
|
|
766 | + }
|
|
767 | + |
|
768 | +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
|
|
769 | + |
|
770 | + {
|
|
771 | + FT_UInt i;
|
|
772 | +#ifdef FT_DEBUG_LEVEL_TRACE
|
|
773 | + int failed_lookups = 0;
|
|
774 | +#endif
|
|
775 | + |
|
776 | + |
|
777 | + for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
|
|
778 | + {
|
|
779 | + FT_UInt32 codepoint = adjustment_database[i].codepoint;
|
|
780 | + FT_Int glyph = FT_Get_Char_Index( face, codepoint );
|
|
781 | + |
|
782 | + |
|
783 | + if ( glyph == 0 )
|
|
784 | + {
|
|
785 | +#ifdef FT_DEBUG_LEVEL_TRACE
|
|
786 | + failed_lookups++;
|
|
787 | +#endif
|
|
788 | + continue;
|
|
789 | + }
|
|
790 | + |
|
791 | + error = af_reverse_character_map_expand( *map, &capacity, memory );
|
|
792 | + if ( error )
|
|
793 | + goto Exit;
|
|
794 | + |
|
795 | + ( *map )->length++;
|
|
796 | + ( *map )->entries[i].glyph_index = glyph;
|
|
797 | + ( *map )->entries[i].codepoint = codepoint;
|
|
798 | + }
|
|
799 | + }
|
|
800 | + |
|
801 | +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
|
|
802 | + |
|
803 | + ft_qsort( ( *map )->entries,
|
|
804 | + ( *map )->length,
|
|
805 | + sizeof ( AF_ReverseMapEntry ),
|
|
806 | + af_reverse_character_map_entry_compare );
|
|
807 | + |
|
808 | + FT_TRACE4(( " reverse character map built successfully"
|
|
809 | + " with %ld entries\n", (*map)->length ));
|
|
810 | + |
|
811 | + Exit:
|
|
812 | + face->charmap = old_charmap;
|
|
813 | + |
|
814 | + if ( error )
|
|
815 | + {
|
|
816 | + FT_TRACE4(( " error while building reverse character map."
|
|
817 | + " Using blank map.\n" ));
|
|
818 | + |
|
819 | + if ( *map )
|
|
820 | + FT_FREE( ( *map )->entries );
|
|
821 | + |
|
822 | + FT_FREE( *map );
|
|
823 | + *map = NULL;
|
|
824 | + return error;
|
|
825 | + }
|
|
826 | + |
|
827 | + return FT_Err_Ok;
|
|
828 | + }
|
|
829 | + |
|
830 | + |
|
831 | + FT_LOCAL_DEF( FT_Error )
|
|
832 | + af_reverse_character_map_done( AF_ReverseCharacterMap map,
|
|
833 | + FT_Memory memory )
|
|
834 | + {
|
|
835 | + if ( map )
|
|
836 | + FT_FREE( map->entries );
|
|
837 | + FT_FREE( map );
|
|
838 | + |
|
839 | + return FT_Err_Ok;
|
|
840 | + }
|
|
841 | + |
|
842 | + |
|
843 | +/* END */ |
1 | +/****************************************************************************
|
|
2 | + *
|
|
3 | + * afadjust.h
|
|
4 | + *
|
|
5 | + * Auto-fitter routines to adjust components based on charcode (header).
|
|
6 | + *
|
|
7 | + * Copyright (C) 2023-2024 by
|
|
8 | + * David Turner, Robert Wilhelm, and Werner Lemberg.
|
|
9 | + *
|
|
10 | + * Written by Craig White <gerzytet@gmail.com>.
|
|
11 | + *
|
|
12 | + * This file is part of the FreeType project, and may only be used,
|
|
13 | + * modified, and distributed under the terms of the FreeType project
|
|
14 | + * license, LICENSE.TXT. By continuing to use, modify, or distribute
|
|
15 | + * this file you indicate that you have read the license and
|
|
16 | + * understand and accept it fully.
|
|
17 | + *
|
|
18 | + */
|
|
19 | + |
|
20 | + |
|
21 | +#ifndef AFADJUST_H_
|
|
22 | +#define AFADJUST_H_
|
|
23 | + |
|
24 | +#include <freetype/fttypes.h>
|
|
25 | + |
|
26 | +#include "afglobal.h"
|
|
27 | +#include "aftypes.h"
|
|
28 | + |
|
29 | + |
|
30 | +FT_BEGIN_HEADER
|
|
31 | + |
|
32 | + |
|
33 | + /* The type of adjustment that should be done to prevent cases where */
|
|
34 | + /* two parts of a character stacked vertically merge, even though they */
|
|
35 | + /* should be separate. */
|
|
36 | + typedef enum AF_VerticalSeparationAdjustmentType_
|
|
37 | + {
|
|
38 | + /* This means that the hinter should find the topmost contour and push */
|
|
39 | + /* it up until its lowest point is one pixel above the highest point */
|
|
40 | + /* not part of that contour. */
|
|
41 | + AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP,
|
|
42 | + |
|
43 | + /* This is the opposite direction. The hinter should find the */
|
|
44 | + /* bottommost contour and push it down until there is a one-pixel gap. */
|
|
45 | + AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN,
|
|
46 | + |
|
47 | + AF_VERTICAL_ADJUSTMENT_NONE
|
|
48 | + |
|
49 | + } AF_VerticalSeparationAdjustmentType;
|
|
50 | + |
|
51 | + |
|
52 | + typedef struct AF_AdjustmentDatabaseEntry_
|
|
53 | + {
|
|
54 | + FT_UInt32 codepoint;
|
|
55 | + AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type;
|
|
56 | + FT_Bool apply_tilde;
|
|
57 | + |
|
58 | + } AF_AdjustmentDatabaseEntry;
|
|
59 | + |
|
60 | + |
|
61 | + FT_LOCAL( AF_VerticalSeparationAdjustmentType )
|
|
62 | + af_lookup_vertical_separation_type( AF_ReverseCharacterMap map,
|
|
63 | + FT_Int glyph_index );
|
|
64 | + |
|
65 | + FT_LOCAL( FT_Bool )
|
|
66 | + af_lookup_tilde_correction_type( AF_ReverseCharacterMap map,
|
|
67 | + FT_Int glyph_index );
|
|
68 | + |
|
69 | + /* Allocate and populate the reverse character map, */
|
|
70 | + /* using the character map within the face. */
|
|
71 | + FT_LOCAL( FT_Error )
|
|
72 | + af_reverse_character_map_new( AF_ReverseCharacterMap *map,
|
|
73 | + AF_FaceGlobals globals );
|
|
74 | + |
|
75 | + /* Free the reverse character map. */
|
|
76 | + FT_LOCAL( FT_Error )
|
|
77 | + af_reverse_character_map_done( AF_ReverseCharacterMap map,
|
|
78 | + FT_Memory memory );
|
|
79 | + |
|
80 | + |
|
81 | +FT_END_HEADER
|
|
82 | + |
|
83 | +#endif /* AFADJUST_H_ */
|
|
84 | + |
|
85 | + |
|
86 | +/* END */ |
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | #include "afglobal.h"
|
23 | 23 | #include "aflatin.h"
|
24 | 24 | #include "aferrors.h"
|
25 | +#include "afadjust.h"
|
|
25 | 26 | |
26 | 27 | |
27 | 28 | /**************************************************************************
|
... | ... | @@ -1155,6 +1156,9 @@ |
1155 | 1156 | af_latin_metrics_check_digits( metrics, face );
|
1156 | 1157 | }
|
1157 | 1158 | |
1159 | + af_reverse_character_map_new( &metrics->root.reverse_charmap,
|
|
1160 | + metrics->root.globals );
|
|
1161 | + |
|
1158 | 1162 | Exit:
|
1159 | 1163 | face->charmap = oldmap;
|
1160 | 1164 | return error;
|
... | ... | @@ -1485,6 +1489,17 @@ |
1485 | 1489 | }
|
1486 | 1490 | |
1487 | 1491 | |
1492 | + FT_CALLBACK_DEF( void )
|
|
1493 | + af_latin_metrics_done( AF_StyleMetrics metrics_ )
|
|
1494 | + {
|
|
1495 | + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
|
|
1496 | + |
|
1497 | + |
|
1498 | + af_reverse_character_map_done( metrics->root.reverse_charmap,
|
|
1499 | + metrics->root.globals->face->memory );
|
|
1500 | + }
|
|
1501 | + |
|
1502 | + |
|
1488 | 1503 | /* Scale global values in both directions. */
|
1489 | 1504 | |
1490 | 1505 | FT_LOCAL_DEF( void )
|
... | ... | @@ -2738,6 +2753,601 @@ |
2738 | 2753 | }
|
2739 | 2754 | |
2740 | 2755 | |
2756 | +#undef FT_COMPONENT
|
|
2757 | +#define FT_COMPONENT afadjust
|
|
2758 | + |
|
2759 | + |
|
2760 | + static void
|
|
2761 | + af_move_contour_vertically( AF_Point contour,
|
|
2762 | + FT_Int movement )
|
|
2763 | + {
|
|
2764 | + AF_Point point = contour;
|
|
2765 | + AF_Point first_point = point;
|
|
2766 | + |
|
2767 | + |
|
2768 | + if ( point )
|
|
2769 | + {
|
|
2770 | + do
|
|
2771 | + {
|
|
2772 | + point->y += movement;
|
|
2773 | + point = point->next;
|
|
2774 | + |
|
2775 | + } while ( point != first_point );
|
|
2776 | + }
|
|
2777 | + }
|
|
2778 | + |
|
2779 | + |
|
2780 | + static FT_Int
|
|
2781 | + af_find_highest_contour( AF_GlyphHints hints )
|
|
2782 | + {
|
|
2783 | + FT_Int highest_contour = -1;
|
|
2784 | + |
|
2785 | + FT_Pos highest_min_y = 0;
|
|
2786 | + FT_Pos current_min_y = 0;
|
|
2787 | + |
|
2788 | + FT_Int contour;
|
|
2789 | + |
|
2790 | + |
|
2791 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
2792 | + {
|
|
2793 | + AF_Point point = hints->contours[contour];
|
|
2794 | + AF_Point first_point = point;
|
|
2795 | + |
|
2796 | + |
|
2797 | + if ( !point )
|
|
2798 | + continue;
|
|
2799 | + |
|
2800 | + current_min_y = point->y;
|
|
2801 | + |
|
2802 | + do
|
|
2803 | + {
|
|
2804 | + if ( point->y < current_min_y )
|
|
2805 | + current_min_y = point->y;
|
|
2806 | + point = point->next;
|
|
2807 | + |
|
2808 | + } while ( point != first_point );
|
|
2809 | + |
|
2810 | + if ( highest_contour == -1 || current_min_y > highest_min_y )
|
|
2811 | + {
|
|
2812 | + highest_min_y = current_min_y;
|
|
2813 | + highest_contour = contour;
|
|
2814 | + }
|
|
2815 | + }
|
|
2816 | + |
|
2817 | + return highest_contour;
|
|
2818 | + }
|
|
2819 | + |
|
2820 | + |
|
2821 | + static void
|
|
2822 | + af_remove_segments_containing_point( AF_GlyphHints hints,
|
|
2823 | + AF_Point point )
|
|
2824 | + {
|
|
2825 | + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
|
|
2826 | + AF_Segment segments = axis->segments;
|
|
2827 | + |
|
2828 | + FT_UInt i;
|
|
2829 | + |
|
2830 | + |
|
2831 | + for ( i = 0; i < axis->num_segments; i++ )
|
|
2832 | + {
|
|
2833 | + AF_Segment seg = &segments[i];
|
|
2834 | + AF_Point p = seg->first;
|
|
2835 | + |
|
2836 | + FT_Bool remove = 0;
|
|
2837 | + |
|
2838 | + |
|
2839 | + while ( 1 )
|
|
2840 | + {
|
|
2841 | + if ( p == point )
|
|
2842 | + {
|
|
2843 | + remove = 1;
|
|
2844 | + break;
|
|
2845 | + }
|
|
2846 | + |
|
2847 | + if ( p == seg->last )
|
|
2848 | + break;
|
|
2849 | + |
|
2850 | + p = p->next;
|
|
2851 | + }
|
|
2852 | + |
|
2853 | + if ( remove )
|
|
2854 | + {
|
|
2855 | + /* First, check the first and last segment of the edge. */
|
|
2856 | + AF_Edge edge = seg->edge;
|
|
2857 | + |
|
2858 | + |
|
2859 | + if ( edge->first == seg && edge->last == seg )
|
|
2860 | + {
|
|
2861 | + /* The edge only consists of the segment to be removed. */
|
|
2862 | + /* Remove the edge. */
|
|
2863 | + *edge = axis->edges[--axis->num_edges];
|
|
2864 | + }
|
|
2865 | + else
|
|
2866 | + {
|
|
2867 | + if ( edge->first == seg )
|
|
2868 | + edge->first = seg->edge_next;
|
|
2869 | + |
|
2870 | + if ( edge->last == seg )
|
|
2871 | + {
|
|
2872 | + edge->last = edge->first;
|
|
2873 | + |
|
2874 | + while ( edge->last->edge_next != seg )
|
|
2875 | + edge->last = edge->last->edge_next;
|
|
2876 | + }
|
|
2877 | + }
|
|
2878 | + |
|
2879 | + /* Now, delete the segment. */
|
|
2880 | + *seg = axis->segments[--axis->num_segments];
|
|
2881 | + |
|
2882 | + i--; /* We have to check the new segment at this position. */
|
|
2883 | + }
|
|
2884 | + }
|
|
2885 | + }
|
|
2886 | + |
|
2887 | + |
|
2888 | + /* Remove all segments containing points on the tilde contour. */
|
|
2889 | + static void
|
|
2890 | + af_latin_remove_tilde_points_from_edges( AF_GlyphHints hints )
|
|
2891 | + {
|
|
2892 | + FT_Int highest_contour = af_find_highest_contour( hints );
|
|
2893 | + AF_Point first_point = hints->contours[highest_contour];
|
|
2894 | + |
|
2895 | + AF_Point p = first_point;
|
|
2896 | + |
|
2897 | + |
|
2898 | + do
|
|
2899 | + {
|
|
2900 | + p = p->next;
|
|
2901 | + af_remove_segments_containing_point( hints, p );
|
|
2902 | + |
|
2903 | + } while ( p != first_point );
|
|
2904 | + }
|
|
2905 | + |
|
2906 | + |
|
2907 | + /*
|
|
2908 | + The tilde-unflattening algorithm sometimes goes too far and makes an
|
|
2909 | + unusually high tilde, where decreasing the ppem will increase the height
|
|
2910 | + instead of a steady decrease in height as less pixels are used.
|
|
2911 | + |
|
2912 | + For example, the 'n tilde' glyph from 'Times New Roman', with forced
|
|
2913 | + autofitting on, exhibits this behaviour in the font size range 16.5 to
|
|
2914 | + 18 ppem.
|
|
2915 | + */
|
|
2916 | + static void
|
|
2917 | + af_latin_stretch_tildes( AF_GlyphHints hints )
|
|
2918 | + {
|
|
2919 | + FT_Int highest_contour = af_find_highest_contour( hints );
|
|
2920 | + AF_Point p = hints->contours[highest_contour];
|
|
2921 | + |
|
2922 | + AF_Point first_point = p;
|
|
2923 | + |
|
2924 | + FT_Pos min_y, max_y;
|
|
2925 | + FT_Short min_fy, max_fy;
|
|
2926 | + |
|
2927 | + FT_Pos min_measurement;
|
|
2928 | + |
|
2929 | + FT_Pos height;
|
|
2930 | + FT_Pos target_height;
|
|
2931 | + |
|
2932 | + |
|
2933 | + min_y = max_y = p->y;
|
|
2934 | + min_fy = max_fy = p->fy;
|
|
2935 | + |
|
2936 | + do
|
|
2937 | + {
|
|
2938 | + p = p->next;
|
|
2939 | + |
|
2940 | + if ( p->y < min_y )
|
|
2941 | + min_y = p->y;
|
|
2942 | + if ( p->y > max_y )
|
|
2943 | + max_y = p->y;
|
|
2944 | + |
|
2945 | + if ( p->fy < min_fy )
|
|
2946 | + min_fy = p->fy;
|
|
2947 | + if ( p->fy > max_fy )
|
|
2948 | + max_fy = p->fy;
|
|
2949 | + |
|
2950 | + } while ( p != first_point );
|
|
2951 | + |
|
2952 | + min_measurement = 32000;
|
|
2953 | + do
|
|
2954 | + {
|
|
2955 | + p = p->next;
|
|
2956 | + |
|
2957 | + if ( !( p->flags & AF_FLAG_CONTROL ) &&
|
|
2958 | + p->prev->y == p->y && p->next->y == p->y &&
|
|
2959 | + p->y != min_y && p->y != max_y &&
|
|
2960 | + p->prev->flags & AF_FLAG_CONTROL &&
|
|
2961 | + p->next->flags & AF_FLAG_CONTROL )
|
|
2962 | + {
|
|
2963 | + /* This point could be a candidate. Find the next and previous */
|
|
2964 | + /* on-curve points, and make sure they are both either above or */
|
|
2965 | + /* below the point, then make the measurement. */
|
|
2966 | + AF_Point prevOn = p->prev;
|
|
2967 | + AF_Point nextOn = p->next;
|
|
2968 | + |
|
2969 | + FT_Pos measurement;
|
|
2970 | + |
|
2971 | + |
|
2972 | + while ( prevOn->flags & AF_FLAG_CONTROL )
|
|
2973 | + prevOn = prevOn->prev;
|
|
2974 | + while ( nextOn->flags & AF_FLAG_CONTROL )
|
|
2975 | + nextOn = nextOn->next;
|
|
2976 | + |
|
2977 | + if ( nextOn->y > p->y && prevOn->y > p->y )
|
|
2978 | + measurement = p->y - min_y;
|
|
2979 | + else if ( nextOn->y < p->y && prevOn->y < p->y )
|
|
2980 | + measurement = max_y - p->y;
|
|
2981 | + else
|
|
2982 | + continue;
|
|
2983 | + |
|
2984 | + if ( measurement < min_measurement )
|
|
2985 | + min_measurement = measurement;
|
|
2986 | + }
|
|
2987 | + } while ( p != first_point );
|
|
2988 | + |
|
2989 | + /* touch all points */
|
|
2990 | + p = first_point;
|
|
2991 | + do
|
|
2992 | + {
|
|
2993 | + p = p->next;
|
|
2994 | + if ( !( p->flags & AF_FLAG_CONTROL ) )
|
|
2995 | + p->flags |= AF_FLAG_TOUCH_Y;
|
|
2996 | + |
|
2997 | + } while ( p != first_point );
|
|
2998 | + |
|
2999 | + height = max_y - min_y;
|
|
3000 | + target_height = min_measurement + 64;
|
|
3001 | + |
|
3002 | + if ( height >= target_height )
|
|
3003 | + return;
|
|
3004 | + |
|
3005 | + p = first_point;
|
|
3006 | + do
|
|
3007 | + {
|
|
3008 | + p = p->next;
|
|
3009 | + p->y = ( ( p->y - min_y ) * target_height / height ) + min_y;
|
|
3010 | + p->fy = ( ( p->fy - min_fy ) * target_height / height ) + min_fy;
|
|
3011 | + p->oy = p->y;
|
|
3012 | + |
|
3013 | + } while ( p != first_point );
|
|
3014 | + }
|
|
3015 | + |
|
3016 | + |
|
3017 | + /*
|
|
3018 | + As part of `af_latin_stretch_tildes`, all points in the tilde are marked
|
|
3019 | + as touched, so the existing grid fitting will leave the tilde misaligned
|
|
3020 | + with the grid.
|
|
3021 | + |
|
3022 | + This function moves the tilde contour down to be grid-fitted. We assume
|
|
3023 | + that if moving the tilde down would cause it to touch or overlap another
|
|
3024 | + countour, the vertical adjustment step will fix it.
|
|
3025 | + |
|
3026 | + Because the vertical adjustment step comes after all other grid-fitting
|
|
3027 | + steps, the top edge of the contour under the tilde is usually aligned
|
|
3028 | + with a horizontal grid line. The vertical gap enforced by the vertical
|
|
3029 | + adjustment is exactly one pixel, so if the top edge of the contour below
|
|
3030 | + the tilde is on a grid line, the resulting tilde contour will also be
|
|
3031 | + grid-aligned.
|
|
3032 | + |
|
3033 | + But in cases where the gap is already big enough so that the vertical
|
|
3034 | + adjustment does nothing, this function ensures that even without the
|
|
3035 | + intervention of the vertical adjustment step, the tilde will be
|
|
3036 | + grid-aligned.
|
|
3037 | + */
|
|
3038 | + static void
|
|
3039 | + af_latin_align_tildes( AF_GlyphHints hints )
|
|
3040 | + {
|
|
3041 | + FT_Int highest_contour = af_find_highest_contour( hints );
|
|
3042 | + |
|
3043 | + AF_Point p = hints->contours[highest_contour];
|
|
3044 | + AF_Point first_point = p;
|
|
3045 | + |
|
3046 | + FT_Pos min_y, max_y;
|
|
3047 | + FT_Pos min_y_rounded;
|
|
3048 | + FT_Pos delta;
|
|
3049 | + |
|
3050 | + |
|
3051 | + do
|
|
3052 | + {
|
|
3053 | + p = p->next;
|
|
3054 | + if ( p->y < min_y )
|
|
3055 | + min_y = p->y;
|
|
3056 | + if ( p->y > max_y )
|
|
3057 | + max_y = p->y;
|
|
3058 | + |
|
3059 | + } while ( p != first_point );
|
|
3060 | + |
|
3061 | + // mid_y = ( min_y + max_y ) / 2;
|
|
3062 | + min_y_rounded = FT_PIX_ROUND( min_y );
|
|
3063 | + delta = min_y_rounded - min_y;
|
|
3064 | + |
|
3065 | + do
|
|
3066 | + {
|
|
3067 | + p = p->next;
|
|
3068 | + p->y += delta;
|
|
3069 | + |
|
3070 | + } while ( p != first_point );
|
|
3071 | + }
|
|
3072 | + |
|
3073 | + |
|
3074 | + /* Return 1 if the given contour overlaps horizontally with the bounding */
|
|
3075 | + /* box of all other contours combined. This is a helper for function */
|
|
3076 | + /* `af_glyph_hints_apply_vertical_separation_adjustments`. */
|
|
3077 | + static FT_Bool
|
|
3078 | + af_check_contour_horizontal_overlap( AF_GlyphHints hints,
|
|
3079 | + FT_Int contour_index )
|
|
3080 | + {
|
|
3081 | + FT_Pos contour_max_x = -32000;
|
|
3082 | + FT_Pos contour_min_x = 32000;
|
|
3083 | + FT_Pos others_max_x = -32000;
|
|
3084 | + FT_Pos others_min_x = 32000;
|
|
3085 | + |
|
3086 | + FT_Int contour;
|
|
3087 | + |
|
3088 | + FT_Bool horizontal_overlap;
|
|
3089 | + |
|
3090 | + |
|
3091 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
3092 | + {
|
|
3093 | + AF_Point first_point = hints->contours[contour];
|
|
3094 | + AF_Point p = first_point;
|
|
3095 | + |
|
3096 | + |
|
3097 | + do
|
|
3098 | + {
|
|
3099 | + p = p->next;
|
|
3100 | + |
|
3101 | + if ( contour == contour_index )
|
|
3102 | + {
|
|
3103 | + if ( p->x < contour_min_x )
|
|
3104 | + contour_min_x = p->x;
|
|
3105 | + if ( p->x > contour_max_x )
|
|
3106 | + contour_max_x = p->x;
|
|
3107 | + }
|
|
3108 | + else
|
|
3109 | + {
|
|
3110 | + if ( p->x < others_min_x )
|
|
3111 | + others_min_x = p->x;
|
|
3112 | + if ( p->x > others_max_x )
|
|
3113 | + others_max_x = p->x;
|
|
3114 | + }
|
|
3115 | + } while ( p != first_point );
|
|
3116 | + }
|
|
3117 | + |
|
3118 | + horizontal_overlap =
|
|
3119 | + ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) ||
|
|
3120 | + ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) ||
|
|
3121 | + ( contour_max_x >= others_max_x && contour_min_x <= others_min_x );
|
|
3122 | + |
|
3123 | + return horizontal_overlap;
|
|
3124 | + }
|
|
3125 | + |
|
3126 | + |
|
3127 | + static void
|
|
3128 | + af_glyph_hints_apply_vertical_separation_adjustments(
|
|
3129 | + AF_GlyphHints hints,
|
|
3130 | + AF_Dimension dim,
|
|
3131 | + FT_Int glyph_index,
|
|
3132 | + AF_ReverseCharacterMap reverse_charmap )
|
|
3133 | + {
|
|
3134 | + FT_TRACE4(( "Entering"
|
|
3135 | + " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
|
|
3136 | + |
|
3137 | + if ( dim != AF_DIMENSION_VERT )
|
|
3138 | + return;
|
|
3139 | + |
|
3140 | + if ( af_lookup_vertical_separation_type( reverse_charmap,
|
|
3141 | + glyph_index ) ==
|
|
3142 | + AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP &&
|
|
3143 | + hints->num_contours >= 2 )
|
|
3144 | + {
|
|
3145 | + FT_Int highest_contour = -1;
|
|
3146 | + FT_Pos highest_min_y = 0;
|
|
3147 | + FT_Pos current_min_y = 0;
|
|
3148 | + |
|
3149 | + FT_Int contour;
|
|
3150 | + FT_Bool horizontal_overlap;
|
|
3151 | + FT_Int adjustment_amount;
|
|
3152 | + |
|
3153 | + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
|
3154 | + " Applying vertical adjustment:"
|
|
3155 | + " AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP\n" ));
|
|
3156 | + |
|
3157 | + /* Figure out which contour is the higher one by finding the one */
|
|
3158 | + /* with the highest minimum y value. */
|
|
3159 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
3160 | + {
|
|
3161 | + AF_Point point = hints->contours[contour];
|
|
3162 | + AF_Point first_point = point;
|
|
3163 | + |
|
3164 | + |
|
3165 | + if ( !point )
|
|
3166 | + continue;
|
|
3167 | + |
|
3168 | + current_min_y = point->y;
|
|
3169 | + |
|
3170 | + do
|
|
3171 | + {
|
|
3172 | + if ( point->y < current_min_y )
|
|
3173 | + current_min_y = point->y;
|
|
3174 | + point = point->next;
|
|
3175 | + |
|
3176 | + } while ( point != first_point );
|
|
3177 | + |
|
3178 | + if ( highest_contour == -1 || current_min_y > highest_min_y )
|
|
3179 | + {
|
|
3180 | + highest_min_y = current_min_y;
|
|
3181 | + highest_contour = contour;
|
|
3182 | + }
|
|
3183 | + }
|
|
3184 | + |
|
3185 | + /* Check for a horizontal overlap between the top contour and the */
|
|
3186 | + /* rest. If there is no overlap, do not adjust. */
|
|
3187 | + horizontal_overlap =
|
|
3188 | + af_check_contour_horizontal_overlap( hints, highest_contour );
|
|
3189 | + if ( !horizontal_overlap )
|
|
3190 | + {
|
|
3191 | + FT_TRACE4(( " Top contour does not horizontally overlap"
|
|
3192 | + " with other contours.\n"
|
|
3193 | + " Skipping adjustment.\n" ));
|
|
3194 | + return;
|
|
3195 | + }
|
|
3196 | + |
|
3197 | + /* If there are any contours that have a maximum y coordinate */
|
|
3198 | + /* greater than or equal to the minimum y coordinate of the */
|
|
3199 | + /* previously found highest contour, bump the high contour up until */
|
|
3200 | + /* the distance is one pixel. */
|
|
3201 | + adjustment_amount = 0;
|
|
3202 | + |
|
3203 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
3204 | + {
|
|
3205 | + AF_Point point;
|
|
3206 | + AF_Point first_point;
|
|
3207 | + |
|
3208 | + FT_Pos max_y;
|
|
3209 | + |
|
3210 | + |
|
3211 | + if ( contour == highest_contour )
|
|
3212 | + continue;
|
|
3213 | + |
|
3214 | + point = hints->contours[contour];
|
|
3215 | + first_point = point;
|
|
3216 | + if ( !point )
|
|
3217 | + continue;
|
|
3218 | + |
|
3219 | + max_y = point->y;
|
|
3220 | + do
|
|
3221 | + {
|
|
3222 | + if ( point->y > max_y )
|
|
3223 | + max_y = point->y;
|
|
3224 | + point = point->next;
|
|
3225 | + |
|
3226 | + } while ( point != first_point );
|
|
3227 | + |
|
3228 | + if ( max_y >= highest_min_y - 64 )
|
|
3229 | + adjustment_amount = 64 - ( highest_min_y - max_y );
|
|
3230 | + }
|
|
3231 | + |
|
3232 | + FT_TRACE4(( " Calculated adjustment amount: %d\n",
|
|
3233 | + adjustment_amount ));
|
|
3234 | + |
|
3235 | + if ( adjustment_amount > 64 )
|
|
3236 | + FT_TRACE4(( " Calculated adjustment amount %d"
|
|
3237 | + " was more than threshold of 64. Not adjusting\n",
|
|
3238 | + adjustment_amount ));
|
|
3239 | + else if ( adjustment_amount > 0 )
|
|
3240 | + {
|
|
3241 | + FT_TRACE4(( " Pushing top contour %d units up\n",
|
|
3242 | + adjustment_amount ));
|
|
3243 | + |
|
3244 | + af_move_contour_vertically( hints->contours[highest_contour],
|
|
3245 | + adjustment_amount );
|
|
3246 | + }
|
|
3247 | + }
|
|
3248 | + |
|
3249 | + else if ( af_lookup_vertical_separation_type( reverse_charmap,
|
|
3250 | + glyph_index ) ==
|
|
3251 | + AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN &&
|
|
3252 | + hints->num_contours >= 2 )
|
|
3253 | + {
|
|
3254 | + FT_Int lowest_contour = -1;
|
|
3255 | + FT_Pos lowest_max_y = 0;
|
|
3256 | + FT_Pos current_max_y = 0;
|
|
3257 | + |
|
3258 | + FT_Int contour;
|
|
3259 | + FT_Int adjustment_amount;
|
|
3260 | + |
|
3261 | + |
|
3262 | + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
|
3263 | + " Applying vertical adjustment:"
|
|
3264 | + " AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN\n" ));
|
|
3265 | + |
|
3266 | + /* Find lowest contour. */
|
|
3267 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
3268 | + {
|
|
3269 | + AF_Point point = hints->contours[contour];
|
|
3270 | + AF_Point first_point = point;
|
|
3271 | + |
|
3272 | + |
|
3273 | + if ( !point )
|
|
3274 | + continue;
|
|
3275 | + |
|
3276 | + current_max_y = point->y;
|
|
3277 | + |
|
3278 | + do
|
|
3279 | + {
|
|
3280 | + if ( point->y > current_max_y )
|
|
3281 | + current_max_y = point->y;
|
|
3282 | + point = point->next;
|
|
3283 | + |
|
3284 | + } while ( point != first_point );
|
|
3285 | + |
|
3286 | + if ( lowest_contour == -1 || current_max_y < lowest_max_y )
|
|
3287 | + {
|
|
3288 | + lowest_max_y = current_max_y;
|
|
3289 | + lowest_contour = contour;
|
|
3290 | + }
|
|
3291 | + }
|
|
3292 | + |
|
3293 | + adjustment_amount = 0;
|
|
3294 | + |
|
3295 | + for ( contour = 0; contour < hints->num_contours; contour++ )
|
|
3296 | + {
|
|
3297 | + AF_Point point;
|
|
3298 | + AF_Point first_point;
|
|
3299 | + |
|
3300 | + FT_Pos min_y;
|
|
3301 | + |
|
3302 | + |
|
3303 | + if ( contour == lowest_contour )
|
|
3304 | + continue;
|
|
3305 | + |
|
3306 | + point = hints->contours[contour];
|
|
3307 | + first_point = point;
|
|
3308 | + if ( !point )
|
|
3309 | + continue;
|
|
3310 | + |
|
3311 | + min_y = point->y;
|
|
3312 | + do
|
|
3313 | + {
|
|
3314 | + if ( point->y < min_y )
|
|
3315 | + min_y = point->y;
|
|
3316 | + point = point->next;
|
|
3317 | + |
|
3318 | + } while ( point != first_point );
|
|
3319 | + |
|
3320 | + if ( min_y <= lowest_max_y - 64 )
|
|
3321 | + adjustment_amount = 64 - ( min_y - lowest_max_y );
|
|
3322 | + }
|
|
3323 | + |
|
3324 | + if ( adjustment_amount > 64 )
|
|
3325 | + FT_TRACE4(( " Calculated adjustment amount %d"
|
|
3326 | + " was more than threshold of 64. Not adjusting\n",
|
|
3327 | + adjustment_amount ));
|
|
3328 | + else if ( adjustment_amount > 0 )
|
|
3329 | + {
|
|
3330 | + FT_TRACE4(( " Pushing bottom contour %d units down\n",
|
|
3331 | + adjustment_amount ));
|
|
3332 | + |
|
3333 | + af_move_contour_vertically( hints->contours[lowest_contour],
|
|
3334 | + -adjustment_amount );
|
|
3335 | + }
|
|
3336 | + }
|
|
3337 | + |
|
3338 | + else
|
|
3339 | + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
|
3340 | + " No vertical adjustment needed\n" ));
|
|
3341 | + |
|
3342 | + FT_TRACE4(( "Exiting"
|
|
3343 | + " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
|
|
3344 | + }
|
|
3345 | + |
|
3346 | + |
|
3347 | +#undef FT_COMPONENT
|
|
3348 | +#define FT_COMPONENT aflatin
|
|
3349 | + |
|
3350 | + |
|
2741 | 3351 | /* Compute the snapped width of a given stem, ignoring very thin ones. */
|
2742 | 3352 | /* There is a lot of voodoo in this function; changing the hard-coded */
|
2743 | 3353 | /* parameters influence the whole hinting process. */
|
... | ... | @@ -3548,6 +4158,47 @@ |
3548 | 4158 | }
|
3549 | 4159 | |
3550 | 4160 | |
4161 | +#ifdef FT_DEBUG_LEVEL_TRACE
|
|
4162 | + /* Print the height of the topmost contour for debugging purposes. */
|
|
4163 | + /* TODO: remove this once the tilde unflattening works. */
|
|
4164 | + static void
|
|
4165 | + af_latin_trace_height( FT_UInt num,
|
|
4166 | + AF_GlyphHints hints )
|
|
4167 | + {
|
|
4168 | + AF_Point p = hints->contours[af_find_highest_contour(hints)];
|
|
4169 | + AF_Point first_point = p;
|
|
4170 | + |
|
4171 | + FT_Pos min_y, max_y;
|
|
4172 | + |
|
4173 | + |
|
4174 | + min_y = max_y = p->y;
|
|
4175 | + |
|
4176 | + do
|
|
4177 | + {
|
|
4178 | + p = p->next;
|
|
4179 | + if ( !(p->flags & AF_FLAG_CONTROL) )
|
|
4180 | + {
|
|
4181 | + if ( p->y < min_y )
|
|
4182 | + min_y = p->y;
|
|
4183 | + if ( p->y > max_y )
|
|
4184 | + max_y = p->y;
|
|
4185 | + }
|
|
4186 | + |
|
4187 | + } while ( p != first_point );
|
|
4188 | + |
|
4189 | + FT_TRACE4(( "height %d: %ld\n", num, max_y - min_y ));
|
|
4190 | + }
|
|
4191 | +#else
|
|
4192 | + static void
|
|
4193 | + af_latin_trace_height( FT_UInt num,
|
|
4194 | + AF_GlyphHints hints )
|
|
4195 | + {
|
|
4196 | + FT_UNUSED( num );
|
|
4197 | + FT_UNUSED( hints );
|
|
4198 | + }
|
|
4199 | +#endif
|
|
4200 | + |
|
4201 | + |
|
3551 | 4202 | /* Apply the complete hinting algorithm to a latin glyph. */
|
3552 | 4203 | |
3553 | 4204 | static FT_Error
|
... | ... | @@ -3582,11 +4233,26 @@ |
3582 | 4233 | |
3583 | 4234 | if ( AF_HINTS_DO_VERTICAL( hints ) )
|
3584 | 4235 | {
|
4236 | + FT_Bool is_tilde = af_lookup_tilde_correction_type(
|
|
4237 | + metrics->root.reverse_charmap, glyph_index );
|
|
4238 | + |
|
4239 | + |
|
4240 | + if ( is_tilde )
|
|
4241 | + {
|
|
4242 | + af_latin_trace_height(0, hints );
|
|
4243 | + af_latin_stretch_tildes( hints );
|
|
4244 | + af_latin_align_tildes( hints );
|
|
4245 | + af_latin_trace_height(1, hints );
|
|
4246 | + }
|
|
4247 | + |
|
3585 | 4248 | axis = &metrics->axis[AF_DIMENSION_VERT];
|
3586 | 4249 | error = af_latin_hints_detect_features( hints,
|
3587 | 4250 | axis->width_count,
|
3588 | 4251 | axis->widths,
|
3589 | 4252 | AF_DIMENSION_VERT );
|
4253 | + if ( is_tilde )
|
|
4254 | + af_latin_remove_tilde_points_from_edges( hints );
|
|
4255 | + |
|
3590 | 4256 | if ( error )
|
3591 | 4257 | goto Exit;
|
3592 | 4258 | |
... | ... | @@ -3602,9 +4268,19 @@ |
3602 | 4268 | ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
|
3603 | 4269 | {
|
3604 | 4270 | af_latin_hint_edges( hints, (AF_Dimension)dim );
|
4271 | + af_latin_trace_height(2, hints );
|
|
3605 | 4272 | af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
|
4273 | + af_latin_trace_height(3, hints );
|
|
3606 | 4274 | af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
|
4275 | + af_latin_trace_height(4, hints );
|
|
3607 | 4276 | af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
|
4277 | + af_latin_trace_height(5, hints );
|
|
4278 | + af_glyph_hints_apply_vertical_separation_adjustments(
|
|
4279 | + hints,
|
|
4280 | + (AF_Dimension)dim,
|
|
4281 | + glyph_index,
|
|
4282 | + metrics->root.reverse_charmap );
|
|
4283 | + af_latin_trace_height(6, hints );
|
|
3608 | 4284 | }
|
3609 | 4285 | }
|
3610 | 4286 | |
... | ... | @@ -3633,7 +4309,7 @@ |
3633 | 4309 | |
3634 | 4310 | (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */
|
3635 | 4311 | (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */
|
3636 | - (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
|
|
4312 | + (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done, /* style_metrics_done */
|
|
3637 | 4313 | (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */
|
3638 | 4314 | |
3639 | 4315 | (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */
|
... | ... | @@ -406,6 +406,27 @@ extern void* af_debug_hints_; |
406 | 406 | |
407 | 407 | typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals;
|
408 | 408 | |
409 | + |
|
410 | + /* Store a mapping from glyphs to unicode codepoints. */
|
|
411 | + /* See `afadjust.c` for details. */
|
|
412 | + typedef struct AF_ReverseMapEntry_
|
|
413 | + {
|
|
414 | + FT_Int glyph_index;
|
|
415 | + FT_UInt32 codepoint;
|
|
416 | + |
|
417 | + } AF_ReverseMapEntry;
|
|
418 | + |
|
419 | + |
|
420 | + typedef struct AF_ReverseCharacterMapRec_
|
|
421 | + {
|
|
422 | + FT_Long length;
|
|
423 | + AF_ReverseMapEntry *entries;
|
|
424 | + |
|
425 | + } AF_ReverseCharacterMapRec;
|
|
426 | + |
|
427 | + typedef struct AF_ReverseCharacterMapRec_* AF_ReverseCharacterMap;
|
|
428 | + |
|
429 | + |
|
409 | 430 | /* This is the main structure that combines everything. Autofit modules */
|
410 | 431 | /* specific to writing systems derive their structures from it, for */
|
411 | 432 | /* example `AF_LatinMetrics'. */
|
... | ... | @@ -418,6 +439,8 @@ extern void* af_debug_hints_; |
418 | 439 | |
419 | 440 | AF_FaceGlobals globals; /* to access properties */
|
420 | 441 | |
442 | + AF_ReverseCharacterMap reverse_charmap;
|
|
443 | + |
|
421 | 444 | } AF_StyleMetricsRec;
|
422 | 445 | |
423 | 446 |
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | #define FT_MAKE_OPTION_SINGLE_OBJECT
|
20 | 20 | |
21 | 21 | #include "ft-hb.c"
|
22 | +#include "afadjust.c"
|
|
22 | 23 | #include "afblue.c"
|
23 | 24 | #include "afcjk.c"
|
24 | 25 | #include "afdummy.c"
|
... | ... | @@ -28,7 +28,8 @@ AUTOF_COMPILE := $(CC) $(ANSIFLAGS) \ |
28 | 28 | |
29 | 29 | # AUTOF driver sources (i.e., C files)
|
30 | 30 | #
|
31 | -AUTOF_DRV_SRC := $(AUTOF_DIR)/afblue.c \
|
|
31 | +AUTOF_DRV_SRC := $(AUTOF_DIR)/afadjust.c \
|
|
32 | + $(AUTOF_DIR)/afblue.c \
|
|
32 | 33 | $(AUTOF_DIR)/afcjk.c \
|
33 | 34 | $(AUTOF_DIR)/afdummy.c \
|
34 | 35 | $(AUTOF_DIR)/afglobal.c \
|
... | ... | @@ -1359,21 +1359,9 @@ |
1359 | 1359 | }
|
1360 | 1360 | |
1361 | 1361 | |
1362 | - /**************************************************************************
|
|
1363 | - *
|
|
1364 | - * @Function:
|
|
1365 | - * find_unicode_charmap
|
|
1366 | - *
|
|
1367 | - * @Description:
|
|
1368 | - * This function finds a Unicode charmap, if there is one.
|
|
1369 | - * And if there is more than one, it tries to favour the more
|
|
1370 | - * extensive one, i.e., one that supports UCS-4 against those which
|
|
1371 | - * are limited to the BMP (said UCS-2 encoding.)
|
|
1372 | - *
|
|
1373 | - * This function is called from open_face() (just below), and also
|
|
1374 | - * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).
|
|
1375 | - */
|
|
1376 | - static FT_Error
|
|
1362 | + /* documentation is in ftobjs.h */
|
|
1363 | + |
|
1364 | + FT_BASE_DEF( FT_Error )
|
|
1377 | 1365 | find_unicode_charmap( FT_Face face )
|
1378 | 1366 | {
|
1379 | 1367 | FT_CharMap* first;
|
... | ... | @@ -694,8 +694,7 @@ |
694 | 694 | FT_UInt instance_index = (FT_UInt)face_index >> 16;
|
695 | 695 | |
696 | 696 | |
697 | - if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
|
|
698 | - instance_index > 0 )
|
|
697 | + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) )
|
|
699 | 698 | {
|
700 | 699 | error = FT_Set_Named_Instance( cffface, instance_index );
|
701 | 700 | if ( error )
|
... | ... | @@ -90,10 +90,15 @@ |
90 | 90 | if ( error )
|
91 | 91 | goto Exit;
|
92 | 92 | |
93 | - Again:
|
|
94 | - /* now, read the rest of the file until we find */
|
|
95 | - /* `StartData' or `/sfnts' */
|
|
93 | + if ( !stream->read ) {
|
|
94 | + /* just parse memory-based streams */
|
|
95 | + offset = stream->size;
|
|
96 | + }
|
|
97 | + else
|
|
96 | 98 | {
|
99 | + /* Find the last `StartData` or `/sfnts`. The parser requires */
|
|
100 | + /* contiguous memory; attempt to pin as little as necessary. */
|
|
101 | + |
|
97 | 102 | /*
|
98 | 103 | * The algorithm is as follows (omitting the case with less than 256
|
99 | 104 | * bytes to fill for simplicity).
|
... | ... | @@ -119,7 +124,8 @@ |
119 | 124 | FT_Byte* p = buffer;
|
120 | 125 | |
121 | 126 | |
122 | - for ( offset = FT_STREAM_POS(); ; offset += 256 )
|
|
127 | + offset = 0;
|
|
128 | + while ( 1 )
|
|
123 | 129 | {
|
124 | 130 | FT_ULong stream_len;
|
125 | 131 | |
... | ... | @@ -127,7 +133,7 @@ |
127 | 133 | stream_len = stream->size - FT_STREAM_POS();
|
128 | 134 | |
129 | 135 | read_len = FT_MIN( read_len, stream_len );
|
130 | - if ( FT_STREAM_READ( p, read_len ) )
|
|
136 | + if ( read_len && FT_STREAM_READ( p, read_len ) )
|
|
131 | 137 | goto Exit;
|
132 | 138 | |
133 | 139 | /* ensure that we do not compare with data beyond the buffer */
|
... | ... | @@ -141,20 +147,23 @@ |
141 | 147 | ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
|
142 | 148 | {
|
143 | 149 | /* save offset of binary data after `StartData' */
|
144 | - offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
|
|
145 | - goto Found;
|
|
150 | + offset = FT_STREAM_POS() - read_len - read_offset
|
|
151 | + + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
|
|
146 | 152 | }
|
147 | 153 | else if ( p[1] == 's' &&
|
148 | 154 | ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
|
149 | 155 | {
|
150 | - offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
|
|
151 | - goto Found;
|
|
156 | + offset = FT_STREAM_POS() - read_len - read_offset
|
|
157 | + + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
|
|
152 | 158 | }
|
153 | 159 | }
|
154 | 160 | |
155 | - if ( read_offset + read_len < STARTDATA_LEN )
|
|
161 | + if ( read_offset + read_len <= STARTDATA_LEN )
|
|
156 | 162 | {
|
157 | - FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
|
|
163 | + if ( offset )
|
|
164 | + goto Found;
|
|
165 | + |
|
166 | + FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" ));
|
|
158 | 167 | error = FT_THROW( Invalid_File_Format );
|
159 | 168 | goto Exit;
|
160 | 169 | }
|
... | ... | @@ -171,9 +180,9 @@ |
171 | 180 | }
|
172 | 181 | |
173 | 182 | Found:
|
174 | - /* We have found the start of the binary data or the `/sfnts' token. */
|
|
175 | - /* Now rewind and extract the frame corresponding to this PostScript */
|
|
176 | - /* section. */
|
|
183 | + /* We have found an efficient range to look for the binary data or */
|
|
184 | + /* `/sfnts' token. Now rewind and extract the frame corresponding to */
|
|
185 | + /* this PostScript section. */
|
|
177 | 186 | |
178 | 187 | ps_len = offset - base_offset;
|
179 | 188 | if ( FT_STREAM_SEEK( base_offset ) ||
|
... | ... | @@ -187,8 +196,8 @@ |
187 | 196 | parser->root.limit = parser->root.cursor + ps_len;
|
188 | 197 | parser->num_dict = FT_UINT_MAX;
|
189 | 198 | |
190 | - /* Finally, we check whether `StartData' or `/sfnts' was real -- */
|
|
191 | - /* it could be in a comment or string. We also get the arguments */
|
|
199 | + /* Find the first real `StartData' or `/sfnts' -- the last one */
|
|
200 | + /* could be in a comment or string. We also get the arguments */
|
|
192 | 201 | /* of `StartData' to find out whether the data is represented in */
|
193 | 202 | /* binary or hex format. */
|
194 | 203 | |
... | ... | @@ -216,6 +225,7 @@ |
216 | 225 | {
|
217 | 226 | T1_TokenRec type_token;
|
218 | 227 | FT_Long binary_length;
|
228 | + FT_ULong found_offset;
|
|
219 | 229 | |
220 | 230 | |
221 | 231 | parser->root.cursor = arg1;
|
... | ... | @@ -234,6 +244,24 @@ |
234 | 244 | parser->binary_length = (FT_ULong)binary_length;
|
235 | 245 | }
|
236 | 246 | |
247 | + /* set the real values for the parser, if different */
|
|
248 | + found_offset = (FT_ULong)( cur - parser->postscript )
|
|
249 | + + STARTDATA_LEN + 1;
|
|
250 | + if ( found_offset != offset )
|
|
251 | + {
|
|
252 | + FT_FRAME_RELEASE( parser->postscript );
|
|
253 | + |
|
254 | + ps_len = found_offset - base_offset;
|
|
255 | + if ( FT_STREAM_SEEK( base_offset ) ||
|
|
256 | + FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
|
|
257 | + goto Exit;
|
|
258 | + |
|
259 | + parser->data_offset = found_offset;
|
|
260 | + parser->postscript_len = ps_len;
|
|
261 | + parser->root.base = parser->postscript;
|
|
262 | + parser->root.cursor = parser->postscript;
|
|
263 | + parser->root.limit = parser->root.cursor + ps_len;
|
|
264 | + }
|
|
237 | 265 | goto Exit;
|
238 | 266 | }
|
239 | 267 | else if ( cur[1] == 's' &&
|
... | ... | @@ -251,11 +279,8 @@ |
251 | 279 | cur = parser->root.cursor;
|
252 | 280 | }
|
253 | 281 | |
254 | - /* we haven't found the correct `StartData'; go back and continue */
|
|
255 | - /* searching */
|
|
256 | - FT_FRAME_RELEASE( parser->postscript );
|
|
257 | - if ( !FT_STREAM_SEEK( offset ) )
|
|
258 | - goto Again;
|
|
282 | + FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" ));
|
|
283 | + error = FT_THROW( Invalid_File_Format );
|
|
259 | 284 | |
260 | 285 | Exit:
|
261 | 286 | return error;
|
... | ... | @@ -661,6 +661,7 @@ |
661 | 661 | FT_UInt32 first_layer_index;
|
662 | 662 | |
663 | 663 | |
664 | + ENSURE_READ_BYTES( 5 );
|
|
664 | 665 | num_layers = FT_NEXT_BYTE( p );
|
665 | 666 | if ( num_layers > colr->num_layers_v1 )
|
666 | 667 | return 0;
|
... | ... | @@ -2142,7 +2142,7 @@ |
2142 | 2142 | innerIndex );
|
2143 | 2143 | |
2144 | 2144 | /* Convert to 16.16 format before adding. */
|
2145 | - v += delta * 4;
|
|
2145 | + v += MUL_INT( delta, 4 );
|
|
2146 | 2146 | |
2147 | 2147 | /* Clamp value range. */
|
2148 | 2148 | v = v >= 0x10000L ? 0x10000 : v;
|
... | ... | @@ -784,8 +784,7 @@ |
784 | 784 | FT_UInt instance_index = (FT_UInt)face_index >> 16;
|
785 | 785 | |
786 | 786 | |
787 | - if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
|
|
788 | - instance_index > 0 )
|
|
787 | + if ( FT_HAS_MULTIPLE_MASTERS( ttface ) )
|
|
789 | 788 | {
|
790 | 789 | error = FT_Set_Named_Instance( ttface, instance_index );
|
791 | 790 | if ( error )
|