freetype-commit
[Top][All Lists]
Advanced

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

[freetype2] gsoc-craig-2023 f8e996bfb: Prototype adjustment database, re


From: Werner Lemberg
Subject: [freetype2] gsoc-craig-2023 f8e996bfb: Prototype adjustment database, reverse character lookup, and fixes for a few characters
Date: Sun, 4 Jun 2023 15:32:22 -0400 (EDT)

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

    Prototype adjustment database, reverse character lookup, and fixes for a 
few characters
---
 src/autofit/afadjust.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/autofit/afadjust.h |  47 +++++++++++++++++
 src/autofit/aflatin.c  |  90 +++++++++++++++++++++++++++++--
 src/autofit/aftypes.h  |   2 +
 src/autofit/autofit.c  |   1 +
 src/base/ftobjs.c      |   1 -
 6 files changed, 277 insertions(+), 4 deletions(-)

diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c
new file mode 100644
index 000000000..00a21a447
--- /dev/null
+++ b/src/autofit/afadjust.c
@@ -0,0 +1,140 @@
+#include "afadjust.h"
+#include <freetype/freetype.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftmemory.h>
+
+#define AF_ADJUSTMENT_DATABASE_LENGTH 12
+
+/*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*/
+FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry )
+adjustment_database[AF_ADJUSTMENT_DATABASE_LENGTH] = {
+    {'i',   AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE},
+    {'j',   AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE},
+    {0xC8,  AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*E with grave*/
+    {0xCC,  AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*I with grave*/
+    {0xD9,  AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*U with grave*/
+    {0xE0,  AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*a with grave*/
+    {0xEC,  AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*i with grave*/
+    {0x114, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*E with macron*/
+    {0x12A, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*I with macron*/
+    {0x12B, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*i with macron*/
+    {0x16A, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*U with macron*/
+    {0x16B, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}  /*u with macron*/
+    /*TODO: find out why E won't work, even though it appears to be 
one-on-one*/
+};
+
+/*Helper function: get the adjustment database entry for a codepoint*/
+FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* )
+af_adjustment_database_lookup( FT_UInt32 codepoint ) {
+    for ( FT_Int entry = 0; entry < AF_ADJUSTMENT_DATABASE_LENGTH; entry++ ) {
+        if ( adjustment_database[entry].codepoint == codepoint ) {
+            return &adjustment_database[entry];
+        }
+    }
+
+    return NULL;
+}
+
+FT_LOCAL_DEF( AF_VerticalSeparationAdjustmentType )
+af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int 
glyph_index ) {
+    FT_UInt32 codepoint = af_reverse_character_map_lookup( map, glyph_index );
+    const AF_AdjustmentDatabaseEntry *entry = af_adjustment_database_lookup( 
codepoint );
+    if ( entry == NULL ) {
+        return AF_VERTICAL_ADJUSTMENT_NONE;
+    }
+    return entry->vertical_separation_adjustment_type;
+}
+
+typedef struct AF_ReverseMapEntry_ {
+    FT_Int glyph_index;
+    FT_UInt32 codepoint;
+} AF_ReverseMapEntry;
+
+typedef struct AF_ReverseCharacterMap_ {
+    FT_UInt length;
+    AF_ReverseMapEntry *entries;
+} AF_ReverseCharacterMap_Rec;
+
+FT_LOCAL_DEF(FT_UInt32)
+af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int 
glyph_index ) {
+    if ( map == NULL ) {
+        return 0;
+    }
+
+    for ( FT_UInt entry = 0; entry < map->length; entry++ ) {
+        if ( map->entries[entry].glyph_index == glyph_index ) {
+            return map->entries[entry].codepoint;
+        }
+    }
+
+    return 0;
+}
+
+FT_LOCAL_DEF( FT_Error )
+af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, 
FT_Memory memory ) {
+    /* Search for a unicode charmap */
+    /* If there isn't one, create a blank map */
+    
+    /*TODO: change this to logic that searches for a "preferred" unicode 
charmap that maps the most codepoints*/
+    /*see find_unicode_charmap*/
+    /*TODO: use GSUB lookups    */
+    FT_CMap unicode_charmap = NULL;
+    for ( FT_UInt i = 0; i < face->num_charmaps; i++ ) {
+        if ( face->charmaps[i]->encoding == FT_ENCODING_UNICODE ) {
+            unicode_charmap = FT_CMAP( face->charmaps[i] );
+        }
+    }
+    
+    if ( unicode_charmap == NULL ) {
+        *map = NULL;
+        return FT_Err_Ok;
+    }
+
+    FT_Error error;
+
+    if ( FT_NEW( *map ) ) {
+        goto Exit;
+    }
+
+    FT_Int capacity = 10;
+    FT_Int size = 0;
+    
+    if ( FT_NEW_ARRAY((*map)->entries, capacity) ) {
+        goto Exit;
+    }
+    for ( FT_Int i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ ) {
+        FT_UInt32 codepoint = adjustment_database[i].codepoint;
+        FT_Int glyph = unicode_charmap->clazz->char_index(unicode_charmap, 
codepoint);
+        if ( glyph == 0 ) {
+            continue;
+        }
+        if (size == capacity) {
+            capacity += capacity / 2;
+            if ( FT_RENEW_ARRAY((*map)->entries, size, capacity) ) {
+                goto Exit;
+            }
+        }
+        size++;
+        (*map)->entries[i].glyph_index = glyph;
+        (*map)->entries[i].codepoint = codepoint;
+    }
+    (*map)->length = size;
+
+Exit:
+    if ( error ) {
+        if ( *map ) {
+            FT_FREE( ( *map )->entries );
+        }
+        FT_FREE( *map );
+        return error;
+    }
+
+    return FT_Err_Ok;
+}
+
+FT_LOCAL_DEF( FT_Error )
+af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ) {
+    FT_FREE( map->entries );
+    return FT_Err_Ok;
+}
\ No newline at end of file
diff --git a/src/autofit/afadjust.h b/src/autofit/afadjust.h
new file mode 100644
index 000000000..f1c8c47d3
--- /dev/null
+++ b/src/autofit/afadjust.h
@@ -0,0 +1,47 @@
+#ifndef AFADJUST_H_
+#define AFADJUST_H_
+
+#include <freetype/fttypes.h>
+
+FT_BEGIN_HEADER
+
+/*The type of adjustment that should be done to prevent cases where 2 parts of 
a character*/
+/*stacked vertically merge, even though they should be separate*/
+typedef enum AF_VerticalSeparationAdjustmentType_ {
+    AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE,
+    /*"One on one" means that the character is expected to be one contour on 
top of another, where the contours should not touch*/
+    /*the hinter will force the contours to have a gap of at least 1 pixel 
between them*/
+    /*by moving the top contour up */
+    AF_VERTICAL_ADJUSTMENT_NONE
+
+    /*others will be needed, such as the case where the lower contour should 
be moved in the adjustment instead of the upper one*/
+    /*or umlats, where there are 2 contours which should be moved together*/
+    /*and a way of handling A and O, where the letter consists of 2 contours*/
+} AF_VerticalSeparationAdjustmentType;
+
+typedef struct AF_AdjustmentDatabaseEntry_ {
+    FT_UInt32 codepoint;
+    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 );
+
+FT_LOCAL( FT_UInt32 )
+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 );
+ 
+/*free the reverse character map*/
+FT_LOCAL( FT_Error )
+af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory );
+
+FT_END_HEADER
+
+#endif
\ No newline at end of file
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 6f672d593..8177c66f1 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -22,6 +22,7 @@
 #include "afglobal.h"
 #include "aflatin.h"
 #include "aferrors.h"
+#include "afadjust.h"
 
 
   /**************************************************************************
@@ -227,7 +228,6 @@
                                      dummy->units_per_em / 100 );
         axis->width_count = num_widths;
       }
-
     Exit:
       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
       {
@@ -1153,6 +1153,8 @@
         goto Exit;
       }
       af_latin_metrics_check_digits( metrics, face );
+      
+      af_reverse_character_map_new( face, &metrics->root.reverse_charmap, 
face->memory );
     }
 
   Exit:
@@ -1502,6 +1504,11 @@
     af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
   }
 
+  FT_CALLBACK_DEF( void )
+  af_latin_metrics_done( AF_StyleMetrics metrics_ ) {
+    AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+    af_reverse_character_map_done( metrics->root.reverse_charmap, 
metrics->root.globals->face->memory );
+  }
 
   /* Extract standard_width from writing system/script specific */
   /* metrics class.                                             */
@@ -2738,6 +2745,83 @@
   }
 
 
+void af_glyph_hints_apply_adjustments(AF_GlyphHints hints, AF_Dimension dim, 
FT_Int glyph_index, AF_ReverseCharacterMap reverse_charmap) {
+  if ( dim != AF_DIMENSION_VERT ) {
+    return;
+  }
+  if ( af_lookup_vertical_seperation_type( reverse_charmap, glyph_index ) == 
AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE &&
+      hints->num_contours == 2 ) {
+    
+    /* Figure out which contout is the higher one by finding the one */
+    /* with the highest minimum y value */
+
+    FT_Int highest_contour = -1;
+    FT_Pos highest_min_y = 0;
+    FT_Pos current_min_y = 0;
+
+    for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) {
+      AF_Point point = hints->contours[contour];
+      AF_Point first_point = point;
+      if ( point == NULL ) { /*TODO: is this necessary?*/
+        continue;
+      }
+      current_min_y = point->y;
+
+      do {
+        if ( point->y < current_min_y ) {
+          current_min_y = point->y;
+        }
+        point = point->next;
+      } while ( point != first_point );
+
+      if ( highest_contour == -1 || current_min_y > highest_min_y ) {
+        highest_min_y = current_min_y;
+        highest_contour = contour;
+      }
+    }
+
+    /* If there are any contours that have a maximum y coordinate */
+    /* greater or equal to the minimum y coordinate of the previously found 
highest*/
+    /* contour, bump the high contour up until the distance is one pixel */
+
+    FT_Int adjustment_amount = 0;
+    for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) {
+      if (contour == highest_contour) {
+        continue;
+      }
+      AF_Point point = hints->contours[contour];
+      AF_Point first_point = point;
+      if ( point == NULL ) {
+        continue;
+      }
+      FT_Pos max_y = point->y;
+
+      do {
+        if ( point->y > max_y ) {
+          max_y = point->y;
+        }
+        point = point->next;
+      } while ( point != first_point );
+
+      if ( max_y >= highest_min_y - 64 ) {
+        adjustment_amount = 64 - (highest_min_y - max_y);
+      }
+    }
+
+    if ( adjustment_amount > 0 ) {
+      AF_Point point = hints->contours[highest_contour];
+      AF_Point first_point = point;
+      if ( point != NULL ) {
+        do {
+          point->y += adjustment_amount;
+          point = point->next;
+        } while ( point != first_point );
+      }
+    }
+  }
+}
+
+
   /* Compute the snapped width of a given stem, ignoring very thin ones. */
   /* There is a lot of voodoo in this function; changing the hard-coded  */
   /* parameters influence the whole hinting process.                     */
