Prototype adjustment database, reverse character lookup, and fixes for a few characters
This commit is contained in:
parent
80a507a6b8
commit
f8e996bfb1
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "afmodule.c"
|
||||
#include "afranges.c"
|
||||
#include "afshaper.c"
|
||||
#include "afadjust.c"
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -1358,7 +1358,6 @@
|
|||
driver );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
|
|
Loading…
Reference in New Issue