freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] gsoc-craig-2023 86e5080e8 2/2: Add support for simple cases


From: Werner Lemberg
Subject: [freetype2] gsoc-craig-2023 86e5080e8 2/2: Add support for simple cases of GSUB lookups
Date: Sat, 26 Aug 2023 23:00:36 -0400 (EDT)

branch: gsoc-craig-2023
commit 86e5080e863001fb6b79f78774a5af3774ae62f2
Author: Craig White <gerzytet@gmail.com>
Commit: Craig White <gerzytet@gmail.com>

    Add support for simple cases of GSUB lookups
---
 src/autofit/afadjust.c | 181 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/autofit/afadjust.h |   9 +--
 src/autofit/aflatin.c  |   2 +-
 src/autofit/aftypes.h  |   5 +-
 4 files changed, 173 insertions(+), 24 deletions(-)

diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c
index 9a23da873..7c684be3e 100644
--- a/src/autofit/afadjust.c
+++ b/src/autofit/afadjust.c
@@ -8,6 +8,11 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  afadjust
 
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    #include <hb.h>
+    #include <hb-ot.h>
+#endif
+
 /*TODO: find out whether capital u/U with accent entries are needed*/
 /*the accent won't merge with the rest of the glyph because the accent mark is 
sitting above empty space*/
 /*
@@ -16,7 +21,7 @@
 FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry )
 adjustment_database[] =
 {
-    {0x21,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* ! */
+    {0x21,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* ! *
     {0x69,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* i */
     {0x6A,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* j */
     {0xA1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*Inverted Exclamation 
Mark*/
@@ -133,6 +138,12 @@ adjustment_database[] =
     {0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}
 };
 
+FT_LOCAL_DEF( FT_Bool )
+af_adjustment_database_entry_equals( const AF_AdjustmentDatabaseEntry* a, 
const AF_AdjustmentDatabaseEntry* b )
+{
+    return a->codepoint == b->codepoint && 
a->vertical_separation_adjustment_type == 
b->vertical_separation_adjustment_type;
+}
+
 /*Helper function: get the adjustment database entry for a codepoint*/
 FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* )
 af_adjustment_database_lookup( FT_UInt32 codepoint ) {
@@ -190,12 +201,12 @@ typedef struct AF_ReverseMapEntry_
 
 typedef struct AF_ReverseCharacterMap_
 {
-    FT_UInt length;
+    FT_Long length;
     AF_ReverseMapEntry *entries;
 } AF_ReverseCharacterMap_Rec;
 
 FT_LOCAL_DEF( FT_UInt32 )
-af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int 
glyph_index )
+af_reverse_character_map_lookup_( AF_ReverseCharacterMap map, FT_Int 
glyph_index, FT_Long length )
 {
     if ( map == NULL )
     {
@@ -225,19 +236,59 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap 
map, FT_Int glyph_index
     return 0;
 }
 
+FT_LOCAL_DEF( FT_UInt32 )
+af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int 
glyph_index )
+{
+    return af_reverse_character_map_lookup_( map, glyph_index, map->length );
+}
+
+/*prepare to add one more entry to the reverse character map
+  this is a helper for af_reverse_character_map_new*/
+FT_LOCAL_DEF( FT_Error )
+af_reverse_character_map_expand( AF_ReverseCharacterMap map, FT_Long 
*capacity, FT_Memory memory )
+{
+    FT_Error error;
+    if ( map->length < *capacity )
+    {
+        return FT_Err_Ok;
+    }
+
+    if ( map->length == *capacity )
+    {
+        FT_Long new_capacity = *capacity + *capacity / 2;
+        if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) ) {
+            return error;
+        }
+        *capacity = new_capacity;
+    }
+
+    return FT_Err_Ok;
+}
+
+/* qsort compare function for reverse character map */
+FT_LOCAL_DEF( FT_Int )
+af_reverse_character_map_entry_compare( const void *a, const void *b ) {
+    const AF_ReverseMapEntry entry_a = *((const AF_ReverseMapEntry *)a);
+    const AF_ReverseMapEntry entry_b = *((const AF_ReverseMapEntry *)b);
+    return entry_a.glyph_index < entry_b.glyph_index ? -1 : 
entry_a.glyph_index > entry_b.glyph_index ? 1 : 0;
+}
+
 FT_LOCAL_DEF( FT_Error )
