Craig White pushed to branch gsoc-craig-2023-final at FreeType / FreeType
Commits:
-
b9095238
by Craig White at 2023-10-31T23:20:01-04:00
6 changed files:
- include/freetype/internal/ftobjs.h
- src/autofit/afadjust.c
- src/autofit/afadjust.h
- src/autofit/aftypes.h
- src/autofit/autofit.c
- src/base/ftobjs.c
Changes:
... | ... | @@ -275,6 +275,26 @@ FT_BEGIN_HEADER |
275 | 275 | FT_GlyphSlot slot,
|
276 | 276 | FT_Render_Mode mode );
|
277 | 277 | |
278 | + /**************************************************************************
|
|
279 | + *
|
|
280 | + * @Function:
|
|
281 | + * find_unicode_charmap
|
|
282 | + *
|
|
283 | + * @Description:
|
|
284 | + * This function finds a Unicode charmap, if there is one.
|
|
285 | + * And if there is more than one, it tries to favour the more
|
|
286 | + * extensive one, i.e., one that supports UCS-4 against those which
|
|
287 | + * are limited to the BMP ( UCS-2 encoding.)
|
|
288 | + *
|
|
289 | + * If a unicode charmap is found, face->charmap is set to it.
|
|
290 | + *
|
|
291 | + * This function is called from open_face(),
|
|
292 | + * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ),
|
|
293 | + * and also from afadjust.c in the autofit module.
|
|
294 | + */
|
|
295 | + FT_BASE( FT_Error )
|
|
296 | + find_unicode_charmap( FT_Face face );
|
|
297 | + |
|
278 | 298 | #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
279 | 299 | |
280 | 300 | typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
|
... | ... | @@ -136,3 +136,222 @@ adjustment_database[] = |
136 | 136 | {0x17D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0},
|
137 | 137 | {0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}
|
138 | 138 | };
|
139 | + |
|
140 | +/*Helper function: get the adjustment database entry for a codepoint*/
|
|
141 | +FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* )
|
|
142 | +af_adjustment_database_lookup( FT_UInt32 codepoint ) {
|
|
143 | + /* Binary search for database entry */
|
|
144 | + FT_Int low = 0;
|
|
145 | + FT_Int high = AF_ADJUSTMENT_DATABASE_LENGTH - 1;
|
|
146 | + while ( high >= low )
|
|
147 | + {
|
|
148 | + FT_Int mid = ( low + high ) / 2;
|
|
149 | + FT_UInt32 mid_codepoint = adjustment_database[mid].codepoint;
|
|
150 | + if ( mid_codepoint < codepoint )
|
|
151 | + {
|
|
152 | + low = mid + 1;
|
|
153 | + }
|
|
154 | + else if ( mid_codepoint > codepoint )
|
|
155 | + {
|
|
156 | + high = mid - 1;
|
|
157 | + }
|
|
158 | + else
|
|
159 | + {
|
|
160 | + return &adjustment_database[mid];
|
|
161 | + }
|
|
162 | + }
|
|
163 | + |
|
164 | + return NULL;
|
|
165 | +}
|
|
166 | + |
|
167 | +FT_LOCAL_DEF( AF_VerticalSeparationAdjustmentType )
|
|
168 | +af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int glyph_index ) {
|
|
169 | + FT_UInt32 codepoint = af_reverse_character_map_lookup( map, glyph_index );
|
|
170 | + const AF_AdjustmentDatabaseEntry *entry = af_adjustment_database_lookup( codepoint );
|
|
171 | + if ( entry == NULL )
|
|
172 | + {
|
|
173 | + return AF_VERTICAL_ADJUSTMENT_NONE;
|
|
174 | + }
|
|
175 | + return entry->vertical_separation_adjustment_type;
|
|
176 | +}
|
|
177 | + |
|
178 | +/*1 if tilde correction should be applied to the topmost contour
|
|
179 | +else 0*/
|
|
180 | +FT_LOCAL_DEF( FT_Bool )
|
|
181 | +af_lookup_tilde_correction_type( AF_ReverseCharacterMap map, FT_Int glyph_index ) {
|
|
182 | + FT_UInt32 codepoint = af_reverse_character_map_lookup( map, glyph_index );
|
|
183 | + const AF_AdjustmentDatabaseEntry *entry = af_adjustment_database_lookup( codepoint );
|
|
184 | + if ( entry == NULL )
|
|
185 | + {
|
|
186 | + return 0;
|
|
187 | + }
|
|
188 | + return entry->apply_tilde;
|
|
189 | +}
|
|
190 | + |
|
191 | +typedef struct AF_ReverseMapEntry_
|
|
192 | +{
|
|
193 | + FT_Int glyph_index;
|
|
194 | + FT_UInt32 codepoint;
|
|
195 | +} AF_ReverseMapEntry;
|
|
196 | + |
|
197 | +typedef struct AF_ReverseCharacterMap_
|
|
198 | +{
|
|
199 | + FT_Long length;
|
|
200 | + AF_ReverseMapEntry *entries;
|
|
201 | +} AF_ReverseCharacterMap_Rec;
|
|
202 | + |
|
203 | +/* qsort compare function for reverse character map */
|
|
204 | +FT_LOCAL_DEF( FT_Int )
|
|
205 | +af_reverse_character_map_entry_compare( const void *a, const void *b ) {
|
|
206 | + const AF_ReverseMapEntry entry_a = *((const AF_ReverseMapEntry *)a);
|
|
207 | + const AF_ReverseMapEntry entry_b = *((const AF_ReverseMapEntry *)b);
|
|
208 | + return entry_a.glyph_index < entry_b.glyph_index ? -1 : entry_a.glyph_index > entry_b.glyph_index ? 1 : 0;
|
|
209 | +}
|
|
210 | + |
|
211 | +FT_LOCAL_DEF( FT_UInt32 )
|
|
212 | +af_reverse_character_map_lookup_( AF_ReverseCharacterMap map, FT_Int glyph_index, FT_Long length )
|
|
213 | +{
|
|
214 | + if ( map == NULL )
|
|
215 | + {
|
|
216 | + return 0;
|
|
217 | + }
|
|
218 | + /* Binary search for reverse character map entry */
|
|
219 | + FT_Int low = 0;
|
|
220 | + FT_Int high = length - 1;
|
|
221 | + while ( high >= low )
|
|
222 | + {
|
|
223 | + FT_Int mid = ( high + low ) / 2;
|
|
224 | + FT_Int mid_glyph_index = map->entries[mid].glyph_index;
|
|
225 | + if ( glyph_index < mid_glyph_index )
|
|
226 | + {
|
|
227 | + high = mid - 1;
|
|
228 | + }
|
|
229 | + else if ( glyph_index > mid_glyph_index )
|
|
230 | + {
|
|
231 | + low = mid + 1;
|
|
232 | + }
|
|
233 | + else
|
|
234 | + {
|
|
235 | + return map->entries[mid].codepoint;
|
|
236 | + }
|
|
237 | + }
|
|
238 | + |
|
239 | + return 0;
|
|
240 | +}
|
|
241 | + |
|
242 | +FT_LOCAL_DEF( FT_UInt32 )
|
|
243 | +af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index )
|
|
244 | +{
|
|
245 | + return af_reverse_character_map_lookup_( map, glyph_index, map->length );
|
|
246 | +}
|
|
247 | + |
|
248 | +/*prepare to add one more entry to the reverse character map
|
|
249 | + this is a helper for af_reverse_character_map_new*/
|
|
250 | +FT_LOCAL_DEF( FT_Error )
|
|
251 | +af_reverse_character_map_expand( AF_ReverseCharacterMap map, FT_Long *capacity, FT_Memory memory )
|
|
252 | +{
|
|
253 | + FT_Error error;
|
|
254 | + if ( map->length < *capacity )
|
|
255 | + {
|
|
256 | + return FT_Err_Ok;
|
|
257 | + }
|
|
258 | + |
|
259 | + if ( map->length == *capacity )
|
|
260 | + {
|
|
261 | + FT_Long new_capacity = *capacity + *capacity / 2;
|
|
262 | + if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) ) {
|
|
263 | + return error;
|
|
264 | + }
|
|
265 | + *capacity = new_capacity;
|
|
266 | + }
|
|
267 | + |
|
268 | + return FT_Err_Ok;
|
|
269 | +}
|
|
270 | + |
|
271 | +FT_LOCAL_DEF( FT_Error )
|
|
272 | +af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals globals )
|
|
273 | +{
|
|
274 | + FT_Face face = globals->face;
|
|
275 | + FT_Memory memory = face->memory;
|
|
276 | + /* Search for a unicode charmap */
|
|
277 | + /* If there isn't one, create a blank map */
|
|
278 | + |
|
279 | + FT_TRACE4(( "af_reverse_character_map_new: building reverse character map\n" ));
|
|
280 | + |
|
281 | + FT_Error error;
|
|
282 | + /* backup face->charmap because find_unicode_charmap sets it */
|
|
283 | + FT_CharMap old_charmap = face->charmap;
|
|
284 | + if ( ( error = find_unicode_charmap( face ) ) )
|
|
285 | + {
|
|
286 | + *map = NULL;
|
|
287 | + goto Exit;
|
|
288 | + }
|
|
289 | + |
|
290 | + if ( FT_NEW( *map ) )
|
|
291 | + {
|
|
292 | + goto Exit;
|
|
293 | + }
|
|
294 | + |
|
295 | + FT_Long capacity = 10;
|
|
296 | + ( *map )->length = 0;
|
|
297 | + |
|
298 | + if ( FT_NEW_ARRAY( ( *map )->entries, capacity) )
|
|
299 | + {
|
|
300 | + goto Exit;
|
|
301 | + }
|
|
302 | + |
|
303 | +#ifdef FT_DEBUG_LEVEL_TRACE
|
|
304 | + int failed_lookups = 0;
|
|
305 | +#endif
|
|
306 | + for ( FT_Int i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
|
|
307 | + {
|
|
308 | + FT_UInt32 codepoint = adjustment_database[i].codepoint;
|
|
309 | + FT_Int glyph = FT_Get_Char_Index( face, codepoint );
|
|
310 | + if ( glyph == 0 )
|
|
311 | + {
|
|
312 | +#ifdef FT_DEBUG_LEVEL_TRACE
|
|
313 | + failed_lookups++;
|
|
314 | +#endif
|
|
315 | + continue;
|
|
316 | + }
|
|
317 | + error = af_reverse_character_map_expand( *map, &capacity, memory );
|
|
318 | + if ( error ) {
|
|
319 | + goto Exit;
|
|
320 | + }
|
|
321 | + |
|
322 | + ( *map )->length++;
|
|
323 | + ( *map )->entries[i].glyph_index = glyph;
|
|
324 | + ( *map )->entries[i].codepoint = codepoint;
|
|
325 | + }
|
|
326 | + |
|
327 | + ft_qsort(
|
|
328 | + ( *map )->entries,
|
|
329 | + ( *map )->length,
|
|
330 | + sizeof( AF_ReverseMapEntry ),
|
|
331 | + af_reverse_character_map_entry_compare
|
|
332 | + );
|
|
333 | + |
|
334 | + FT_TRACE4(( " reverse character map built successfully"\
|
|
335 | + " with %d entries\n", (*map)->length ));
|
|
336 | + |
|
337 | +Exit:
|
|
338 | + face->charmap = old_charmap;
|
|
339 | + if ( error )
|
|
340 | + {
|
|
341 | + FT_TRACE4(( " error while building reverse character map. Using blank map.\n" ));
|
|
342 | + if ( *map )
|
|
343 | + {
|
|
344 | + FT_FREE( ( *map )->entries );
|
|
345 | + }
|
|
346 | + FT_FREE( *map );
|
|
347 | + return error;
|
|
348 | + }
|
|
349 | + |
|
350 | + return FT_Err_Ok;
|
|
351 | +}
|
|
352 | + |
|
353 | +FT_LOCAL_DEF( FT_Error )
|
|
354 | +af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ) {
|
|
355 | + FT_FREE( map->entries );
|
|
356 | + return FT_Err_Ok;
|
|
357 | +} |
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | #define AFADJUST_H_
|
3 | 3 | |
4 | 4 | #include <freetype/fttypes.h>
|
5 | +#include "afglobal.h"
|
|
5 | 6 | |
6 | 7 | FT_BEGIN_HEADER
|
7 | 8 | |
... | ... | @@ -20,10 +21,29 @@ typedef enum AF_VerticalSeparationAdjustmentType_ |
20 | 21 | AF_VERTICAL_ADJUSTMENT_NONE
|
21 | 22 | } AF_VerticalSeparationAdjustmentType;
|
22 | 23 | |
23 | -typedef struct AF_AdjustmentDatabaseEntry_ {
|
|
24 | - FT_UInt32 codepoint;
|
|
25 | - AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type;
|
|
26 | - } AF_AdjustmentDatabaseEntry;
|
|
24 | +typedef struct AF_AdjustmentDatabaseEntry_
|
|
25 | +{
|
|
26 | + FT_UInt32 codepoint;
|
|
27 | + AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type;
|
|
28 | + FT_Bool apply_tilde;
|
|
29 | +} AF_AdjustmentDatabaseEntry;
|
|
30 | + |
|
31 | +FT_LOCAL(AF_VerticalSeparationAdjustmentType)
|
|
32 | +af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int glyph_index );
|
|
33 | + |
|
34 | +FT_LOCAL( FT_Bool )
|
|
35 | +af_lookup_tilde_correction_type( AF_ReverseCharacterMap map, FT_Int glyph_index );
|
|
36 | + |
|
37 | +FT_LOCAL( FT_UInt32 )
|
|
38 | +af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index );
|
|
39 | + |
|
40 | +/*allocate and populate the reverse character map, using the character map within the face*/
|
|
41 | +FT_LOCAL( FT_Error )
|
|
42 | +af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals globals );
|
|
43 | + |
|
44 | +/*free the reverse character map*/
|
|
45 | +FT_LOCAL( FT_Error )
|
|
46 | +af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory );
|
|
27 | 47 | |
28 | 48 | struct AF_ReverseCharacterMap_;
|
29 | 49 |
... | ... | @@ -406,6 +406,12 @@ extern void* af_debug_hints_; |
406 | 406 | |
407 | 407 | typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals;
|
408 | 408 | |
409 | + /*stores a mapping from glyphs to unicode codepoints
|
|
410 | + see afadjust.c for details */
|
|
411 | + struct AF_ReverseCharacterMap_;
|
|
412 | + |
|
413 | + typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap;
|
|
414 | + |
|
409 | 415 | /* This is the main structure that combines everything. Autofit modules */
|
410 | 416 | /* specific to writing systems derive their structures from it, for */
|
411 | 417 | /* example `AF_LatinMetrics'. */
|
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #include "afmodule.c"
|
31 | 31 | #include "afranges.c"
|
32 | 32 | #include "afshaper.c"
|
33 | +#include "afadjust.c"
|
|
33 | 34 | |
34 | 35 | |
35 | 36 | /* END */ |
... | ... | @@ -1358,22 +1358,7 @@ |
1358 | 1358 | driver );
|
1359 | 1359 | }
|
1360 | 1360 | |
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
|
|
1361 | + FT_Error
|
|
1377 | 1362 | find_unicode_charmap( FT_Face face )
|
1378 | 1363 | {
|
1379 | 1364 | FT_CharMap* first;
|