summaryrefslogtreecommitdiffstats
path: root/src/autofit/aflatin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/autofit/aflatin.c')
-rw-r--r--src/autofit/aflatin.c371
1 files changed, 249 insertions, 122 deletions
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 30145a2..ef0157a 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -4,7 +4,7 @@
/* */
/* Auto-fitter hinting routines for latin script (body). */
/* */
-/* Copyright 2003-2011 by */
+/* Copyright 2003-2013 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -20,6 +20,7 @@
#include FT_ADVANCES_H
#include FT_INTERNAL_DEBUG_H
+#include "afglobal.h"
#include "aflatin.h"
#include "aferrors.h"
@@ -53,30 +54,36 @@
FT_LOCAL_DEF( void )
af_latin_metrics_init_widths( AF_LatinMetrics metrics,
- FT_Face face,
- FT_ULong charcode )
+ FT_Face face )
{
/* scan the array of segments in each direction */
AF_GlyphHintsRec hints[1];
+ FT_TRACE5(( "standard widths computation\n"
+ "===========================\n\n" ));
+
af_glyph_hints_init( hints, face->memory );
metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
metrics->axis[AF_DIMENSION_VERT].width_count = 0;
{
- FT_Error error;
- FT_UInt glyph_index;
- int dim;
- AF_LatinMetricsRec dummy[1];
- AF_Scaler scaler = &dummy->root.scaler;
+ FT_Error error;
+ FT_UInt glyph_index;
+ int dim;
+ AF_LatinMetricsRec dummy[1];
+ AF_Scaler scaler = &dummy->root.scaler;
- glyph_index = FT_Get_Char_Index( face, charcode );
+ glyph_index = FT_Get_Char_Index( face,
+ metrics->root.clazz->standard_char );
if ( glyph_index == 0 )
goto Exit;
+ FT_TRACE5(( "standard character: 0x%X (glyph index %d)\n",
+ metrics->root.clazz->standard_char, glyph_index ));
+
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if ( error || face->glyph->outline.n_points <= 0 )
goto Exit;
@@ -138,7 +145,10 @@
}
}
- af_sort_widths( num_widths, axis->widths );
+ /* this also replaces multiple almost identical stem widths */
+ /* with a single one (the value 100 is heuristic) */
+ af_sort_and_quantize_widths( &num_widths, axis->widths,
+ dummy->units_per_em / 100 );
axis->width_count = num_widths;
}
@@ -157,9 +167,28 @@
axis->edge_distance_threshold = stdw / 5;
axis->standard_width = stdw;
axis->extra_light = 0;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_UInt i;
+
+
+ FT_TRACE5(( "%s widths:\n",
+ dim == AF_DIMENSION_VERT ? "horizontal"
+ : "vertical" ));
+
+ FT_TRACE5(( " %d (standard)", axis->standard_width ));
+ for ( i = 1; i < axis->width_count; i++ )
+ FT_TRACE5(( " %d", axis->widths[i].org ));
+
+ FT_TRACE5(( "\n" ));
+ }
+#endif
}
}
+ FT_TRACE5(( "\n" ));
+
af_glyph_hints_done( hints );
}
@@ -195,15 +224,15 @@
AF_LatinBlue blue;
FT_Error error;
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
- FT_GlyphSlot glyph = face->glyph;
+ FT_Outline outline;
/* we compute the blues simply by loading each character from the */
/* `af_latin_blue_chars[blues]' string, then finding its top-most or */
/* bottom-most points (depending on `AF_IS_TOP_BLUE') */
- FT_TRACE5(( "blue zones computation\n" ));
- FT_TRACE5(( "------------------------------------------------\n" ));
+ FT_TRACE5(( "blue zones computation\n"
+ "======================\n\n" ));
for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
{
@@ -213,7 +242,7 @@
FT_Pos* blue_shoot;
- FT_TRACE5(( "blue %3d: ", bb ));
+ FT_TRACE5(( "blue zone %d:\n", bb ));
num_flats = 0;
num_rounds = 0;
@@ -222,28 +251,27 @@
{
FT_UInt glyph_index;
FT_Pos best_y; /* same as points.y */
- FT_Int best_point, best_first, best_last;
+ FT_Int best_point, best_contour_first, best_contour_last;
FT_Vector* points;
FT_Bool round = 0;
- FT_TRACE5(( "'%c'", *p ));
-
/* load the character in the face -- skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
if ( glyph_index == 0 )
continue;
- error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
- if ( error || glyph->outline.n_points <= 0 )
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ outline = face->glyph->outline;
+ if ( error || outline.n_points <= 0 )
continue;
/* now compute min or max point indices and coordinates */
- points = glyph->outline.points;
- best_point = -1;
- best_y = 0; /* make compiler happy */
- best_first = 0; /* ditto */
- best_last = 0; /* ditto */
+ points = outline.points;
+ best_point = -1;
+ best_y = 0; /* make compiler happy */
+ best_contour_first = 0; /* ditto */
+ best_contour_last = 0; /* ditto */
{
FT_Int nn;
@@ -251,15 +279,13 @@
FT_Int last = -1;
- for ( nn = 0;
- nn < glyph->outline.n_contours;
- first = last + 1, nn++ )
+ for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
{
FT_Int old_best_point = best_point;
FT_Int pp;
- last = glyph->outline.contours[nn];
+ last = outline.contours[nn];
/* Avoid single-point contours since they are never rasterized. */
/* In some fonts, they correspond to mark attachment points */
@@ -288,11 +314,11 @@
if ( best_point != old_best_point )
{
- best_first = first;
- best_last = last;
+ best_contour_first = first;
+ best_contour_last = last;
}
}
- FT_TRACE5(( "%5d", best_y ));
+ FT_TRACE5(( " %c %ld", *p, best_y ));
}
/* now check whether the point belongs to a straight or round */
@@ -300,47 +326,86 @@
/* lies, then inspect its previous and next points */
if ( best_point >= 0 )
{
+ FT_Pos best_x = points[best_point].x;
FT_Int prev, next;
+ FT_Int best_on_point_first, best_on_point_last;
FT_Pos dist;
- /* now look for the previous and next points that are not on the */
- /* same Y coordinate. Threshold the `closeness'... */
+ if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
+ {
+ best_on_point_first = best_point;
+ best_on_point_last = best_point;
+ }
+ else
+ {
+ best_on_point_first = -1;
+ best_on_point_last = -1;
+ }
+
+ /* look for the previous and next points that are not on the */
+ /* same Y coordinate, then threshold the `closeness'... */
prev = best_point;
next = prev;
do
{
- if ( prev > best_first )
+ if ( prev > best_contour_first )
prev--;
else
- prev = best_last;
+ prev = best_contour_last;
- dist = points[prev].y - best_y;
- if ( dist < -5 || dist > 5 )
- break;
+ dist = FT_ABS( points[prev].y - best_y );
+ /* accept a small distance or a small angle (both values are */
+ /* heuristic; value 20 corresponds to approx. 2.9 degrees) */
+ if ( dist > 5 )
+ if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
+ break;
+
+ if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
+ {
+ best_on_point_first = prev;
+ if ( best_on_point_last < 0 )
+ best_on_point_last = prev;
+ }
} while ( prev != best_point );
do
{
- if ( next < best_last )
+ if ( next < best_contour_last )
next++;
else
- next = best_first;
+ next = best_contour_first;
- dist = points[next].y - best_y;
- if ( dist < -5 || dist > 5 )
- break;
+ dist = FT_ABS( points[next].y - best_y );
+ if ( dist > 5 )
+ if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
+ break;
+
+ if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
+ {
+ best_on_point_last = next;
+ if ( best_on_point_first < 0 )
+ best_on_point_first = next;
+ }
} while ( next != best_point );
/* now set the `round' flag depending on the segment's kind */
- round = FT_BOOL(
- FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
- FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+ /* (value 8 is heuristic) */
+ if ( best_on_point_first >= 0 &&
+ best_on_point_last >= 0 &&
+ (FT_UInt)( FT_ABS( points[best_on_point_last].x -
+ points[best_on_point_first].x ) ) >
+ metrics->units_per_em / 8 )
+ round = 0;
+ else
+ round = FT_BOOL(
+ FT_CURVE_TAG( outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+ FT_CURVE_TAG( outline.tags[next] ) != FT_CURVE_TAG_ON );
- FT_TRACE5(( "%c ", round ? 'r' : 'f' ));
+ FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
}
if ( round )
@@ -349,15 +414,13 @@
flats[num_flats++] = best_y;
}
- FT_TRACE5(( "\n" ));
-
if ( num_flats == 0 && num_rounds == 0 )
{
/*
* we couldn't find a single glyph to compute this blue zone,
* we will simply ignore it then
*/
- FT_TRACE5(( "empty\n" ));
+ FT_TRACE5(( " empty\n" ));
continue;
}
@@ -400,8 +463,13 @@
if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
+ {
*blue_ref =
*blue_shoot = ( shoot + ref ) / 2;
+
+ FT_TRACE5(( " [overshoot smaller than reference,"
+ " taking mean value]\n" ));
+ }
}
blue->flags = 0;
@@ -416,7 +484,9 @@
if ( bb == AF_LATIN_BLUE_SMALL_TOP )
blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
- FT_TRACE5(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ FT_TRACE5(( " -> reference = %ld\n"
+ " overshoot = %ld\n",
+ *blue_ref, *blue_shoot ));
}
FT_TRACE5(( "\n" ));
@@ -478,41 +548,20 @@
af_latin_metrics_init( AF_LatinMetrics metrics,
FT_Face face )
{
- FT_Error error = AF_Err_Ok;
FT_CharMap oldmap = face->charmap;
- FT_UInt ee;
-
- static const FT_Encoding latin_encodings[] =
- {
- FT_ENCODING_UNICODE,
- FT_ENCODING_APPLE_ROMAN,
- FT_ENCODING_ADOBE_STANDARD,
- FT_ENCODING_ADOBE_LATIN_1,
-
- FT_ENCODING_NONE /* end of list */
- };
metrics->units_per_em = face->units_per_EM;
- /* do we have a latin charmap in there? */
- for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
- {
- error = FT_Select_Charmap( face, latin_encodings[ee] );
- if ( !error )
- break;
- }
-
- if ( !error )
+ if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
{
- /* For now, compute the standard width and height from the `o'. */
- af_latin_metrics_init_widths( metrics, face, 'o' );
+ af_latin_metrics_init_widths( metrics, face );
af_latin_metrics_init_blues( metrics, face );
af_latin_metrics_check_digits( metrics, face );
}
FT_Set_Charmap( face, oldmap );
- return AF_Err_Ok;
+ return FT_Err_Ok;
}
@@ -569,9 +618,26 @@
if ( blue )
{
- FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
- FT_Pos fitted = ( scaled + 40 ) & ~63;
+ FT_Pos scaled;
+ FT_Pos threshold;
+ FT_Pos fitted;
+ FT_UInt limit;
+ FT_UInt ppem;
+
+
+ scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
+ ppem = metrics->root.scaler.face->size->metrics.x_ppem;
+ limit = metrics->root.globals->increase_x_height;
+ threshold = 40;
+
+ /* if the `increase-x-height' property is active, */
+ /* we round up much more often */
+ if ( limit &&
+ ppem <= limit &&
+ ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN )
+ threshold = 52;
+ fitted = ( scaled + threshold ) & ~63;
if ( scaled != fitted )
{
@@ -677,7 +743,7 @@
if ( delta2 < 32 )
delta2 = 0;
- else if ( delta < 48 )
+ else if ( delta2 < 48 )
delta2 = 32;
else
delta2 = 64;
@@ -705,6 +771,7 @@
{
metrics->root.scaler.render_mode = scaler->render_mode;
metrics->root.scaler.face = scaler->face;
+ metrics->root.scaler.flags = scaler->flags;
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
@@ -728,7 +795,7 @@
{
AF_AxisHints axis = &hints->axis[dim];
FT_Memory memory = hints->memory;
- FT_Error error = AF_Err_Ok;
+ FT_Error error = FT_Err_Ok;
AF_Segment segment = NULL;
AF_SegmentRec seg0;
AF_Point* contour = hints->contours;
@@ -848,7 +915,7 @@
on_edge = 0;
segment = NULL;
- /* fallthrough */
+ /* fall through */
}
}
@@ -884,8 +951,8 @@
} /* contours */
- /* now slightly increase the height of segments when this makes */
- /* sense -- this is used to better detect and ignore serifs */
+ /* now slightly increase the height of segments if this makes */
+ /* sense -- this is used to better detect and ignore serifs */
{
AF_Segment segments = axis->segments;
AF_Segment segments_end = segments + axis->num_segments;
@@ -1040,7 +1107,7 @@
AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
- FT_Error error = AF_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_Memory memory = hints->memory;
AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
@@ -1169,17 +1236,17 @@
}
- /*********************************************************************/
- /* */
- /* Good, we will now compute each edge's properties according to */
- /* the segments found on its position. Basically, these are */
- /* */
- /* - the edge's main direction */
- /* - stem edge, serif edge or both (which defaults to stem then) */
- /* - rounded edge, straight or both (which defaults to straight) */
- /* - link for edge */
- /* */
- /*********************************************************************/
+ /******************************************************************/
+ /* */
+ /* Good, we now compute each edge's properties according to the */
+ /* segments found on its position. Basically, these are */
+ /* */
+ /* - the edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straight or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /******************************************************************/
/* first of all, set the `edge' field in each segment -- this is */
/* required in order to compute edge links */
@@ -1367,7 +1434,7 @@
/* for each horizontal edge search the blue zone which is closest */
for ( ; edge < edge_limit; edge++ )
{
- FT_Int bb;
+ FT_UInt bb;
AF_Width best_blue = NULL;
FT_Pos best_dist; /* initial threshold */
@@ -1380,7 +1447,7 @@
if ( best_dist > 64 / 2 )
best_dist = 64 / 2;
- for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
+ for ( bb = 0; bb < latin->blue_count; bb++ )
{
AF_LatinBlue blue = latin->blues + bb;
FT_Bool is_top_blue, is_major_dir;
@@ -1476,9 +1543,7 @@
#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
- {
metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
- }
#endif
scaler_flags = hints->scaler_flags;
@@ -1518,7 +1583,7 @@
hints->scaler_flags = scaler_flags;
hints->other_flags = other_flags;
- return AF_Err_Ok;
+ return FT_Err_Ok;
}
@@ -1722,7 +1787,7 @@
if ( delta < 0 )
delta = -delta;
- if (delta >= 16)
+ if ( delta >= 16 )
{
dist = org_dist;
if ( dist < 48 )
@@ -1762,7 +1827,7 @@
stem_edge->pos = base_edge->pos + fitted_width;
- FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to (%.2f),"
+ FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f,"
" dist was %.2f, now %.2f\n",
stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
@@ -1808,9 +1873,13 @@
AF_Edge anchor = NULL;
FT_Int has_serifs = 0;
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_UInt num_actions = 0;
+#endif
+
- FT_TRACE5(("%s edge hinting\n", dim == AF_DIMENSION_VERT ? "horizontal"
- : "vertical"));
+ FT_TRACE5(( "%s edge hinting\n",
+ dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" ));
/* we begin by aligning all stems relative to the blue zone */
/* if needed -- that's only for horizontal edges */
@@ -1844,10 +1913,20 @@
if ( !edge1 )
continue;
- FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to (%.2f),"
- " was (%.2f)\n",
- edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
- edge1->pos / 64.0 ));
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( !anchor )
+ FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f,"
+ " was %.2f (anchor=edge %d)\n",
+ edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
+ edge1->pos / 64.0, edge - edges ));
+ else
+ FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f,"
+ " was %.2f\n",
+ edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
+ edge1->pos / 64.0 ));
+
+ num_actions++;
+#endif
edge1->pos = blue->fit;
edge1->flags |= AF_EDGE_DONE;
@@ -1856,6 +1935,10 @@
{
af_latin_align_linked_edge( hints, dim, edge1, edge2 );
edge2->flags |= AF_EDGE_DONE;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ num_actions++;
+#endif
}
if ( !anchor )
@@ -1890,6 +1973,10 @@
af_latin_align_linked_edge( hints, dim, edge2, edge );
edge->flags |= AF_EDGE_DONE;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ num_actions++;
+#endif
continue;
}
@@ -1947,16 +2034,20 @@
else
edge->pos = FT_PIX_ROUND( edge->opos );
+ anchor = edge;
+ edge->flags |= AF_EDGE_DONE;
+
FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
- " snapped to (%.2f) (%.2f)\n",
+ " snapped to %.2f and %.2f\n",
edge - edges, edge->opos / 64.0,
edge2 - edges, edge2->opos / 64.0,
edge->pos / 64.0, edge2->pos / 64.0 ));
- anchor = edge;
-
- edge->flags |= AF_EDGE_DONE;
af_latin_align_linked_edge( hints, dim, edge, edge2 );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ num_actions += 2;
+#endif
}
else
{
@@ -1989,7 +2080,7 @@
cur_pos1 = FT_PIX_ROUND( org_center );
- if (cur_len <= 64 )
+ if ( cur_len <= 64 )
{
u_off = 32;
d_off = 32;
@@ -2016,12 +2107,13 @@
edge->pos = cur_pos1 - cur_len / 2;
edge2->pos = cur_pos1 + cur_len / 2;
- FT_TRACE5(( " STEM: %d (opos=%.2f) to %d (opos=%.2f)"
- " snapped to (%.2f) and (%.2f)\n",
+ FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
+ " snapped to %.2f and %.2f\n",
edge - edges, edge->opos / 64.0,
edge2 - edges, edge2->opos / 64.0,
edge->pos / 64.0, edge2->pos / 64.0 ));
}
+
else
{
org_pos = anchor->pos + ( edge->opos - anchor->opos );
@@ -2046,20 +2138,29 @@
edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
edge2->pos = edge->pos + cur_len;
- FT_TRACE5(( " STEM: %d (opos=%.2f) to %d (opos=%.2f)"
- " snapped to (%.2f) and (%.2f)\n",
+ FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
+ " snapped to %.2f and %.2f\n",
edge - edges, edge->opos / 64.0,
edge2 - edges, edge2->opos / 64.0,
edge->pos / 64.0, edge2->pos / 64.0 ));
}
+#ifdef FT_DEBUG_LEVEL_TRACE
+ num_actions++;
+#endif
+
edge->flags |= AF_EDGE_DONE;
edge2->flags |= AF_EDGE_DONE;
if ( edge > edges && edge->pos < edge[-1].pos )
{
- FT_TRACE5(( " BOUND: %d (pos=%.2f) to (%.2f)\n",
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
+
+ num_actions++;
+#endif
+
edge->pos = edge[-1].pos;
}
}
@@ -2154,7 +2255,7 @@
{
af_latin_align_serif_edge( hints, edge->serif, edge );
FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
- " aligned to (%.2f)\n",
+ " aligned to %.2f\n",
edge - edges, edge->opos / 64.0,
edge->serif - edges, edge->serif->opos / 64.0,
edge->pos / 64.0 ));
@@ -2164,7 +2265,7 @@
edge->pos = FT_PIX_ROUND( edge->opos );
anchor = edge;
FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)"
- " snapped to (%.2f)\n",
+ " snapped to %.2f\n",
edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
}
else
@@ -2191,7 +2292,7 @@
after->pos - before->pos,
after->opos - before->opos );
- FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f)"
+ FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f"
" from %d (opos=%.2f)\n",
edge - edges, edge->opos / 64.0,
edge->pos / 64.0,
@@ -2201,26 +2302,49 @@
{
edge->pos = anchor->pos +
( ( edge->opos - anchor->opos + 16 ) & ~31 );
-
FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)"
- " snapped to (%.2f)\n",
+ " snapped to %.2f\n",
edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
}
}
+#ifdef FT_DEBUG_LEVEL_TRACE
+ num_actions++;
+#endif
edge->flags |= AF_EDGE_DONE;
if ( edge > edges && edge->pos < edge[-1].pos )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
+ edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
+
+ num_actions++;
+#endif
edge->pos = edge[-1].pos;
+ }
if ( edge + 1 < edge_limit &&
edge[1].flags & AF_EDGE_DONE &&
edge->pos > edge[1].pos )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
+ edge - edges, edge->pos / 64.0, edge[1].pos / 64.0 ));
+
+ num_actions++;
+#endif
+
edge->pos = edge[1].pos;
+ }
}
}
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( !num_actions )
+ FT_TRACE5(( " (none)\n" ));
FT_TRACE5(( "\n" ));
+#endif
}
@@ -2333,10 +2457,12 @@
AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), /* Enclosed Alphanumerics */
AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), /* Latin Extended-C */
AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */
+ AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), /* Supplemental Punctuation */
AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */
AF_UNIRANGE_REC( 0xA720UL, 0xA7FFUL ), /* Latin Extended-D */
AF_UNIRANGE_REC( 0xFB00UL, 0xFB06UL ), /* Alphab. Present. Forms (Latin Ligs) */
AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ), /* Mathematical Alphanumeric Symbols */
+ AF_UNIRANGE_REC( 0x1F100UL, 0x1F1FFUL ), /* Enclosed Alphanumeric Supplement */
AF_UNIRANGE_REC( 0UL, 0UL )
};
@@ -2344,6 +2470,7 @@
AF_DEFINE_SCRIPT_CLASS( af_latin_script_class,
AF_SCRIPT_LATIN,
af_latin_uniranges,
+ 'o',
sizeof ( AF_LatinMetricsRec ),