-af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, 
FT_Memory memory )
+af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals 
globals )
 {
+    FT_Face face = globals->face;
+    FT_Memory memory = face->memory;
     /* Search for a unicode charmap */
     /* If there isn't one, create a blank map */
 
+
     /*TODO: use GSUB lookups    */
     FT_TRACE4(( "af_reverse_character_map_new: building reverse character 
map\n" ));
 
     FT_Error error;
     /* backup face->charmap because find_unicode_charmap sets it */
     FT_CharMap old_charmap = face->charmap;
-    if (( error = find_unicode_charmap( face ) )) {
+    if ( ( error = find_unicode_charmap( face ) ) ) {
         *map = NULL;
         goto Exit;
     }
@@ -247,8 +298,8 @@ af_reverse_character_map_new( FT_Face face, 
AF_ReverseCharacterMap *map, FT_Memo
         goto Exit;
     }
 
-    FT_Int capacity = 10;
-    FT_Int size = 0;
+    FT_Long capacity = 10;
+    ( *map )->length = 0;
 
     if ( FT_NEW_ARRAY( ( *map )->entries, capacity) )
     {
@@ -268,19 +319,117 @@ af_reverse_character_map_new( FT_Face face, 
AF_ReverseCharacterMap *map, FT_Memo
 #endif
             continue;
         }
-        if ( size == capacity )
+        error = af_reverse_character_map_expand( *map, &capacity, memory );
+        if ( error ) {
+            goto Exit;
+        }
+
+        ( *map )->length++;
+        ( *map )->entries[i].glyph_index = glyph;
+        ( *map )->entries[i].codepoint = codepoint;
+    }
+
+    ft_qsort(
+        ( *map )->entries,
+        ( *map )->length,
+        sizeof( AF_ReverseMapEntry ),
+        af_reverse_character_map_entry_compare
+    );
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+    hb_font_t *hb_font = globals->hb_font;
+    hb_face_t *hb_face = hb_font_get_face( hb_font );
+    hb_set_t  *feature_indicies = hb_set_create();
+    FT_Long oldlength = ( *map )->length;
+    hb_ot_layout_collect_lookups(
+        hb_face,
+        HB_OT_TAG_GSUB,
+        NULL, /*all scripts*/
+        NULL, /*all languages*/
+        NULL, /*all features*/
+        feature_indicies
+    );
+    hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
+
+    FT_UInt added_entries = 0;
+    while ( hb_set_next(feature_indicies, &feature_index) )
+    {
+        hb_codepoint_t output_glyph_index;
+        /*TODO: find out whether I can reuse set instances instead of 
recreating*/
+        hb_set_t *glyphs_before = hb_set_create();
+        hb_set_t *glyphs_input = hb_set_create();
+        hb_set_t *glyphs_after = hb_set_create();
+        hb_set_t *glyphs_output = hb_set_create();
+        hb_ot_layout_lookup_collect_glyphs( hb_face, HB_OT_TAG_GSUB,
+                                            feature_index, glyphs_before,
+                                            glyphs_input, glyphs_after,
+                                            glyphs_output);
+        /*Don't consider anything involving context.  Just do the
+          simple cases*/
+        if ( hb_set_get_population( glyphs_before ) > 0 ||
+             hb_set_get_population( glyphs_after ) > 0 )
+        {
+            continue;
+        }
+        if ( hb_set_get_population( glyphs_output ) != 1 )
         {
-            capacity += capacity / 2;
-            if ( FT_RENEW_ARRAY((*map)->entries, size, capacity) )
+            continue;
+        }
+
+        hb_codepoint_t input_glyph_index = HB_SET_VALUE_INVALID;
+        const AF_AdjustmentDatabaseEntry* input_entry = NULL;
+        FT_UInt32 input_codepoint;
+        while ( hb_set_next( glyphs_input, &input_glyph_index ) ) {
+            input_codepoint = af_reverse_character_map_lookup_( *map, 
input_glyph_index, oldlength );
+            if ( input_codepoint == 0 )
+            {
+                continue;
+            }
+            const AF_AdjustmentDatabaseEntry* entry = 
af_adjustment_database_lookup( input_codepoint );
+            if ( entry == NULL )
             {
-                goto Exit;
+                continue;
+            }
+
+            if ( input_entry == NULL )
+            {
+                input_entry = entry;
+            }
+            else
+            {
+                if ( !af_adjustment_database_entry_equals( input_entry, entry 
) )
+                {
+                    goto end;
+                }
             }
         }
-        size++;
-        ( *map )->entries[i].glyph_index = glyph;
-        ( *map )->entries[i].codepoint = codepoint;
+
+
+        output_glyph_index = HB_SET_VALUE_INVALID;
+        hb_set_next( glyphs_output, &output_glyph_index );
+
+        /*Make pair output glyph index -> input unicode*/
+        error = af_reverse_character_map_expand( *map, &capacity, memory );
+        if ( error ) {
+            goto Exit;
+        }
+
+        FT_Long index = ( *map )->length++;
+        ( *map )->entries[index].glyph_index = output_glyph_index;
+        ( *map )->entries[index].codepoint = input_codepoint;
+        FT_TRACE4(("Adding entry: %d -> %d\n", output_glyph_index, 
input_codepoint));
+
+        end: ;
     }
-    ( *map )->length = size;
+
+    ft_qsort(
+        ( *map )->entries,
+        ( *map )->length,
+        sizeof( AF_ReverseMapEntry ),
+        af_reverse_character_map_entry_compare
+    );
+
+#endif /*FT_CONFIG_OPTION_USE_HARFBUZZ*/
 
 Exit:
     face->charmap = old_charmap;
@@ -296,7 +445,7 @@ Exit:
     }
 #ifdef FT_DEBUG_LEVEL_TRACE
     FT_TRACE4(( "    reverse character map built successfully"\
-                " with %d entries and %d failed lookups.\n", size, 
failed_lookups ));
+                " with %d entries and %d failed lookups.\n", (*map)->length, 
failed_lookups ));
 #endif
     return FT_Err_Ok;
 }
