summaryrefslogtreecommitdiffstats
path: root/src/truetype
diff options
context:
space:
mode:
authorVictoria Lease <violets@google.com>2013-06-10 13:55:54 -0700
committerVictoria Lease <violets@google.com>2013-06-10 16:14:43 -0700
commit727dee178a392d20eb050d0c446f2fcc29058fa1 (patch)
treec3764963cd9267a20d27a3267af298e172529216 /src/truetype
parent8afe960626dbf326354b836fd4d63e05b6974195 (diff)
downloadandroid_external_freetype-727dee178a392d20eb050d0c446f2fcc29058fa1.tar.gz
android_external_freetype-727dee178a392d20eb050d0c446f2fcc29058fa1.tar.bz2
android_external_freetype-727dee178a392d20eb050d0c446f2fcc29058fa1.zip
Update freetype to 5e094c6fb2ddd6e8901a5679e2cbb8fa476a38ee
Integrated patches from freetype2 git repository, up to hashval 5e094c6fb2ddd6e8901a5679e2cbb8fa476a38ee, which is post-2.4.12. Most recent commit message from freetype git: [truetype] Improve handling of broken sbit advance widths. Noteworthy patches included: [cff] Add a new Type 2 interpreter and hinter. Add support for color embedded bitmaps (eg. color emoji). Change-Id: Ia8b6a67bc18f841b24f44edf80f81f663185b598
Diffstat (limited to 'src/truetype')
-rw-r--r--src/truetype/truetype.c3
-rw-r--r--src/truetype/ttdriver.c132
-rw-r--r--src/truetype/ttgload.c367
-rw-r--r--src/truetype/ttgxvar.c105
-rw-r--r--src/truetype/ttinterp.c1563
-rw-r--r--src/truetype/ttinterp.h79
-rw-r--r--src/truetype/ttobjs.c87
-rw-r--r--src/truetype/ttobjs.h25
-rw-r--r--src/truetype/ttpic.c21
-rw-r--r--src/truetype/ttpic.h39
-rw-r--r--src/truetype/ttpload.c26
-rw-r--r--src/truetype/ttsubpix.c1011
-rw-r--r--src/truetype/ttsubpix.h110
13 files changed, 2892 insertions, 676 deletions
diff --git a/src/truetype/truetype.c b/src/truetype/truetype.c
index 4bd1209..576912b 100644
--- a/src/truetype/truetype.c
+++ b/src/truetype/truetype.c
@@ -4,7 +4,7 @@
/* */
/* FreeType TrueType driver component (body only). */
/* */
-/* Copyright 1996-2001, 2004, 2006 by */
+/* Copyright 1996-2001, 2004, 2006, 2012 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -27,6 +27,7 @@
#ifdef TT_USE_BYTECODE_INTERPRETER
#include "ttinterp.c"
+#include "ttsubpix.c"
#endif
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index 3669d45..fb25706 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -4,7 +4,7 @@
/* */
/* TrueType font driver implementation (body). */
/* */
-/* Copyright 1996-2012 by */
+/* Copyright 1996-2013 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -29,6 +29,8 @@
#include FT_SERVICE_TRUETYPE_ENGINE_H
#include FT_SERVICE_TRUETYPE_GLYF_H
+#include FT_SERVICE_PROPERTIES_H
+#include FT_TRUETYPE_DRIVER_H
#include "ttdriver.h"
#include "ttgload.h"
@@ -52,6 +54,73 @@
#define FT_COMPONENT trace_ttdriver
+ /*
+ * PROPERTY SERVICE
+ *
+ */
+ static FT_Error
+ tt_property_set( FT_Module module, /* TT_Driver */
+ const char* property_name,
+ const void* value )
+ {
+ FT_Error error = FT_Err_Ok;
+ TT_Driver driver = (TT_Driver)module;
+
+
+ if ( !ft_strcmp( property_name, "interpreter-version" ) )
+ {
+ FT_UInt* interpreter_version = (FT_UInt*)value;
+
+
+#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( *interpreter_version != TT_INTERPRETER_VERSION_35 )
+ error = FT_ERR( Unimplemented_Feature );
+ else
+#endif
+ driver->interpreter_version = *interpreter_version;
+
+ return error;
+ }
+
+ FT_TRACE0(( "tt_property_set: missing property `%s'\n",
+ property_name ));
+ return FT_THROW( Missing_Property );
+ }
+
+
+ static FT_Error
+ tt_property_get( FT_Module module, /* TT_Driver */
+ const char* property_name,
+ const void* value )
+ {
+ FT_Error error = FT_Err_Ok;
+ TT_Driver driver = (TT_Driver)module;
+
+ FT_UInt interpreter_version = driver->interpreter_version;
+
+
+ if ( !ft_strcmp( property_name, "interpreter-version" ) )
+ {
+ FT_UInt* val = (FT_UInt*)value;
+
+
+ *val = interpreter_version;
+
+ return error;
+ }
+
+ FT_TRACE0(( "tt_property_get: missing property `%s'\n",
+ property_name ));
+ return FT_THROW( Missing_Property );
+ }
+
+
+ FT_DEFINE_SERVICE_PROPERTIESREC(
+ tt_service_properties,
+ (FT_Properties_SetFunc)tt_property_set,
+ (FT_Properties_GetFunc)tt_property_get )
+
+
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
@@ -163,7 +232,7 @@
}
}
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
/*************************************************************************/
@@ -187,7 +256,7 @@
{
TT_Face ttface = (TT_Face)size->face;
TT_Size ttsize = (TT_Size)size;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
ttsize->strike_index = strike_index;
@@ -221,7 +290,7 @@
FT_Size_Request req )
{
TT_Size ttsize = (TT_Size)size;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
@@ -294,13 +363,13 @@
if ( !slot )
- return TT_Err_Invalid_Slot_Handle;
+ return FT_THROW( Invalid_Slot_Handle );
if ( !size )
- return TT_Err_Invalid_Size_Handle;
+ return FT_THROW( Invalid_Size_Handle );
if ( !face )
- return TT_Err_Invalid_Argument;
+ return FT_THROW( Invalid_Argument );
#ifdef FT_CONFIG_OPTION_INCREMENTAL
if ( glyph_index >= (FT_UInt)face->num_glyphs &&
@@ -308,7 +377,7 @@
#else
if ( glyph_index >= (FT_UInt)face->num_glyphs )
#endif
- return TT_Err_Invalid_Argument;
+ return FT_THROW( Invalid_Argument );
if ( load_flags & FT_LOAD_NO_HINTING )
{
@@ -353,13 +422,13 @@
/*************************************************************************/
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- FT_DEFINE_SERVICE_MULTIMASTERSREC(tt_service_gx_multi_masters,
+ FT_DEFINE_SERVICE_MULTIMASTERSREC(
+ tt_service_gx_multi_masters,
(FT_Get_MM_Func) NULL,
(FT_Set_MM_Design_Func) NULL,
(FT_Set_MM_Blend_Func) TT_Set_MM_Blend,
(FT_Get_MM_Var_Func) TT_Get_MM_Var,
- (FT_Set_Var_Design_Func)TT_Set_Var_Design
- )
+ (FT_Set_Var_Design_Func)TT_Set_Var_Design )
#endif
static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine =
@@ -379,25 +448,28 @@
#endif /* TT_USE_BYTECODE_INTERPRETER */
};
- FT_DEFINE_SERVICE_TTGLYFREC(tt_service_truetype_glyf,
- (TT_Glyf_GetLocationFunc)tt_face_get_location
- )
+ FT_DEFINE_SERVICE_TTGLYFREC(
+ tt_service_truetype_glyf,
+ (TT_Glyf_GetLocationFunc)tt_face_get_location )
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- FT_DEFINE_SERVICEDESCREC4(tt_services,
+ FT_DEFINE_SERVICEDESCREC5(
+ tt_services,
FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE,
- FT_SERVICE_ID_MULTI_MASTERS, &FT_TT_SERVICE_GX_MULTI_MASTERS_GET,
+ FT_SERVICE_ID_MULTI_MASTERS, &TT_SERVICE_GX_MULTI_MASTERS_GET,
FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine,
- FT_SERVICE_ID_TT_GLYF, &FT_TT_SERVICE_TRUETYPE_GLYF_GET
- )
+ FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET,
+ FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET )
#else
- FT_DEFINE_SERVICEDESCREC3(tt_services,
+ FT_DEFINE_SERVICEDESCREC4(
+ tt_services,
FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE,
FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine,
- FT_SERVICE_ID_TT_GLYF, &FT_TT_SERVICE_TRUETYPE_GLYF_GET
- )
+ FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET,
+ FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET )
#endif
+
FT_CALLBACK_DEF( FT_Module_Interface )
tt_get_interface( FT_Module driver, /* TT_Driver */
const char* tt_interface )
@@ -408,7 +480,7 @@
SFNT_Service sfnt;
- /* FT_TT_SERVICES_GET derefers `library' in PIC mode */
+ /* TT_SERVICES_GET derefers `library' in PIC mode */
#ifdef FT_CONFIG_OPTION_PIC
if ( !driver )
return NULL;
@@ -417,7 +489,7 @@
return NULL;
#endif
- result = ft_service_list_lookup( FT_TT_SERVICES_GET, tt_interface );
+ result = ft_service_list_lookup( TT_SERVICES_GET, tt_interface );
if ( result != NULL )
return result;
@@ -445,18 +517,19 @@
/* The FT_DriverInterface structure is defined in ftdriver.h. */
#ifdef TT_USE_BYTECODE_INTERPRETER
-#define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER
+#define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER
#else
-#define TT_HINTER_FLAG 0
+#define TT_HINTER_FLAG 0
#endif
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-#define TT_SIZE_SELECT tt_size_select
+#define TT_SIZE_SELECT tt_size_select
#else
-#define TT_SIZE_SELECT 0
+#define TT_SIZE_SELECT 0
#endif
- FT_DEFINE_DRIVER( tt_driver_class,
+ FT_DEFINE_DRIVER(
+ tt_driver_class,
FT_MODULE_FONT_DRIVER |
FT_MODULE_DRIVER_SCALABLE |
@@ -485,9 +558,6 @@
tt_slot_init,
0, /* FT_Slot_DoneFunc */
- ft_stub_set_char_sizes, /* FT_CONFIG_OPTION_OLD_INTERNALS */
- ft_stub_set_pixel_sizes, /* FT_CONFIG_OPTION_OLD_INTERNALS */
-
tt_glyph_load,
tt_get_kerning,
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index ce8c888..f640a6c 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -4,7 +4,7 @@
/* */
/* TrueType Glyph Loader (body). */
/* */
-/* Copyright 1996-2012 */
+/* Copyright 1996-2013 */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -23,6 +23,7 @@
#include FT_INTERNAL_SFNT_H
#include FT_TRUETYPE_TAGS_H
#include FT_OUTLINE_H
+#include FT_TRUETYPE_DRIVER_H
#include "ttgload.h"
#include "ttpload.h"
@@ -32,6 +33,7 @@
#endif
#include "tterrors.h"
+#include "ttsubpix.h"
/*************************************************************************/
@@ -131,7 +133,10 @@
tt_get_metrics( TT_Loader loader,
FT_UInt glyph_index )
{
- TT_Face face = (TT_Face)loader->face;
+ TT_Face face = (TT_Face)loader->face;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
FT_Short left_bearing = 0, top_bearing = 0;
FT_UShort advance_width = 0, advance_height = 0;
@@ -149,6 +154,18 @@
loader->top_bearing = top_bearing;
loader->vadvance = advance_height;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+ {
+ if ( loader->exec )
+ loader->exec->sph_tweak_flags = 0;
+
+ /* this may not be the right place for this, but it works */
+ if ( loader->exec && loader->exec->ignore_x_mode )
+ sph_set_tweaks( loader, glyph_index );
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
if ( !loader->linear_def )
{
loader->linear_def = 1;
@@ -252,10 +269,6 @@
}
-#undef IS_HINTED
-#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
-
-
/*************************************************************************/
/* */
/* The following functions are used by default with TrueType fonts. */
@@ -286,7 +299,7 @@
loader->cursor = stream->cursor;
loader->limit = stream->limit;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -308,7 +321,7 @@
if ( p + 10 > limit )
- return TT_Err_Invalid_Outline;
+ return FT_THROW( Invalid_Outline );
loader->n_contours = FT_NEXT_SHORT( p );
@@ -324,7 +337,7 @@
loader->bbox.yMax ));
loader->cursor = p;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -409,14 +422,14 @@
{
FT_TRACE0(( "TT_Load_Simple_Glyph: too many instructions (%d)\n",
n_ins ));
- error = TT_Err_Too_Many_Hints;
+ error = FT_THROW( Too_Many_Hints );
goto Fail;
}
if ( ( limit - p ) < n_ins )
{
FT_TRACE0(( "TT_Load_Simple_Glyph: instruction count mismatch\n" ));
- error = TT_Err_Too_Many_Hints;
+ error = FT_THROW( Too_Many_Hints );
goto Fail;
}
@@ -546,7 +559,7 @@
return error;
Invalid_Outline:
- error = TT_Err_Invalid_Outline;
+ error = FT_THROW( Invalid_Outline );
goto Fail;
}
@@ -667,7 +680,7 @@
return error;
Invalid_Composite:
- error = TT_Err_Invalid_Composite;
+ error = FT_THROW( Invalid_Composite );
goto Fail;
}
@@ -714,6 +727,11 @@
TT_Hint_Glyph( TT_Loader loader,
FT_Bool is_composite )
{
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Face face = (TT_Face)loader->face;
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
+
TT_GlyphZone zone = &loader->zone;
FT_Pos origin;
@@ -813,7 +831,18 @@
loader->pp4 = zone->cur[zone->n_points - 1];
}
- return TT_Err_Ok;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+ {
+ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
+ FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
+
+ else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
+ FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ return FT_Err_Ok;
}
@@ -831,7 +860,7 @@
TT_Process_Simple_Glyph( TT_Loader loader )
{
FT_GlyphLoader gloader = loader->gloader;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_Outline* outline;
FT_Int n_points;
@@ -889,25 +918,83 @@
loader->zone.n_points + 4 );
}
- /* scale the glyph */
- if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
{
- FT_Vector* vec = outline->points;
- FT_Vector* limit = outline->points + n_points;
- FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale;
- FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Face face = (TT_Face)loader->face;
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
+
+ FT_String* family = face->root.family_name;
+ FT_Int ppem = loader->size->metrics.x_ppem;
+ FT_String* style = face->root.style_name;
+ FT_Int x_scale_factor = 1000;
+#endif
+
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = outline->points + n_points;
+
+ FT_Fixed x_scale = 0; /* pacify compiler */
+ FT_Fixed y_scale = 0;
+
+ FT_Bool do_scale = FALSE;
- for ( ; vec < limit; vec++ )
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
{
- vec->x = FT_MulFix( vec->x, x_scale );
- vec->y = FT_MulFix( vec->y, y_scale );
+ /* scale, but only if enabled and only if TT hinting is being used */
+ if ( IS_HINTED( loader->load_flags ) )
+ x_scale_factor = sph_test_tweak_x_scaling( face,
+ family,
+ ppem,
+ style,
+ loader->glyph_index );
+ /* scale the glyph */
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
+ x_scale_factor != 1000 )
+ {
+ x_scale = FT_MulDiv( ((TT_Size)loader->size)->metrics.x_scale,
+ x_scale_factor, 1000 );
+ y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+
+ /* compensate for any scaling by de/emboldening; */
+ /* the amount was determined via experimentation */
+ if ( x_scale_factor != 1000 && ppem > 11 )
+ FT_Outline_EmboldenXY( outline,
+ FT_MulFix( 1280 * ppem,
+ 1000 - x_scale_factor ),
+ 0 );
+ do_scale = TRUE;
+ }
}
+ else
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
- loader->pp1 = outline->points[n_points - 4];
- loader->pp2 = outline->points[n_points - 3];
- loader->pp3 = outline->points[n_points - 2];
- loader->pp4 = outline->points[n_points - 1];
+ {
+ /* scale the glyph */
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ x_scale = ((TT_Size)loader->size)->metrics.x_scale;
+ y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+
+ do_scale = TRUE;
+ }
+ }
+
+ if ( do_scale )
+ {
+ for ( ; vec < limit; vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ loader->pp1 = outline->points[n_points - 4];
+ loader->pp2 = outline->points[n_points - 3];
+ loader->pp3 = outline->points[n_points - 2];
+ loader->pp4 = outline->points[n_points - 1];
+ }
}
if ( IS_HINTED( loader->load_flags ) )
@@ -974,7 +1061,7 @@
l += num_base_points;
if ( k >= num_base_points ||
l >= num_points )
- return TT_Err_Invalid_Composite;
+ return FT_THROW( Invalid_Composite );
p1 = gloader->base.outline.points + k;
p2 = gloader->base.outline.points + l;
@@ -988,7 +1075,7 @@
y = subglyph->arg2;
if ( !x && !y )
- return TT_Err_Ok;
+ return FT_Err_Ok;
/* Use a default value dependent on */
/* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old TT */
@@ -1033,16 +1120,10 @@
/* */
/* This algorithm is a guess and works much better than the above. */
/* */
- FT_Fixed mac_xscale = FT_SqrtFixed(
- (FT_Int32)FT_MulFix( subglyph->transform.xx,
- subglyph->transform.xx ) +
- (FT_Int32)FT_MulFix( subglyph->transform.xy,
- subglyph->transform.xy ) );
- FT_Fixed mac_yscale = FT_SqrtFixed(
- (FT_Int32)FT_MulFix( subglyph->transform.yy,
- subglyph->transform.yy ) +
- (FT_Int32)FT_MulFix( subglyph->transform.yx,
- subglyph->transform.yx ) );
+ FT_Fixed mac_xscale = FT_Hypot( subglyph->transform.xx,
+ subglyph->transform.xy );
+ FT_Fixed mac_yscale = FT_Hypot( subglyph->transform.yy,
+ subglyph->transform.yx );
x = FT_MulFix( x, mac_xscale );
@@ -1074,7 +1155,7 @@
base_vec + num_base_points,
x, y );
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -1143,7 +1224,7 @@
FT_TRACE1(( "TT_Process_Composite_Glyph: "
"too many instructions (%d) for glyph with length %d\n",
n_ins, loader->byte_len ));
- return TT_Err_Too_Many_Hints;
+ return FT_THROW( Too_Many_Hints );
}
tmp = loader->exec->glyphSize;
@@ -1157,7 +1238,7 @@
return error;
}
else if ( n_ins == 0 )
- return TT_Err_Ok;
+ return FT_Err_Ok;
if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) )
return error;
@@ -1213,7 +1294,7 @@
FT_UInt recurse_count,
FT_Bool header_only )
{
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_Fixed x_scale, y_scale;
FT_ULong offset;
TT_Face face = (TT_Face)loader->face;
@@ -1236,14 +1317,14 @@
if ( recurse_count > 1 &&
recurse_count > face->max_profile.maxComponentDepth )
{
- error = TT_Err_Invalid_Composite;
+ error = FT_THROW( Invalid_Composite );
goto Exit;
}
/* check glyph index */
if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
{
- error = TT_Err_Invalid_Glyph_Index;
+ error = FT_THROW( Invalid_Glyph_Index );
goto Exit;
}
@@ -1307,7 +1388,7 @@
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
{
FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" ));
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -1374,7 +1455,7 @@
loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale );
}
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
@@ -1588,7 +1669,7 @@
else
{
/* invalid composite count (negative but not -1) */
- error = TT_Err_Invalid_Outline;
+ error = FT_THROW( Invalid_Outline );
goto Exit;
}
@@ -1618,11 +1699,15 @@
compute_glyph_metrics( TT_Loader loader,
FT_UInt glyph_index )
{
+ TT_Face face = (TT_Face)loader->face;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
+#endif
+
FT_BBox bbox;
- TT_Face face = (TT_Face)loader->face;
FT_Fixed y_scale;
TT_GlyphSlot glyph = loader->glyph;
- TT_Size size = (TT_Size)loader->size;
+ TT_Size size = (TT_Size)loader->size;
y_scale = 0x10000L;
@@ -1653,8 +1738,30 @@
size->root.metrics.x_ppem,
glyph_index );
- if ( widthp )
- glyph->metrics.horiAdvance = *widthp << 6;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+ {
+ FT_Bool ignore_x_mode;
+
+
+ ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) !=
+ FT_RENDER_MODE_MONO );
+
+ if ( widthp &&
+ ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
+ !ignore_x_mode ||
+ SPH_OPTION_BITMAP_WIDTHS ) )
+ glyph->metrics.horiAdvance = *widthp << 6;
+ }
+ else
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ {
+ if ( widthp )
+ glyph->metrics.horiAdvance = *widthp << 6;
+ }
}
/* set glyph dimensions */
@@ -1833,7 +1940,9 @@
{
TT_Face face;
FT_Stream stream;
+#ifdef TT_USE_BYTECODE_INTERPRETER
FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
+#endif
face = (TT_Face)glyph->face;
@@ -1849,6 +1958,23 @@
TT_ExecContext exec;
FT_Bool grayscale;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
+
+ FT_Bool subpixel_hinting = FALSE;
+ FT_Bool grayscale_hinting = TRUE;
+
+#if 0
+ /* not used yet */
+ FT_Bool compatible_widths;
+ FT_Bool symmetrical_smoothing;
+ FT_Bool bgr;
+ FT_Bool subpixel_positioned;
+#endif
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ FT_Bool reexecute = FALSE;
+
if ( !size->cvt_ready )
{
@@ -1863,24 +1989,113 @@
exec = size->debug ? size->context
: ( (TT_Driver)FT_FACE_DRIVER( face ) )->context;
if ( !exec )
- return TT_Err_Could_Not_Find_Context;
+ return FT_THROW( Could_Not_Find_Context );
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
+ {
+ subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags )
+ != FT_RENDER_MODE_MONO ) &&
+ SPH_OPTION_SET_SUBPIXEL );
+
+ if ( subpixel_hinting )
+ grayscale = grayscale_hinting = FALSE;
+ else if ( SPH_OPTION_SET_GRAYSCALE )
+ {
+ grayscale = grayscale_hinting = TRUE;
+ subpixel_hinting = FALSE;
+ }
+ else
+ grayscale = grayscale_hinting = FALSE;
+
+ if ( FT_IS_TRICKY( glyph->face ) )
+ subpixel_hinting = grayscale_hinting = FALSE;
+
+ exec->ignore_x_mode = subpixel_hinting || grayscale_hinting;
+ exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
+ if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
+ exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
+
+#if 1
+ exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
+ exec->symmetrical_smoothing = FALSE;
+ exec->bgr = FALSE;
+ exec->subpixel_positioned = TRUE;
+#else /* 0 */
+ exec->compatible_widths =
+ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ TT_LOAD_COMPATIBLE_WIDTHS );
+ exec->symmetrical_smoothing =
+ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ TT_LOAD_SYMMETRICAL_SMOOTHING );
+ exec->bgr =
+ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ TT_LOAD_BGR );
+ exec->subpixel_positioned =
+ FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ TT_LOAD_SUBPIXEL_POSITIONED );
+#endif /* 0 */
+
+ }
+ else
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
- grayscale =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO );
+ {
+ grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ FT_RENDER_MODE_MONO );
+ }
TT_Load_Context( exec, face, size );
- /* a change from mono to grayscale rendering (and vice versa) */
- /* requires a re-execution of the CVT program */
- if ( grayscale != exec->grayscale )
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
{
- FT_UInt i;
+ /* a change from mono to subpixel rendering (and vice versa) */
+ /* requires a re-execution of the CVT program */
+ if ( subpixel_hinting != exec->subpixel_hinting )
+ {
+ FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
+ " re-executing `prep' table\n" ));
+
+ exec->subpixel_hinting = subpixel_hinting;
+ reexecute = TRUE;
+ }
+
+ /* a change from mono to grayscale rendering (and vice versa) */
+ /* requires a re-execution of the CVT program */
+ if ( grayscale != exec->grayscale_hinting )
+ {
+ FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
+ " re-executing `prep' table\n" ));
+
+ exec->grayscale_hinting = grayscale_hinting;
+ reexecute = TRUE;
+ }
+ }
+ else
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
- FT_TRACE4(( "tt_loader_init: grayscale change,"
- " re-executing `prep' table\n" ));
+ {
+ /* a change from mono to grayscale rendering (and vice versa) */
+ /* requires a re-execution of the CVT program */
+ if ( grayscale != exec->grayscale )
+ {
+ FT_TRACE4(( "tt_loader_init: grayscale change,"
+ " re-executing `prep' table\n" ));
+
+ exec->grayscale = grayscale;
+ reexecute = TRUE;
+ }
+ }
+
+ if ( reexecute )
+ {
+ FT_UInt i;
- exec->grayscale = grayscale;
for ( i = 0; i < size->cvt_size; i++ )
size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
@@ -1918,7 +2133,7 @@
FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 );
- if ( error == TT_Err_Table_Missing )
+ if ( FT_ERR_EQ( error, Table_Missing ) )
loader->glyf_offset = 0;
else if ( error )
{
@@ -1946,7 +2161,7 @@
loader->glyph = (FT_GlyphSlot)glyph;
loader->stream = stream;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -1983,13 +2198,11 @@
FT_UInt glyph_index,
FT_Int32 load_flags )
{
- TT_Face face;
FT_Error error;
TT_LoaderRec loader;
- face = (TT_Face)glyph->face;
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
@@ -2003,10 +2216,7 @@
error = load_sbit_image( size, glyph, glyph_index, load_flags );
if ( !error )
{
- FT_Face root = &face->root;
-
-
- if ( FT_IS_SCALABLE( root ) )
+ if ( FT_IS_SCALABLE( glyph->face ) )
{
/* for the bbox we need the header only */
(void)tt_loader_init( &loader, size, glyph, load_flags, TRUE );
@@ -2014,9 +2224,16 @@
glyph->linearHoriAdvance = loader.linear;
glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax -
loader.vadvance;
+
+ /* sanity check: if `horiAdvance' in the sbit metric */
+ /* structure isn't set, use `linearHoriAdvance' */
+ if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance )
+ glyph->metrics.horiAdvance =
+ FT_MulFix( glyph->linearHoriAdvance,
+ size->root.metrics.x_scale );
}
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
}
@@ -2024,10 +2241,10 @@
/* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */
if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid )
- return TT_Err_Invalid_Size_Handle;
+ return FT_THROW( Invalid_Size_Handle );
if ( load_flags & FT_LOAD_SBITS_ONLY )
- return TT_Err_Invalid_Argument;
+ return FT_THROW( Invalid_Argument );
error = tt_loader_init( &loader, size, glyph, load_flags, FALSE );
if ( error )
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 69b702f..7899d36 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -4,7 +4,7 @@
/* */
/* TrueType GX Font Variation loader */
/* */
-/* Copyright 2004-2011 by */
+/* Copyright 2004-2013 by */
/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -61,9 +61,9 @@
#define FT_Stream_FTell( stream ) \
- ( (stream)->cursor - (stream)->base )
+ (FT_ULong)( (stream)->cursor - (stream)->base )
#define FT_Stream_SeekSet( stream, off ) \
- ( (stream)->cursor = (stream)->base+(off) )
+ ( (stream)->cursor = (stream)->base + (off) )
/*************************************************************************/
@@ -91,7 +91,9 @@
/* indicates that there is a delta for every point without needing to */
/* enumerate all of them. */
/* */
-#define ALL_POINTS (FT_UShort*)( -1 )
+
+ /* ensure that value `0' has the same width as a pointer */
+#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0
#define GX_PT_POINTS_ARE_WORDS 0x80
@@ -130,7 +132,7 @@
FT_Int j;
FT_Int first;
FT_Memory memory = stream->memory;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_UNUSED( error );
@@ -215,7 +217,7 @@
FT_Offset i;
FT_UInt j;
FT_Memory memory = stream->memory;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_UNUSED( error );
@@ -283,7 +285,7 @@
FT_Memory memory = stream->memory;
GX_Blend blend = face->blend;
GX_AVarSegment segment;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_ULong version;
FT_Long axisCount;
FT_Int i, j;
@@ -412,7 +414,7 @@
if ( gvar_head.version != (FT_Long)0x00010000L ||
gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
{
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -501,11 +503,9 @@
FT_Fixed* im_end_coords )
{
FT_UInt i;
- FT_Fixed apply;
- FT_Fixed temp;
+ FT_Fixed apply = 0x10000L;
- apply = 0x10000L;
for ( i = 0; i < blend->num_axis; ++i )
{
if ( tuple_coords[i] == 0 )
@@ -525,11 +525,10 @@
else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
/* not an intermediate tuple */
- apply = FT_MulDiv( apply,
+ apply = FT_MulFix( apply,
blend->normalizedcoords[i] > 0
? blend->normalizedcoords[i]
- : -blend->normalizedcoords[i],
- 0x10000L );
+ : -blend->normalizedcoords[i] );
else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
blend->normalizedcoords[i] >= im_end_coords[i] )
@@ -539,20 +538,14 @@
}
else if ( blend->normalizedcoords[i] < tuple_coords[i] )
- {
- temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i],
- 0x10000L,
- tuple_coords[i] - im_start_coords[i]);
- apply = FT_MulDiv( apply, temp, 0x10000L );
- }
+ apply = FT_MulDiv( apply,
+ blend->normalizedcoords[i] - im_start_coords[i],
+ tuple_coords[i] - im_start_coords[i] );
else
- {
- temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i],
- 0x10000L,
- im_end_coords[i] - tuple_coords[i] );
- apply = FT_MulDiv( apply, temp, 0x10000L );
- }
+ apply = FT_MulDiv( apply,
+ im_end_coords[i] - blend->normalizedcoords[i],
+ im_end_coords[i] - tuple_coords[i] );
}
return apply;
@@ -619,7 +612,7 @@
FT_Stream stream = face->root.stream;
FT_Memory memory = face->root.memory;
FT_ULong table_len;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_ULong fvar_start;
FT_Int i, j;
FT_MM_Var* mmvar = NULL;
@@ -690,7 +683,7 @@
fvar_head.offsetToData + fvar_head.axisCount * 20U +
fvar_head.instanceCount * fvar_head.instanceSize > table_len )
{
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -712,7 +705,7 @@
mmvar->num_axis =
fvar_head.axisCount;
mmvar->num_designs =
- (FT_UInt)-1; /* meaningless in this context; each glyph */
+ ~0U; /* meaningless in this context; each glyph */
/* may have a different number of designs */
/* (or tuples, as called by Apple) */
mmvar->num_namedstyles =
@@ -856,7 +849,7 @@
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_MM_Var* mmvar;
FT_UInt i;
@@ -884,14 +877,14 @@
if ( num_coords != mmvar->num_axis )
{
- error = TT_Err_Invalid_Argument;
+ error = FT_THROW( Invalid_Argument );
goto Exit;
}
for ( i = 0; i < num_coords; ++i )
if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
{
- error = TT_Err_Invalid_Argument;
+ error = FT_THROW( Invalid_Argument );
goto Exit;
}
@@ -992,7 +985,7 @@
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_Fixed* normalized = NULL;
GX_Blend blend;
FT_MM_Var* mmvar;
@@ -1013,7 +1006,7 @@
if ( num_coords != mmvar->num_axis )
{
- error = TT_Err_Invalid_Argument;
+ error = FT_THROW( Invalid_Argument );
goto Exit;
}
@@ -1029,24 +1022,16 @@
{
if ( coords[i] > a->maximum || coords[i] < a->minimum )
{
- error = TT_Err_Invalid_Argument;
+ error = FT_THROW( Invalid_Argument );
goto Exit;
}
if ( coords[i] < a->def )
- {
- normalized[i] = -FT_MulDiv( coords[i] - a->def,
- 0x10000L,
- a->minimum - a->def );
- }
+ normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def );
else if ( a->maximum == a->def )
normalized[i] = 0;
else
- {
- normalized[i] = FT_MulDiv( coords[i] - a->def,
- 0x10000L,
- a->maximum - a->def );
- }
+ normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def );
}
if ( !blend->avar_checked )
@@ -1061,15 +1046,11 @@
if ( normalized[i] < av->correspondence[j].fromCoord )
{
normalized[i] =
- FT_MulDiv(
- FT_MulDiv(
- normalized[i] - av->correspondence[j - 1].fromCoord,
- 0x10000L,
- av->correspondence[j].fromCoord -
- av->correspondence[j - 1].fromCoord ),
- av->correspondence[j].toCoord -
- av->correspondence[j - 1].toCoord,
- 0x10000L ) +
+ FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
+ av->correspondence[j].toCoord -
+ av->correspondence[j - 1].toCoord,
+ av->correspondence[j].fromCoord -
+ av->correspondence[j - 1].fromCoord ) +
av->correspondence[j - 1].toCoord;
break;
}
@@ -1141,7 +1122,7 @@
{
FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
@@ -1149,7 +1130,7 @@
{
FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
@@ -1158,13 +1139,13 @@
{
FT_TRACE2(( "is missing\n" ));
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
if ( FT_FRAME_ENTER( table_len ) )
{
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
@@ -1173,7 +1154,7 @@
{
FT_TRACE2(( "bad table version\n" ));
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto FExit;
}
@@ -1344,7 +1325,7 @@
if ( !face->doblend || blend == NULL )
- return TT_Err_Invalid_Argument;
+ return FT_THROW( Invalid_Argument );
/* to be freed by the caller */
if ( FT_NEW_ARRAY( delta_xy, n_points ) )
@@ -1354,7 +1335,7 @@
if ( glyph_index >= blend->gv_glyphcnt ||
blend->glyphoffsets[glyph_index] ==
blend->glyphoffsets[glyph_index + 1] )
- return TT_Err_Ok; /* no variation data for this glyph */
+ return FT_Err_Ok; /* no variation data for this glyph */
if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
@@ -1404,7 +1385,7 @@
}
else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
{
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Fail3;
}
else
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index 3acb24a..798d4a9 100644
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -4,7 +4,7 @@
/* */
/* TrueType bytecode interpreter (body). */
/* */
-/* Copyright 1996-2012 */
+/* Copyright 1996-2013 */
/* by David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -25,20 +25,16 @@
#include FT_INTERNAL_CALC_H
#include FT_TRIGONOMETRY_H
#include FT_SYSTEM_H
+#include FT_TRUETYPE_DRIVER_H
#include "ttinterp.h"
-
#include "tterrors.h"
+#include "ttsubpix.h"
#ifdef TT_USE_BYTECODE_INTERPRETER
-#define TT_MULFIX FT_MulFix
-#define TT_MULDIV FT_MulDiv
-#define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
-
-
/*************************************************************************/
/* */
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
@@ -52,7 +48,7 @@
/* */
/* In order to detect infinite loops in the code, we set up a counter */
/* within the run loop. A single stroke of interpretation is now */
- /* limited to a maximal number of opcodes defined below. */
+ /* limited to a maximum number of opcodes defined below. */
/* */
#define MAX_RUNNABLE_OPCODES 1000000L
@@ -136,6 +132,11 @@
#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
+#define SUBPIXEL_HINTING \
+ ( ((TT_Driver)FT_FACE_DRIVER( CUR.face ))->interpreter_version == \
+ TT_INTERPRETER_VERSION_38 )
+
+
/*************************************************************************/
/* */
/* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
@@ -232,6 +233,14 @@
#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
+ /*************************************************************************/
+ /* */
+ /* This macro computes (a*2^14)/b and complements TT_MulFix14. */
+ /* */
+#define TT_DivFix14( a, b ) \
+ FT_DivFix( a, (b) << 2 )
+
+
#undef SUCCESS
#define SUCCESS 0
@@ -301,7 +310,7 @@
exec->IP = IP;
exec->curRange = range;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -337,7 +346,7 @@
exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
exec->codeRangeTable[range - 1].size = length;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -370,7 +379,7 @@
exec->codeRangeTable[range - 1].base = NULL;
exec->codeRangeTable[range - 1].size = 0;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -428,7 +437,7 @@
FT_FREE( exec );
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -478,7 +487,7 @@
exec->face = NULL;
exec->size = NULL;
- return TT_Err_Ok;
+ return FT_Err_Ok;
Fail_Memory:
FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
@@ -530,7 +539,7 @@
*size = new_max;
}
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -637,7 +646,7 @@
exec->instruction_trap = FALSE;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -680,7 +689,7 @@
for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
size->codeRangeTable[i] = exec->codeRangeTable[i];
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -716,7 +725,7 @@
if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
- != TT_Err_Ok )
+ != FT_Err_Ok )
return error;
exec->zp0 = exec->pts;
@@ -753,7 +762,7 @@
if ( !debug )
return TT_RunIns( exec );
else
- return TT_Err_Ok;
+ return FT_Err_Ok;
#endif
}
@@ -1463,7 +1472,7 @@
#else
- /* compute (a*b)/2^14 with maximal accuracy and rounding */
+ /* compute (a*b)/2^14 with maximum accuracy and rounding */
static FT_Int32
TT_MulFix14( FT_Int32 a,
FT_Int b )
@@ -1476,7 +1485,7 @@
l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
m = ( a >> 16 ) * b;
- lo = l + (FT_UInt32)( m << 16 );
+ lo = l + ( (FT_UInt32)m << 16 );
hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
/* divide the result by 2^14 with rounding */
@@ -1488,12 +1497,12 @@
l = lo + 0x2000U;
hi += l < lo;
- return ( hi << 18 ) | ( l >> 14 );
+ return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
}
#endif
- /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
+ /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
static FT_Int32
TT_DotFix14( FT_Int32 ax,
FT_Int32 ay,
@@ -1508,14 +1517,14 @@
l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
m = ( ax >> 16 ) * bx;
- lo1 = l + (FT_UInt32)( m << 16 );
+ lo1 = l + ( (FT_UInt32)m << 16 );
hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
/* compute ay*by as 64-bit value */
l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
m = ( ay >> 16 ) * by;
- lo2 = l + (FT_UInt32)( m << 16 );
+ lo2 = l + ( (FT_UInt32)m << 16 );
hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
/* add them */
@@ -1531,100 +1540,10 @@
l = lo + 0x2000U;
hi += ( l < lo );
- return ( hi << 18 ) | ( l >> 14 );
+ return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
}
- /* return length of given vector */
-
-#if 0
-
- static FT_Int32
- TT_VecLen( FT_Int32 x,
- FT_Int32 y )
- {
- FT_Int32 m, hi1, hi2, hi;
- FT_UInt32 l, lo1, lo2, lo;
-
-
- /* compute x*x as 64-bit value */
- lo = (FT_UInt32)( x & 0xFFFFU );
- hi = x >> 16;
-
- l = lo * lo;
- m = hi * lo;
- hi = hi * hi;
-
- lo1 = l + (FT_UInt32)( m << 17 );
- hi1 = hi + ( m >> 15 ) + ( lo1 < l );
-
- /* compute y*y as 64-bit value */
- lo = (FT_UInt32)( y & 0xFFFFU );
- hi = y >> 16;
-
- l = lo * lo;
- m = hi * lo;
- hi = hi * hi;
-
- lo2 = l + (FT_UInt32)( m << 17 );
- hi2 = hi + ( m >> 15 ) + ( lo2 < l );
-
- /* add them to get 'x*x+y*y' as 64-bit value */
- lo = lo1 + lo2;
- hi = hi1 + hi2 + ( lo < lo1 );
-
- /* compute the square root of this value */
- {
- FT_UInt32 root, rem, test_div;
- FT_Int count;
-
-
- root = 0;
-
- {
- rem = 0;
- count = 32;
- do
- {
- rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
- hi = ( hi << 2 ) | ( lo >> 30 );
- lo <<= 2;
- root <<= 1;
- test_div = ( root << 1 ) + 1;
-
- if ( rem >= test_div )
- {
- rem -= test_div;
- root += 1;
- }
- } while ( --count );
- }
-
- return (FT_Int32)root;
- }
- }
-
-#else
-
- /* this version uses FT_Vector_Length which computes the same value */
- /* much, much faster.. */
- /* */
- static FT_F26Dot6
- TT_VecLen( FT_F26Dot6 X,
- FT_F26Dot6 Y )
- {
- FT_Vector v;
-
-
- v.x = X;
- v.y = Y;
-
- return FT_Vector_Length( &v );
- }
-
-#endif
-
-
/*************************************************************************/
/* */
/* <Function> */
@@ -1661,14 +1580,14 @@
else
{
- FT_Long x, y;
+ FT_F26Dot6 x, y;
- x = TT_MULDIV( CUR.GS.projVector.x,
- CUR.tt_metrics.x_ratio, 0x4000 );
- y = TT_MULDIV( CUR.GS.projVector.y,
- CUR.tt_metrics.y_ratio, 0x4000 );
- CUR.tt_metrics.ratio = TT_VecLen( x, y );
+ x = TT_MulFix14( CUR.tt_metrics.x_ratio,
+ CUR.GS.projVector.x );
+ y = TT_MulFix14( CUR.tt_metrics.y_ratio,
+ CUR.GS.projVector.y );
+ CUR.tt_metrics.ratio = FT_Hypot( x, y );
}
}
}
@@ -1679,7 +1598,7 @@
static FT_Long
Current_Ppem( EXEC_OP )
{
- return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
+ return FT_MulFix( CUR.tt_metrics.ppem, CURRENT_Ratio() );
}
@@ -1700,7 +1619,7 @@
FT_CALLBACK_DEF( FT_F26Dot6 )
Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
{
- return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
+ return FT_MulFix( CUR.cvt[idx], CURRENT_Ratio() );
}
@@ -1786,7 +1705,7 @@
if ( aRange < 1 || aRange > 3 )
{
- CUR.error = TT_Err_Bad_Argument;
+ CUR.error = FT_THROW( Bad_Argument );
return FAILURE;
}
@@ -1794,7 +1713,7 @@
if ( range->base == NULL ) /* invalid coderange */
{
- CUR.error = TT_Err_Invalid_CodeRange;
+ CUR.error = FT_THROW( Invalid_CodeRange );
return FAILURE;
}
@@ -1804,7 +1723,7 @@
if ( aIP > range->size )
{
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
return FAILURE;
}
@@ -1850,9 +1769,12 @@
if ( v != 0 )
{
- zone->cur[point].x += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( !SUBPIXEL_HINTING ||
+ ( !CUR.ignore_x_mode ||
+ ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
}
@@ -1861,9 +1783,7 @@
if ( v != 0 )
{
- zone->cur[point].y += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
+ zone->cur[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
}
@@ -1902,16 +1822,12 @@
v = CUR.GS.freeVector.x;
if ( v != 0 )
- zone->org[point].x += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
+ zone->org[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
v = CUR.GS.freeVector.y;
if ( v != 0 )
- zone->org[point].y += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
+ zone->org[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
}
@@ -1932,7 +1848,12 @@
{
FT_UNUSED_EXEC;
- zone->cur[point].x += distance;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( !SUBPIXEL_HINTING ||
+ !CUR.ignore_x_mode )
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ zone->cur[point].x += distance;
+
zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
}
@@ -2193,7 +2114,7 @@
}
else
{
- val = - FT_PIX_CEIL( compensation - distance );
+ val = -FT_PIX_CEIL( compensation - distance );
if ( val > 0 )
val = 0;
}
@@ -2404,8 +2325,9 @@
/* Sets Super Round parameters. */
/* */
/* <Input> */
- /* GridPeriod :: Grid period */
- /* selector :: SROUND opcode */
+ /* GridPeriod :: The grid period. */
+ /* */
+ /* selector :: The SROUND opcode. */
/* */
static void
SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
@@ -2617,13 +2539,10 @@
if ( CUR.GS.dualVector.x == 0x4000 )
CUR.func_dualproj = Project_x;
+ else if ( CUR.GS.dualVector.y == 0x4000 )
+ CUR.func_dualproj = Project_y;
else
- {
- if ( CUR.GS.dualVector.y == 0x4000 )
- CUR.func_dualproj = Project_y;
- else
- CUR.func_dualproj = Dual_Project;
- }
+ CUR.func_dualproj = Dual_Project;
/* Force recalculation of cached aspect ratio */
CUR.tt_metrics.ratio = 0;
@@ -2633,61 +2552,50 @@
#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
if ( CUR.GS.freeVector.x == 0x4000 )
- CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
+ CUR.F_dot_P = CUR.GS.projVector.x;
+ else if ( CUR.GS.freeVector.y == 0x4000 )
+ CUR.F_dot_P = CUR.GS.projVector.y;
else
- {
- if ( CUR.GS.freeVector.y == 0x4000 )
- CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
- else
- CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
- (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
- }
+ CUR.F_dot_P = ( (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x +
+ (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y ) >>
+ 14;
if ( CUR.GS.projVector.x == 0x4000 )
CUR.func_project = (TT_Project_Func)Project_x;
+ else if ( CUR.GS.projVector.y == 0x4000 )
+ CUR.func_project = (TT_Project_Func)Project_y;
else
- {
- if ( CUR.GS.projVector.y == 0x4000 )
- CUR.func_project = (TT_Project_Func)Project_y;
- else
- CUR.func_project = (TT_Project_Func)Project;
- }
+ CUR.func_project = (TT_Project_Func)Project;
if ( CUR.GS.dualVector.x == 0x4000 )
CUR.func_dualproj = (TT_Project_Func)Project_x;
+ else if ( CUR.GS.dualVector.y == 0x4000 )
+ CUR.func_dualproj = (TT_Project_Func)Project_y;
else
- {
- if ( CUR.GS.dualVector.y == 0x4000 )
- CUR.func_dualproj = (TT_Project_Func)Project_y;
- else
- CUR.func_dualproj = (TT_Project_Func)Dual_Project;
- }
+ CUR.func_dualproj = (TT_Project_Func)Dual_Project;
CUR.func_move = (TT_Move_Func)Direct_Move;
CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
- if ( CUR.F_dot_P == 0x40000000L )
+ if ( CUR.F_dot_P == 0x4000L )
{
if ( CUR.GS.freeVector.x == 0x4000 )
{
CUR.func_move = (TT_Move_Func)Direct_Move_X;
CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
}
- else
+ else if ( CUR.GS.freeVector.y == 0x4000 )
{
- if ( CUR.GS.freeVector.y == 0x4000 )
- {
- CUR.func_move = (TT_Move_Func)Direct_Move_Y;
- CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
- }
+ CUR.func_move = (TT_Move_Func)Direct_Move_Y;
+ CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
}
}
/* at small sizes, F_dot_P can become too small, resulting */
/* in overflows and `spikes' in a number of glyphs like `w'. */
- if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
- CUR.F_dot_P = 0x40000000L;
+ if ( FT_ABS( CUR.F_dot_P ) < 0x400L )
+ CUR.F_dot_P = 0x4000L;
/* Disable cached aspect ratio */
CUR.tt_metrics.ratio = 0;
@@ -2716,98 +2624,33 @@
/* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
/* R is undefined. */
/* */
-
-
static FT_Bool
Normalize( EXEC_OP_ FT_F26Dot6 Vx,
FT_F26Dot6 Vy,
FT_UnitVector* R )
{
FT_F26Dot6 W;
- FT_Bool S1, S2;
FT_UNUSED_EXEC;
- if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
+ if ( FT_ABS( Vx ) < 0x4000L && FT_ABS( Vy ) < 0x4000L )
{
- Vx *= 0x100;
- Vy *= 0x100;
-
- W = TT_VecLen( Vx, Vy );
-
- if ( W == 0 )
+ if ( Vx == 0 && Vy == 0 )
{
/* XXX: UNDOCUMENTED! It seems that it is possible to try */
/* to normalize the vector (0,0). Return immediately. */
return SUCCESS;
}
- R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
- R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
-
- return SUCCESS;
+ Vx *= 0x4000;
+ Vy *= 0x4000;
}
- W = TT_VecLen( Vx, Vy );
-
- Vx = FT_MulDiv( Vx, 0x4000L, W );
- Vy = FT_MulDiv( Vy, 0x4000L, W );
-
- W = Vx * Vx + Vy * Vy;
-
- /* Now, we want that Sqrt( W ) = 0x4000 */
- /* Or 0x10000000 <= W < 0x10004000 */
-
- if ( Vx < 0 )
- {
- Vx = -Vx;
- S1 = TRUE;
- }
- else
- S1 = FALSE;
+ W = FT_Hypot( Vx, Vy );
- if ( Vy < 0 )
- {
- Vy = -Vy;
- S2 = TRUE;
- }
- else
- S2 = FALSE;
-
- while ( W < 0x10000000L )
- {
- /* We need to increase W by a minimal amount */
- if ( Vx < Vy )
- Vx++;
- else
- Vy++;
-
- W = Vx * Vx + Vy * Vy;
- }
-
- while ( W >= 0x10004000L )
- {
- /* We need to decrease W by a minimal amount */
- if ( Vx < Vy )
- Vx--;
- else
- Vy--;
-
- W = Vx * Vx + Vy * Vy;
- }
-
- /* Note that in various cases, we can only */
- /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
-
- if ( S1 )
- Vx = -Vx;
-
- if ( S2 )
- Vy = -Vy;
-
- R->x = (FT_F2Dot14)Vx; /* Type conversion */
- R->y = (FT_F2Dot14)Vy; /* Type conversion */
+ R->x = (FT_F2Dot14)TT_DivFix14( Vx, W );
+ R->y = (FT_F2Dot14)TT_DivFix14( Vy, W );
return SUCCESS;
}
@@ -2835,7 +2678,7 @@
BOUNDS( aIdx2, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return FAILURE;
}
@@ -3091,10 +2934,10 @@
CUR.func_round = (TT_Round_Func)Round_Super_45;
-#define DO_SLOOP \
- if ( args[0] < 0 ) \
- CUR.error = TT_Err_Bad_Argument; \
- else \
+#define DO_SLOOP \
+ if ( args[0] < 0 ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ else \
CUR.GS.loop = args[0];
@@ -3110,14 +2953,9 @@
CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
- /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
- /* */
- /* It seems that the value that is read here is */
- /* expressed in 16.16 format rather than in font */
- /* units. */
- /* */
-#define DO_SSW \
- CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
+#define DO_SSW \
+ CUR.GS.single_width_value = FT_MulFix( args[0], \
+ CUR.tt_metrics.scale );
#define DO_FLIPON \
@@ -3181,21 +3019,21 @@
args[0] = CUR.top;
-#define DO_CINDEX \
- { \
- FT_Long L; \
- \
- \
- L = args[0]; \
- \
- if ( L <= 0 || L > CUR.args ) \
- { \
- if ( CUR.pedantic_hinting ) \
- CUR.error = TT_Err_Invalid_Reference; \
- args[0] = 0; \
- } \
- else \
- args[0] = CUR.stack[CUR.args - L]; \
+#define DO_CINDEX \
+ { \
+ FT_Long L; \
+ \
+ \
+ L = args[0]; \
+ \
+ if ( L <= 0 || L > CUR.args ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ CUR.error = FT_THROW( Invalid_Reference ); \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR.stack[CUR.args - L]; \
}
@@ -3203,24 +3041,24 @@
if ( args[1] != 0 ) \
{ \
if ( args[0] == 0 && CUR.args == 0 ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.IP += args[0]; \
if ( CUR.IP < 0 || \
( CUR.callTop > 0 && \
CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.step_ins = FALSE; \
}
#define DO_JMPR \
if ( args[0] == 0 && CUR.args == 0 ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.IP += args[0]; \
if ( CUR.IP < 0 || \
( CUR.callTop > 0 && \
CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.step_ins = FALSE;
@@ -3228,12 +3066,12 @@
if ( args[1] == 0 ) \
{ \
if ( args[0] == 0 && CUR.args == 0 ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.IP += args[0]; \
if ( CUR.IP < 0 || \
( CUR.callTop > 0 && \
CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
- CUR.error = TT_Err_Bad_Argument; \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.step_ins = FALSE; \
}
@@ -3292,13 +3130,13 @@
#define DO_DIV \
if ( args[1] == 0 ) \
- CUR.error = TT_Err_Divide_By_Zero; \
+ CUR.error = FT_THROW( Divide_By_Zero ); \
else \
- args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
+ args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
#define DO_MUL \
- args[0] = TT_MULDIV( args[0], args[1], 64L );
+ args[0] = FT_MulDiv( args[0], args[1], 64L );
#define DO_ABS \
@@ -3316,6 +3154,45 @@
#define DO_CEILING \
args[0] = FT_PIX_CEIL( args[0] );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+#define DO_RS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDSL( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ ARRAY_BOUND_ERROR; \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ { \
+ /* subpixel hinting - avoid Typeman Dstroke and */ \
+ /* IStroke and Vacuform rounds */ \
+ \
+ if ( SUBPIXEL_HINTING && \
+ CUR.ignore_x_mode && \
+ ( ( I == 24 && \
+ ( CUR.face->sph_found_func_flags & \
+ ( SPH_FDEF_SPACING_1 | \
+ SPH_FDEF_SPACING_2 ) ) ) || \
+ ( I == 22 && \
+ ( CUR.sph_in_func_flags & \
+ SPH_FDEF_TYPEMAN_STROKES ) ) || \
+ ( I == 8 && \
+ ( CUR.face->sph_found_func_flags & \
+ SPH_FDEF_VACUFORM_ROUND_1 ) && \
+ CUR.iup_called ) ) ) \
+ args[0] = 0; \
+ else \
+ args[0] = CUR.storage[I]; \
+ } \
+ }
+
+#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
#define DO_RS \
{ \
@@ -3335,6 +3212,8 @@
args[0] = CUR.storage[I]; \
}
+#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
#define DO_WS \
{ \
@@ -3402,12 +3281,12 @@
} \
} \
else \
- CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
+ CUR.cvt[I] = FT_MulFix( args[1], CUR.tt_metrics.scale ); \
}
-#define DO_DEBUG \
- CUR.error = TT_Err_Debug_OpCode;
+#define DO_DEBUG \
+ CUR.error = FT_THROW( Debug_OpCode );
#define DO_ROUND \
@@ -3435,10 +3314,10 @@
#undef ARRAY_BOUND_ERROR
-#define ARRAY_BOUND_ERROR \
- { \
- CUR.error = TT_Err_Invalid_Reference; \
- return; \
+#define ARRAY_BOUND_ERROR \
+ { \
+ CUR.error = FT_THROW( Invalid_Reference ); \
+ return; \
}
@@ -4417,7 +4296,7 @@
if ( L <= 0 || L > CUR.args )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
else
{
@@ -4487,7 +4366,7 @@
}
Fail_Overflow:
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
return FAILURE;
}
@@ -4592,6 +4471,106 @@
TT_DefRecord* rec;
TT_DefRecord* limit;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* arguments to opcodes are skipped by `SKIP_Code' */
+ FT_Byte opcode_pattern[9][12] = {
+ /* #0 inline delta function 1 */
+ {
+ 0x4B, /* PPEM */
+ 0x53, /* GTEQ */
+ 0x23, /* SWAP */
+ 0x4B, /* PPEM */
+ 0x51, /* LTEQ */
+ 0x5A, /* AND */
+ 0x58, /* IF */
+ 0x38, /* SHPIX */
+ 0x1B, /* ELSE */
+ 0x21, /* POP */
+ 0x21, /* POP */
+ 0x59 /* EIF */
+ },
+ /* #1 inline delta function 2 */
+ {
+ 0x4B, /* PPEM */
+ 0x54, /* EQ */
+ 0x58, /* IF */
+ 0x38, /* SHPIX */
+ 0x1B, /* ELSE */
+ 0x21, /* POP */
+ 0x21, /* POP */
+ 0x59 /* EIF */
+ },
+ /* #2 diagonal stroke function */
+ {
+ 0x20, /* DUP */
+ 0x20, /* DUP */
+ 0xB0, /* PUSHB_1 */
+ /* 1 */
+ 0x60, /* ADD */
+ 0x46, /* GC_cur */
+ 0xB0, /* PUSHB_1 */
+ /* 64 */
+ 0x23, /* SWAP */
+ 0x42 /* WS */
+ },
+ /* #3 VacuFormRound function */
+ {
+ 0x45, /* RCVT */
+ 0x23, /* SWAP */
+ 0x46, /* GC_cur */
+ 0x60, /* ADD */
+ 0x20, /* DUP */
+ 0xB0 /* PUSHB_1 */
+ /* 38 */
+ },
+ /* #4 TTFautohint bytecode (old) */
+ {
+ 0x20, /* DUP */
+ 0x64, /* ABS */
+ 0xB0, /* PUSHB_1 */
+ /* 32 */
+ 0x60, /* ADD */
+ 0x66, /* FLOOR */
+ 0x23, /* SWAP */
+ 0xB0 /* PUSHB_1 */
+ },
+ /* #5 spacing function 1 */
+ {
+ 0x01, /* SVTCA_x */
+ 0xB0, /* PUSHB_1 */
+ /* 24 */
+ 0x43, /* RS */
+ 0x58 /* IF */
+ },
+ /* #6 spacing function 2 */
+ {
+ 0x01, /* SVTCA_x */
+ 0x18, /* RTG */
+ 0xB0, /* PUSHB_1 */
+ /* 24 */
+ 0x43, /* RS */
+ 0x58 /* IF */
+ },
+ /* #7 TypeMan Talk DiagEndCtrl function */
+ {
+ 0x01, /* SVTCA_x */
+ 0x20, /* DUP */
+ 0xB0, /* PUSHB_1 */
+ /* 3 */
+ 0x25, /* CINDEX */
+ },
+ /* #8 TypeMan Talk Align */
+ {
+ 0x06, /* SPVTL */
+ 0x7D, /* RDTG */
+ },
+ };
+ FT_UShort opcode_patterns = 9;
+ FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
+ FT_UShort i;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
/* some font programs are broken enough to redefine functions! */
/* We will then parse the current table. */
@@ -4611,7 +4590,7 @@
/* check that there is enough room for new functions */
if ( CUR.numFDefs >= CUR.maxFDefs )
{
- CUR.error = TT_Err_Too_Many_Function_Defs;
+ CUR.error = FT_THROW( Too_Many_Function_Defs );
return;
}
CUR.numFDefs++;
@@ -4621,28 +4600,149 @@
/* func # must be within unsigned 16-bit integer */
if ( n > 0xFFFFU )
{
- CUR.error = TT_Err_Too_Many_Function_Defs;
+ CUR.error = FT_THROW( Too_Many_Function_Defs );
return;
}
- rec->range = CUR.curRange;
- rec->opc = (FT_UInt16)n;
- rec->start = CUR.IP + 1;
- rec->active = TRUE;
+ rec->range = CUR.curRange;
+ rec->opc = (FT_UInt16)n;
+ rec->start = CUR.IP + 1;
+ rec->active = TRUE;
+ rec->inline_delta = FALSE;
+ rec->sph_fdef_flags = 0x0000;
if ( n > CUR.maxFunc )
CUR.maxFunc = (FT_UInt16)n;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* We don't know for sure these are typeman functions, */
+ /* however they are only active when RS 22 is called */
+ if ( n >= 64 && n <= 66 )
+ rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
+#endif
+
/* Now skip the whole function definition. */
/* We don't allow nested IDEFS & FDEFs. */
while ( SKIP_Code() == SUCCESS )
{
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( SUBPIXEL_HINTING )
+ {
+ for ( i = 0; i < opcode_patterns; i++ )
+ {
+ if ( opcode_pointer[i] < opcode_size[i] &&
+ CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
+ {
+ opcode_pointer[i] += 1;
+
+ if ( opcode_pointer[i] == opcode_size[i] )
+ {
+ FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
+ i, n,
+ CUR.face->root.family_name,
+ CUR.face->root.style_name ));
+
+ switch ( i )
+ {
+ case 0:
+ rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
+ break;
+
+ case 1:
+ rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
+ break;
+
+ case 2:
+ switch ( n )
+ {
+ /* needs to be implemented still */
+ case 58:
+ rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
+ }
+ break;
+
+ case 3:
+ switch ( n )
+ {
+ case 0:
+ rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
+ }
+ break;
+
+ case 4:
+ /* probably not necessary to detect anymore */
+ rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
+ break;
+
+ case 5:
+ switch ( n )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 7:
+ case 8:
+ rec->sph_fdef_flags |= SPH_FDEF_SPACING_1;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
+ }
+ break;
+
+ case 6:
+ switch ( n )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 7:
+ case 8:
+ rec->sph_fdef_flags |= SPH_FDEF_SPACING_2;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
+ }
+ break;
+
+ case 7:
+ rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
+ break;
+
+ case 8:
+#if 0
+ rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
+ CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
+#endif
+ break;
+ }
+ opcode_pointer[i] = 0;
+ }
+ }
+
+ else
+ opcode_pointer[i] = 0;
+ }
+
+ /* Set sph_compatibility_mode only when deltas are detected */
+ CUR.face->sph_compatibility_mode =
+ ( ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
+ ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
+ }
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
switch ( CUR.opcode )
{
case 0x89: /* IDEF */
case 0x2C: /* FDEF */
- CUR.error = TT_Err_Nested_DEFS;
+ CUR.error = FT_THROW( Nested_DEFS );
return;
case 0x2D: /* ENDF */
@@ -4667,9 +4767,13 @@
FT_UNUSED_ARG;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ CUR.sph_in_func_flags = 0x0000;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
{
- CUR.error = TT_Err_ENDF_In_Exec_Stream;
+ CUR.error = FT_THROW( ENDF_In_Exec_Stream );
return;
}
@@ -4751,10 +4855,21 @@
if ( !def->active )
goto Fail;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ ( ( CUR.iup_called &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
+ ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) )
+ goto Fail;
+ else
+ CUR.sph_in_func_flags = def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
/* check the call stack */
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4772,10 +4887,11 @@
def->start );
CUR.step_ins = FALSE;
+
return;
Fail:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
@@ -4828,10 +4944,19 @@
if ( !def->active )
goto Fail;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
+ goto Fail;
+ else
+ CUR.sph_in_func_flags = def->sph_fdef_flags;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
/* check stack */
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4851,10 +4976,11 @@
CUR.step_ins = FALSE;
}
+
return;
Fail:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
@@ -4885,7 +5011,7 @@
/* check that there is enough room for a new instruction */
if ( CUR.numIDefs >= CUR.maxIDefs )
{
- CUR.error = TT_Err_Too_Many_Instruction_Defs;
+ CUR.error = FT_THROW( Too_Many_Instruction_Defs );
return;
}
CUR.numIDefs++;
@@ -4894,7 +5020,7 @@
/* opcode must be unsigned 8-bit integer */
if ( 0 > args[0] || args[0] > 0x00FF )
{
- CUR.error = TT_Err_Too_Many_Instruction_Defs;
+ CUR.error = FT_THROW( Too_Many_Instruction_Defs );
return;
}
@@ -4915,7 +5041,7 @@
{
case 0x89: /* IDEF */
case 0x2C: /* FDEF */
- CUR.error = TT_Err_Nested_DEFS;
+ CUR.error = FT_THROW( Nested_DEFS );
return;
case 0x2D: /* ENDF */
return;
@@ -4949,7 +5075,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4976,7 +5102,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -5006,7 +5132,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -5031,7 +5157,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -5074,7 +5200,7 @@
if ( BOUNDSL( L, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
R = 0;
}
else
@@ -5111,7 +5237,7 @@
if ( BOUNDS( L, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5155,7 +5281,7 @@
BOUNDS( K, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
D = 0;
}
else
@@ -5184,15 +5310,15 @@
{
/* this should be faster */
D = CUR_Func_dualproj( vec1, vec2 );
- D = TT_MULFIX( D, CUR.metrics.x_scale );
+ D = FT_MulFix( D, CUR.metrics.x_scale );
}
else
{
FT_Vector vec;
- vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
- vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
+ vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
+ vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
D = CUR_fast_dualproj( &vec );
}
@@ -5200,6 +5326,13 @@
}
}
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode && FT_ABS( D ) == 64 )
+ D += 1;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
args[0] = D;
}
@@ -5225,7 +5358,7 @@
BOUNDS( p1, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5265,6 +5398,12 @@
A = v1->x - v2->x;
B = v1->y - v2->y;
+
+ if ( A == 0 && B == 0 )
+ {
+ A = 0x4000;
+ aOpc = 0;
+ }
}
if ( ( aOpc & 1 ) != 0 )
@@ -5303,7 +5442,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5332,7 +5471,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5361,7 +5500,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5390,7 +5529,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5421,7 +5560,7 @@
if ( K < 1 || K > 2 )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5519,7 +5658,7 @@
if ( CUR.top < CUR.GS.loop )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
goto Fail;
}
@@ -5533,7 +5672,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -5568,7 +5707,7 @@
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5596,7 +5735,7 @@
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5630,7 +5769,7 @@
if ( BOUNDS( p, zp.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
*refp = 0;
return FAILURE;
}
@@ -5657,12 +5796,8 @@
else
#endif
{
- *x = TT_MULDIV( d,
- (FT_Long)CUR.GS.freeVector.x * 0x10000L,
- CUR.F_dot_P );
- *y = TT_MULDIV( d,
- (FT_Long)CUR.GS.freeVector.y * 0x10000L,
- CUR.F_dot_P );
+ *x = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.x, CUR.F_dot_P );
+ *y = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.y, CUR.F_dot_P );
}
return SUCCESS;
@@ -5732,7 +5867,7 @@
if ( CUR.top < CUR.GS.loop )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -5748,11 +5883,18 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
else
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* doesn't follow Cleartype spec but produces better result */
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode )
+ MOVE_Zp2_Point( point, 0, dy, TRUE );
+ else
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
MOVE_Zp2_Point( point, dx, dy, TRUE );
CUR.GS.loop--;
@@ -5772,7 +5914,7 @@
/* */
/* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
/* contour in the twilight zone, namely contour number */
- /* zero. */
+ /* zero which includes all points of it. */
/* */
static void
Ins_SHC( INS_ARG )
@@ -5791,7 +5933,7 @@
if ( BOUNDS( contour, bounds ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5839,7 +5981,7 @@
if ( BOUNDS( args[0], 2 ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5877,12 +6019,15 @@
{
FT_F26Dot6 dx, dy;
FT_UShort point;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_Int B1, B2;
+#endif
if ( CUR.top < CUR.GS.loop + 1 )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -5891,13 +6036,13 @@
{
if ( CUR.GS.both_x_axis )
{
- dx = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
+ dx = (FT_UInt32)args[0];
dy = 0;
}
else
{
dx = 0;
- dy = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
+ dy = (FT_UInt32)args[0];
}
}
else
@@ -5917,13 +6062,95 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
else
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ {
+ /* If not using ignore_x_mode rendering, allow ZP2 move. */
+ /* If inline deltas aren't allowed, skip ZP2 move. */
+ /* If using ignore_x_mode rendering, allow ZP2 point move if: */
+ /* - freedom vector is y and sph_compatibility_mode is off */
+ /* - the glyph is composite and the move is in the Y direction */
+ /* - the glyph is specifically set to allow SHPIX moves */
+ /* - the move is on a previously Y-touched point */
+
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode )
+ {
+ /* save point for later comparison */
+ if ( CUR.GS.freeVector.y != 0 )
+ B1 = CUR.zp2.cur[point].y;
+ else
+ B1 = CUR.zp2.cur[point].x;
+
+ if ( !CUR.face->sph_compatibility_mode &&
+ CUR.GS.freeVector.y != 0 )
+ {
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ /* save new point */
+ if ( CUR.GS.freeVector.y != 0 )
+ {
+ B2 = CUR.zp2.cur[point].y;
+
+ /* reverse any disallowed moves */
+ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
+ ( B1 & 63 ) != 0 &&
+ ( B2 & 63 ) != 0 &&
+ B1 != B2 )
+ MOVE_Zp2_Point( point, -dx, -dy, TRUE );
+ }
+ }
+ else if ( CUR.face->sph_compatibility_mode )
+ {
+ if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
+ {
+ dx = FT_PIX_ROUND( B1 + dx ) - B1;
+ dy = FT_PIX_ROUND( B1 + dy ) - B1;
+ }
+
+ /* skip post-iup deltas */
+ if ( CUR.iup_called &&
+ ( ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
+ ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
+ goto Skip;
+
+ if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
+ ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ||
+ ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
+ ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) )
+ MOVE_Zp2_Point( point, 0, dy, TRUE );
+
+ /* save new point */
+ if ( CUR.GS.freeVector.y != 0 )
+ {
+ B2 = CUR.zp2.cur[point].y;
+
+ /* reverse any disallowed moves */
+ if ( ( B1 & 63 ) == 0 &&
+ ( B2 & 63 ) != 0 &&
+ B1 != B2 )
+ MOVE_Zp2_Point( point, 0, -dy, TRUE );
+ }
+ }
+ else if ( CUR.sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+ }
+ else
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+ }
+
+ Skip:
+
+#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
MOVE_Zp2_Point( point, dx, dy, TRUE );
+#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
CUR.GS.loop--;
}
@@ -5945,6 +6172,21 @@
FT_UShort point;
FT_F26Dot6 distance;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_F26Dot6 control_value_cutin;
+
+
+ if ( SUBPIXEL_HINTING )
+ {
+ control_value_cutin = CUR.GS.control_value_cutin;
+
+ if ( CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ control_value_cutin = 0;
+ }
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
point = (FT_UShort)args[0];
@@ -5952,7 +6194,7 @@
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5968,6 +6210,15 @@
distance = CUR_Func_project( CUR.zp1.cur + point,
CUR.zp0.cur + CUR.GS.rp0 );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* subpixel hinting - make MSIRP respect CVT cut-in; */
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
+ FT_ABS( distance - args[1] ) >= control_value_cutin )
+ distance = args[1];
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
CUR_Func_move( &CUR.zp1, point, args[1] - distance );
CUR.GS.rp1 = CUR.GS.rp0;
@@ -5988,8 +6239,8 @@
Ins_MDAP( INS_ARG )
{
FT_UShort point;
- FT_F26Dot6 cur_dist,
- distance;
+ FT_F26Dot6 cur_dist;
+ FT_F26Dot6 distance;
point = (FT_UShort)args[0];
@@ -5997,15 +6248,25 @@
if ( BOUNDS( point, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
if ( ( CUR.opcode & 1 ) != 0 )
{
cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
- distance = CUR_Func_round( cur_dist,
- CUR.tt_metrics.compensations[0] ) - cur_dist;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 )
+ distance = ROUND_None(
+ cur_dist,
+ CUR.tt_metrics.compensations[0] ) - cur_dist;
+ else
+#endif
+ distance = CUR_Func_round(
+ cur_dist,
+ CUR.tt_metrics.compensations[0] ) - cur_dist;
}
else
distance = 0;
@@ -6028,18 +6289,29 @@
{
FT_ULong cvtEntry;
FT_UShort point;
- FT_F26Dot6 distance,
- org_dist;
+ FT_F26Dot6 distance;
+ FT_F26Dot6 org_dist;
+ FT_F26Dot6 control_value_cutin;
- cvtEntry = (FT_ULong)args[1];
- point = (FT_UShort)args[0];
+ control_value_cutin = CUR.GS.control_value_cutin;
+ cvtEntry = (FT_ULong)args[1];
+ point = (FT_UShort)args[0];
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
+ CUR.GS.freeVector.y == 0 &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ control_value_cutin = 0;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
if ( BOUNDS( point, CUR.zp0.n_points ) ||
BOUNDSL( cvtEntry, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6067,21 +6339,45 @@
if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
{
- CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
- CUR.GS.freeVector.x );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
+ /* Determined via experimentation and may be incorrect... */
+ if ( !SUBPIXEL_HINTING ||
+ ( !CUR.ignore_x_mode ||
+ !CUR.face->sph_compatibility_mode ) )
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
+ CUR.GS.freeVector.x );
CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
CUR.GS.freeVector.y ),
CUR.zp0.cur[point] = CUR.zp0.org[point];
}
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
+ distance > 0 &&
+ CUR.GS.freeVector.y != 0 )
+ distance = 0;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
- if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
+ if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cut-in flag */
{
- if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
+ if ( FT_ABS( distance - org_dist ) > control_value_cutin )
distance = org_dist;
- distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 )
+ distance = ROUND_None( distance,
+ CUR.tt_metrics.compensations[0] );
+ else
+#endif
+ distance = CUR_Func_round( distance,
+ CUR.tt_metrics.compensations[0] );
}
CUR_Func_move( &CUR.zp0, point, distance - org_dist );
@@ -6102,16 +6398,26 @@
Ins_MDRP( INS_ARG )
{
FT_UShort point;
- FT_F26Dot6 org_dist, distance;
+ FT_F26Dot6 org_dist, distance, minimum_distance;
+ minimum_distance = CUR.GS.minimum_distance;
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ minimum_distance = 0;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
point = (FT_UShort)args[0];
if ( BOUNDS( point, CUR.zp1.n_points ) ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6138,15 +6444,15 @@
{
/* this should be faster */
org_dist = CUR_Func_dualproj( vec1, vec2 );
- org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
+ org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale );
}
else
{
FT_Vector vec;
- vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
- vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
+ vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
+ vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
org_dist = CUR_fast_dualproj( &vec );
}
@@ -6166,9 +6472,20 @@
/* round flag */
if ( ( CUR.opcode & 4 ) != 0 )
+ {
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 )
+ distance = ROUND_None(
+ org_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ else
+#endif
distance = CUR_Func_round(
org_dist,
CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ }
else
distance = ROUND_None(
org_dist,
@@ -6180,13 +6497,13 @@
{
if ( org_dist >= 0 )
{
- if ( distance < CUR.GS.minimum_distance )
- distance = CUR.GS.minimum_distance;
+ if ( distance < minimum_distance )
+ distance = minimum_distance;
}
else
{
- if ( distance > -CUR.GS.minimum_distance )
- distance = -CUR.GS.minimum_distance;
+ if ( distance > -minimum_distance )
+ distance = -minimum_distance;
}
}
@@ -6221,11 +6538,28 @@
FT_F26Dot6 cvt_dist,
distance,
cur_dist,
- org_dist;
-
-
- point = (FT_UShort)args[0];
- cvtEntry = (FT_ULong)( args[1] + 1 );
+ org_dist,
+ control_value_cutin,
+ minimum_distance;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_Int B1;
+ FT_Int B2;
+ FT_Bool reverse_move = FALSE;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+ minimum_distance = CUR.GS.minimum_distance;
+ control_value_cutin = CUR.GS.control_value_cutin;
+ point = (FT_UShort)args[0];
+ cvtEntry = (FT_ULong)( args[1] + 1 );
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.x != 0 &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
+ control_value_cutin = minimum_distance = 0;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
/* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
@@ -6234,7 +6568,7 @@
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6280,7 +6614,20 @@
cvt_dist = -cvt_dist;
}
- /* control value cutin and round */
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.freeVector.y != 0 &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
+ {
+ if ( cur_dist < -64 )
+ cvt_dist -= 16;
+ else if ( cur_dist > 64 && cur_dist < 84 )
+ cvt_dist += 32;
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ /* control value cut-in and round */
if ( ( CUR.opcode & 4 ) != 0 )
{
@@ -6301,7 +6648,7 @@
/* `ttinst2.doc', version 1.66, is thus incorrect since */
/* it implies `>=' instead of `>'. */
- if ( FT_ABS( cvt_dist - org_dist ) > CUR.GS.control_value_cutin )
+ if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
cvt_dist = org_dist;
}
@@ -6310,9 +6657,23 @@
CUR.tt_metrics.compensations[CUR.opcode & 3] );
}
else
+ {
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /* do cvt cut-in always in MIRP for sph */
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.GS.gep0 == CUR.GS.gep1 )
+ {
+ if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
+ cvt_dist = org_dist;
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
distance = ROUND_None(
cvt_dist,
CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ }
/* minimum distance test */
@@ -6320,18 +6681,65 @@
{
if ( org_dist >= 0 )
{
- if ( distance < CUR.GS.minimum_distance )
- distance = CUR.GS.minimum_distance;
+ if ( distance < minimum_distance )
+ distance = minimum_distance;
}
else
{
- if ( distance > -CUR.GS.minimum_distance )
- distance = -CUR.GS.minimum_distance;
+ if ( distance > -minimum_distance )
+ distance = -minimum_distance;
}
}
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING )
+ {
+ B1 = CUR.zp1.cur[point].y;
+
+ /* Round moves if necessary */
+ if ( CUR.ignore_x_mode &&
+ CUR.GS.freeVector.y != 0 &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
+ distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
+
+ if ( CUR.ignore_x_mode &&
+ CUR.GS.freeVector.y != 0 &&
+ ( CUR.opcode & 16 ) == 0 &&
+ ( CUR.opcode & 8 ) == 0 &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
+ distance += 64;
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING )
+ {
+ B2 = CUR.zp1.cur[point].y;
+
+ /* Reverse move if necessary */
+ if ( CUR.ignore_x_mode )
+ {
+ if ( CUR.face->sph_compatibility_mode &&
+ CUR.GS.freeVector.y != 0 &&
+ ( B1 & 63 ) == 0 &&
+ ( B2 & 63 ) != 0 )
+ reverse_move = TRUE;
+
+ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
+ CUR.GS.freeVector.y != 0 &&
+ ( B2 & 63 ) != 0 &&
+ ( B1 & 63 ) != 0 )
+ reverse_move = TRUE;
+ }
+
+ if ( reverse_move )
+ CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
+ }
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
Fail:
CUR.GS.rp1 = CUR.GS.rp0;
@@ -6357,11 +6765,22 @@
FT_UNUSED_ARG;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.iup_called &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
+ {
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
if ( CUR.top < CUR.GS.loop ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6375,7 +6794,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -6409,7 +6828,7 @@
a0, a1,
b0, b1;
- FT_F26Dot6 discriminant;
+ FT_F26Dot6 discriminant, dotproduct;
FT_F26Dot6 dx, dy,
dax, day,
@@ -6434,10 +6853,12 @@
BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
+ /* Cramer's rule */
+
dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
@@ -6449,15 +6870,25 @@
CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
- discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
- TT_MULDIV( day, dbx, 0x40 );
+ discriminant = FT_MulDiv( dax, -dby, 0x40 ) +
+ FT_MulDiv( day, dbx, 0x40 );
+ dotproduct = FT_MulDiv( dax, dbx, 0x40 ) +
+ FT_MulDiv( day, dby, 0x40 );
- if ( FT_ABS( discriminant ) >= 0x40 )
+ /* The discriminant above is actually a cross product of vectors */
+ /* da and db. Together with the dot product, they can be used as */
+ /* surrogates for sine and cosine of the angle between the vectors. */
+ /* Indeed, */
+ /* dotproduct = |da||db|cos(angle) */
+ /* discriminant = |da||db|sin(angle) . */
+ /* We use these equations to reject grazing intersections by */
+ /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
+ if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) )
{
- val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
+ val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 );
- R.x = TT_MULDIV( val, dax, discriminant );
- R.y = TT_MULDIV( val, day, discriminant );
+ R.x = FT_MulDiv( val, dax, discriminant );
+ R.y = FT_MulDiv( val, day, discriminant );
CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
@@ -6498,7 +6929,7 @@
BOUNDS( p2, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -6533,7 +6964,7 @@
if ( CUR.top < CUR.GS.loop )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6547,7 +6978,7 @@
if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto Fail;
}
@@ -6581,9 +7012,9 @@
FT_Vector vec;
- vec.x = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
+ vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
CUR.metrics.x_scale );
- vec.y = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
+ vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
CUR.metrics.y_scale );
old_range = CUR_fast_dualproj( &vec );
@@ -6603,7 +7034,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
continue;
@@ -6618,9 +7049,9 @@
FT_Vector vec;
- vec.x = TT_MULFIX( CUR.zp2.orus[point].x - orus_base->x,
+ vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x,
CUR.metrics.x_scale );
- vec.y = TT_MULFIX( CUR.zp2.orus[point].y - orus_base->y,
+ vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y,
CUR.metrics.y_scale );
org_dist = CUR_fast_dualproj( &vec );
@@ -6629,9 +7060,24 @@
cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
if ( org_dist )
- new_dist = ( old_range != 0 )
- ? TT_MULDIV( org_dist, cur_range, old_range )
- : cur_dist;
+ {
+ if ( old_range )
+ new_dist = FT_MulDiv( org_dist, cur_range, old_range );
+ else
+ {
+ /* This is the same as what MS does for the invalid case: */
+ /* */
+ /* delta = (Original_Pt - Original_RP1) - */
+ /* (Current_Pt - Current_RP1) */
+ /* */
+ /* In FreeType speak: */
+ /* */
+ /* new_dist = cur_dist - */
+ /* org_dist - cur_dist; */
+
+ new_dist = -org_dist;
+ }
+ }
else
new_dist = 0;
@@ -6662,7 +7108,7 @@
if ( BOUNDS( point, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -6791,12 +7237,12 @@
if ( !scale_valid )
{
scale_valid = 1;
- scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
- 0x10000L, orus2 - orus1 );
+ scale = FT_DivFix( org2 + delta2 - ( org1 + delta1 ),
+ orus2 - orus1 );
}
x = ( org1 + delta1 ) +
- TT_MULFIX( worker->orus[i].x - orus1, scale );
+ FT_MulFix( worker->orus[i].x - orus1, scale );
}
worker->curs[i].x = x;
}
@@ -6851,6 +7297,16 @@
contour = 0;
point = 0;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode )
+ {
+ CUR.iup_called = TRUE;
+ if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
+ return;
+ }
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
do
{
end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
@@ -6920,6 +7376,16 @@
FT_UShort A;
FT_ULong C;
FT_Long B;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_UShort B1, B2;
+
+
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.iup_called &&
+ ( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
+ goto Fail;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
@@ -6932,7 +7398,7 @@
if ( CUR.args < n )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
n = CUR.args;
}
@@ -6950,7 +7416,7 @@
if ( CUR.args < 2 )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
CUR.args = 0;
goto Fail;
}
@@ -6993,12 +7459,82 @@
B++;
B = B * 64 / ( 1L << CUR.GS.delta_shift );
- CUR_Func_move( &CUR.zp0, A, B );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( SUBPIXEL_HINTING )
+ {
+ /*
+ * Allow delta move if
+ *
+ * - not using ignore_x_mode rendering
+ * - glyph is specifically set to allow it
+ * - glyph is composite and freedom vector is not subpixel
+ * vector
+ */
+ if ( !CUR.ignore_x_mode ||
+ ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
+ ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) )
+ CUR_Func_move( &CUR.zp0, A, B );
+
+ /* Otherwise apply subpixel hinting and */
+ /* compatibility mode rules */
+ else if ( CUR.ignore_x_mode )
+ {
+ if ( CUR.GS.freeVector.y != 0 )
+ B1 = CUR.zp0.cur[A].y;
+ else
+ B1 = CUR.zp0.cur[A].x;
+
+#if 0
+ /* Standard Subpixel Hinting: Allow y move. */
+ /* This messes up dejavu and may not be needed... */
+ if ( !CUR.face->sph_compatibility_mode &&
+ CUR.GS.freeVector.y != 0 )
+ CUR_Func_move( &CUR.zp0, A, B );
+ else
+#endif /* 0 */
+
+ /* Compatibility Mode: Allow x or y move if point touched in */
+ /* Y direction. */
+ if ( CUR.face->sph_compatibility_mode &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
+ {
+ /* save the y value of the point now; compare after move */
+ B1 = CUR.zp0.cur[A].y;
+
+ if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
+ B = FT_PIX_ROUND( B1 + B ) - B1;
+
+ /* Allow delta move if using sph_compatibility_mode, */
+ /* IUP has not been called, and point is touched on Y. */
+ if ( !CUR.iup_called &&
+ ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
+ CUR_Func_move( &CUR.zp0, A, B );
+ }
+
+ B2 = CUR.zp0.cur[A].y;
+
+ /* Reverse this move if it results in a disallowed move */
+ if ( CUR.GS.freeVector.y != 0 &&
+ ( ( CUR.face->sph_compatibility_mode &&
+ ( B1 & 63 ) == 0 &&
+ ( B2 & 63 ) != 0 ) ||
+ ( ( CUR.sph_tweak_flags &
+ SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
+ ( B1 & 63 ) != 0 &&
+ ( B2 & 63 ) != 0 ) ) )
+ CUR_Func_move( &CUR.zp0, A, -B );
+ }
+ }
+ else
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ CUR_Func_move( &CUR.zp0, A, B );
}
}
else
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
Fail:
@@ -7030,7 +7566,7 @@
if ( CUR.args < n )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
n = CUR.args;
}
@@ -7047,7 +7583,7 @@
if ( CUR.args < 2 )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
CUR.args = 0;
goto Fail;
}
@@ -7061,7 +7597,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -7123,22 +7659,119 @@
K = 0;
- /* We return MS rasterizer version 1.7 for the font scaler. */
- if ( ( args[0] & 1 ) != 0 )
- K = 35;
-
- /* Has the glyph been rotated? */
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ /********************************/
+ /* RASTERIZER VERSION */
+ /* Selector Bit: 0 */
+ /* Return Bit(s): 0-7 */
+ /* */
+ if ( SUBPIXEL_HINTING &&
+ ( args[0] & 1 ) != 0 &&
+ CUR.ignore_x_mode )
+ {
+ K = CUR.rasterizer_version;
+ FT_TRACE7(( "Setting rasterizer version %d\n",
+ CUR.rasterizer_version ));
+ }
+ else
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+ if ( ( args[0] & 1 ) != 0 )
+ K = TT_INTERPRETER_VERSION_35;
+
+ /********************************/
+ /* GLYPH ROTATED */
+ /* Selector Bit: 1 */
+ /* Return Bit(s): 8 */
+ /* */
if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
K |= 0x80;
- /* Has the glyph been stretched? */
+ /********************************/
+ /* GLYPH STRETCHED */
+ /* Selector Bit: 2 */
+ /* Return Bit(s): 9 */
+ /* */
if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
K |= 1 << 8;
- /* Are we hinting for grayscale? */
+ /********************************/
+ /* HINTING FOR GRAYSCALE */
+ /* Selector Bit: 5 */
+ /* Return Bit(s): 12 */
+ /* */
if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
K |= 1 << 12;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( SUBPIXEL_HINTING &&
+ CUR.ignore_x_mode &&
+ CUR.rasterizer_version >= TT_INTERPRETER_VERSION_35 )
+ {
+ /********************************/
+ /* HINTING FOR GRAYSCALE */
+ /* Selector Bit: 5 */
+ /* Return Bit(s): 12 */
+ /* */
+ if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting )
+ K |= 1 << 12;
+
+ /********************************/
+ /* HINTING FOR SUBPIXEL */
+ /* Selector Bit: 6 */
+ /* Return Bit(s): 13 */
+ /* */
+ if ( ( args[0] & 64 ) != 0 &&
+ CUR.subpixel_hinting &&
+ CUR.rasterizer_version >= 37 )
+ {
+ K |= 1 << 13;
+
+ /* the stuff below is irrelevant if subpixel_hinting is not set */
+
+ /********************************/
+ /* COMPATIBLE WIDTHS ENABLED */
+ /* Selector Bit: 7 */
+ /* Return Bit(s): 14 */
+ /* */
+ /* Functionality still needs to be added */
+ if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths )
+ K |= 1 << 14;
+
+ /********************************/
+ /* SYMMETRICAL SMOOTHING */
+ /* Selector Bit: 8 */
+ /* Return Bit(s): 15 */
+ /* */
+ /* Functionality still needs to be added */
+ if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )
+ K |= 1 << 15;
+
+ /********************************/
+ /* HINTING FOR BGR? */
+ /* Selector Bit: 9 */
+ /* Return Bit(s): 16 */
+ /* */
+ /* Functionality still needs to be added */
+ if ( ( args[0] & 512 ) != 0 && CUR.bgr )
+ K |= 1 << 16;
+
+ if ( CUR.rasterizer_version >= 38 )
+ {
+ /********************************/
+ /* SUBPIXEL POSITIONED? */
+ /* Selector Bit: 10 */
+ /* Return Bit(s): 17 */
+ /* */
+ /* Functionality still needs to be added */
+ if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned )
+ K |= 1 << 17;
+ }
+ }
+ }
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
args[0] = K;
}
@@ -7161,7 +7794,7 @@
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -7180,7 +7813,7 @@
}
}
- CUR.error = TT_Err_Invalid_Opcode;
+ CUR.error = FT_THROW( Invalid_Opcode );
}
@@ -7507,13 +8140,31 @@
FT_EXPORT_DEF( FT_Error )
TT_RunIns( TT_ExecContext exc )
{
- FT_Long ins_counter = 0; /* executed instructions counter */
+ FT_Long ins_counter = 0; /* executed instructions counter */
+ FT_UShort i;
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_Byte opcode_pattern[1][2] = {
+ /* #8 TypeMan Talk Align */
+ {
+ 0x06, /* SPVTL */
+ 0x7D, /* RDTG */
+ },
+ };
+ FT_UShort opcode_patterns = 1;
+ FT_UShort opcode_pointer[1] = { 0 };
+ FT_UShort opcode_size[1] = { 1 };
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
#ifdef TT_CONFIG_OPTION_STATIC_RASTER
cur = *exc;
#endif
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ CUR.iup_called = FALSE;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
/* set CVT functions */
CUR.tt_metrics.ratio = 0;
if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
@@ -7560,12 +8211,9 @@
/* One can also interpret it as the index of the last argument. */
if ( CUR.args < 0 )
{
- FT_UShort i;
-
-
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Too_Few_Arguments;
+ CUR.error = FT_THROW( Too_Few_Arguments );
goto LErrorLabel_;
}
@@ -7582,12 +8230,45 @@
/* statement. */
if ( CUR.new_top > CUR.stackSize )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
goto LErrorLabel_;
}
CUR.step_ins = TRUE;
- CUR.error = TT_Err_Ok;
+ CUR.error = FT_Err_Ok;
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ if ( SUBPIXEL_HINTING )
+ {
+ for ( i = 0; i < opcode_patterns; i++ )
+ {
+ if ( opcode_pointer[i] < opcode_size[i] &&
+ CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
+ {
+ opcode_pointer[i] += 1;
+
+ if ( opcode_pointer[i] == opcode_size[i] )
+ {
+ FT_TRACE7(( "sph: opcode ptrn: %d, %s %s\n",
+ i,
+ CUR.face->root.family_name,
+ CUR.face->root.style_name ));
+
+ switch ( i )
+ {
+ case 0:
+ break;
+ }
+ opcode_pointer[i] = 0;
+ }
+ }
+ else
+ opcode_pointer[i] = 0;
+ }
+ }
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
@@ -7801,7 +8482,6 @@
Ins_MDAP( EXEC_ARG_ args );
break;
-
case 0x30: /* IUP */
case 0x31: /* IUP */
Ins_IUP( EXEC_ARG_ args );
@@ -7861,7 +8541,7 @@
break;
Set_Invalid_Ref:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
break;
case 0x43: /* RS */
@@ -8151,11 +8831,12 @@
#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
- if ( CUR.error != TT_Err_Ok )
+ if ( CUR.error )
{
switch ( CUR.error )
{
- case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
+ /* looking for redefined instructions */
+ case FT_ERR( Invalid_Opcode ):
{
TT_DefRecord* def = CUR.IDefs;
TT_DefRecord* limit = def + CUR.numIDefs;
@@ -8170,7 +8851,7 @@
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto LErrorLabel_;
}
@@ -8190,7 +8871,7 @@
}
}
- CUR.error = TT_Err_Invalid_Opcode;
+ CUR.error = FT_THROW( Invalid_Opcode );
goto LErrorLabel_;
#if 0
@@ -8216,14 +8897,14 @@
/* increment instruction counter and check if we didn't */
/* run this program for too long (e.g. infinite loops). */
if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
- return TT_Err_Execution_Too_Long;
+ return FT_THROW( Execution_Too_Long );
LSuiteLabel_:
if ( CUR.IP >= CUR.codeSize )
{
if ( CUR.callTop > 0 )
{
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
goto LErrorLabel_;
}
else
@@ -8237,10 +8918,10 @@
*exc = cur;
#endif
- return TT_Err_Ok;
+ return FT_Err_Ok;
LErrorCodeOverflow_:
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
LErrorLabel_:
diff --git a/src/truetype/ttinterp.h b/src/truetype/ttinterp.h
index 6d0fc03..69f5011 100644
--- a/src/truetype/ttinterp.h
+++ b/src/truetype/ttinterp.h
@@ -4,7 +4,7 @@
/* */
/* TrueType bytecode interpreter (specification). */
/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010 by */
+/* Copyright 1996-2007, 2010, 2012-2013 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -107,6 +107,48 @@ FT_BEGIN_HEADER
} TT_CallRec, *TT_CallStack;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ /*************************************************************************/
+ /* */
+ /* These structures define rules used to tweak subpixel hinting for */
+ /* various fonts. "", 0, "", NULL value indicates to match any value. */
+ /* */
+
+#define SPH_MAX_NAME_SIZE 32
+#define SPH_MAX_CLASS_MEMBERS 100
+
+ typedef struct SPH_TweakRule_
+ {
+ const char family[SPH_MAX_NAME_SIZE];
+ const FT_UInt ppem;
+ const char style[SPH_MAX_NAME_SIZE];
+ const FT_ULong glyph;
+
+ } SPH_TweakRule;
+
+
+ typedef struct SPH_ScaleRule_
+ {
+ const char family[SPH_MAX_NAME_SIZE];
+ const FT_UInt ppem;
+ const char style[SPH_MAX_NAME_SIZE];
+ const FT_ULong glyph;
+ const FT_ULong scale;
+
+ } SPH_ScaleRule;
+
+
+ typedef struct SPH_Font_Class_
+ {
+ const char name[SPH_MAX_NAME_SIZE];
+ const char member[SPH_MAX_CLASS_MEMBERS][SPH_MAX_NAME_SIZE];
+
+ } SPH_Font_Class;
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
/*************************************************************************/
/* */
/* The main structure for the interpreter which collects all necessary */
@@ -218,12 +260,43 @@ FT_BEGIN_HEADER
FT_Bool grayscale; /* are we hinting for grayscale? */
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ TT_Round_Func func_round_sphn; /* subpixel rounding function */
+
+ FT_Bool grayscale_hinting; /* Using grayscale hinting? */
+ FT_Bool subpixel_hinting; /* Using subpixel hinting? */
+ FT_Bool native_hinting; /* Using native hinting? */
+ FT_Bool ignore_x_mode; /* Standard rendering mode for */
+ /* subpixel hinting. On if gray */
+ /* or subpixel hinting is on ) */
+
+ /* The following 4 aren't fully implemented but here for MS rasterizer */
+ /* compatibility. */
+ FT_Bool compatible_widths; /* compatible widths? */
+ FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */
+ FT_Bool bgr; /* bgr instead of rgb? */
+ FT_Bool subpixel_positioned; /* subpixel positioned */
+ /* (DirectWrite ClearType)? */
+
+ FT_Int rasterizer_version; /* MS rasterizer version */
+
+ FT_Bool iup_called; /* IUP called for glyph? */
+
+ FT_ULong sph_tweak_flags; /* flags to control */
+ /* hint tweaks */
+
+ FT_ULong sph_in_func_flags; /* flags to indicate if in */
+ /* special functions */
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
} TT_ExecContextRec;
extern const TT_GraphicsState tt_default_graphics_state;
+#ifdef TT_USE_BYTECODE_INTERPRETER
FT_LOCAL( FT_Error )
TT_Goto_CodeRange( TT_ExecContext exec,
FT_Int range,
@@ -246,6 +319,7 @@ FT_BEGIN_HEADER
FT_Long multiplier,
void* _pbuff,
FT_ULong new_max );
+#endif /* TT_USE_BYTECODE_INTERPRETER */
/*************************************************************************/
@@ -270,6 +344,8 @@ FT_BEGIN_HEADER
FT_EXPORT( TT_ExecContext )
TT_New_Context( TT_Driver driver );
+
+#ifdef TT_USE_BYTECODE_INTERPRETER
FT_LOCAL( FT_Error )
TT_Done_Context( TT_ExecContext exec );
@@ -285,6 +361,7 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
TT_Run_Context( TT_ExecContext exec,
FT_Bool debug );
+#endif /* TT_USE_BYTECODE_INTERPRETER */
/*************************************************************************/
diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c
index 814c713..7897efa 100644
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -4,7 +4,7 @@
/* */
/* Objects manager (body). */
/* */
-/* Copyright 1996-2011 */
+/* Copyright 1996-2013 */
/* 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_STREAM_H
#include FT_TRUETYPE_TAGS_H
#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_DRIVER_H
#include "ttgload.h"
#include "ttpload.h"
@@ -244,7 +245,7 @@
tt_check_trickyness_sfnt_ids( TT_Face face )
{
#define TRICK_SFNT_IDS_PER_FACE 3
-#define TRICK_SFNT_IDS_NUM_FACES 13
+#define TRICK_SFNT_IDS_NUM_FACES 17
static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
[TRICK_SFNT_IDS_PER_FACE] = {
@@ -317,6 +318,26 @@
{ 0x00000000, 0x00000000 }, /* cvt */
{ 0x0d3de9cb, 0x00000141 }, /* fpgm */
{ 0xd4127766, 0x00002280 } /* prep */
+ },
+ { /* NEC FA-Gothic, 1996 */
+ { 0x00000000, 0x00000000 }, /* cvt */
+ { 0x4a692698, 0x000001f0 }, /* fpgm */
+ { 0x340d4346, 0x00001fca } /* prep */
+ },
+ { /* NEC FA-Minchou, 1996 */
+ { 0x00000000, 0x00000000 }, /* cvt */
+ { 0xcd34c604, 0x00000166 }, /* fpgm */
+ { 0x6cf31046, 0x000022b0 } /* prep */
+ },
+ { /* NEC FA-RoundGothicB, 1996 */
+ { 0x00000000, 0x00000000 }, /* cvt */
+ { 0x5da75315, 0x0000019d }, /* fpgm */
+ { 0x40745a5f, 0x000022e0 } /* prep */
+ },
+ { /* NEC FA-RoundGothicM, 1996 */
+ { 0x00000000, 0x00000000 }, /* cvt */
+ { 0xf055fc48, 0x000001c2 }, /* fpgm */
+ { 0x3900ded3, 0x00001e18 } /* prep */
}
};
@@ -501,7 +522,7 @@
if ( !sfnt )
{
FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" ));
- error = TT_Err_Missing_Module;
+ error = FT_THROW( Missing_Module );
goto Exit;
}
@@ -531,7 +552,7 @@
/* If we are performing a simple font format check, exit immediately. */
if ( face_index < 0 )
- return TT_Err_Ok;
+ return FT_Err_Ok;
/* Load font directory */
error = sfnt->load_face( stream, face, face_index, num_params, params );
@@ -631,7 +652,7 @@
return error;
Bad_Format:
- error = TT_Err_Unknown_File_Format;
+ error = FT_THROW( Unknown_File_Format );
goto Exit;
}
@@ -732,7 +753,7 @@
exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context;
if ( !exec )
- return TT_Err_Could_Not_Find_Context;
+ return FT_THROW( Could_Not_Find_Context );
TT_Load_Context( exec, face, size );
@@ -744,7 +765,7 @@
exec->threshold = 0;
exec->instruction_trap = FALSE;
- exec->F_dot_P = 0x10000L;
+ exec->F_dot_P = 0x4000L;
exec->pedantic_hinting = pedantic;
@@ -785,7 +806,7 @@
}
}
else
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
if ( !error )
TT_Save_Context( exec, size );
@@ -826,7 +847,7 @@
exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context;
if ( !exec )
- return TT_Err_Could_Not_Find_Context;
+ return FT_THROW( Could_Not_Find_Context );
TT_Load_Context( exec, face, size );
@@ -856,7 +877,27 @@
}
}
else
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
+
+ /* UNDOCUMENTED! The MS rasterizer doesn't allow the following */
+ /* graphics state variables to be modified by the CVT program. */
+
+ exec->GS.dualVector.x = 0x4000;
+ exec->GS.dualVector.y = 0;
+ exec->GS.projVector.x = 0x4000;
+ exec->GS.projVector.y = 0x0;
+ exec->GS.freeVector.x = 0x4000;
+ exec->GS.freeVector.y = 0x0;
+
+ exec->GS.rp0 = 0;
+ exec->GS.rp1 = 0;
+ exec->GS.rp2 = 0;
+
+ exec->GS.gep0 = 1;
+ exec->GS.gep1 = 1;
+ exec->GS.gep2 = 1;
+
+ exec->GS.loop = 1;
/* save as default graphics state */
size->GS = exec->GS;
@@ -1003,7 +1044,7 @@
tt_size_ready_bytecode( TT_Size size,
FT_Bool pedantic )
{
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
if ( !size->bytecode_ready )
@@ -1070,7 +1111,7 @@
tt_size_init( FT_Size ttsize ) /* TT_Size */
{
TT_Size size = (TT_Size)ttsize;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
#ifdef TT_USE_BYTECODE_INTERPRETER
size->bytecode_ready = 0;
@@ -1126,7 +1167,7 @@
tt_size_reset( TT_Size size )
{
TT_Face face;
- FT_Error error = TT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
FT_Size_Metrics* metrics;
@@ -1140,7 +1181,7 @@
*metrics = size->root.metrics;
if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 )
- return TT_Err_Invalid_PPem;
+ return FT_THROW( Invalid_PPem );
/* This bit flag, if set, indicates that the ppems must be */
/* rounded to integers. Nearly all TrueType fonts have this bit */
@@ -1170,16 +1211,14 @@
size->ttmetrics.scale = metrics->x_scale;
size->ttmetrics.ppem = metrics->x_ppem;
size->ttmetrics.x_ratio = 0x10000L;
- size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem,
- 0x10000L,
+ size->ttmetrics.y_ratio = FT_DivFix( metrics->y_ppem,
metrics->x_ppem );
}
else
{
size->ttmetrics.scale = metrics->y_scale;
size->ttmetrics.ppem = metrics->y_ppem;
- size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem,
- 0x10000L,
+ size->ttmetrics.x_ratio = FT_DivFix( metrics->x_ppem,
metrics->y_ppem );
size->ttmetrics.y_ratio = 0x10000L;
}
@@ -1219,15 +1258,21 @@
if ( !TT_New_Context( driver ) )
- return TT_Err_Could_Not_Find_Context;
+ return FT_THROW( Could_Not_Find_Context );
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ driver->interpreter_version = TT_INTERPRETER_VERSION_38;
#else
+ driver->interpreter_version = TT_INTERPRETER_VERSION_35;
+#endif
+
+#else /* !TT_USE_BYTECODE_INTERPRETER */
FT_UNUSED( ttdriver );
-#endif
+#endif /* !TT_USE_BYTECODE_INTERPRETER */
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h
index 47e4129..a11dd37 100644
--- a/src/truetype/ttobjs.h
+++ b/src/truetype/ttobjs.h
@@ -4,7 +4,7 @@
/* */
/* Objects manager (specification). */
/* */
-/* Copyright 1996-2009, 2011-2012 by */
+/* Copyright 1996-2009, 2011-2013 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -173,11 +173,13 @@ FT_BEGIN_HEADER
/* */
typedef struct TT_DefRecord_
{
- FT_Int range; /* in which code range is it located? */
- FT_Long start; /* where does it start? */
- FT_Long end; /* where does it end? */
- FT_UInt opc; /* function #, or instruction code */
- FT_Bool active; /* is it active? */
+ FT_Int range; /* in which code range is it located? */
+ FT_Long start; /* where does it start? */
+ FT_Long end; /* where does it end? */
+ FT_UInt opc; /* function #, or instruction code */
+ FT_Bool active; /* is it active? */
+ FT_Bool inline_delta; /* is function that defines inline delta? */
+ FT_ULong sph_fdef_flags; /* flags to identify special functions */
} TT_DefRecord, *TT_DefArray;
@@ -190,7 +192,7 @@ FT_BEGIN_HEADER
{
FT_Fixed xx, xy; /* transformation matrix coefficients */
FT_Fixed yx, yy;
- FT_F26Dot6 ox, oy; /* offsets */
+ FT_F26Dot6 ox, oy; /* offsets */
} TT_Transform;
@@ -345,11 +347,12 @@ FT_BEGIN_HEADER
/* */
typedef struct TT_DriverRec_
{
- FT_DriverRec root;
+ FT_DriverRec root;
+
TT_ExecContext context; /* execution context */
TT_GlyphZoneRec zone; /* glyph loader points zone */
- void* extension_component;
+ FT_UInt interpreter_version;
} TT_DriverRec;
@@ -427,6 +430,10 @@ FT_BEGIN_HEADER
tt_slot_init( FT_GlyphSlot slot );
+ /* auxiliary */
+#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
+
+
FT_END_HEADER
#endif /* __TTOBJS_H__ */
diff --git a/src/truetype/ttpic.c b/src/truetype/ttpic.c
index 65ca845..edefae7 100644
--- a/src/truetype/ttpic.c
+++ b/src/truetype/ttpic.c
@@ -4,7 +4,7 @@
/* */
/* The FreeType position independent code services for truetype module. */
/* */
-/* Copyright 2009, 2010 by */
+/* Copyright 2009, 2010, 2012, 2013 by */
/* Oran Agra and Mickey Gabel. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -22,30 +22,29 @@
#include "ttpic.h"
#include "tterrors.h"
+
#ifdef FT_CONFIG_OPTION_PIC
/* forward declaration of PIC init functions from ttdriver.c */
FT_Error
FT_Create_Class_tt_services( FT_Library library,
FT_ServiceDescRec** output_class );
-
void
FT_Destroy_Class_tt_services( FT_Library library,
FT_ServiceDescRec* clazz );
-
void
FT_Init_Class_tt_service_gx_multi_masters(
FT_Service_MultiMastersRec* sv_mm );
-
void
FT_Init_Class_tt_service_truetype_glyf(
FT_Service_TTGlyfRec* sv_ttglyf );
+
void
tt_driver_class_pic_free( FT_Library library )
{
FT_PIC_Container* pic_container = &library->pic_container;
- FT_Memory memory = library->memory;
+ FT_Memory memory = library->memory;
if ( pic_container->truetype )
@@ -66,18 +65,19 @@
tt_driver_class_pic_init( FT_Library library )
{
FT_PIC_Container* pic_container = &library->pic_container;
- FT_Error error = TT_Err_Ok;
- TTModulePIC* container;
+ FT_Error error = FT_Err_Ok;
+ TTModulePIC* container = NULL;
FT_Memory memory = library->memory;
/* allocate pointer, clear and set global container pointer */
- if ( FT_ALLOC ( container, sizeof ( *container ) ) )
+ if ( FT_ALLOC( container, sizeof ( *container ) ) )
return error;
FT_MEM_SET( container, 0, sizeof ( *container ) );
pic_container->truetype = container;
- /* initialize pointer table - this is how the module usually expects this data */
+ /* initialize pointer table - this is how the module usually */
+ /* expects this data */
error = FT_Create_Class_tt_services( library,
&container->tt_services );
if ( error )
@@ -88,7 +88,8 @@
#endif
FT_Init_Class_tt_service_truetype_glyf(
&container->tt_service_truetype_glyf );
-Exit:
+
+ Exit:
if ( error )
tt_driver_class_pic_free( library );
return error;
diff --git a/src/truetype/ttpic.h b/src/truetype/ttpic.h
index 48f43a5..cfb4ee6 100644
--- a/src/truetype/ttpic.h
+++ b/src/truetype/ttpic.h
@@ -4,7 +4,7 @@
/* */
/* The FreeType position independent code services for truetype module. */
/* */
-/* Copyright 2009 by */
+/* Copyright 2009, 2012, 2013 by */
/* Oran Agra and Mickey Gabel. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -23,29 +23,43 @@
FT_BEGIN_HEADER
#ifndef FT_CONFIG_OPTION_PIC
-#define FT_TT_SERVICES_GET tt_services
-#define FT_TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters
-#define FT_TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf
+
+#define TT_SERVICES_GET tt_services
+#define TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters
+#define TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf
+#define TT_SERVICE_PROPERTIES_GET tt_service_properties
#else /* FT_CONFIG_OPTION_PIC */
#include FT_MULTIPLE_MASTERS_H
#include FT_SERVICE_MULTIPLE_MASTERS_H
#include FT_SERVICE_TRUETYPE_GLYF_H
+#include FT_SERVICE_PROPERTIES_H
+
- typedef struct TTModulePIC_
+ typedef struct TTModulePIC_
{
- FT_ServiceDescRec* tt_services;
+ FT_ServiceDescRec* tt_services;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- FT_Service_MultiMastersRec tt_service_gx_multi_masters;
+ FT_Service_MultiMastersRec tt_service_gx_multi_masters;
#endif
- FT_Service_TTGlyfRec tt_service_truetype_glyf;
+ FT_Service_TTGlyfRec tt_service_truetype_glyf;
+ FT_Service_PropertiesRec tt_service_properties;
+
} TTModulePIC;
-#define GET_PIC(lib) ((TTModulePIC*)((lib)->pic_container.truetype))
-#define FT_TT_SERVICES_GET (GET_PIC(library)->tt_services)
-#define FT_TT_SERVICE_GX_MULTI_MASTERS_GET (GET_PIC(library)->tt_service_gx_multi_masters)
-#define FT_TT_SERVICE_TRUETYPE_GLYF_GET (GET_PIC(library)->tt_service_truetype_glyf)
+
+#define GET_PIC( lib ) \
+ ( (TTModulePIC*)((lib)->pic_container.truetype) )
+#define TT_SERVICES_GET \
+ ( GET_PIC( library )->tt_services )
+#define TT_SERVICE_GX_MULTI_MASTERS_GET \
+ ( GET_PIC( library )->tt_service_gx_multi_masters )
+#define TT_SERVICE_TRUETYPE_GLYF_GET \
+ ( GET_PIC( library )->tt_service_truetype_glyf )
+#define TT_SERVICE_PROPERTIES_GET \
+ ( GET_PIC( library )->tt_service_properties )
+
/* see ttpic.c for the implementation */
void
@@ -58,6 +72,7 @@ FT_BEGIN_HEADER
/* */
+
FT_END_HEADER
#endif /* __TTPIC_H__ */
diff --git a/src/truetype/ttpload.c b/src/truetype/ttpload.c
index bb6005d..9723a51 100644
--- a/src/truetype/ttpload.c
+++ b/src/truetype/ttpload.c
@@ -4,7 +4,7 @@
/* */
/* TrueType-specific tables loader (body). */
/* */
-/* Copyright 1996-2002, 2004-2012 by */
+/* Copyright 1996-2002, 2004-2013 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -72,7 +72,7 @@
/* it is possible that a font doesn't have a glyf table at all */
/* or its size is zero */
- if ( error == TT_Err_Table_Missing )
+ if ( FT_ERR_EQ( error, Table_Missing ) )
face->glyf_len = 0;
else if ( error )
goto Exit;
@@ -81,7 +81,7 @@
error = face->goto_table( face, TTAG_loca, stream, &table_len );
if ( error )
{
- error = TT_Err_Locations_Missing;
+ error = FT_THROW( Locations_Missing );
goto Exit;
}
@@ -92,7 +92,7 @@
if ( table_len >= 0x40000L )
{
FT_TRACE2(( "table too large\n" ));
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Exit;
}
face->num_locations = table_len >> shift;
@@ -104,7 +104,7 @@
if ( table_len >= 0x20000L )
{
FT_TRACE2(( "table too large\n" ));
- error = TT_Err_Invalid_Table;
+ error = FT_THROW( Invalid_Table );
goto Exit;
}
face->num_locations = table_len >> shift;
@@ -296,7 +296,7 @@
face->cvt_size = 0;
face->cvt = NULL;
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
goto Exit;
}
@@ -334,7 +334,7 @@
FT_UNUSED( face );
FT_UNUSED( stream );
- return TT_Err_Ok;
+ return FT_Err_Ok;
#endif
}
@@ -375,7 +375,7 @@
{
face->font_program = NULL;
face->font_program_size = 0;
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
FT_TRACE2(( "is missing\n" ));
}
@@ -396,7 +396,7 @@
FT_UNUSED( face );
FT_UNUSED( stream );
- return TT_Err_Ok;
+ return FT_Err_Ok;
#endif
}
@@ -436,7 +436,7 @@
{
face->cvt_program = NULL;
face->cvt_program_size = 0;
- error = TT_Err_Ok;
+ error = FT_Err_Ok;
FT_TRACE2(( "is missing\n" ));
}
@@ -457,7 +457,7 @@
FT_UNUSED( face );
FT_UNUSED( stream );
- return TT_Err_Ok;
+ return FT_Err_Ok;
#endif
}
@@ -495,7 +495,7 @@
/* this table is optional */
error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
if ( error || table_size < 8 )
- return TT_Err_Ok;
+ return FT_Err_Ok;
if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
goto Exit;
@@ -525,7 +525,7 @@
if ( version != 0 || num_records > 255 || record_size > 0x10001L )
{
- error = TT_Err_Invalid_File_Format;
+ error = FT_THROW( Invalid_File_Format );
goto Fail;
}
diff --git a/src/truetype/ttsubpix.c b/src/truetype/ttsubpix.c
new file mode 100644
index 0000000..28470ad
--- /dev/null
+++ b/src/truetype/ttsubpix.c
@@ -0,0 +1,1011 @@
+/***************************************************************************/
+/* */
+/* ttsubpix.c */
+/* */
+/* TrueType Subpixel Hinting. */
+/* */
+/* Copyright 2010-2013 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_DRIVER_H
+
+#include "ttsubpix.h"
+
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ /*************************************************************************/
+ /* */
+ /* These rules affect how the TT Interpreter does hinting, with the */
+ /* goal of doing subpixel hinting by (in general) ignoring x moves. */
+ /* Some of these rules are fixes that go above and beyond the */
+ /* stated techniques in the MS whitepaper on Cleartype, due to */
+ /* artifacts in many glyphs. So, these rules make some glyphs render */
+ /* better than they do in the MS rasterizer. */
+ /* */
+ /* "" string or 0 int/char indicates to apply to all glyphs. */
+ /* "-" used as dummy placeholders, but any non-matching string works. */
+ /* */
+ /* Some of this could arguably be implemented in fontconfig, however: */
+ /* */
+ /* - Fontconfig can't set things on a glyph-by-glyph basis. */
+ /* - The tweaks that happen here are very low-level, from an average */
+ /* user's point of view and are best implemented in the hinter. */
+ /* */
+ /* The goal is to make the subpixel hinting techniques as generalized */
+ /* as possible across all fonts to prevent the need for extra rules such */
+ /* as these. */
+ /* */
+ /* The rule structure is designed so that entirely new rules can easily */
+ /* be added when a new compatibility feature is discovered. */
+ /* */
+ /* The rule structures could also use some enhancement to handle ranges. */
+ /* */
+ /* ****************** WORK IN PROGRESS ******************* */
+ /* */
+
+ /* These are `classes' of fonts that can be grouped together and used in */
+ /* rules below. A blank entry "" is required at the end of these! */
+#define FAMILY_CLASS_RULES_SIZE 7
+
+ static const SPH_Font_Class FAMILY_CLASS_Rules
+ [FAMILY_CLASS_RULES_SIZE] =
+ {
+ { "MS Legacy Fonts",
+ { "Aharoni",
+ "Andale Mono",
+ "Andalus",
+ "Angsana New",
+ "AngsanaUPC",
+ "Arabic Transparent",
+ "Arial Black",
+ "Arial Narrow",
+ "Arial Unicode MS",
+ "Arial",
+ "Batang",
+ "Browallia New",
+ "BrowalliaUPC",
+ "Comic Sans MS",
+ "Cordia New",
+ "CordiaUPC",
+ "Courier New",
+ "DFKai-SB",
+ "David Transparent",
+ "David",
+ "DilleniaUPC",
+ "Estrangelo Edessa",
+ "EucrosiaUPC",
+ "FangSong_GB2312",
+ "Fixed Miriam Transparent",
+ "FrankRuehl",
+ "Franklin Gothic Medium",
+ "FreesiaUPC",
+ "Garamond",
+ "Gautami",
+ "Georgia",
+ "Gulim",
+ "Impact",
+ "IrisUPC",
+ "JasmineUPC",
+ "KaiTi_GB2312",
+ "KodchiangUPC",
+ "Latha",
+ "Levenim MT",
+ "LilyUPC",
+ "Lucida Console",
+ "Lucida Sans Unicode",
+ "MS Gothic",
+ "MS Mincho",
+ "MV Boli",
+ "Mangal",
+ "Marlett",
+ "Microsoft Sans Serif",
+ "Mingliu",
+ "Miriam Fixed",
+ "Miriam Transparent",
+ "Miriam",
+ "Narkisim",
+ "Palatino Linotype",
+ "Raavi",
+ "Rod Transparent",
+ "Rod",
+ "Shruti",
+ "SimHei",
+ "Simplified Arabic Fixed",
+ "Simplified Arabic",
+ "Simsun",
+ "Sylfaen",
+ "Symbol",
+ "Tahoma",
+ "Times New Roman",
+ "Traditional Arabic",
+ "Trebuchet MS",
+ "Tunga",
+ "Verdana",
+ "Webdings",
+ "Wingdings",
+ "",
+ },
+ },
+ { "Core MS Legacy Fonts",
+ { "Arial Black",
+ "Arial Narrow",
+ "Arial Unicode MS",
+ "Arial",
+ "Comic Sans MS",
+ "Courier New",
+ "Garamond",
+ "Georgia",
+ "Impact",
+ "Lucida Console",
+ "Lucida Sans Unicode",
+ "Microsoft Sans Serif",
+ "Palatino Linotype",
+ "Tahoma",
+ "Times New Roman",
+ "Trebuchet MS",
+ "Verdana",
+ "",
+ },
+ },
+ { "Apple Legacy Fonts",
+ { "Geneva",
+ "Times",
+ "Monaco",
+ "Century",
+ "Chalkboard",
+ "Lobster",
+ "Century Gothic",
+ "Optima",
+ "Lucida Grande",
+ "Gill Sans",
+ "Baskerville",
+ "Helvetica",
+ "Helvetica Neue",
+ "",
+ },
+ },
+ { "Legacy Sans Fonts",
+ { "Andale Mono",
+ "Arial Unicode MS",
+ "Arial",
+ "Century Gothic",
+ "Comic Sans MS",
+ "Franklin Gothic Medium",
+ "Geneva",
+ "Lucida Console",
+ "Lucida Grande",
+ "Lucida Sans Unicode",
+ "Lucida Sans Typewriter",
+ "Microsoft Sans Serif",
+ "Monaco",
+ "Tahoma",
+ "Trebuchet MS",
+ "Verdana",
+ "",
+ },
+ },
+
+ { "Misc Legacy Fonts",
+ { "Dark Courier", "", }, },
+ { "Verdana Clones",
+ { "DejaVu Sans",
+ "Bitstream Vera Sans", "", }, },
+ { "Verdana and Clones",
+ { "DejaVu Sans",
+ "Bitstream Vera Sans",
+ "Verdana", "", }, },
+ };
+
+
+ /* Define this to force natural (i.e. not bitmap-compatible) widths. */
+ /* The default leans strongly towards natural widths except for a few */
+ /* legacy fonts where a selective combination produces nicer results. */
+/* #define FORCE_NATURAL_WIDTHS */
+
+
+ /* Define `classes' of styles that can be grouped together and used in */
+ /* rules below. A blank entry "" is required at the end of these! */
+#define STYLE_CLASS_RULES_SIZE 5
+
+ const SPH_Font_Class STYLE_CLASS_Rules
+ [STYLE_CLASS_RULES_SIZE] =
+ {
+ { "Regular Class",
+ { "Regular",
+ "Book",
+ "Medium",
+ "Roman",
+ "Normal",
+ "",
+ },
+ },
+ { "Regular/Italic Class",
+ { "Regular",
+ "Book",
+ "Medium",
+ "Italic",
+ "Oblique",
+ "Roman",
+ "Normal",
+ "",
+ },
+ },
+ { "Bold/BoldItalic Class",
+ { "Bold",
+ "Bold Italic",
+ "Black",
+ "",
+ },
+ },
+ { "Bold/Italic/BoldItalic Class",
+ { "Bold",
+ "Bold Italic",
+ "Black",
+ "Italic",
+ "Oblique",
+ "",
+ },
+ },
+ { "Regular/Bold Class",
+ { "Regular",
+ "Book",
+ "Medium",
+ "Normal",
+ "Roman",
+ "Bold",
+ "Black",
+ "",
+ },
+ },
+ };
+
+
+ /* Force special legacy fixes for fonts. */
+#define COMPATIBILITY_MODE_RULES_SIZE 1
+
+ const SPH_TweakRule COMPATIBILITY_MODE_Rules
+ [COMPATIBILITY_MODE_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */
+#define PIXEL_HINTING_RULES_SIZE 2
+
+ const SPH_TweakRule PIXEL_HINTING_Rules
+ [PIXEL_HINTING_RULES_SIZE] =
+ {
+ /* these characters are almost always safe */
+ { "Courier New", 12, "Italic", 'z' },
+ { "Courier New", 11, "Italic", 'z' },
+ };
+
+
+ /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */
+#define DO_SHPIX_RULES_SIZE 1
+
+ const SPH_TweakRule DO_SHPIX_Rules
+ [DO_SHPIX_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Skip Y moves that start with a point that is not on a Y pixel */
+ /* boundary and don't move that point to a Y pixel boundary. */
+#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 4
+
+ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules
+ [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
+ {
+ /* fix vwxyz thinness*/
+ { "Consolas", 0, "", 0 },
+ /* Fix thin middle stems */
+ { "Core MS Legacy Fonts", 0, "Regular", 0 },
+ /* Cyrillic small letter I */
+ { "Legacy Sans Fonts", 0, "", 0 },
+ /* Fix artifacts with some Regular & Bold */
+ { "Verdana Clones", 0, "", 0 },
+ };
+
+
+#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
+
+ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
+ [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
+ {
+ /* Fixes < and > */
+ { "Courier New", 0, "Regular", 0 },
+ };
+
+
+ /* Skip Y moves that start with a point that is not on a Y pixel */
+ /* boundary and don't move that point to a Y pixel boundary. */
+#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2
+
+ const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules
+ [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] =
+ {
+ /* Maintain thickness of diagonal in 'N' */
+ { "Times New Roman", 0, "Regular/Bold Class", 'N' },
+ { "Georgia", 0, "Regular/Bold Class", 'N' },
+ };
+
+
+ /* Skip Y moves that move a point off a Y pixel boundary. */
+#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1
+
+ const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules
+ [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
+
+ const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
+ [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Round moves that don't move a point to a Y pixel boundary. */
+#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2
+
+ const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules
+ [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
+ {
+ /* Droid font instructions don't snap Y to pixels */
+ { "Droid Sans", 0, "Regular/Italic Class", 0 },
+ { "Droid Sans Mono", 0, "", 0 },
+ };
+
+
+#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
+
+ const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
+ [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Allow a Direct_Move along X freedom vector if matched. */
+#define ALLOW_X_DMOVE_RULES_SIZE 1
+
+ const SPH_TweakRule ALLOW_X_DMOVE_Rules
+ [ALLOW_X_DMOVE_RULES_SIZE] =
+ {
+ /* Fixes vanishing diagonal in 4 */
+ { "Verdana", 0, "Regular", '4' },
+ };
+
+
+ /* Return MS rasterizer version 35 if matched. */
+#define RASTERIZER_35_RULES_SIZE 8
+
+ const SPH_TweakRule RASTERIZER_35_Rules
+ [RASTERIZER_35_RULES_SIZE] =
+ {
+ /* This seems to be the only way to make these look good */
+ { "Times New Roman", 0, "Regular", 'i' },
+ { "Times New Roman", 0, "Regular", 'j' },
+ { "Times New Roman", 0, "Regular", 'm' },
+ { "Times New Roman", 0, "Regular", 'r' },
+ { "Times New Roman", 0, "Regular", 'a' },
+ { "Times New Roman", 0, "Regular", 'n' },
+ { "Times New Roman", 0, "Regular", 'p' },
+ { "Times", 0, "", 0 },
+ };
+
+
+ /* Don't round to the subpixel grid. Round to pixel grid. */
+#define NORMAL_ROUND_RULES_SIZE 1
+
+ const SPH_TweakRule NORMAL_ROUND_Rules
+ [NORMAL_ROUND_RULES_SIZE] =
+ {
+ /* Fix serif thickness for certain ppems */
+ /* Can probably be generalized somehow */
+ { "Courier New", 0, "", 0 },
+ };
+
+
+ /* Skip IUP instructions if matched. */
+#define SKIP_IUP_RULES_SIZE 1
+
+ const SPH_TweakRule SKIP_IUP_Rules
+ [SKIP_IUP_RULES_SIZE] =
+ {
+ { "Arial", 13, "Regular", 'a' },
+ };
+
+
+ /* Skip MIAP Twilight hack if matched. */
+#define MIAP_HACK_RULES_SIZE 1
+
+ const SPH_TweakRule MIAP_HACK_Rules
+ [MIAP_HACK_RULES_SIZE] =
+ {
+ { "Geneva", 12, "", 0 },
+ };
+
+
+ /* Skip DELTAP instructions if matched. */
+#define ALWAYS_SKIP_DELTAP_RULES_SIZE 23
+
+ const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
+ [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
+ {
+ { "Georgia", 0, "Regular", 'k' },
+ /* fix various problems with e in different versions */
+ { "Trebuchet MS", 14, "Regular", 'e' },
+ { "Trebuchet MS", 13, "Regular", 'e' },
+ { "Trebuchet MS", 15, "Regular", 'e' },
+ { "Trebuchet MS", 0, "Italic", 'v' },
+ { "Trebuchet MS", 0, "Italic", 'w' },
+ { "Trebuchet MS", 0, "Regular", 'Y' },
+ { "Arial", 11, "Regular", 's' },
+ /* prevent problems with '3' and others */
+ { "Verdana", 10, "Regular", 0 },
+ { "Verdana", 9, "Regular", 0 },
+ /* Cyrillic small letter short I */
+ { "Legacy Sans Fonts", 0, "", 0x438 },
+ { "Legacy Sans Fonts", 0, "", 0x439 },
+ { "Arial", 10, "Regular", '6' },
+ { "Arial", 0, "Bold/BoldItalic Class", 'a' },
+ /* Make horizontal stems consistent with the rest */
+ { "Arial", 24, "Bold", 'a' },
+ { "Arial", 25, "Bold", 'a' },
+ { "Arial", 24, "Bold", 's' },
+ { "Arial", 25, "Bold", 's' },
+ { "Arial", 34, "Bold", 's' },
+ { "Arial", 35, "Bold", 's' },
+ { "Arial", 36, "Bold", 's' },
+ { "Arial", 25, "Regular", 's' },
+ { "Arial", 26, "Regular", 's' },
+ };
+
+
+ /* Always do DELTAP instructions if matched. */
+#define ALWAYS_DO_DELTAP_RULES_SIZE 1
+
+ const SPH_TweakRule ALWAYS_DO_DELTAP_Rules
+ [ALWAYS_DO_DELTAP_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Don't allow ALIGNRP after IUP. */
+#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1
+
+ static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules
+ [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] =
+ {
+ /* Prevent creation of dents in outline */
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Don't allow DELTAP after IUP. */
+#define NO_DELTAP_AFTER_IUP_RULES_SIZE 1
+
+ static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules
+ [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+ /* Don't allow CALL after IUP. */
+#define NO_CALL_AFTER_IUP_RULES_SIZE 1
+
+ static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules
+ [NO_CALL_AFTER_IUP_RULES_SIZE] =
+ {
+ /* Prevent creation of dents in outline */
+ { "-", 0, "", 0 },
+ };
+
+
+ /* De-embolden these glyphs slightly. */
+#define DEEMBOLDEN_RULES_SIZE 9
+
+ static const SPH_TweakRule DEEMBOLDEN_Rules
+ [DEEMBOLDEN_RULES_SIZE] =
+ {
+ { "Courier New", 0, "Bold", 'A' },
+ { "Courier New", 0, "Bold", 'W' },
+ { "Courier New", 0, "Bold", 'w' },
+ { "Courier New", 0, "Bold", 'M' },
+ { "Courier New", 0, "Bold", 'X' },
+ { "Courier New", 0, "Bold", 'K' },
+ { "Courier New", 0, "Bold", 'x' },
+ { "Courier New", 0, "Bold", 'z' },
+ { "Courier New", 0, "Bold", 'v' },
+ };
+
+
+ /* Embolden these glyphs slightly. */
+#define EMBOLDEN_RULES_SIZE 2
+
+ static const SPH_TweakRule EMBOLDEN_Rules
+ [EMBOLDEN_RULES_SIZE] =
+ {
+ { "Courier New", 0, "Regular", 0 },
+ { "Courier New", 0, "Italic", 0 },
+ };
+
+
+ /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */
+ /* similar to Windows XP. */
+#define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
+
+ static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules
+ [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
+ {
+ { "Times New Roman", 16, "Italic", '2' },
+ { "Times New Roman", 16, "Italic", '5' },
+ { "Times New Roman", 16, "Italic", '7' },
+ { "Times New Roman", 16, "Regular", '2' },
+ { "Times New Roman", 16, "Regular", '5' },
+ { "Times New Roman", 16, "Regular", '7' },
+ { "Times New Roman", 17, "Italic", '2' },
+ { "Times New Roman", 17, "Italic", '5' },
+ { "Times New Roman", 17, "Italic", '7' },
+ { "Times New Roman", 17, "Regular", '2' },
+ { "Times New Roman", 17, "Regular", '5' },
+ { "Times New Roman", 17, "Regular", '7' },
+ };
+
+
+ /* This fudges distance on 2 to get rid of the vanishing stem issue. */
+ /* A real solution to this is certainly welcome. */
+#define COURIER_NEW_2_HACK_RULES_SIZE 15
+
+ static const SPH_TweakRule COURIER_NEW_2_HACK_Rules
+ [COURIER_NEW_2_HACK_RULES_SIZE] =
+ {
+ { "Courier New", 10, "Regular", '2' },
+ { "Courier New", 11, "Regular", '2' },
+ { "Courier New", 12, "Regular", '2' },
+ { "Courier New", 13, "Regular", '2' },
+ { "Courier New", 14, "Regular", '2' },
+ { "Courier New", 15, "Regular", '2' },
+ { "Courier New", 16, "Regular", '2' },
+ { "Courier New", 17, "Regular", '2' },
+ { "Courier New", 18, "Regular", '2' },
+ { "Courier New", 19, "Regular", '2' },
+ { "Courier New", 20, "Regular", '2' },
+ { "Courier New", 21, "Regular", '2' },
+ { "Courier New", 22, "Regular", '2' },
+ { "Courier New", 23, "Regular", '2' },
+ { "Courier New", 24, "Regular", '2' },
+ };
+
+
+#ifndef FORCE_NATURAL_WIDTHS
+
+ /* Use compatible widths with these glyphs. Compatible widths is always */
+ /* on when doing B/W TrueType instructing, but is used selectively here, */
+ /* typically on glyphs with 3 or more vertical stems. */
+#define COMPATIBLE_WIDTHS_RULES_SIZE 38
+
+ static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
+ [COMPATIBLE_WIDTHS_RULES_SIZE] =
+ {
+ { "Arial Unicode MS", 12, "Regular Class", 'm' },
+ { "Arial Unicode MS", 14, "Regular Class", 'm' },
+ /* Cyrillic small letter sha */
+ { "Arial", 10, "Regular Class", 0x448 },
+ { "Arial", 11, "Regular Class", 'm' },
+ { "Arial", 12, "Regular Class", 'm' },
+ /* Cyrillic small letter sha */
+ { "Arial", 12, "Regular Class", 0x448 },
+ { "Arial", 13, "Regular Class", 0x448 },
+ { "Arial", 14, "Regular Class", 'm' },
+ /* Cyrillic small letter sha */
+ { "Arial", 14, "Regular Class", 0x448 },
+ { "Arial", 15, "Regular Class", 0x448 },
+ { "Arial", 17, "Regular Class", 'm' },
+ { "DejaVu Sans", 15, "Regular Class", 0 },
+ { "Microsoft Sans Serif", 11, "Regular Class", 0 },
+ { "Microsoft Sans Serif", 12, "Regular Class", 0 },
+ { "Segoe UI", 11, "Regular Class", 0 },
+ { "Monaco", 0, "Regular Class", 0 },
+ { "Segoe UI", 12, "Regular Class", 'm' },
+ { "Segoe UI", 14, "Regular Class", 'm' },
+ { "Tahoma", 11, "Regular Class", 0 },
+ { "Times New Roman", 16, "Regular Class", 'c' },
+ { "Times New Roman", 16, "Regular Class", 'm' },
+ { "Times New Roman", 16, "Regular Class", 'o' },
+ { "Times New Roman", 16, "Regular Class", 'w' },
+ { "Trebuchet MS", 11, "Regular Class", 0 },
+ { "Trebuchet MS", 12, "Regular Class", 0 },
+ { "Trebuchet MS", 14, "Regular Class", 0 },
+ { "Trebuchet MS", 15, "Regular Class", 0 },
+ { "Ubuntu", 12, "Regular Class", 'm' },
+ /* Cyrillic small letter sha */
+ { "Verdana", 10, "Regular Class", 0x448 },
+ { "Verdana", 11, "Regular Class", 0x448 },
+ { "Verdana and Clones", 12, "Regular Class", 'i' },
+ { "Verdana and Clones", 12, "Regular Class", 'j' },
+ { "Verdana and Clones", 12, "Regular Class", 'l' },
+ { "Verdana and Clones", 12, "Regular Class", 'm' },
+ { "Verdana and Clones", 13, "Regular Class", 'i' },
+ { "Verdana and Clones", 13, "Regular Class", 'j' },
+ { "Verdana and Clones", 13, "Regular Class", 'l' },
+ { "Verdana and Clones", 14, "Regular Class", 'm' },
+ };
+
+
+ /* Scaling slightly in the x-direction prior to hinting results in */
+ /* more visually pleasing glyphs in certain cases. */
+ /* This sometimes needs to be coordinated with compatible width rules. */
+ /* A value of 1000 corresponds to a scaled value of 1.0. */
+
+#define X_SCALING_RULES_SIZE 50
+
+ static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] =
+ {
+ { "DejaVu Sans", 12, "Regular Class", 'm', 950 },
+ { "Verdana and Clones", 12, "Regular Class", 'a', 1100 },
+ { "Verdana and Clones", 13, "Regular Class", 'a', 1050 },
+ { "Arial", 11, "Regular Class", 'm', 975 },
+ { "Arial", 12, "Regular Class", 'm', 1050 },
+ /* Cyrillic small letter el */
+ { "Arial", 13, "Regular Class", 0x43B, 950 },
+ { "Arial", 13, "Regular Class", 'o', 950 },
+ { "Arial", 13, "Regular Class", 'e', 950 },
+ { "Arial", 14, "Regular Class", 'm', 950 },
+ /* Cyrillic small letter el */
+ { "Arial", 15, "Regular Class", 0x43B, 925 },
+ { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 },
+ { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 },
+ { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 },
+ { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 },
+ { "DejaVu Sans", 12, "Regular Class", 'l', 975 },
+ { "DejaVu Sans", 12, "Regular Class", 'i', 975 },
+ { "DejaVu Sans", 12, "Regular Class", 'j', 975 },
+ { "DejaVu Sans", 13, "Regular Class", 'l', 950 },
+ { "DejaVu Sans", 13, "Regular Class", 'i', 950 },
+ { "DejaVu Sans", 13, "Regular Class", 'j', 950 },
+ { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 },
+ { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 },
+ { "Georgia", 10, "", 0, 1050 },
+ { "Georgia", 11, "", 0, 1100 },
+ { "Georgia", 12, "", 0, 1025 },
+ { "Georgia", 13, "", 0, 1050 },
+ { "Georgia", 16, "", 0, 1050 },
+ { "Georgia", 17, "", 0, 1030 },
+ { "Liberation Sans", 12, "Regular Class", 'm', 1100 },
+ { "Lucida Grande", 11, "Regular Class", 'm', 1100 },
+ { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 },
+ { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 },
+ { "Segoe UI", 12, "Regular Class", 'H', 1050 },
+ { "Segoe UI", 12, "Regular Class", 'm', 1050 },
+ { "Segoe UI", 14, "Regular Class", 'm', 1050 },
+ { "Tahoma", 11, "Regular Class", 'i', 975 },
+ { "Tahoma", 11, "Regular Class", 'l', 975 },
+ { "Tahoma", 11, "Regular Class", 'j', 900 },
+ { "Tahoma", 11, "Regular Class", 'm', 918 },
+ { "Verdana", 10, "Regular/Italic Class", 0, 1100 },
+ { "Verdana", 12, "Regular Class", 'm', 975 },
+ { "Verdana", 12, "Regular/Italic Class", 0, 1050 },
+ { "Verdana", 13, "Regular/Italic Class", 'i', 950 },
+ { "Verdana", 13, "Regular/Italic Class", 'j', 950 },
+ { "Verdana", 13, "Regular/Italic Class", 'l', 950 },
+ { "Verdana", 16, "Regular Class", 0, 1050 },
+ { "Verdana", 9, "Regular/Italic Class", 0, 1050 },
+ { "Times New Roman", 16, "Regular Class", 'm', 918 },
+ { "Trebuchet MS", 11, "Regular Class", 'm', 800 },
+ { "Trebuchet MS", 12, "Regular Class", 'm', 800 },
+ };
+
+#else
+
+#define COMPATIBLE_WIDTHS_RULES_SIZE 1
+
+ static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
+ [COMPATIBLE_WIDTHS_RULES_SIZE] =
+ {
+ { "-", 0, "", 0 },
+ };
+
+
+#define X_SCALING_RULES_SIZE 1
+
+ static const SPH_ScaleRule X_SCALING_Rules
+ [X_SCALING_RULES_SIZE] =
+ {
+ { "-", 0, "", 0, 1000 },
+ };
+
+#endif /* FORCE_NATURAL_WIDTHS */
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ is_member_of_family_class( const FT_String* detected_font_name,
+ const FT_String* rule_font_name )
+ {
+ FT_UInt i, j;
+
+
+ /* Does font name match rule family? */
+ if ( strcmp( detected_font_name, rule_font_name ) == 0 )
+ return TRUE;
+
+ /* Is font name a wildcard ""? */
+ if ( strcmp( rule_font_name, "" ) == 0 )
+ return TRUE;
+
+ /* Is font name contained in a class list? */
+ for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ )
+ {
+ if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 )
+ {
+ for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
+ {
+ if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 )
+ continue;
+ if ( strcmp( FAMILY_CLASS_Rules[i].member[j],
+ detected_font_name ) == 0 )
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ is_member_of_style_class( const FT_String* detected_font_style,
+ const FT_String* rule_font_style )
+ {
+ FT_UInt i, j;
+
+
+ /* Does font style match rule style? */
+ if ( strcmp( detected_font_style, rule_font_style ) == 0 )
+ return TRUE;
+
+ /* Is font style a wildcard ""? */
+ if ( strcmp( rule_font_style, "" ) == 0 )
+ return TRUE;
+
+ /* Is font style contained in a class list? */
+ for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ )
+ {
+ if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 )
+ {
+ for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
+ {
+ if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 )
+ continue;
+ if ( strcmp( STYLE_CLASS_Rules[i].member[j],
+ detected_font_style ) == 0 )
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ sph_test_tweak( TT_Face face,
+ const FT_String* family,
+ FT_UInt ppem,
+ const FT_String* style,
+ FT_UInt glyph_index,
+ const SPH_TweakRule* rule,
+ FT_UInt num_rules )
+ {
+ FT_UInt i;
+
+
+ /* rule checks may be able to be optimized further */
+ for ( i = 0; i < num_rules; i++ )
+ {
+ if ( family &&
+ ( is_member_of_family_class ( family, rule[i].family ) ) )
+ if ( rule[i].ppem == 0 ||
+ rule[i].ppem == ppem )
+ if ( style &&
+ is_member_of_style_class ( style, rule[i].style ) )
+ if ( rule[i].glyph == 0 ||
+ FT_Get_Char_Index( (FT_Face)face,
+ rule[i].glyph ) == glyph_index )
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+ static FT_UInt
+ scale_test_tweak( TT_Face face,
+ const FT_String* family,
+ FT_UInt ppem,
+ const FT_String* style,
+ FT_UInt glyph_index,
+ const SPH_ScaleRule* rule,
+ FT_UInt num_rules )
+ {
+ FT_UInt i;
+
+
+ /* rule checks may be able to be optimized further */
+ for ( i = 0; i < num_rules; i++ )
+ {
+ if ( family &&
+ ( is_member_of_family_class ( family, rule[i].family ) ) )
+ if ( rule[i].ppem == 0 ||
+ rule[i].ppem == ppem )
+ if ( style &&
+ is_member_of_style_class( style, rule[i].style ) )
+ if ( rule[i].glyph == 0 ||
+ FT_Get_Char_Index( (FT_Face)face,
+ rule[i].glyph ) == glyph_index )
+ return rule[i].scale;
+ }
+
+ return 1000;
+ }
+
+
+ FT_LOCAL_DEF( FT_UInt )
+ sph_test_tweak_x_scaling( TT_Face face,
+ const FT_String* family,
+ FT_UInt ppem,
+ const FT_String* style,
+ FT_UInt glyph_index )
+ {
+ return scale_test_tweak( face, family, ppem, style, glyph_index,
+ X_SCALING_Rules, X_SCALING_RULES_SIZE );
+ }
+
+
+#define TWEAK_RULES( x ) \
+ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
+ x##_Rules, x##_RULES_SIZE ) ) \
+ loader->exec->sph_tweak_flags |= SPH_TWEAK_##x;
+
+#define TWEAK_RULES_EXCEPTIONS( x ) \
+ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
+ x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
+ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x;
+
+
+ FT_LOCAL_DEF( void )
+ sph_set_tweaks( TT_Loader loader,
+ FT_UInt glyph_index )
+ {
+ TT_Face face = (TT_Face)loader->face;
+ FT_String* family = face->root.family_name;
+ int ppem = loader->size->metrics.x_ppem;
+ FT_String* style = face->root.style_name;
+
+
+ /* don't apply rules if style isn't set */
+ if ( !face->root.style_name )
+ return;
+
+#ifdef SPH_DEBUG_MORE_VERBOSE
+ printf( "%s,%d,%s,%c=%d ",
+ family, ppem, style, glyph_index, glyph_index );
+#endif
+
+ TWEAK_RULES( PIXEL_HINTING );
+
+ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING )
+ {
+ loader->exec->ignore_x_mode = FALSE;
+ return;
+ }
+
+ TWEAK_RULES( ALLOW_X_DMOVE );
+ TWEAK_RULES( ALWAYS_DO_DELTAP );
+ TWEAK_RULES( ALWAYS_SKIP_DELTAP );
+ TWEAK_RULES( DEEMBOLDEN );
+ TWEAK_RULES( DO_SHPIX );
+ TWEAK_RULES( EMBOLDEN );
+ TWEAK_RULES( MIAP_HACK );
+ TWEAK_RULES( NORMAL_ROUND );
+ TWEAK_RULES( NO_ALIGNRP_AFTER_IUP );
+ TWEAK_RULES( NO_CALL_AFTER_IUP );
+ TWEAK_RULES( NO_DELTAP_AFTER_IUP );
+ TWEAK_RULES( RASTERIZER_35 );
+ TWEAK_RULES( SKIP_IUP );
+
+ TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES );
+ TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES );
+
+ TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP );
+
+ TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES );
+ TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
+
+ TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
+ TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
+
+ if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
+ {
+ if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 )
+ {
+ loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
+ loader->exec->size->cvt_ready = FALSE;
+
+ tt_size_ready_bytecode(
+ loader->exec->size,
+ FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
+ }
+ else
+ loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
+ }
+ else
+ {
+ if ( loader->exec->rasterizer_version !=
+ SPH_OPTION_SET_RASTERIZER_VERSION )
+ {
+ loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
+ loader->exec->size->cvt_ready = FALSE;
+
+ tt_size_ready_bytecode(
+ loader->exec->size,
+ FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
+ }
+ else
+ loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
+ }
+
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
+ TWEAK_RULES( COURIER_NEW_2_HACK );
+ }
+
+ if ( sph_test_tweak( face, family, ppem, style, glyph_index,
+ COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
+ loader->exec->face->sph_compatibility_mode = TRUE;
+
+
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ if ( sph_test_tweak( face, family, ppem, style, glyph_index,
+ COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
+ loader->exec->compatible_widths |= TRUE;
+ }
+ }
+
+#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ /* ANSI C doesn't like empty source files */
+ typedef int _tt_subpix_dummy;
+
+#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+/* END */
diff --git a/src/truetype/ttsubpix.h b/src/truetype/ttsubpix.h
new file mode 100644
index 0000000..8a54fc7
--- /dev/null
+++ b/src/truetype/ttsubpix.h
@@ -0,0 +1,110 @@
+/***************************************************************************/
+/* */
+/* ttsubpix.h */
+/* */
+/* TrueType Subpixel Hinting. */
+/* */
+/* Copyright 2010-2013 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTSUBPIX_H__
+#define __TTSUBPIX_H__
+
+#include <ft2build.h>
+#include "ttobjs.h"
+#include "ttinterp.h"
+
+
+FT_BEGIN_HEADER
+
+
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+
+ /*************************************************************************/
+ /* */
+ /* ID flags to identify special functions at FDEF and runtime. */
+ /* */
+ /* */
+#define SPH_FDEF_INLINE_DELTA_1 0x0000001
+#define SPH_FDEF_INLINE_DELTA_2 0x0000002
+#define SPH_FDEF_DIAGONAL_STROKE 0x0000004
+#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008
+#define SPH_FDEF_TTFAUTOHINT_1 0x0000010
+#define SPH_FDEF_SPACING_1 0x0000020
+#define SPH_FDEF_SPACING_2 0x0000040
+#define SPH_FDEF_TYPEMAN_STROKES 0x0000080
+#define SPH_FDEF_TYPEMAN_DIAGENDCTRL 0x0000100
+
+
+ /*************************************************************************/
+ /* */
+ /* Tweak flags that are set for each glyph by the below rules. */
+ /* */
+ /* */
+#define SPH_TWEAK_ALLOW_X_DMOVE 0x0000001
+#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000002
+#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000004
+#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000008
+#define SPH_TWEAK_DEEMBOLDEN 0x0000010
+#define SPH_TWEAK_DO_SHPIX 0x0000020
+#define SPH_TWEAK_EMBOLDEN 0x0000040
+#define SPH_TWEAK_MIAP_HACK 0x0000080
+#define SPH_TWEAK_NORMAL_ROUND 0x0000100
+#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0000200
+#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0000400
+#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0000800
+#define SPH_TWEAK_PIXEL_HINTING 0x0001000
+#define SPH_TWEAK_RASTERIZER_35 0x0002000
+#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0004000
+#define SPH_TWEAK_SKIP_IUP 0x0008000
+#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0010000
+#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0020000
+#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0040000
+#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP 0x0080000
+
+
+ FT_LOCAL( FT_Bool )
+ sph_test_tweak( TT_Face face,
+ const FT_String* family,
+ FT_UInt ppem,
+ const FT_String* style,
+ FT_UInt glyph_index,
+ const SPH_TweakRule* rule,
+ FT_UInt num_rules );
+
+ FT_LOCAL( FT_UInt )
+ sph_test_tweak_x_scaling( TT_Face face,
+ const FT_String* family,
+ FT_UInt ppem,
+ const FT_String* style,
+ FT_UInt glyph_index );
+
+ FT_LOCAL( void )
+ sph_set_tweaks( TT_Loader loader,
+ FT_UInt glyph_index );
+
+
+ /* These macros are defined absent a method for setting them */
+#define SPH_OPTION_BITMAP_WIDTHS FALSE
+#define SPH_OPTION_SET_SUBPIXEL TRUE
+#define SPH_OPTION_SET_GRAYSCALE FALSE
+#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE
+#define SPH_OPTION_SET_RASTERIZER_VERSION 38
+
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+FT_END_HEADER
+
+#endif /* __TTSUBPIX_H__ */
+
+/* END */