parent
815a8995d0
commit
58b9dced9c
12 changed files with 1052 additions and 32 deletions
@ -0,0 +1,18 @@ |
||||
SubDir FT2_TOP src autofit ; |
||||
|
||||
{ |
||||
local _sources ; |
||||
|
||||
if $(FT2_MULTI) |
||||
{ |
||||
_sources = afangles afglobal afhints aflatin ; |
||||
} |
||||
else |
||||
{ |
||||
_sources = autofit ; |
||||
} |
||||
|
||||
Library $(FT2_LIB) : $(_sources).c ; |
||||
} |
||||
|
||||
# end of src/autofir Jamfile |
@ -0,0 +1,505 @@ |
||||
#include "afloader.h" |
||||
#include "afhints.h" |
||||
#include "afglobal.h" |
||||
#include "aflatin.h" |
||||
|
||||
FT_LOCAL_DEF( void ) |
||||
af_loader_init( AF_Loader loader, |
||||
FT_Memory memory ) |
||||
{ |
||||
FT_ZERO( loader ); |
||||
|
||||
af_glyph_hints_init( &loader->hints, memory ); |
||||
} |
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Error ) |
||||
af_loader_reset( AF_Loader loader, |
||||
FT_Face face ) |
||||
{ |
||||
FT_Error error = 0; |
||||
|
||||
FT_ZERO( loader ); |
||||
|
||||
loader->face = face; |
||||
loader->gloader = face->slot->internal->loader; |
||||
loader->globals = (AF_FaceGlobals) face->autohint.data; |
||||
|
||||
if ( loader->globals == NULL ) |
||||
{ |
||||
error = af_face_globals_new( &face, &loader->globals ); |
||||
if ( !error ) |
||||
{ |
||||
face->autohint.data = (FT_Pointer) loader->globals; |
||||
face->autohint.finalizer = (FT_Generic_Finalizer) af_face_globals_free; |
||||
} |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
|
||||
FT_LOCAL_DEF( void ) |
||||
af_loader_done( AF_Loader loader ) |
||||
{ |
||||
loader->face = face; |
||||
loader->globals = NULL; |
||||
loader->gloader = NULL; |
||||
} |
||||
|
||||
|
||||
static FT_Error |
||||
af_hinter_load_g( AF_Loader loader, |
||||
AF_Scaler scaler, |
||||
FT_UInt glyph_index, |
||||
FT_Int32 load_flags, |
||||
FT_UInt depth ) |
||||
{ |
||||
FT_Error error = 0; |
||||
FT_Face face = loader->face; |
||||
AF_FaceGlobals globals = loader->globals; |
||||
FT_GlyphLoader gloader = loader->gloader; |
||||
AF_ScriptMetrics metrics = loader->metrics; |
||||
AF_GlyphHints hints = &loader->hints; |
||||
FT_GlyphSlot slot = face->glyph; |
||||
FT_Slot_Internal internal = slot->internal; |
||||
|
||||
error = FT_Load_Glyph( face, glyph_index, load_flags ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
loader->transformed = internal->glyph_transformed; |
||||
if ( loader->transformed ) |
||||
{ |
||||
FT_Matrix inverse; |
||||
|
||||
loader->trans_matrix = internal->glyph_matrix; |
||||
loader->trans_delta = internal->glyph_delta; |
||||
|
||||
inverse = loader->trans_matrix; |
||||
FT_Matrix_Invert( &inverse ); |
||||
FT_Vector_Transform( &loader->trans_delta, &inverse ); |
||||
} |
||||
|
||||
/* set linear metrics */ |
||||
slot->linearHoriAdvance = slot->metrics.horiAdvance; |
||||
slot->linearVertAdvance = slot->metrics.vertAdvance; |
||||
|
||||
switch ( slot->format ) |
||||
{ |
||||
case FT_GLYPH_FORMAT_OUTLINE: |
||||
/* translate the loaded glyph when an internal transform
|
||||
* is needed |
||||
*/ |
||||
if ( loader->transformed ) |
||||
{ |
||||
FT_Vector* point = slot->outline.points; |
||||
FT_Vector* limit = point + slot->outline.n_points; |
||||
|
||||
for ( ; point < limit; point++ ) |
||||
{ |
||||
point->x += loader->trans_delta.x; |
||||
point->y += loader->trans_delta.y; |
||||
} |
||||
} |
||||
|
||||
/* copy the outline points in the loader's current */ |
||||
/* extra points which is used to keep original glyph coordinates */ |
||||
error = FT_GlyphLoader_CheckPoints( gloader, |
||||
slot->outline.n_points + 2, |
||||
slot->outline.n_contours ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
FT_ARRAY_COPY( gloader->current.extra_points, |
||||
slot->outline.points, |
||||
slot->outline.n_points ); |
||||
|
||||
FT_ARRAY_COPY( gloader->current.outline.contours, |
||||
slot->outline.contours, |
||||
slot->outline.n_contours ); |
||||
|
||||
FT_ARRAY_COPY( gloader->current.outline.tags, |
||||
slot->outline.tags, |
||||
slot->outline.n_points ); |
||||
|
||||
gloader->current.outline.n_points = slot->outline.n_points; |
||||
gloader->current.outline.n_contours = slot->outline.n_contours; |
||||
|
||||
/* compute original phantom points */ |
||||
loader->pp1.x = hints->x_delta; |
||||
loader->pp1.y = hints->y_delta; |
||||
loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, |
||||
hints->x_scale ) + hints->x_delta; |
||||
loader->pp2.y = hints->y_delta; |
||||
|
||||
/* be sure to check for spacing glyphs */ |
||||
if ( slot->outline.n_points == 0 ) |
||||
goto Hint_Metrics; |
||||
|
||||
/* now load the slot image into the auto-outline and run the */ |
||||
/* automatic hinting process */ |
||||
error = metrics->clazz->script_hints_init( hints, scaler, |
||||
&gloader->current.outline, |
||||
metrics ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* apply the hints */ |
||||
error = metrics->clazz->script_hints_apply( hints, scaler, |
||||
&gloader->current.outline, |
||||
metrics ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* we now need to hint the metrics according to the change in */ |
||||
/* width/positioning that occured during the hinting process */ |
||||
{ |
||||
FT_Pos old_advance, old_rsb, old_lsb, new_lsb; |
||||
AF_Edge edge1 = outline->vert_edges; /* leftmost edge */ |
||||
AF_Edge edge2 = edge1 + |
||||
outline->num_vedges - 1; /* rightmost edge */ |
||||
|
||||
|
||||
old_advance = hinter->pp2.x; |
||||
old_rsb = old_advance - edge2->opos; |
||||
old_lsb = edge1->opos; |
||||
new_lsb = edge1->pos; |
||||
|
||||
hinter->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb ); |
||||
hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb ); |
||||
|
||||
#if 0 |
||||
/* try to fix certain bad advance computations */ |
||||
if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 ) |
||||
hinter->pp2.x += 64; |
||||
#endif |
||||
} |
||||
|
||||
/* good, we simply add the glyph to our loader's base */ |
||||
FT_GlyphLoader_Add( gloader ); |
||||
break; |
||||
|
||||
case FT_GLYPH_FORMAT_COMPOSITE: |
||||
{ |
||||
FT_UInt nn, num_subglyphs = slot->num_subglyphs; |
||||
FT_UInt num_base_subgs, start_point; |
||||
FT_SubGlyph subglyph; |
||||
|
||||
|
||||
start_point = gloader->base.outline.n_points; |
||||
|
||||
/* first of all, copy the subglyph descriptors in the glyph loader */ |
||||
error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
FT_ARRAY_COPY( gloader->current.subglyphs, |
||||
slot->subglyphs, |
||||
num_subglyphs ); |
||||
|
||||
gloader->current.num_subglyphs = num_subglyphs; |
||||
num_base_subgs = gloader->base.num_subglyphs; |
||||
|
||||
/* now, read each subglyph independently */ |
||||
for ( nn = 0; nn < num_subglyphs; nn++ ) |
||||
{ |
||||
FT_Vector pp1, pp2; |
||||
FT_Pos x, y; |
||||
FT_UInt num_points, num_new_points, num_base_points; |
||||
|
||||
|
||||
/* gloader.current.subglyphs can change during glyph loading due */ |
||||
/* to re-allocation -- we must recompute the current subglyph on */ |
||||
/* each iteration */ |
||||
subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
||||
|
||||
pp1 = hinter->pp1; |
||||
pp2 = hinter->pp2; |
||||
|
||||
num_base_points = gloader->base.outline.n_points; |
||||
|
||||
error = af_loader_load_g( loader, scaler, subglyph->index, |
||||
load_flags, depth + 1 ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* recompute subglyph pointer */ |
||||
subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
||||
|
||||
if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) |
||||
{ |
||||
pp1 = hinter->pp1; |
||||
pp2 = hinter->pp2; |
||||
} |
||||
else |
||||
{ |
||||
hinter->pp1 = pp1; |
||||
hinter->pp2 = pp2; |
||||
} |
||||
|
||||
num_points = gloader->base.outline.n_points; |
||||
num_new_points = num_points - num_base_points; |
||||
|
||||
/* now perform the transform required for this subglyph */ |
||||
|
||||
if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | |
||||
FT_SUBGLYPH_FLAG_XY_SCALE | |
||||
FT_SUBGLYPH_FLAG_2X2 ) ) |
||||
{ |
||||
FT_Vector* cur = gloader->base.outline.points + |
||||
num_base_points; |
||||
FT_Vector* org = gloader->base.extra_points + |
||||
num_base_points; |
||||
FT_Vector* limit = cur + num_new_points; |
||||
|
||||
|
||||
for ( ; cur < limit; cur++, org++ ) |
||||
{ |
||||
FT_Vector_Transform( cur, &subglyph->transform ); |
||||
FT_Vector_Transform( org, &subglyph->transform ); |
||||
} |
||||
} |
||||
|
||||
/* apply offset */ |
||||
|
||||
if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) |
||||
{ |
||||
FT_Int k = subglyph->arg1; |
||||
FT_UInt l = subglyph->arg2; |
||||
FT_Vector* p1; |
||||
FT_Vector* p2; |
||||
|
||||
|
||||
if ( start_point + k >= num_base_points || |
||||
l >= (FT_UInt)num_new_points ) |
||||
{ |
||||
error = FT_Err_Invalid_Composite; |
||||
goto Exit; |
||||
} |
||||
|
||||
l += num_base_points; |
||||
|
||||
/* for now, only use the current point coordinates; */ |
||||
/* we may consider another approach in the near future */ |
||||
p1 = gloader->base.outline.points + start_point + k; |
||||
p2 = gloader->base.outline.points + start_point + l; |
||||
|
||||
x = p1->x - p2->x; |
||||
y = p1->y - p2->y; |
||||
} |
||||
else |
||||
{ |
||||
x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; |
||||
y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; |
||||
|
||||
x = FT_PIX_ROUND(x); |
||||
y = FT_PIX_ROUND(y); |
||||
} |
||||
|
||||
{ |
||||
FT_Outline dummy = gloader->base.outline; |
||||
|
||||
|
||||
dummy.points += num_base_points; |
||||
dummy.n_points = (short)num_new_points; |
||||
|
||||
FT_Outline_Translate( &dummy, x, y ); |
||||
} |
||||
} |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
/* we don't support other formats (yet?) */ |
||||
error = AF_Err_Unimplemented_Feature; |
||||
} |
||||
|
||||
Hint_Metrics: |
||||
if ( depth == 0 ) |
||||
{ |
||||
FT_BBox bbox; |
||||
|
||||
|
||||
/* transform the hinted outline if needed */ |
||||
if ( hinter->transformed ) |
||||
FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix ); |
||||
|
||||
/* we must translate our final outline by -pp1.x and compute */ |
||||
/* the new metrics */ |
||||
if ( hinter->pp1.x ) |
||||
FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 ); |
||||
|
||||
FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); |
||||
bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); |
||||
bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); |
||||
bbox.xMax = FT_PIX_CEIL( bbox.xMax ); |
||||
bbox.yMax = FT_PIX_CEIL( bbox.yMax ); |
||||
|
||||
slot->metrics.width = bbox.xMax - bbox.xMin; |
||||
slot->metrics.height = bbox.yMax - bbox.yMin; |
||||
slot->metrics.horiBearingX = bbox.xMin; |
||||
slot->metrics.horiBearingY = bbox.yMax; |
||||
|
||||
/* for mono-width fonts (like Andale, Courier, etc.) we need */ |
||||
/* to keep the original rounded advance width */ |
||||
if ( !FT_IS_FIXED_WIDTH( slot->face ) ) |
||||
slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; |
||||
else |
||||
slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, |
||||
x_scale ); |
||||
|
||||
slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); |
||||
|
||||
/* now copy outline into glyph slot */ |
||||
af_loader_rewind( slot->internal->loader ); |
||||
error = af_loader_copy_points( slot->internal->loader, gloader ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
slot->outline = slot->internal->loader->base.outline; |
||||
slot->format = FT_GLYPH_FORMAT_OUTLINE; |
||||
} |
||||
|
||||
#ifdef DEBUG_HINTER |
||||
af_debug_hinter = hinter; |
||||
#endif |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* load and hint a given glyph */ |
||||
FT_LOCAL_DEF( FT_Error ) |
||||
af_loader_load_g( AF_Hinter hinter, |
||||
FT_GlyphSlot slot, |
||||
FT_Size size, |
||||
FT_UInt glyph_index, |
||||
FT_Int32 load_flags ) |
||||
{ |
||||
FT_Face face = slot->face; |
||||
FT_Error error; |
||||
FT_Fixed x_scale = size->metrics.x_scale; |
||||
FT_Fixed y_scale = size->metrics.y_scale; |
||||
AF_Face_Globals face_globals = FACE_GLOBALS( face ); |
||||
FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags ); |
||||
|
||||
|
||||
/* first of all, we need to check that we're using the correct face and */ |
||||
/* global hints to load the glyph */ |
||||
if ( hinter->face != face || hinter->globals != face_globals ) |
||||
{ |
||||
hinter->face = face; |
||||
if ( !face_globals ) |
||||
{ |
||||
error = af_hinter_new_face_globals( hinter, face, 0 ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
} |
||||
hinter->globals = FACE_GLOBALS( face ); |
||||
face_globals = FACE_GLOBALS( face ); |
||||
|
||||
} |
||||
|
||||
#ifdef FT_CONFIG_CHESTER_BLUE_SCALE |
||||
|
||||
/* try to optimize the y_scale so that the top of non-capital letters
|
||||
* is aligned on a pixel boundary whenever possible |
||||
*/ |
||||
{ |
||||
AF_Globals design = &face_globals->design; |
||||
FT_Pos shoot = design->blue_shoots[AF_BLUE_SMALL_TOP]; |
||||
|
||||
|
||||
/* the value of 'shoot' will be -1000 if the font doesn't have */ |
||||
/* small latin letters; we simply check the sign here... */ |
||||
if ( shoot > 0 ) |
||||
{ |
||||
FT_Pos scaled = FT_MulFix( shoot, y_scale ); |
||||
FT_Pos fitted = FT_PIX_ROUND( scaled ); |
||||
|
||||
|
||||
if ( scaled != fitted ) |
||||
{ |
||||
/* adjust y_scale
|
||||
*/ |
||||
y_scale = FT_MulDiv( y_scale, fitted, scaled ); |
||||
|
||||
/* adust x_scale
|
||||
*/ |
||||
if ( fitted < scaled ) |
||||
x_scale -= x_scale / 50; /* x_scale*0.98 with integers */ |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ |
||||
|
||||
/* now, we must check the current character pixel size to see if we */ |
||||
/* need to rescale the global metrics */ |
||||
if ( face_globals->x_scale != x_scale || |
||||
face_globals->y_scale != y_scale ) |
||||
af_hinter_scale_globals( hinter, x_scale, y_scale ); |
||||
|
||||
af_loader_rewind( hinter->loader ); |
||||
|
||||
/* reset hinting flags according to load flags and current render target */ |
||||
hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) ); |
||||
hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) ); |
||||
|
||||
#ifdef DEBUG_HINTER |
||||
hinter->do_horz_hints = !af_debug_disable_vert; /* not a bug, the meaning */ |
||||
hinter->do_vert_hints = !af_debug_disable_horz; /* of h/v is inverted! */ |
||||
#endif |
||||
|
||||
/* we snap the width of vertical stems for the monochrome and */ |
||||
/* horizontal LCD rendering targets only. Corresponds to X snapping. */ |
||||
hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || |
||||
hint_mode == FT_RENDER_MODE_LCD ); |
||||
|
||||
/* we snap the width of horizontal stems for the monochrome and */ |
||||
/* vertical LCD rendering targets only. Corresponds to Y snapping. */ |
||||
hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || |
||||
hint_mode == FT_RENDER_MODE_LCD_V ); |
||||
|
||||
hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); |
||||
|
||||
load_flags |= FT_LOAD_NO_SCALE |
||||
| FT_LOAD_IGNORE_TRANSFORM; |
||||
load_flags &= ~FT_LOAD_RENDER; |
||||
|
||||
error = af_hinter_load( hinter, glyph_index, load_flags, 0 ); |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
static FT_Error |
||||
af_loader_load_glyph( AF_Loader loader, |
||||
AF_Scaler scaler, |
||||
FT_UInt glyph_index ) |
||||
{ |
||||
FT_Error error; |
||||
FT_Face face = scaler->face; |
||||
|
||||
error = af_loader_reset( loader, face ); |
||||
if ( !error ) |
||||
{ |
||||
AF_ScriptMetrics metrics; |
||||
|
||||
error = af_face_globals_get_metrics( globals, gindex, &metrics ); |
||||
if ( !error ) |
||||
{ |
||||
metrics->clazz->script_metrics_scale( metrics, scaler ); |
||||
|
||||
error = af_loader_load_g( loader, scaler, metrics, glyph_index, |
||||
/* load_flags */, 0 ); |
||||
} |
||||
} |
||||
return error; |
||||
} |
@ -0,0 +1,46 @@ |
||||
#ifndef __AF_LOADER_H__ |
||||
#define __AF_LOADER_H__ |
||||
|
||||
#include "afhints.h" |
||||
#include "afglobal.h" |
||||
|
||||
FT_BEGIN_HEADER |
||||
|
||||
typedef struct AF_LoaderRec_ |
||||
{ |
||||
FT_Face face; /* current face */ |
||||
AF_FaceGlobals globals; /* current face globals */ |
||||
FT_GlyphLoader gloader; /* glyph loader */ |
||||
AF_GlyphHintsRec hints; |
||||
AF_ScriptMetrics metrics; |
||||
FT_Bool transformed; |
||||
FT_Matrix trans_matrix; |
||||
FT_Vector trans_delta; |
||||
FT_Vector pp1; |
||||
FT_Vector pp2; |
||||
|
||||
} AF_LoaderRec, *AF_Loader; |
||||
|
||||
FT_LOCAL( void ) |
||||
af_loader_init( AF_Loader loader, |
||||
FT_Memory memory ); |
||||
|
||||
FT_LOCAL( FT_Error ) |
||||
af_loader_reset( AF_Loader loader, |
||||
FT_Face face ); |
||||
|
||||
FT_LOCAL( void ) |
||||
af_loader_done( AF_Loader loader ); |
||||
|
||||
FT_LOCAL( FT_Error ) |
||||
af_loader_load_glyph( AF_Loader loader, |
||||
FT_UInt gindex, |
||||
FT_UInt32 load_flags, |
||||
FT_UInt depth ); |
||||
|
||||
/* */ |
||||
|
||||
FT_END_HEADER |
||||
|
||||
#endif /* __AF_LOADER_H__ */ |
||||
|
@ -0,0 +1,437 @@ |
||||
#include "afmodule.h" |
||||
#include "afhints.h" |
||||
#include "afglobal.h" |
||||
#include "aflatin.h" |
||||
|
||||
static FT_Error |
||||
af_hinter_load( AF_Hinter hinter, |
||||
FT_UInt glyph_index, |
||||
FT_Int32 load_flags, |
||||
FT_UInt depth ) |
||||
{ |
||||
FT_Face face = hinter->face; |
||||
FT_GlyphSlot slot = face->glyph; |
||||
FT_Slot_Internal internal = slot->internal; |
||||
FT_Fixed x_scale = hinter->globals->x_scale; |
||||
FT_Fixed y_scale = hinter->globals->y_scale; |
||||
FT_Error error; |
||||
AF_Outline outline = hinter->glyph; |
||||
AF_Loader gloader = hinter->loader; |
||||
|
||||
|
||||
/* load the glyph */ |
||||
error = FT_Load_Glyph( face, glyph_index, load_flags ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */ |
||||
hinter->transformed = internal->glyph_transformed; |
||||
|
||||
if ( hinter->transformed ) |
||||
{ |
||||
FT_Matrix imatrix; |
||||
|
||||
|
||||
imatrix = internal->glyph_matrix; |
||||
hinter->trans_delta = internal->glyph_delta; |
||||
hinter->trans_matrix = imatrix; |
||||
|
||||
FT_Matrix_Invert( &imatrix ); |
||||
FT_Vector_Transform( &hinter->trans_delta, &imatrix ); |
||||
} |
||||
|
||||
/* set linear horizontal metrics */ |
||||
slot->linearHoriAdvance = slot->metrics.horiAdvance; |
||||
slot->linearVertAdvance = slot->metrics.vertAdvance; |
||||
|
||||
switch ( slot->format ) |
||||
{ |
||||
case FT_GLYPH_FORMAT_OUTLINE: |
||||
|
||||
/* translate glyph outline if we need to */ |
||||
if ( hinter->transformed ) |
||||
{ |
||||
FT_UInt n = slot->outline.n_points; |
||||
FT_Vector* point = slot->outline.points; |
||||
|
||||
|
||||
for ( ; n > 0; point++, n-- ) |
||||
{ |
||||
point->x += hinter->trans_delta.x; |
||||
point->y += hinter->trans_delta.y; |
||||
} |
||||
} |
||||
|
||||
/* copy the outline points in the loader's current */ |
||||
/* extra points which is used to keep original glyph coordinates */ |
||||
error = af_loader_check_points( gloader, slot->outline.n_points + 2, |
||||
slot->outline.n_contours ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
FT_ARRAY_COPY( gloader->current.extra_points, slot->outline.points, |
||||
slot->outline.n_points ); |
||||
|
||||
FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours, |
||||
slot->outline.n_contours ); |
||||
|
||||
FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags, |
||||
slot->outline.n_points ); |
||||
|
||||
gloader->current.outline.n_points = slot->outline.n_points; |
||||
gloader->current.outline.n_contours = slot->outline.n_contours; |
||||
|
||||
/* compute original phantom points */ |
||||
hinter->pp1.x = 0; |
||||
hinter->pp1.y = 0; |
||||
hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale ); |
||||
hinter->pp2.y = 0; |
||||
|
||||
/* be sure to check for spacing glyphs */ |
||||
if ( slot->outline.n_points == 0 ) |
||||
goto Hint_Metrics; |
||||
|
||||
/* now load the slot image into the auto-outline and run the */ |
||||
/* automatic hinting process */ |
||||
error = af_outline_load( outline, x_scale, y_scale, face ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* perform feature detection */ |
||||
af_outline_detect_features( outline ); |
||||
|
||||
if ( hinter->do_vert_hints ) |
||||
{ |
||||
af_outline_compute_blue_edges( outline, hinter->globals ); |
||||
af_outline_scale_blue_edges( outline, hinter->globals ); |
||||
} |
||||
|
||||
/* perform alignment control */ |
||||
af_hinter_hint_edges( hinter ); |
||||
af_hinter_align( hinter ); |
||||
|
||||
/* now save the current outline into the loader's current table */ |
||||
af_outline_save( outline, gloader ); |
||||
|
||||
/* we now need to hint the metrics according to the change in */ |
||||
/* width/positioning that occured during the hinting process */ |
||||
{ |
||||
FT_Pos old_advance, old_rsb, old_lsb, new_lsb; |
||||
AF_Edge edge1 = outline->vert_edges; /* leftmost edge */ |
||||
AF_Edge edge2 = edge1 + |
||||
outline->num_vedges - 1; /* rightmost edge */ |
||||
|
||||
|
||||
old_advance = hinter->pp2.x; |
||||
old_rsb = old_advance - edge2->opos; |
||||
old_lsb = edge1->opos; |
||||
new_lsb = edge1->pos; |
||||
|
||||
hinter->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb ); |
||||
hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb ); |
||||
|
||||
#if 0 |
||||
/* try to fix certain bad advance computations */ |
||||
if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 ) |
||||
hinter->pp2.x += 64; |
||||
#endif |
||||
} |
||||
|
||||
/* good, we simply add the glyph to our loader's base */ |
||||
af_loader_add( gloader ); |
||||
break; |
||||
|
||||
case FT_GLYPH_FORMAT_COMPOSITE: |
||||
{ |
||||
FT_UInt nn, num_subglyphs = slot->num_subglyphs; |
||||
FT_UInt num_base_subgs, start_point; |
||||
FT_SubGlyph subglyph; |
||||
|
||||
|
||||
start_point = gloader->base.outline.n_points; |
||||
|
||||
/* first of all, copy the subglyph descriptors in the glyph loader */ |
||||
error = af_loader_check_subglyphs( gloader, num_subglyphs ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs, |
||||
num_subglyphs ); |
||||
|
||||
gloader->current.num_subglyphs = num_subglyphs; |
||||
num_base_subgs = gloader->base.num_subglyphs; |
||||
|
||||
/* now, read each subglyph independently */ |
||||
for ( nn = 0; nn < num_subglyphs; nn++ ) |
||||
{ |
||||
FT_Vector pp1, pp2; |
||||
FT_Pos x, y; |
||||
FT_UInt num_points, num_new_points, num_base_points; |
||||
|
||||
|
||||
/* gloader.current.subglyphs can change during glyph loading due */ |
||||
/* to re-allocation -- we must recompute the current subglyph on */ |
||||
/* each iteration */ |
||||
subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
||||
|
||||
pp1 = hinter->pp1; |
||||
pp2 = hinter->pp2; |
||||
|
||||
num_base_points = gloader->base.outline.n_points; |
||||
|
||||
error = af_hinter_load( hinter, subglyph->index, |
||||
load_flags, depth + 1 ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
/* recompute subglyph pointer */ |
||||
subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
||||
|
||||
if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) |
||||
{ |
||||
pp1 = hinter->pp1; |
||||
pp2 = hinter->pp2; |
||||
} |
||||
else |
||||
{ |
||||
hinter->pp1 = pp1; |
||||
hinter->pp2 = pp2; |
||||
} |
||||
|
||||
num_points = gloader->base.outline.n_points; |
||||
num_new_points = num_points - num_base_points; |
||||
|
||||
/* now perform the transform required for this subglyph */ |
||||
|
||||
if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | |
||||
FT_SUBGLYPH_FLAG_XY_SCALE | |
||||
FT_SUBGLYPH_FLAG_2X2 ) ) |
||||
{ |
||||
FT_Vector* cur = gloader->base.outline.points + |
||||
num_base_points; |
||||
FT_Vector* org = gloader->base.extra_points + |
||||
num_base_points; |
||||
FT_Vector* limit = cur + num_new_points; |
||||
|
||||
|
||||
for ( ; cur < limit; cur++, org++ ) |
||||
{ |
||||
FT_Vector_Transform( cur, &subglyph->transform ); |
||||
FT_Vector_Transform( org, &subglyph->transform ); |
||||
} |
||||
} |
||||
|
||||
/* apply offset */ |
||||
|
||||
if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) |
||||
{ |
||||
FT_Int k = subglyph->arg1; |
||||
FT_UInt l = subglyph->arg2; |
||||
FT_Vector* p1; |
||||
FT_Vector* p2; |
||||
|
||||
|
||||
if ( start_point + k >= num_base_points || |
||||
l >= (FT_UInt)num_new_points ) |
||||
{ |
||||
error = AF_Err_Invalid_Composite; |
||||
goto Exit; |
||||
} |
||||
|
||||
l += num_base_points; |
||||
|
||||
/* for now, only use the current point coordinates; */ |
||||
/* we may consider another approach in the near future */ |
||||
p1 = gloader->base.outline.points + start_point + k; |
||||
p2 = gloader->base.outline.points + start_point + l; |
||||
|
||||
x = p1->x - p2->x; |
||||
y = p1->y - p2->y; |
||||
} |
||||
else |
||||
{ |
||||
x = FT_MulFix( subglyph->arg1, x_scale ); |
||||
y = FT_MulFix( subglyph->arg2, y_scale ); |
||||
|
||||
x = FT_PIX_ROUND(x); |
||||
y = FT_PIX_ROUND(y); |
||||
} |
||||
|
||||
{ |
||||
FT_Outline dummy = gloader->base.outline; |
||||
|
||||
|
||||
dummy.points += num_base_points; |
||||
dummy.n_points = (short)num_new_points; |
||||
|
||||
FT_Outline_Translate( &dummy, x, y ); |
||||
} |
||||
} |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
/* we don't support other formats (yet?) */ |
||||
error = AF_Err_Unimplemented_Feature; |
||||
} |
||||
|
||||
Hint_Metrics: |
||||
if ( depth == 0 ) |
||||
{ |
||||
FT_BBox bbox; |
||||
|
||||
|
||||
/* transform the hinted outline if needed */ |
||||
if ( hinter->transformed ) |
||||
FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix ); |
||||
|
||||
/* we must translate our final outline by -pp1.x and compute */ |
||||
/* the new metrics */ |
||||
if ( hinter->pp1.x ) |
||||
FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 ); |
||||
|
||||
FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); |
||||
bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); |
||||
bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); |
||||
bbox.xMax = FT_PIX_CEIL( bbox.xMax ); |
||||
bbox.yMax = FT_PIX_CEIL( bbox.yMax ); |
||||
|
||||
slot->metrics.width = bbox.xMax - bbox.xMin; |
||||
slot->metrics.height = bbox.yMax - bbox.yMin; |
||||
slot->metrics.horiBearingX = bbox.xMin; |
||||
slot->metrics.horiBearingY = bbox.yMax; |
||||
|
||||
/* for mono-width fonts (like Andale, Courier, etc.) we need */ |
||||
/* to keep the original rounded advance width */ |
||||
if ( !FT_IS_FIXED_WIDTH( slot->face ) ) |
||||
slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; |
||||
else |
||||
slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, |
||||
x_scale ); |
||||
|
||||
slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); |
||||
|
||||
/* now copy outline into glyph slot */ |
||||
af_loader_rewind( slot->internal->loader ); |
||||
error = af_loader_copy_points( slot->internal->loader, gloader ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
slot->outline = slot->internal->loader->base.outline; |
||||
slot->format = FT_GLYPH_FORMAT_OUTLINE; |
||||
} |
||||
|
||||
#ifdef DEBUG_HINTER |
||||
af_debug_hinter = hinter; |
||||
#endif |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
/* load and hint a given glyph */ |
||||
FT_LOCAL_DEF( FT_Error ) |
||||
af_hinter_load_glyph( AF_Hinter hinter, |
||||
FT_GlyphSlot slot, |
||||
FT_Size size, |
||||
FT_UInt glyph_index, |
||||
FT_Int32 load_flags ) |
||||
{ |
||||
FT_Face face = slot->face; |
||||
FT_Error error; |
||||
FT_Fixed x_scale = size->metrics.x_scale; |
||||
FT_Fixed y_scale = size->metrics.y_scale; |
||||
AF_Face_Globals face_globals = FACE_GLOBALS( face ); |
||||
FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags ); |
||||
|
||||
|
||||
/* first of all, we need to check that we're using the correct face and */ |
||||
/* global hints to load the glyph */ |
||||
if ( hinter->face != face || hinter->globals != face_globals ) |
||||
{ |
||||
hinter->face = face; |
||||
if ( !face_globals ) |
||||
{ |
||||
error = af_hinter_new_face_globals( hinter, face, 0 ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
} |
||||
hinter->globals = FACE_GLOBALS( face ); |
||||
face_globals = FACE_GLOBALS( face ); |
||||
|
||||
} |
||||
|
||||
#ifdef FT_CONFIG_CHESTER_BLUE_SCALE |
||||
|
||||
/* try to optimize the y_scale so that the top of non-capital letters
|
||||
* is aligned on a pixel boundary whenever possible |
||||
*/ |
||||
{ |
||||
AF_Globals design = &face_globals->design; |
||||
FT_Pos shoot = design->blue_shoots[AF_BLUE_SMALL_TOP]; |
||||
|
||||
|
||||
/* the value of 'shoot' will be -1000 if the font doesn't have */ |
||||
/* small latin letters; we simply check the sign here... */ |
||||
if ( shoot > 0 ) |
||||
{ |
||||
FT_Pos scaled = FT_MulFix( shoot, y_scale ); |
||||
FT_Pos fitted = FT_PIX_ROUND( scaled ); |
||||
|
||||
|
||||
if ( scaled != fitted ) |
||||
{ |
||||
/* adjust y_scale
|
||||
*/ |
||||
y_scale = FT_MulDiv( y_scale, fitted, scaled ); |
||||
|
||||
/* adust x_scale
|
||||
*/ |
||||
if ( fitted < scaled ) |
||||
x_scale -= x_scale / 50; /* x_scale*0.98 with integers */ |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ |
||||
|
||||
/* now, we must check the current character pixel size to see if we */ |
||||
/* need to rescale the global metrics */ |
||||
if ( face_globals->x_scale != x_scale || |
||||
face_globals->y_scale != y_scale ) |
||||
af_hinter_scale_globals( hinter, x_scale, y_scale ); |
||||
|
||||
af_loader_rewind( hinter->loader ); |
||||
|
||||
/* reset hinting flags according to load flags and current render target */ |
||||
hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) ); |
||||
hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) ); |
||||
|
||||
#ifdef DEBUG_HINTER |
||||
hinter->do_horz_hints = !af_debug_disable_vert; /* not a bug, the meaning */ |
||||
hinter->do_vert_hints = !af_debug_disable_horz; /* of h/v is inverted! */ |
||||
#endif |
||||
|
||||
/* we snap the width of vertical stems for the monochrome and */ |
||||
/* horizontal LCD rendering targets only. Corresponds to X snapping. */ |
||||
hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || |
||||
hint_mode == FT_RENDER_MODE_LCD ); |
||||
|
||||
/* we snap the width of horizontal stems for the monochrome and */ |
||||
/* vertical LCD rendering targets only. Corresponds to Y snapping. */ |
||||
hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || |
||||
hint_mode == FT_RENDER_MODE_LCD_V ); |
||||
|
||||
hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); |
||||
|
||||
load_flags |= FT_LOAD_NO_SCALE |
||||
| FT_LOAD_IGNORE_TRANSFORM; |
||||
load_flags &= ~FT_LOAD_RENDER; |
||||
|
||||
error = af_hinter_load( hinter, glyph_index, load_flags, 0 ); |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
@ -0,0 +1,5 @@ |
||||
#ifndef __AFMODULE_H__ |
||||
#define __AFMODULE_H__ |
||||
|
||||
#endif /* __AFMODULE_H__ */ |
||||
|
@ -0,0 +1,7 @@ |
||||
#define FT_MAKE_OPTION_SINGLE_OBJECT |
||||
|
||||
#include <ft2build.h> |
||||
#include "afangles.c" |
||||
#include "afglobal.c" |
||||
#include "afhints.c" |
||||
#include "aflatin.c" |
Loading…
Reference in new issue