diff --git a/src/autofit/afadjust.h b/src/autofit/afadjust.h
index 179f4fd5e..3ac24ae83 100644
--- a/src/autofit/afadjust.h
+++ b/src/autofit/afadjust.h
@@ -1,7 +1,8 @@
 #ifndef AFADJUST_H_
 #define AFADJUST_H_
-
 #include <freetype/fttypes.h>
+#include "aftypes.h"
+#include "afglobal.h"
 
 FT_BEGIN_HEADER
 
@@ -28,10 +29,6 @@ typedef struct AF_AdjustmentDatabaseEntry_
   AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type;
 } AF_AdjustmentDatabaseEntry;
 
-struct AF_ReverseCharacterMap_;
-
-typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap;
-
 FT_LOCAL(AF_VerticalSeparationAdjustmentType)
 af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int 
glyph_index );
 
@@ -43,7 +40,7 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap map, 
FT_Int glyph_index
 
 /*allocate and populate the reverse character map, using the character map 
within the face*/
 FT_LOCAL( FT_Error )
-af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, 
FT_Memory memory );
+af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals 
globals );
 
 /*free the reverse character map*/
 FT_LOCAL( FT_Error )
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 690f2ada3..ce5da7feb 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -1154,7 +1154,7 @@
       }
       af_latin_metrics_check_digits( metrics, face );
 
-      af_reverse_character_map_new( face, &metrics->root.reverse_charmap, 
face->memory );
+      af_reverse_character_map_new( &metrics->root.reverse_charmap, 
metrics->root.globals );
     }
 
   Exit:
diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h
index aca173567..f04e77826 100644
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -39,7 +39,6 @@
 #include <freetype/internal/ftdebug.h>
 
 #include "afblue.h"
-#include "afadjust.h"
 
 #ifdef FT_DEBUG_AUTOFIT
 #include FT_CONFIG_STANDARD_LIBRARY_H
@@ -411,6 +410,10 @@ extern void*  af_debug_hints_;
   /* specific to writing systems derive their structures from it, for      */
   /* example `AF_LatinMetrics'.                                            */
 
+  struct AF_ReverseCharacterMap_;
+
+  typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap;
+
   typedef struct  AF_StyleMetricsRec_
   {
     AF_StyleClass   style_class;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]