@@ -3605,6 +3689,7 @@
         af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
         af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
         af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
+        af_glyph_hints_apply_adjustments(hints, (AF_Dimension) dim, 
glyph_index, metrics->root.reverse_charmap);
       }
     }
 
@@ -3633,12 +3718,11 @@
 
     (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,        /* 
style_metrics_init    */
     (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,       /* 
style_metrics_scale   */
-    (AF_WritingSystem_DoneMetricsFunc) NULL,                         /* 
style_metrics_done    */
+    (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done,        /* 
style_metrics_done    */
     (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* 
style_metrics_getstdw */
 
     (AF_WritingSystem_InitHintsFunc)   af_latin_hints_init,          /* 
style_hints_init      */
     (AF_WritingSystem_ApplyHintsFunc)  af_latin_hints_apply          /* 
style_hints_apply     */
   )
 
-
 /* END */
diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h
index 661519449..aca173567 100644
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -39,6 +39,7 @@
 #include <freetype/internal/ftdebug.h>
 
 #include "afblue.h"
+#include "afadjust.h"
 
 #ifdef FT_DEBUG_AUTOFIT
 #include FT_CONFIG_STANDARD_LIBRARY_H
@@ -417,6 +418,7 @@ extern void*  af_debug_hints_;
     FT_Bool         digits_have_same_width;
 
     AF_FaceGlobals  globals;    /* to access properties */
+    AF_ReverseCharacterMap  reverse_charmap;
 
   } AF_StyleMetricsRec;
 
diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c
index 8bd609b5e..55017186d 100644
--- a/src/autofit/autofit.c
+++ b/src/autofit/autofit.c
@@ -30,6 +30,7 @@
 #include "afmodule.c"
 #include "afranges.c"
 #include "afshaper.c"
+#include "afadjust.c"
 
 
 /* END */
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index abfa3ab0e..b379868ba 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -1358,7 +1358,6 @@
                       driver );
   }
 
-
   /**************************************************************************
    *
    * @Function:



reply via email to

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