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.c439
1 files changed, 265 insertions, 174 deletions
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 15a241e..a1f2b33 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -2,9 +2,9 @@
/* */
/* aflatin.c */
/* */
-/* Auto-fitter hinting routines for latin script (body). */
+/* Auto-fitter hinting routines for latin writing system (body). */
/* */
-/* Copyright 2003-2013 by */
+/* Copyright 2003-2014 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -21,6 +21,7 @@
#include FT_INTERNAL_DEBUG_H
#include "afglobal.h"
+#include "afpic.h"
#include "aflatin.h"
#include "aferrors.h"
@@ -61,10 +62,10 @@
FT_TRACE5(( "\n"
- "latin standard widths computation (script `%s')\n"
- "=================================================\n"
+ "latin standard widths computation (style `%s')\n"
+ "=====================================================\n"
"\n",
- af_script_names[metrics->root.script_class->script] ));
+ af_style_names[metrics->root.style_class->style] ));
af_glyph_hints_init( hints, face->memory );
@@ -73,20 +74,66 @@
{
FT_Error error;
- FT_UInt glyph_index;
+ FT_ULong glyph_index;
+ FT_Long y_offset;
int dim;
AF_LatinMetricsRec dummy[1];
AF_Scaler scaler = &dummy->root.scaler;
+#ifdef FT_CONFIG_OPTION_PIC
+ AF_FaceGlobals globals = metrics->root.globals;
+#endif
- glyph_index = FT_Get_Char_Index(
- face,
- metrics->root.script_class->standard_char );
- if ( glyph_index == 0 )
- goto Exit;
+ AF_StyleClass style_class = metrics->root.style_class;
+ AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET
+ [style_class->script];
+
+ FT_UInt32 standard_char;
+
+
+ /*
+ * We check more than a single standard character to catch features
+ * like `c2sc' (small caps from caps) that don't contain lowercase
+ * letters by definition, or other features that mainly operate on
+ * numerals.
+ */
+
+ standard_char = script_class->standard_char1;
+ af_get_char_index( &metrics->root,
+ standard_char,
+ &glyph_index,
+ &y_offset );
+ if ( !glyph_index )
+ {
+ if ( script_class->standard_char2 )
+ {
+ standard_char = script_class->standard_char2;
+ af_get_char_index( &metrics->root,
+ standard_char,
+ &glyph_index,
+ &y_offset );
+ if ( !glyph_index )
+ {
+ if ( script_class->standard_char3 )
+ {
+ standard_char = script_class->standard_char3;
+ af_get_char_index( &metrics->root,
+ standard_char,
+ &glyph_index,
+ &y_offset );
+ if ( !glyph_index )
+ goto Exit;
+ }
+ else
+ goto Exit;
+ }
+ }
+ else
+ goto Exit;
+ }
FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
- metrics->root.script_class->standard_char, glyph_index ));
+ standard_char, glyph_index ));
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if ( error || face->glyph->outline.n_points <= 0 )
@@ -105,7 +152,7 @@
scaler->render_mode = FT_RENDER_MODE_NORMAL;
scaler->flags = 0;
- af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
+ af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
error = af_glyph_hints_reload( hints, &face->glyph->outline );
if ( error )
@@ -124,7 +171,15 @@
if ( error )
goto Exit;
+ /*
+ * We assume that the glyphs selected for the stem width
+ * computation are `featureless' enough so that the linking
+ * algorithm works fine without adjustments of its scoring
+ * function.
+ */
af_latin_hints_link_segments( hints,
+ 0,
+ NULL,
(AF_Dimension)dim );
seg = axhints->segments;
@@ -214,12 +269,14 @@
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
FT_Outline outline;
- AF_Blue_Stringset bss = metrics->root.script_class->blue_stringset;
+ AF_StyleClass sc = metrics->root.style_class;
+
+ AF_Blue_Stringset bss = sc->blue_stringset;
const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
- /* we walk over the blue character strings as specified in the */
- /* script's entry in the `af_blue_stringset' array */
+ /* we walk over the blue character strings as specified in the */
+ /* style's entry in the `af_blue_stringset' array */
FT_TRACE5(( "latin blue zones computation\n"
"============================\n"
@@ -249,6 +306,14 @@
have_flag = 1;
}
+ if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
+ {
+ if ( have_flag )
+ FT_TRACE5(( ", " ));
+ FT_TRACE5(( "neutral" ));
+ have_flag = 1;
+ }
+
if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
{
if ( have_flag )
@@ -277,7 +342,8 @@
while ( *p )
{
FT_ULong ch;
- FT_UInt glyph_index;
+ FT_ULong glyph_index;
+ FT_Long y_offset;
FT_Pos best_y; /* same as points.y */
FT_Int best_point, best_contour_first, best_contour_last;
FT_Vector* points;
@@ -287,7 +353,7 @@
GET_UTF8_CHAR( ch, p );
/* load the character in the face -- skip unknown or empty ones */
- glyph_index = FT_Get_Char_Index( face, ch );
+ af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset );
if ( glyph_index == 0 )
{
FT_TRACE5(( " U+%04lX unavailable\n", ch ));
@@ -470,6 +536,13 @@
FT_Int last;
FT_Bool hit;
+ /* we intentionally declare these two variables */
+ /* outside of the loop since various compilers emit */
+ /* incorrect warning messages otherwise, talking about */
+ /* `possibly uninitialized variables' */
+ FT_Int p_first = 0; /* make compiler happy */
+ FT_Int p_last = 0;
+
FT_Bool left2right;
@@ -502,7 +575,6 @@
{
FT_Bool l2r;
FT_Pos d;
- FT_Int p_first, p_last;
if ( !hit )
@@ -575,7 +647,10 @@
if ( FT_ABS( points[next].x - points[first].x ) <=
20 * dist )
{
- last--;
+ if ( last > best_contour_first )
+ last--;
+ else
+ last = best_contour_last;
break;
}
@@ -606,6 +681,12 @@
}
}
+ /* for computing blue zones, we add the y offset as returned */
+ /* by the currently used OpenType feature -- for example, */
+ /* superscript glyphs might be identical to subscript glyphs */
+ /* with a vertical shift */
+ best_y += y_offset;
+
FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
/* now set the `round' flag depending on the segment's kind: */
@@ -629,6 +710,13 @@
FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
FT_CURVE_TAG_ON );
+ if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
+ {
+ /* only use flat segments for a neutral blue zone */
+ FT_TRACE5(( " (round, skipped)\n" ));
+ continue;
+ }
+
FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
}
@@ -699,6 +787,8 @@
blue->flags = 0;
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
blue->flags |= AF_LATIN_BLUE_TOP;
+ if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
+ blue->flags |= AF_LATIN_BLUE_NEUTRAL;
/*
* The following flag is used later to adjust the y and x scales
@@ -733,10 +823,11 @@
/* digit `0' is 0x30 in all supported charmaps */
for ( i = 0x30; i <= 0x39; i++ )
{
- FT_UInt glyph_index;
+ FT_ULong glyph_index;
+ FT_Long y_offset;
- glyph_index = FT_Get_Char_Index( face, i );
+ af_get_char_index( &metrics->root, i, &glyph_index, &y_offset );
if ( glyph_index == 0 )
continue;
@@ -879,11 +970,11 @@
FT_TRACE5((
"af_latin_metrics_scale_dim:"
- " x height alignment (script `%s'):\n"
+ " x height alignment (style `%s'):\n"
" "
" vertical scaling changed from %.4f to %.4f (by %d%%)\n"
"\n",
- af_script_names[metrics->root.script_class->script],
+ af_style_names[metrics->root.style_class->style],
axis->org_scale / 65536.0,
scale / 65536.0,
( fitted - scaled ) * 100 / scaled ));
@@ -906,9 +997,9 @@
metrics->root.scaler.y_delta = delta;
}
- FT_TRACE5(( "%s widths (script `%s')\n",
+ FT_TRACE5(( "%s widths (style `%s')\n",
dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
- af_script_names[metrics->root.script_class->script] ));
+ af_style_names[metrics->root.style_class->style] ));
/* scale the widths */
for ( nn = 0; nn < axis->width_count; nn++ )
@@ -933,15 +1024,15 @@
#ifdef FT_DEBUG_LEVEL_TRACE
if ( axis->extra_light )
- FT_TRACE5(( "`%s' script is extra light (at current resolution)\n"
+ FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
"\n",
- af_script_names[metrics->root.script_class->script] ));
+ af_style_names[metrics->root.style_class->style] ));
#endif
if ( dim == AF_DIMENSION_VERT )
{
- FT_TRACE5(( "blue zones (script `%s')\n",
- af_script_names[metrics->root.script_class->script] ));
+ FT_TRACE5(( "blue zones (style `%s')\n",
+ af_style_names[metrics->root.style_class->style] ));
/* scale the blue zones */
for ( nn = 0; nn < axis->blue_count; nn++ )
@@ -1277,25 +1368,40 @@
}
- /* Link segments to form stems and serifs. */
+ /* Link segments to form stems and serifs. If `width_count' and */
+ /* `widths' are non-zero, use them to fine-tune the scoring function. */
FT_LOCAL_DEF( void )
af_latin_hints_link_segments( AF_GlyphHints hints,
+ FT_UInt width_count,
+ AF_WidthRec* widths,
AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
AF_Segment segments = axis->segments;
AF_Segment segment_limit = segments + axis->num_segments;
- FT_Pos len_threshold, len_score;
+ FT_Pos len_threshold, len_score, dist_score, max_width;
AF_Segment seg1, seg2;
+ if ( width_count )
+ max_width = widths[width_count - 1].org;
+ else
+ max_width = 0;
+
+ /* a heuristic value to set up a minimum value for overlapping */
len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
if ( len_threshold == 0 )
len_threshold = 1;
+ /* a heuristic value to weight lengths */
len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
+ /* a heuristic value to weight distances (no call to */
+ /* AF_LATIN_CONSTANT needed, since we work on multiples */
+ /* of the stem width) */
+ dist_score = 3000;
+
/* now compare each segment to the others */
for ( seg1 = segments; seg1 < segment_limit; seg1++ )
{
@@ -1315,10 +1421,9 @@
if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
{
/* compute distance between the two segments */
- FT_Pos dist = pos2 - pos1;
- FT_Pos min = seg1->min_coord;
- FT_Pos max = seg1->max_coord;
- FT_Pos len, score;
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len;
if ( min < seg2->min_coord )
@@ -1328,15 +1433,49 @@
max = seg2->max_coord;
/* compute maximum coordinate difference of the two segments */
+ /* (this is, how much they overlap) */
len = max - min;
if ( len >= len_threshold )
{
- /* small coordinate differences cause a higher score, and */
- /* segments with a greater distance cause a higher score also */
- score = dist + len_score / len;
+ /*
+ * The score is the sum of two demerits indicating the
+ * `badness' of a fit, measured along the segments' main axis
+ * and orthogonal to it, respectively.
+ *
+ * o The less overlapping along the main axis, the worse it
+ * is, causing a larger demerit.
+ *
+ * o The nearer the orthogonal distance to a stem width, the
+ * better it is, causing a smaller demerit. For simplicity,
+ * however, we only increase the demerit for values that
+ * exceed the largest stem width.
+ */
+
+ FT_Pos dist = pos2 - pos1;
+
+ FT_Pos dist_demerit, score;
+
+
+ if ( max_width )
+ {
+ /* distance demerits are based on multiples of `max_width'; */
+ /* we scale by 1024 for getting more precision */
+ FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
+
+
+ if ( delta > 10000 )
+ dist_demerit = 32000;
+ else if ( delta > 0 )
+ dist_demerit = delta * delta / dist_score;
+ else
+ dist_demerit = 0;
+ }
+ else
+ dist_demerit = dist; /* default if no widths available */
+
+ score = dist_demerit + len_score / len;
/* and we search for the smallest score */
- /* of the sum of the two values */
if ( score < seg1->score )
{
seg1->score = score;
@@ -1668,6 +1807,8 @@
FT_LOCAL_DEF( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints,
+ FT_UInt width_count,
+ AF_WidthRec* widths,
AF_Dimension dim )
{
FT_Error error;
@@ -1676,7 +1817,7 @@
error = af_latin_hints_compute_segments( hints, dim );
if ( !error )
{
- af_latin_hints_link_segments( hints, dim );
+ af_latin_hints_link_segments( hints, width_count, widths, dim );
error = af_latin_hints_compute_edges( hints, dim );
}
@@ -1705,8 +1846,9 @@
for ( ; edge < edge_limit; edge++ )
{
FT_UInt bb;
- AF_Width best_blue = NULL;
- FT_Pos best_dist; /* initial threshold */
+ AF_Width best_blue = NULL;
+ FT_Bool best_blue_is_neutral = 0;
+ FT_Pos best_dist; /* initial threshold */
/* compute the initial threshold as a fraction of the EM size */
@@ -1720,24 +1862,26 @@
for ( bb = 0; bb < latin->blue_count; bb++ )
{
AF_LatinBlue blue = latin->blues + bb;
- FT_Bool is_top_blue, is_major_dir;
+ FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
/* skip inactive blue zones (i.e., those that are too large) */
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
continue;
- /* if it is a top zone, check for right edges -- if it is a bottom */
- /* zone, check for left edges */
- /* */
- /* of course, that's for TrueType */
- is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
- is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
-
- /* if it is a top zone, the edge must be against the major */
- /* direction; if it is a bottom zone, it must be in the major */
- /* direction */
- if ( is_top_blue ^ is_major_dir )
+ /* if it is a top zone, check for right edges (against the major */
+ /* direction); if it is a bottom zone, check for left edges (in */
+ /* the major direction) -- this assumes the TrueType convention */
+ /* for the orientation of contours */
+ is_top_blue =
+ (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
+ is_neutral_blue =
+ (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
+ is_major_dir =
+ FT_BOOL( edge->dir == axis->major_dir );
+
+ /* neutral blue zones are handled for both directions */
+ if ( is_top_blue ^ is_major_dir || is_neutral_blue )
{
FT_Pos dist;
@@ -1750,15 +1894,19 @@
dist = FT_MulFix( dist, scale );
if ( dist < best_dist )
{
- best_dist = dist;
- best_blue = &blue->ref;
+ best_dist = dist;
+ best_blue = &blue->ref;
+ best_blue_is_neutral = is_neutral_blue;
}
/* now compare it to the overshoot position and check whether */
/* the edge is rounded, and whether the edge is over the */
/* reference position of a top zone, or under the reference */
- /* position of a bottom zone */
- if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
+ /* position of a bottom zone (provided we don't have a */
+ /* neutral blue zone) */
+ if ( edge->flags & AF_EDGE_ROUND &&
+ dist != 0 &&
+ !is_neutral_blue )
{
FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
@@ -1772,8 +1920,9 @@
dist = FT_MulFix( dist, scale );
if ( dist < best_dist )
{
- best_dist = dist;
- best_blue = &blue->shoot;
+ best_dist = dist;
+ best_blue = &blue->shoot;
+ best_blue_is_neutral = is_neutral_blue;
}
}
}
@@ -1781,7 +1930,11 @@
}
if ( best_blue )
+ {
edge->blue_edge = best_blue;
+ if ( best_blue_is_neutral )
+ edge->flags |= AF_EDGE_NEUTRAL;
+ }
}
}
@@ -1797,7 +1950,7 @@
FT_Face face = metrics->root.scaler.face;
- af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
+ af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
/*
* correct x_scale and y_scale if needed, since they may have
@@ -2099,7 +2252,7 @@
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 - hints->axis[dim].edges, stem_edge->opos / 64.0,
stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
}
@@ -2148,9 +2301,9 @@
#endif
- FT_TRACE5(( "latin %s edge hinting (script `%s')\n",
+ FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
- af_script_names[hints->metrics->script_class->script] ));
+ af_style_names[hints->metrics->style_class->style] ));
/* we begin by aligning all stems relative to the blue zone */
/* if needed -- that's only for horizontal edges */
@@ -2166,14 +2319,41 @@
if ( edge->flags & AF_EDGE_DONE )
continue;
- blue = edge->blue_edge;
edge1 = NULL;
edge2 = edge->link;
+ /*
+ * If a stem contains both a neutral and a non-neutral blue zone,
+ * skip the neutral one. Otherwise, outlines with different
+ * directions might be incorrectly aligned at the same vertical
+ * position.
+ *
+ * If we have two neutral blue zones, skip one of them.
+ *
+ */
+ if ( edge->blue_edge && edge2 && edge2->blue_edge )
+ {
+ FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
+ FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
+
+
+ if ( ( neutral && neutral2 ) || neutral2 )
+ {
+ edge2->blue_edge = NULL;
+ edge2->flags &= ~AF_EDGE_NEUTRAL;
+ }
+ else if ( neutral )
+ {
+ edge->blue_edge = NULL;
+ edge->flags &= ~AF_EDGE_NEUTRAL;
+ }
+ }
+
+ blue = edge->blue_edge;
if ( blue )
edge1 = edge;
- /* flip edges if the other stem is aligned to a blue zone */
+ /* flip edges if the other edge is aligned to a blue zone */
else if ( edge2 && edge2->blue_edge )
{
blue = edge2->blue_edge;
@@ -2240,7 +2420,7 @@
/* this should not happen, but it's better to be safe */
if ( edge2->blue_edge )
{
- FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2-edges ));
+ FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges ));
af_latin_align_linked_edge( hints, dim, edge2, edge );
edge->flags |= AF_EDGE_DONE;
@@ -2629,6 +2809,8 @@
FT_Error error;
int dim;
+ AF_LatinAxis axis;
+
error = af_glyph_hints_reload( hints, outline );
if ( error )
@@ -2642,14 +2824,22 @@
if ( AF_HINTS_DO_HORIZONTAL( hints ) )
#endif
{
- error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
+ axis = &metrics->axis[AF_DIMENSION_HORZ];
+ error = af_latin_hints_detect_features( hints,
+ axis->width_count,
+ axis->widths,
+ AF_DIMENSION_HORZ );
if ( error )
goto Exit;
}
if ( AF_HINTS_DO_VERTICAL( hints ) )
{
- error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
+ axis = &metrics->axis[AF_DIMENSION_VERT];
+ error = af_latin_hints_detect_features( hints,
+ axis->width_count,
+ axis->widths,
+ AF_DIMENSION_VERT );
if ( error )
goto Exit;
@@ -2709,111 +2899,12 @@
sizeof ( AF_LatinMetricsRec ),
- (AF_Script_InitMetricsFunc) af_latin_metrics_init,
- (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale,
- (AF_Script_DoneMetricsFunc) NULL,
-
- (AF_Script_InitHintsFunc) af_latin_hints_init,
- (AF_Script_ApplyHintsFunc) af_latin_hints_apply
- )
-
-
- /* XXX: this should probably fine tuned to differentiate better between */
- /* scripts... */
-
- static const AF_Script_UniRangeRec af_latn_uniranges[] =
- {
- AF_UNIRANGE_REC( 0x0020UL, 0x007FUL ), /* Basic Latin (no control chars) */
- AF_UNIRANGE_REC( 0x00A0UL, 0x00FFUL ), /* Latin-1 Supplement (no control chars) */
- AF_UNIRANGE_REC( 0x0100UL, 0x017FUL ), /* Latin Extended-A */
- AF_UNIRANGE_REC( 0x0180UL, 0x024FUL ), /* Latin Extended-B */
- AF_UNIRANGE_REC( 0x0250UL, 0x02AFUL ), /* IPA Extensions */
- AF_UNIRANGE_REC( 0x02B0UL, 0x02FFUL ), /* Spacing Modifier Letters */
- AF_UNIRANGE_REC( 0x0300UL, 0x036FUL ), /* Combining Diacritical Marks */
- AF_UNIRANGE_REC( 0x1D00UL, 0x1D7FUL ), /* Phonetic Extensions */
- AF_UNIRANGE_REC( 0x1D80UL, 0x1DBFUL ), /* Phonetic Extensions Supplement */
- AF_UNIRANGE_REC( 0x1DC0UL, 0x1DFFUL ), /* Combining Diacritical Marks Supplement */
- AF_UNIRANGE_REC( 0x1E00UL, 0x1EFFUL ), /* Latin Extended Additional */
- AF_UNIRANGE_REC( 0x2000UL, 0x206FUL ), /* General Punctuation */
- AF_UNIRANGE_REC( 0x2070UL, 0x209FUL ), /* Superscripts and Subscripts */
- AF_UNIRANGE_REC( 0x20A0UL, 0x20CFUL ), /* Currency Symbols */
- AF_UNIRANGE_REC( 0x2150UL, 0x218FUL ), /* Number Forms */
- AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), /* Enclosed Alphanumerics */
- AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), /* Latin Extended-C */
- AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), /* Supplemental Punctuation */
- 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 )
- };
-
- static const AF_Script_UniRangeRec af_grek_uniranges[] =
- {
- AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), /* Greek and Coptic */
- AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), /* Greek Extended */
- AF_UNIRANGE_REC( 0UL, 0UL )
- };
-
- static const AF_Script_UniRangeRec af_cyrl_uniranges[] =
- {
- AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), /* Cyrillic */
- AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), /* Cyrillic Supplement */
- AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */
- AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */
- AF_UNIRANGE_REC( 0UL, 0UL )
- };
-
- static const AF_Script_UniRangeRec af_hebr_uniranges[] =
- {
- AF_UNIRANGE_REC( 0x0590UL, 0x05FFUL ), /* Hebrew */
- AF_UNIRANGE_REC( 0xFB1DUL, 0xFB4FUL ), /* Alphab. Present. Forms (Hebrew) */
- AF_UNIRANGE_REC( 0UL, 0UL )
- };
-
-
- AF_DEFINE_SCRIPT_CLASS(
- af_latn_script_class,
-
- AF_SCRIPT_LATN,
- AF_BLUE_STRINGSET_LATN,
- AF_WRITING_SYSTEM_LATIN,
-
- af_latn_uniranges,
- 'o'
- )
-
- AF_DEFINE_SCRIPT_CLASS(
- af_grek_script_class,
-
- AF_SCRIPT_GREK,
- AF_BLUE_STRINGSET_GREK,
- AF_WRITING_SYSTEM_LATIN,
-
- af_grek_uniranges,
- 0x3BF /* ο */
- )
-
- AF_DEFINE_SCRIPT_CLASS(
- af_cyrl_script_class,
-
- AF_SCRIPT_CYRL,
- AF_BLUE_STRINGSET_CYRL,
- AF_WRITING_SYSTEM_LATIN,
-
- af_cyrl_uniranges,
- 0x43E /* о */
- )
-
- AF_DEFINE_SCRIPT_CLASS(
- af_hebr_script_class,
-
- AF_SCRIPT_HEBR,
- AF_BLUE_STRINGSET_HEBR,
- AF_WRITING_SYSTEM_LATIN,
+ (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,
+ (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,
+ (AF_WritingSystem_DoneMetricsFunc) NULL,
- af_hebr_uniranges,
- 0x5DD /* ם */
+ (AF_WritingSystem_InitHintsFunc) af_latin_hints_init,
+ (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply
)