Craig White pushed to branch gsoc-craig-2023 at FreeType / FreeType
Commits:
-
fa336db6
by Craig White at 2023-08-12T22:47:00-04:00
-
86e5080e
by Craig White at 2023-08-26T22:58:43-04:00
4 changed files:
Changes:
... | ... | @@ -8,12 +8,20 @@ |
8 | 8 | #undef FT_COMPONENT
|
9 | 9 | #define FT_COMPONENT afadjust
|
10 | 10 | |
11 | +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
|
|
12 | + #include <hb.h>
|
|
13 | + #include <hb-ot.h>
|
|
14 | +#endif
|
|
15 | + |
|
11 | 16 | /*TODO: find out whether capital u/U with accent entries are needed*/
|
12 | 17 | /*the accent won't merge with the rest of the glyph because the accent mark is sitting above empty space*/
|
18 | +/*
|
|
19 | + All entries in this list must be sorted by unicode codepoint ascending
|
|
20 | +*/
|
|
13 | 21 | FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry )
|
14 | 22 | adjustment_database[] =
|
15 | 23 | {
|
16 | - {0x21, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* ! */
|
|
24 | + {0x21, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* ! *
|
|
17 | 25 | {0x69, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* i */
|
18 | 26 | {0x6A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* j */
|
19 | 27 | {0xA1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*Inverted Exclamation Mark*/
|
... | ... | @@ -130,6 +138,12 @@ adjustment_database[] = |
130 | 138 | {0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}
|
131 | 139 | };
|
132 | 140 | |
141 | +FT_LOCAL_DEF( FT_Bool )
|
|
142 | +af_adjustment_database_entry_equals( const AF_AdjustmentDatabaseEntry* a, const AF_AdjustmentDatabaseEntry* b )
|
|
143 | +{
|
|
144 | + return a->codepoint == b->codepoint && a->vertical_separation_adjustment_type == b->vertical_separation_adjustment_type;
|
|
145 | +}
|
|
146 | + |
|
133 | 147 | /*Helper function: get the adjustment database entry for a codepoint*/
|
134 | 148 | FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* )
|
135 | 149 | af_adjustment_database_lookup( FT_UInt32 codepoint ) {
|
... | ... | @@ -187,12 +201,12 @@ typedef struct AF_ReverseMapEntry_ |
187 | 201 | |
188 | 202 | typedef struct AF_ReverseCharacterMap_
|
189 | 203 | {
|
190 | - FT_UInt length;
|
|
204 | + FT_Long length;
|
|
191 | 205 | AF_ReverseMapEntry *entries;
|
192 | 206 | } AF_ReverseCharacterMap_Rec;
|
193 | 207 | |
194 | 208 | FT_LOCAL_DEF( FT_UInt32 )
|
195 | -af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index )
|
|
209 | +af_reverse_character_map_lookup_( AF_ReverseCharacterMap map, FT_Int glyph_index, FT_Long length )
|
|
196 | 210 | {
|
197 | 211 | if ( map == NULL )
|
198 | 212 | {
|
... | ... | @@ -222,19 +236,59 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index |
222 | 236 | return 0;
|
223 | 237 | }
|
224 | 238 | |
239 | +FT_LOCAL_DEF( FT_UInt32 )
|
|
240 | +af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index )
|
|
241 | +{
|
|
242 | + return af_reverse_character_map_lookup_( map, glyph_index, map->length );
|
|
243 | +}
|
|
244 | + |
|
245 | +/*prepare to add one more entry to the reverse character map
|
|
246 | + this is a helper for af_reverse_character_map_new*/
|
|
247 | +FT_LOCAL_DEF( FT_Error )
|
|
248 | +af_reverse_character_map_expand( AF_ReverseCharacterMap map, FT_Long *capacity, FT_Memory memory )
|
|
249 | +{
|
|
250 | + FT_Error error;
|
|
251 | + if ( map->length < *capacity )
|
|
252 | + {
|
|
253 | + return FT_Err_Ok;
|
|
254 | + }
|
|
255 | + |
|
256 | + if ( map->length == *capacity )
|
|
257 | + {
|
|
258 | + FT_Long new_capacity = *capacity + *capacity / 2;
|
|
259 | + if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) ) {
|
|
260 | + return error;
|
|
261 | + }
|
|
262 | + *capacity = new_capacity;
|
|
263 | + }
|
|
264 | + |
|
265 | + return FT_Err_Ok;
|
|
266 | +}
|
|
267 | + |
|
268 | +/* qsort compare function for reverse character map */
|
|
269 | +FT_LOCAL_DEF( FT_Int )
|
|
270 | +af_reverse_character_map_entry_compare( const void *a, const void *b ) {
|
|
271 | + const AF_ReverseMapEntry entry_a = *((const AF_ReverseMapEntry *)a);
|
|
272 | + const AF_ReverseMapEntry entry_b = *((const AF_ReverseMapEntry *)b);
|
|
273 | + return entry_a.glyph_index < entry_b.glyph_index ? -1 : entry_a.glyph_index > entry_b.glyph_index ? 1 : 0;
|
|
274 | +}
|
|
275 | + |
|
225 | 276 | FT_LOCAL_DEF( FT_Error )
|
226 | -af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memory memory )
|
|
277 | +af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals globals )
|
|
227 | 278 | {
|
279 | + FT_Face face = globals->face;
|
|
280 | + FT_Memory memory = face->memory;
|
|
228 | 281 | /* Search for a unicode charmap */
|
229 | 282 | /* If there isn't one, create a blank map */
|
230 | 283 | |
284 | + |
|
231 | 285 | /*TODO: use GSUB lookups */
|
232 | 286 | FT_TRACE4(( "af_reverse_character_map_new: building reverse character map\n" ));
|
233 | 287 | |
234 | 288 | FT_Error error;
|
235 | 289 | /* backup face->charmap because find_unicode_charmap sets it */
|
236 | 290 | FT_CharMap old_charmap = face->charmap;
|
237 | - if (( error = find_unicode_charmap( face ) )) {
|
|
291 | + if ( ( error = find_unicode_charmap( face ) ) ) {
|
|
238 | 292 | *map = NULL;
|
239 | 293 | goto Exit;
|
240 | 294 | }
|
... | ... | @@ -244,8 +298,8 @@ af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memo |
244 | 298 | goto Exit;
|
245 | 299 | }
|
246 | 300 | |
247 | - FT_Int capacity = 10;
|
|
248 | - FT_Int size = 0;
|
|
301 | + FT_Long capacity = 10;
|
|
302 | + ( *map )->length = 0;
|
|
249 | 303 | |
250 | 304 | if ( FT_NEW_ARRAY( ( *map )->entries, capacity) )
|
251 | 305 | {
|
... | ... | @@ -265,19 +319,117 @@ af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memo |
265 | 319 | #endif
|
266 | 320 | continue;
|
267 | 321 | }
|
268 | - if ( size == capacity )
|
|
322 | + error = af_reverse_character_map_expand( *map, &capacity, memory );
|
|
323 | + if ( error ) {
|
|
324 | + goto Exit;
|
|
325 | + }
|
|
326 | + |
|
327 | + ( *map )->length++;
|
|
328 | + ( *map )->entries[i].glyph_index = glyph;
|
|
329 | + ( *map )->entries[i].codepoint = codepoint;
|
|
330 | + }
|
|
331 | + |
|
332 | + ft_qsort(
|
|
333 | + ( *map )->entries,
|
|
334 | + ( *map )->length,
|
|
335 | + sizeof( AF_ReverseMapEntry ),
|
|
336 | + af_reverse_character_map_entry_compare
|
|
337 | + );
|
|
338 | + |
|
339 | +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
|
|
340 | + hb_font_t *hb_font = globals->hb_font;
|
|
341 | + hb_face_t *hb_face = hb_font_get_face( hb_font );
|
|
342 | + hb_set_t *feature_indicies = hb_set_create();
|
|
343 | + FT_Long oldlength = ( *map )->length;
|
|
344 | + hb_ot_layout_collect_lookups(
|
|
345 | + hb_face,
|
|
346 | + HB_OT_TAG_GSUB,
|
|
347 | + NULL, /*all scripts*/
|
|
348 | + NULL, /*all languages*/
|
|
349 | + NULL, /*all features*/
|
|
350 | + feature_indicies
|
|
351 | + );
|
|
352 | + hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
|
|
353 | + |
|
354 | + FT_UInt added_entries = 0;
|
|
355 | + while ( hb_set_next(feature_indicies, &feature_index) )
|
|
356 | + {
|
|
357 | + hb_codepoint_t output_glyph_index;
|
|
358 | + /*TODO: find out whether I can reuse set instances instead of recreating*/
|
|
359 | + hb_set_t *glyphs_before = hb_set_create();
|
|
360 | + hb_set_t *glyphs_input = hb_set_create();
|
|
361 | + hb_set_t *glyphs_after = hb_set_create();
|
|
362 | + hb_set_t *glyphs_output = hb_set_create();
|
|
363 | + hb_ot_layout_lookup_collect_glyphs( hb_face, HB_OT_TAG_GSUB,
|
|
364 | + feature_index, glyphs_before,
|
|
365 | + glyphs_input, glyphs_after,
|
|
366 | + glyphs_output);
|
|
367 | + /*Don't consider anything involving context. Just do the
|
|
368 | + simple cases*/
|
|
369 | + if ( hb_set_get_population( glyphs_before ) > 0 ||
|
|
370 | + hb_set_get_population( glyphs_after ) > 0 )
|
|
371 | + {
|
|
372 | + continue;
|
|
373 | + }
|
|
374 | + if ( hb_set_get_population( glyphs_output ) != 1 )
|
|
269 | 375 | {
|
270 | - capacity += capacity / 2;
|
|
271 | - if ( FT_RENEW_ARRAY((*map)->entries, size, capacity) )
|
|
376 | + continue;
|
|
377 | + }
|
|
378 | + |
|
379 | + hb_codepoint_t input_glyph_index = HB_SET_VALUE_INVALID;
|
|
380 | + const AF_AdjustmentDatabaseEntry* input_entry = NULL;
|
|
381 | + FT_UInt32 input_codepoint;
|
|
382 | + while ( hb_set_next( glyphs_input, &input_glyph_index ) ) {
|
|
383 | + input_codepoint = af_reverse_character_map_lookup_( *map, input_glyph_index, oldlength );
|
|
384 | + if ( input_codepoint == 0 )
|
|
385 | + {
|
|
386 | + continue;
|
|
387 | + }
|
|
388 | + const AF_AdjustmentDatabaseEntry* entry = af_adjustment_database_lookup( input_codepoint );
|
|
389 | + if ( entry == NULL )
|
|
272 | 390 | {
|
273 | - goto Exit;
|
|
391 | + continue;
|
|
392 | + }
|
|
393 | + |
|
394 | + if ( input_entry == NULL )
|
|
395 | + {
|
|
396 | + input_entry = entry;
|
|
397 | + }
|
|
398 | + else
|
|
399 | + {
|
|
400 | + if ( !af_adjustment_database_entry_equals( input_entry, entry ) )
|
|
401 | + {
|
|
402 | + goto end;
|
|
403 | + }
|
|
274 | 404 | }
|
275 | 405 | }
|
276 | - size++;
|
|
277 | - ( *map )->entries[i].glyph_index = glyph;
|
|
278 | - ( *map )->entries[i].codepoint = codepoint;
|
|
406 | + |
|
407 | + |
|
408 | + output_glyph_index = HB_SET_VALUE_INVALID;
|
|
409 | + hb_set_next( glyphs_output, &output_glyph_index );
|
|
410 | + |
|
411 | + /*Make pair output glyph index -> input unicode*/
|
|
412 | + error = af_reverse_character_map_expand( *map, &capacity, memory );
|
|
413 | + if ( error ) {
|
|
414 | + goto Exit;
|
|
415 | + }
|
|
416 | + |
|
417 | + FT_Long index = ( *map )->length++;
|
|
418 | + ( *map )->entries[index].glyph_index = output_glyph_index;
|
|
419 | + ( *map )->entries[index].codepoint = input_codepoint;
|
|
420 | + FT_TRACE4(("Adding entry: %d -> %d\n", output_glyph_index, input_codepoint));
|
|
421 | + |
|
422 | + end: ;
|
|
279 | 423 | }
|
280 | - ( *map )->length = size;
|
|
424 | + |
|
425 | + ft_qsort(
|
|
426 | + ( *map )->entries,
|
|
427 | + ( *map )->length,
|
|
428 | + sizeof( AF_ReverseMapEntry ),
|
|
429 | + af_reverse_character_map_entry_compare
|
|
430 | + );
|
|
431 | + |
|
432 | +#endif /*FT_CONFIG_OPTION_USE_HARFBUZZ*/
|
|
281 | 433 | |
282 | 434 | Exit:
|
283 | 435 | face->charmap = old_charmap;
|
... | ... | @@ -293,7 +445,7 @@ Exit: |
293 | 445 | }
|
294 | 446 | #ifdef FT_DEBUG_LEVEL_TRACE
|
295 | 447 | FT_TRACE4(( " reverse character map built successfully"\
|
296 | - " with %d entries and %d failed lookups.\n", size, failed_lookups ));
|
|
448 | + " with %d entries and %d failed lookups.\n", (*map)->length, failed_lookups ));
|
|
297 | 449 | #endif
|
298 | 450 | return FT_Err_Ok;
|
299 | 451 | }
|
1 | 1 | #ifndef AFADJUST_H_
|
2 | 2 | #define AFADJUST_H_
|
3 | - |
|
4 | 3 | #include <freetype/fttypes.h>
|
4 | +#include "aftypes.h"
|
|
5 | +#include "afglobal.h"
|
|
5 | 6 | |
6 | 7 | FT_BEGIN_HEADER
|
7 | 8 | |
... | ... | @@ -28,10 +29,6 @@ typedef struct AF_AdjustmentDatabaseEntry_ |
28 | 29 | AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type;
|
29 | 30 | } AF_AdjustmentDatabaseEntry;
|
30 | 31 | |
31 | -struct AF_ReverseCharacterMap_;
|
|
32 | - |
|
33 | -typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap;
|
|
34 | - |
|
35 | 32 | FT_LOCAL(AF_VerticalSeparationAdjustmentType)
|
36 | 33 | af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int glyph_index );
|
37 | 34 | |
... | ... | @@ -43,7 +40,7 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index |
43 | 40 | |
44 | 41 | /*allocate and populate the reverse character map, using the character map within the face*/
|
45 | 42 | FT_LOCAL( FT_Error )
|
46 | -af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memory memory );
|
|
43 | +af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals globals );
|
|
47 | 44 | |
48 | 45 | /*free the reverse character map*/
|
49 | 46 | FT_LOCAL( FT_Error )
|
... | ... | @@ -1154,7 +1154,7 @@ |
1154 | 1154 | }
|
1155 | 1155 | af_latin_metrics_check_digits( metrics, face );
|
1156 | 1156 | |
1157 | - af_reverse_character_map_new( face, &metrics->root.reverse_charmap, face->memory );
|
|
1157 | + af_reverse_character_map_new( &metrics->root.reverse_charmap, metrics->root.globals );
|
|
1158 | 1158 | }
|
1159 | 1159 | |
1160 | 1160 | Exit:
|
... | ... | @@ -2799,6 +2799,87 @@ af_find_highest_contour( AF_GlyphHints hints ) { |
2799 | 2799 | return highest_contour;
|
2800 | 2800 | }
|
2801 | 2801 | |
2802 | +static void
|
|
2803 | +af_remove_segments_containing_point(AF_GlyphHints hints, AF_Point point)
|
|
2804 | +{
|
|
2805 | + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
|
|
2806 | + AF_Segment segments = axis->segments;
|
|
2807 | + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
|
|
2808 | + for ( FT_Int i = 0; i < axis->num_segments; i++ )
|
|
2809 | + {
|
|
2810 | + AF_Segment seg = &segments[i];
|
|
2811 | + FT_Bool remove = 0;
|
|
2812 | + for ( AF_Point p = seg->first; p <= seg->last; p = p->next )
|
|
2813 | + {
|
|
2814 | + if ( p == point )
|
|
2815 | + {
|
|
2816 | + remove = 1;
|
|
2817 | + break;
|
|
2818 | + }
|
|
2819 | + }
|
|
2820 | + |
|
2821 | + if ( remove )
|
|
2822 | + {
|
|
2823 | + FT_TRACE4(("Removing segment %d\n", i));
|
|
2824 | + /* first, check the first and last fields of the edge */
|
|
2825 | + AF_Edge edge = seg->edge;
|
|
2826 | + if ( edge->first == seg && edge->last == seg )
|
|
2827 | + {
|
|
2828 | + /* The edge only consists of the segment to be removed. remove the edge*/
|
|
2829 | + *edge = axis->edges[--axis->num_edges];
|
|
2830 | + }
|
|
2831 | + else
|
|
2832 | + {
|
|
2833 | + if ( edge->first == seg )
|
|
2834 | + {
|
|
2835 | + edge->first = seg->edge_next;
|
|
2836 | + }
|
|
2837 | + if ( edge->last == seg )
|
|
2838 | + {
|
|
2839 | + edge->last = edge->first;
|
|
2840 | + while ( edge->last->edge_next != seg )
|
|
2841 | + {
|
|
2842 | + edge->last = edge->last->edge_next;
|
|
2843 | + }
|
|
2844 | + }
|
|
2845 | + }
|
|
2846 | + |
|
2847 | + /* Now, delete the segment */
|
|
2848 | + *seg = axis->segments[--axis->num_segments];
|
|
2849 | + |
|
2850 | + i--; /* we have to check the new segment at this position */
|
|
2851 | + }
|
|
2852 | + }
|
|
2853 | +}
|
|
2854 | + |
|
2855 | +static void
|
|
2856 | +af_latin_stretch_tildes_step_2( AF_GlyphHints hints,
|
|
2857 | + FT_Int glyph_index,
|
|
2858 | + AF_ReverseCharacterMap reverse_charmap )
|
|
2859 | +{
|
|
2860 | + if (af_lookup_tilde_correction_type(reverse_charmap, glyph_index)) {
|
|
2861 | + FT_Int highest_contour = af_find_highest_contour(hints);
|
|
2862 | + AF_Point first_point = hints->contours[highest_contour];
|
|
2863 | + |
|
2864 | + /* search for any curve tips that are on a y extrema, and delete any
|
|
2865 | + segments that contain this point.*/
|
|
2866 | + AF_Point p = first_point;
|
|
2867 | + |
|
2868 | + do
|
|
2869 | + {
|
|
2870 | + p = p->next;
|
|
2871 | + if ( /*!(p->flags & AF_FLAG_CONTROL)
|
|
2872 | + && p->prev->y == p->y && p->next->y == p->y
|
|
2873 | + && p->prev->flags & AF_FLAG_CONTROL
|
|
2874 | + && p->next->flags & AF_FLAG_CONTROL*/ 1 )
|
|
2875 | + {
|
|
2876 | + af_remove_segments_containing_point( hints, p );
|
|
2877 | + }
|
|
2878 | + } while ( p != first_point );
|
|
2879 | + }
|
|
2880 | + |
|
2881 | +}
|
|
2882 | + |
|
2802 | 2883 | void
|
2803 | 2884 | af_latin_stretch_tildes( AF_GlyphHints hints,
|
2804 | 2885 | FT_Int glyph_index,
|
... | ... | @@ -2814,82 +2895,99 @@ af_latin_stretch_tildes( AF_GlyphHints hints, |
2814 | 2895 | FT_Short min_fy, max_fy;
|
2815 | 2896 | min_fy = max_fy = p->fy;
|
2816 | 2897 | |
2817 | - do {
|
|
2898 | + do
|
|
2899 | + {
|
|
2818 | 2900 | p = p->next;
|
2819 | - if ( p->y < min_y ) {
|
|
2901 | + if ( p->y < min_y )
|
|
2902 | + {
|
|
2820 | 2903 | min_y = p->y;
|
2821 | 2904 | }
|
2822 | - if ( p->y > max_y ) {
|
|
2905 | + if ( p->y > max_y )
|
|
2906 | + {
|
|
2823 | 2907 | max_y = p->y;
|
2824 | 2908 | }
|
2825 | 2909 | |
2826 | - if ( p->fy < min_fy ) {
|
|
2910 | + if ( p->fy < min_fy )
|
|
2911 | + {
|
|
2827 | 2912 | min_fy = p->fy;
|
2828 | 2913 | }
|
2829 | 2914 | |
2830 | - if ( p->fy > max_fy ) {
|
|
2915 | + if ( p->fy > max_fy )
|
|
2916 | + {
|
|
2831 | 2917 | max_fy = p->fy;
|
2832 | 2918 | }
|
2833 | 2919 | |
2834 | - } while ( p != first_point );
|
|
2920 | + }
|
|
2921 | + while ( p != first_point );
|
|
2835 | 2922 | |
2836 | 2923 | FT_Pos min_measurement = 32000;
|
2837 | 2924 | FT_UInt measurements_taken = 0;
|
2838 | 2925 | |
2839 | - do {
|
|
2926 | + do
|
|
2927 | + {
|
|
2840 | 2928 | p = p->next;
|
2841 | 2929 | if ( !(p->flags & AF_FLAG_CONTROL)
|
2842 | 2930 | && p->prev->y == p->y && p->next->y == p->y
|
2843 | 2931 | && p->y != min_y && p->y != max_y
|
2844 | 2932 | && p->prev->flags & AF_FLAG_CONTROL
|
2845 | - && p->next->flags & AF_FLAG_CONTROL ) {
|
|
2933 | + && p->next->flags & AF_FLAG_CONTROL )
|
|
2934 | + {
|
|
2846 | 2935 | /* This point could be a candidate. Find the next and previous on-curve */
|
2847 | 2936 | /* points, and make sure they are both either above or below the point, */
|
2848 | 2937 | /* Then make the measurement */
|
2849 | 2938 | AF_Point prevOn = p->prev;
|
2850 | 2939 | AF_Point nextOn = p->next;
|
2851 | - while ( prevOn->flags & AF_FLAG_CONTROL ) {
|
|
2940 | + while ( prevOn->flags & AF_FLAG_CONTROL )
|
|
2941 | + {
|
|
2852 | 2942 | prevOn = prevOn->prev;
|
2853 | 2943 | }
|
2854 | - while ( nextOn->flags & AF_FLAG_CONTROL ) {
|
|
2944 | + while ( nextOn->flags & AF_FLAG_CONTROL )
|
|
2945 | + {
|
|
2855 | 2946 | nextOn = nextOn->next;
|
2856 | 2947 | }
|
2857 | 2948 | FT_Pos measurement;
|
2858 | - if ( nextOn->y > p->y && prevOn->y > p->y ) {
|
|
2949 | + if ( nextOn->y > p->y && prevOn->y > p->y )
|
|
2950 | + {
|
|
2859 | 2951 | measurement = p->y - min_y;
|
2860 | - } else if ( nextOn->y < p->y && prevOn->y < p->y ) {
|
|
2952 | + }
|
|
2953 | + else if ( nextOn->y < p->y && prevOn->y < p->y )
|
|
2954 | + {
|
|
2861 | 2955 | measurement = max_y - p->y;
|
2862 | - } else {
|
|
2956 | + }
|
|
2957 | + else
|
|
2958 | + {
|
|
2863 | 2959 | continue;
|
2864 | 2960 | }
|
2865 | 2961 | |
2866 | - if (measurement < min_measurement) {
|
|
2962 | + if (measurement < min_measurement)
|
|
2963 | + {
|
|
2867 | 2964 | min_measurement = measurement;
|
2868 | 2965 | }
|
2869 | 2966 | measurements_taken++;
|
2870 | 2967 | }
|
2871 | 2968 | |
2872 | - } while ( p != first_point );
|
|
2969 | + }
|
|
2970 | + while ( p != first_point );
|
|
2873 | 2971 | |
2874 | 2972 | FT_Pos height = max_y - min_y;
|
2875 | 2973 | |
2876 | 2974 | FT_Pos target_height = min_measurement + 64;
|
2877 | - if ( height >= target_height ) {
|
|
2975 | + if ( height >= target_height )
|
|
2976 | + {
|
|
2878 | 2977 | return;
|
2879 | 2978 | }
|
2880 | 2979 | |
2881 | 2980 | p = first_point;
|
2882 | - do {
|
|
2981 | + do
|
|
2982 | + {
|
|
2883 | 2983 | p = p->next;
|
2884 | - /*if ( p->flags & AF_FLAG_CONTROL ) {
|
|
2885 | - continue;
|
|
2886 | - }*/
|
|
2887 | 2984 | p->y = ((p->y - min_y) * target_height / height) + min_y;
|
2888 | 2985 | p->fy = ((p->fy - min_fy) * target_height / height) + min_fy;
|
2889 | 2986 | p->oy = p->y;
|
2890 | 2987 | if ( !(p->flags & AF_FLAG_CONTROL) )
|
2891 | 2988 | p->flags |= AF_FLAG_TOUCH_Y;
|
2892 | - } while ( p != first_point );
|
|
2989 | + }
|
|
2990 | + while ( p != first_point );
|
|
2893 | 2991 | |
2894 | 2992 | FT_TRACE4(( "af_latin_stretch_tildes: Height: %d, measurement: %d, measurements taken: %d\n", height, min_measurement, measurements_taken ));
|
2895 | 2993 | |
... | ... | @@ -2898,18 +2996,73 @@ af_latin_stretch_tildes( AF_GlyphHints hints, |
2898 | 2996 | p = first_point;
|
2899 | 2997 | do {
|
2900 | 2998 | p = p->next;
|
2901 | - if ( p->y < new_min_y ) {
|
|
2999 | + if ( p->y < new_min_y )
|
|
3000 | + {
|
|
2902 | 3001 | new_min_y = p->y;
|
2903 | 3002 | }
|
2904 | - if ( p->y > new_max_y ) {
|
|
3003 | + if ( p->y > new_max_y )
|
|
3004 | + {
|
|
2905 | 3005 | new_max_y = p->y;
|
2906 | 3006 | }
|
2907 | - } while ( p != first_point );
|
|
3007 | + }
|
|
3008 | + while ( p != first_point );
|
|
3009 | + |
|
3010 | + FT_TRACE4(( "af_latin_stretch_tildes: New height: %d\n, miny: %d, maxy: %d", new_max_y - new_min_y, new_min_y, new_max_y));
|
|
3011 | + }
|
|
3012 | +}
|
|
3013 | + |
|
3014 | +/*True if the given contour overlaps horizontally with the bounding box
|
|
3015 | + Of all other contours combined.
|
|
3016 | + This is a helper for af_glyph_hints_apply_vertical_separation_adjustments */
|
|
3017 | +FT_Bool
|
|
3018 | +af_check_contour_horizontal_overlap( AF_GlyphHints hints,
|
|
3019 | + FT_Int contour_index )
|
|
3020 | +{
|
|
3021 | + FT_Pos contour_max_x = -32000;
|
|
3022 | + FT_Pos contour_min_x = 32000;
|
|
3023 | + FT_Pos others_max_x = -32000;
|
|
3024 | + FT_Pos others_min_x = 32000;
|
|
2908 | 3025 | |
2909 | - FT_TRACE4(( "af_latin_stretch_tildes_merp: New height: %d\n, miny: %d, maxy: %d", new_max_y - new_min_y, new_min_y, new_max_y));
|
|
3026 | + for ( FT_Int contour = 0; contour < hints->num_contours; contour++ )
|
|
3027 | + {
|
|
3028 | + AF_Point first_point = hints->contours[contour];
|
|
3029 | + AF_Point p = first_point;
|
|
3030 | + |
|
3031 | + do
|
|
3032 | + {
|
|
3033 | + p = p->next;
|
|
3034 | + if ( contour == contour_index )
|
|
3035 | + {
|
|
3036 | + if ( p->x < contour_min_x )
|
|
3037 | + {
|
|
3038 | + contour_min_x = p->x;
|
|
3039 | + }
|
|
3040 | + if ( p->x > contour_max_x )
|
|
3041 | + {
|
|
3042 | + contour_max_x = p->x;
|
|
3043 | + }
|
|
3044 | + }
|
|
3045 | + else /* ( contour != contour_index ) */
|
|
3046 | + {
|
|
3047 | + if ( p->x < others_min_x )
|
|
3048 | + {
|
|
3049 | + others_min_x = p->x;
|
|
3050 | + }
|
|
3051 | + if ( p->x > others_max_x )
|
|
3052 | + {
|
|
3053 | + others_max_x = p->x;
|
|
3054 | + }
|
|
3055 | + }
|
|
3056 | + }
|
|
3057 | + while (p != first_point);
|
|
2910 | 3058 | }
|
2911 | 3059 | |
3060 | + FT_Bool horizontal_overlap =
|
|
3061 | + (others_min_x <= contour_max_x && contour_max_x <= others_max_x) ||
|
|
3062 | + (others_min_x <= contour_min_x && contour_min_x <= others_max_x) ||
|
|
3063 | + (contour_max_x >= others_max_x && contour_min_x <= others_min_x);
|
|
2912 | 3064 | |
3065 | + return horizontal_overlap;
|
|
2913 | 3066 | }
|
2914 | 3067 | |
2915 | 3068 | void
|
... | ... | @@ -2961,6 +3114,15 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
2961 | 3114 | }
|
2962 | 3115 | }
|
2963 | 3116 | |
3117 | + /* check for a horizontal overtap between the top contour and the rest */
|
|
3118 | + /* if there is no overlap, do not adjust. */
|
|
3119 | + |
|
3120 | + FT_Bool horizontal_overlap = af_check_contour_horizontal_overlap( hints, highest_contour );
|
|
3121 | + if (!horizontal_overlap) {
|
|
3122 | + FT_TRACE4(( " Top contour does not horizontally overlap with other contours. Skipping adjustment.\n" ));
|
|
3123 | + return;
|
|
3124 | + }
|
|
3125 | + |
|
2964 | 3126 | /* If there are any contours that have a maximum y coordinate */
|
2965 | 3127 | /* greater or equal to the minimum y coordinate of the previously found highest*/
|
2966 | 3128 | /* contour, bump the high contour up until the distance is one pixel */
|
... | ... | @@ -2995,9 +3157,13 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
2995 | 3157 | }
|
2996 | 3158 | }
|
2997 | 3159 | |
2998 | - FT_TRACE4(( " Pushing top contour %d units up\n", adjustment_amount ));
|
|
2999 | - if ( adjustment_amount > 0 )
|
|
3160 | + if ( adjustment_amount > 64 )
|
|
3161 | + {
|
|
3162 | + FT_TRACE4(( " Calculated adjustment amount %d was more than threshold of 64. Not adjusting\n", adjustment_amount ));
|
|
3163 | + }
|
|
3164 | + else if ( adjustment_amount > 0 )
|
|
3000 | 3165 | {
|
3166 | + FT_TRACE4(( " Pushing top contour %d units up\n", adjustment_amount ));
|
|
3001 | 3167 | af_move_contour_vertically(hints->contours[highest_contour], adjustment_amount);
|
3002 | 3168 | }
|
3003 | 3169 | } else if ( af_lookup_vertical_seperation_type( reverse_charmap, glyph_index ) == AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN
|
... | ... | @@ -3065,9 +3231,13 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
3065 | 3231 | adjustment_amount = 64 - ( min_y - lowest_max_y );
|
3066 | 3232 | }
|
3067 | 3233 | |
3068 | - FT_TRACE4(( " Pushing bottom contour %d units down\n", adjustment_amount ));
|
|
3069 | - if ( adjustment_amount > 0 )
|
|
3234 | + if ( adjustment_amount > 64 )
|
|
3235 | + {
|
|
3236 | + FT_TRACE4(( " Calculated adjustment amount %d was more than threshold of 64. Not adjusting\n", adjustment_amount ));
|
|
3237 | + }
|
|
3238 | + else if ( adjustment_amount > 0 )
|
|
3070 | 3239 | {
|
3240 | + FT_TRACE4(( " Pushing bottom contour %d units down\n", adjustment_amount ));
|
|
3071 | 3241 | af_move_contour_vertically(hints->contours[lowest_contour], -adjustment_amount);
|
3072 | 3242 | }
|
3073 | 3243 | }
|
... | ... | @@ -3900,7 +4070,6 @@ static void traceheight(FT_UInt num, AF_GlyphHints hints) { |
3900 | 4070 | |
3901 | 4071 | FT_Pos min_y, max_y;
|
3902 | 4072 | min_y = max_y = p->y;
|
3903 | - FT_UInt candidates = 0;
|
|
3904 | 4073 | |
3905 | 4074 | do {
|
3906 | 4075 | p = p->next;
|
... | ... | @@ -3952,12 +4121,13 @@ static void traceheight(FT_UInt num, AF_GlyphHints hints) { |
3952 | 4121 | |
3953 | 4122 | if ( AF_HINTS_DO_VERTICAL( hints ) )
|
3954 | 4123 | {
|
3955 | - af_latin_stretch_tildes( hints, glyph_index, metrics->root.reverse_charmap );
|
|
4124 | + /*af_latin_stretch_tildes( hints, glyph_index, metrics->root.reverse_charmap );*/
|
|
3956 | 4125 | axis = &metrics->axis[AF_DIMENSION_VERT];
|
3957 | 4126 | error = af_latin_hints_detect_features( hints,
|
3958 | 4127 | axis->width_count,
|
3959 | 4128 | axis->widths,
|
3960 | 4129 | AF_DIMENSION_VERT );
|
4130 | + af_latin_stretch_tildes_step_2( hints, glyph_index, metrics->root.reverse_charmap );
|
|
3961 | 4131 | if ( error )
|
3962 | 4132 | goto Exit;
|
3963 | 4133 |
... | ... | @@ -39,7 +39,6 @@ |
39 | 39 | #include <freetype/internal/ftdebug.h>
|
40 | 40 | |
41 | 41 | #include "afblue.h"
|
42 | -#include "afadjust.h"
|
|
43 | 42 | |
44 | 43 | #ifdef FT_DEBUG_AUTOFIT
|
45 | 44 | #include FT_CONFIG_STANDARD_LIBRARY_H
|
... | ... | @@ -411,6 +410,10 @@ extern void* af_debug_hints_; |
411 | 410 | /* specific to writing systems derive their structures from it, for */
|
412 | 411 | /* example `AF_LatinMetrics'. */
|
413 | 412 | |
413 | + struct AF_ReverseCharacterMap_;
|
|
414 | + |
|
415 | + typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap;
|
|
416 | + |
|
414 | 417 | typedef struct AF_StyleMetricsRec_
|
415 | 418 | {
|
416 | 419 | AF_StyleClass style_class;
|