From 8ccb4552a965821f2e5e9913b9c600322667483c Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 16 Jan 2004 09:51:00 +0000 Subject: [PATCH] updates --- src/autofit/Jamfile | 18 ++ src/autofit/afglobal.c | 7 +- src/autofit/afglobal.h | 5 +- src/autofit/afhints.c | 7 +- src/autofit/aflatin.c | 27 +-- src/autofit/aflatin.h | 18 +- src/autofit/afloader.c | 505 +++++++++++++++++++++++++++++++++++++++++ src/autofit/afloader.h | 46 ++++ src/autofit/afmodule.c | 437 +++++++++++++++++++++++++++++++++++ src/autofit/afmodule.h | 5 + src/autofit/aftypes.h | 2 + src/autofit/autofit.c | 7 + 12 files changed, 1052 insertions(+), 32 deletions(-) create mode 100644 src/autofit/Jamfile create mode 100644 src/autofit/afloader.c create mode 100644 src/autofit/afloader.h create mode 100644 src/autofit/afmodule.c create mode 100644 src/autofit/afmodule.h create mode 100644 src/autofit/autofit.c diff --git a/src/autofit/Jamfile b/src/autofit/Jamfile new file mode 100644 index 000000000..a5a6445f5 --- /dev/null +++ b/src/autofit/Jamfile @@ -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 diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c index e3f569b45..636203637 100644 --- a/src/autofit/afglobal.c +++ b/src/autofit/afglobal.c @@ -184,11 +184,10 @@ FT_UInt gindex, AF_ScriptMetrics *ametrics ) { - AF_Script script; AF_ScriptMetrics metrics = NULL; FT_UInt index; AF_ScriptClass clazz; - FT_Error error; + FT_Error error = 0; if ( gindex >= globals->glyph_count ) { @@ -203,6 +202,8 @@ { /* create the global metrics object when needed */ + FT_Memory memory = globals->face->memory; + if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) goto Exit; @@ -221,7 +222,7 @@ } } - globals->metrics[ script ] = metrics; + globals->metrics[ clazz->script ] = metrics; } Exit: diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h index 81b4800bc..64f35c3ff 100644 --- a/src/autofit/afglobal.h +++ b/src/autofit/afglobal.h @@ -20,13 +20,12 @@ FT_BEGIN_HEADER * */ typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; - + FT_LOCAL( FT_Error ) af_face_globals_new( FT_Face face, AF_FaceGlobals *aglobals ); - FT_LOCAL( FT_Error ) af_face_globals_get_metrics( AF_FaceGlobals globals, FT_UInt gindex, @@ -36,7 +35,7 @@ FT_BEGIN_HEADER af_face_globals_free( AF_FaceGlobals globals ); /* */ - + FT_END_HEADER #endif /* __AF_GLOBALS_H__ */ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index 04275f36d..9645cf796 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -303,6 +303,7 @@ FT_Fixed y_scale = scaler->y_scale; FT_Pos x_delta = scaler->x_delta; FT_Pos y_delta = scaler->y_delta; + FT_Memory memory = hints->memory; hints->scaler_flags = scaler->flags; hints->other_flags = 0; @@ -505,13 +506,13 @@ in_x = point->fx - prev->fx; in_y = point->fy - prev->fy; - point->in_dir = af_compute_direction( in_x, in_y ); + point->in_dir = af_direction_compute( in_x, in_y ); next = point->next; out_x = next->fx - point->fx; out_y = next->fy - point->fy; - point->out_dir = af_compute_direction( out_x, out_y ); + point->out_dir = af_direction_compute( out_x, out_y ); if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) { @@ -623,8 +624,6 @@ AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Flags touch_flag; - AF_Point point; - AF_Edge edge; if ( dim == AF_DIMENSION_HORZ ) diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index ac9a7c607..2fd7236bf 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -176,7 +176,7 @@ extremum = point; point++; - if ( AF_IS_TOP_BLUE( bb ) ) + if ( AF_LATIN_IS_TOP_BLUE( bb ) ) { for ( ; point < point_limit; point++ ) if ( point->y > extremum->y ) @@ -325,7 +325,6 @@ AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); } - Exit: return; } @@ -398,7 +397,6 @@ for ( nn = 0; nn < axis->blue_count; nn++ ) { AF_LatinBlue blue = & axis->blues[nn]; - FT_UInt flags = blue->flags & ~AF_LATIN_BLUE_ACTIVE; FT_Pos dist; blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; @@ -1150,7 +1148,7 @@ */ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) hints->other_flags |= AF_LATIN_HINTS_VERT_SNAP; - + /* XXX */ if ( mode != FT_RENDER_MODE_LIGHT ) @@ -1163,7 +1161,7 @@ */ if ( AF_HINTS_DO_HORIZONTAL(hints) ) af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ ); - + if ( AF_HINTS_DO_VERTICAL(hints) ) { af_latin_hints_detect_features( hints, AF_DIMENSION_VERT ); @@ -1243,7 +1241,7 @@ FT_Pos dist = width; FT_Int sign = 0; FT_Int vertical = AF_HINTS_DO_VERTICAL( hints ); - + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) return width; @@ -1254,8 +1252,8 @@ sign = 1; } - if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAPPING( hints ) ) || - ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAPPING( hints ) ) ) + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ /* */ @@ -1282,7 +1280,7 @@ if ( axis->width_count > 0 ) { delta = dist - axis->widths[0].cur; - + if ( delta < 0 ) delta = -delta; @@ -1699,7 +1697,7 @@ anchor = edge; } else - edge->pos = anchor->pos + + edge->pos = anchor->pos + FT_PIX_ROUND( edge->opos - anchor->opos ); edge->flags |= AF_EDGE_DONE; @@ -1722,11 +1720,14 @@ AF_LatinMetrics metrics ) { AF_Dimension dim; - + + FT_UNUSED( scaler ); + FT_UNUSED( metrics ); + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { - if ( (dim == AF_DIMENSION_HORZ && AF_LATIN_HINTS_DO_HORIZONTAL(hints)) || - (dim == AF_DIMENSION_VERT && AF_LATIN_HINTS_DO_VERTICAL(hints)) ) + if ( (dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL(hints)) || + (dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL(hints)) ) { af_latin_hint_edges( hints, dim ); af_glyph_hints_align_edge_points( hints, dim ); diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h index a2595038a..c3476c564 100644 --- a/src/autofit/aflatin.h +++ b/src/autofit/aflatin.h @@ -4,8 +4,8 @@ #include "afhints.h" FT_BEGIN_HEADER - - /* + + /* * the latin-specific script class * */ @@ -38,7 +38,7 @@ FT_BEGIN_HEADER AF_LATIN_BLUE_SMALL_TOP, AF_LATIN_BLUE_SMALL_BOTTOM, AF_LATIN_BLUE_SMALL_MINOR, - + AF_LATIN_BLUE_MAX }; @@ -53,7 +53,7 @@ FT_BEGIN_HEADER { AF_LATIN_BLUE_ACTIVE = (1 << 0), AF_LATIN_BLUE_TOP = (1 << 1), - + AF_LATIN_BLUE_FLAG_MAX }; @@ -63,7 +63,7 @@ FT_BEGIN_HEADER AF_WidthRec ref; AF_WidthRec shoot; FT_UInt flags; - + } AF_LatinBlueRec, *AF_LatinBlue; @@ -71,11 +71,11 @@ FT_BEGIN_HEADER { FT_Fixed scale; FT_Pos delta; - + FT_UInt width_count; AF_WidthRec widths[ AF_LATIN_MAX_WIDTHS ]; FT_Pos edge_distance_threshold; - + /* ignored for horizontal metrics */ FT_Bool control_overshoot; FT_UInt blue_count; @@ -89,7 +89,7 @@ FT_BEGIN_HEADER AF_ScriptMetricsRec root; FT_UInt units_per_em; AF_LatinAxisRec axis[ AF_DIMENSION_MAX ]; - + } AF_LatinMetricsRec, *AF_LatinMetrics; @@ -117,7 +117,7 @@ FT_BEGIN_HEADER AF_LATIN_HINTS_HORZ_SNAP = (1 << 0), /* enable stem width snapping */ AF_LATIN_HINTS_VERT_SNAP = (1 << 1), /* enable stem height snapping */ AF_LATIN_HINTS_STEM_ADJUST = (1 << 2), /* enable stem width/height adjustment */ - AF_LATIN_HINTS_MONO = (1 << 3), /* indicate monochrome rendering */ + AF_LATIN_HINTS_MONO = (1 << 3) /* indicate monochrome rendering */ }; #define AF_LATIN_HINTS_DO_HORZ_SNAP(h) \ diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c new file mode 100644 index 000000000..e2b5260f9 --- /dev/null +++ b/src/autofit/afloader.c @@ -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; + } diff --git a/src/autofit/afloader.h b/src/autofit/afloader.h new file mode 100644 index 000000000..8385035e4 --- /dev/null +++ b/src/autofit/afloader.h @@ -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__ */ + diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c new file mode 100644 index 000000000..811ec3b8e --- /dev/null +++ b/src/autofit/afmodule.c @@ -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; + } diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h new file mode 100644 index 000000000..cf7e05bfe --- /dev/null +++ b/src/autofit/afmodule.h @@ -0,0 +1,5 @@ +#ifndef __AFMODULE_H__ +#define __AFMODULE_H__ + +#endif /* __AFMODULE_H__ */ + diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 0f1d243cc..f34771e99 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -227,10 +227,12 @@ FT_BEGIN_HEADER typedef FT_Error (*AF_Script_InitHintsFunc)( AF_GlyphHints hints, AF_Scaler scaler, + FT_Outline* outline, AF_ScriptMetrics metrics ); typedef void (*AF_Script_ApplyHintsFunc)( AF_GlyphHints hints, AF_Scaler scaler, + FT_Outline* outline, AF_ScriptMetrics metrics ); diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c new file mode 100644 index 000000000..b8b1c506b --- /dev/null +++ b/src/autofit/autofit.c @@ -0,0 +1,7 @@ +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include +#include "afangles.c" +#include "afglobal.c" +#include "afhints.c" +#include "aflatin.c"