Prototype adjustment database, reverse character lookup, and fixes for a few characters

This commit is contained in:
Craig White 2023-06-04 15:31:13 -04:00
parent 80a507a6b8
commit f8e996bfb1
6 changed files with 277 additions and 4 deletions

140
src/autofit/afadjust.c Normal file
View File

@ -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;
}

47
src/autofit/afadjust.h Normal file
View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -30,6 +30,7 @@
#include "afmodule.c"
#include "afranges.c"
#include "afshaper.c"
#include "afadjust.c"
/* END */

View File

@ -1358,7 +1358,6 @@
driver );
}
/**************************************************************************
*
* @Function: