summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src/truetype/ttinterp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/freetype/src/truetype/ttinterp.c')
-rw-r--r--src/3rdparty/freetype/src/truetype/ttinterp.c2676
1 files changed, 1927 insertions, 749 deletions
diff --git a/src/3rdparty/freetype/src/truetype/ttinterp.c b/src/3rdparty/freetype/src/truetype/ttinterp.c
index d1769b8d2a..eccd4aaccb 100644
--- a/src/3rdparty/freetype/src/truetype/ttinterp.c
+++ b/src/3rdparty/freetype/src/truetype/ttinterp.c
@@ -4,8 +4,8 @@
/* */
/* TrueType bytecode interpreter (body). */
/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
-/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* Copyright 1996-2014 */
+/* 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 */
@@ -16,25 +16,25 @@
/***************************************************************************/
+/* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
+/* issues; many thanks! */
+
+
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#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 */
@@ -48,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
@@ -132,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 */
@@ -167,6 +172,9 @@
#define CUR_Func_round( d, c ) \
CUR.func_round( EXEC_ARG_ d, c )
+#define CUR_Func_cur_ppem() \
+ CUR.func_cur_ppem( EXEC_ARG )
+
#define CUR_Func_read_cvt( index ) \
CUR.func_read_cvt( EXEC_ARG_ index )
@@ -179,12 +187,6 @@
#define CURRENT_Ratio() \
Current_Ratio( EXEC_ARG )
-#define CURRENT_Ppem() \
- Current_Ppem( EXEC_ARG )
-
-#define CUR_Ppem() \
- Cur_PPEM( EXEC_ARG )
-
#define INS_SxVTL( a, b, c, d ) \
Ins_SxVTL( EXEC_ARG_ a, b, c, d )
@@ -223,9 +225,18 @@
/*************************************************************************/
/* */
- /* A simple bounds-checking macro. */
+ /* Two simple bounds-checking macros. */
+ /* */
+#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 BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
+#define TT_DivFix14( a, b ) \
+ FT_DivFix( a, (b) << 2 )
+
#undef SUCCESS
#define SUCCESS 0
@@ -268,10 +279,7 @@
/* <InOut> */
/* exec :: The target execution context. */
/* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_LOCAL_DEF( FT_Error )
+ FT_LOCAL_DEF( void )
TT_Goto_CodeRange( TT_ExecContext exec,
FT_Int range,
FT_Long IP )
@@ -295,8 +303,6 @@
exec->codeSize = coderange->size;
exec->IP = IP;
exec->curRange = range;
-
- return TT_Err_Ok;
}
@@ -318,10 +324,7 @@
/* <InOut> */
/* exec :: The target execution context. */
/* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_LOCAL_DEF( FT_Error )
+ FT_LOCAL_DEF( void )
TT_Set_CodeRange( TT_ExecContext exec,
FT_Int range,
void* base,
@@ -331,8 +334,6 @@
exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
exec->codeRangeTable[range - 1].size = length;
-
- return TT_Err_Ok;
}
@@ -350,13 +351,7 @@
/* <InOut> */
/* exec :: The target execution context. */
/* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* Does not set the Error variable. */
- /* */
- FT_LOCAL_DEF( FT_Error )
+ FT_LOCAL_DEF( void )
TT_Clear_CodeRange( TT_ExecContext exec,
FT_Int range )
{
@@ -364,8 +359,6 @@
exec->codeRangeTable[range - 1].base = NULL;
exec->codeRangeTable[range - 1].size = 0;
-
- return TT_Err_Ok;
}
@@ -389,13 +382,10 @@
/* */
/* memory :: A handle to the parent memory object. */
/* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
- FT_LOCAL_DEF( FT_Error )
+ FT_LOCAL_DEF( void )
TT_Done_Context( TT_ExecContext exec )
{
FT_Memory memory = exec->memory;
@@ -422,8 +412,6 @@
exec->face = NULL;
FT_FREE( exec );
-
- return TT_Err_Ok;
}
@@ -473,11 +461,10 @@
exec->face = NULL;
exec->size = NULL;
- return TT_Err_Ok;
+ return FT_Err_Ok;
Fail_Memory:
- FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
- (FT_Long)exec ));
+ FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
TT_Done_Context( exec );
return error;
@@ -508,7 +495,7 @@
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
- static FT_Error
+ FT_LOCAL_DEF( FT_Error )
Update_Max( FT_Memory memory,
FT_ULong* size,
FT_Long multiplier,
@@ -526,7 +513,7 @@
*size = new_max;
}
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -594,6 +581,12 @@
exec->storage = size->storage;
exec->twilight = size->twilight;
+
+ /* In case of multi-threading it can happen that the old size object */
+ /* no longer exists, thus we must clear all glyph zone references. */
+ ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) );
+ exec->zp1 = exec->zp0;
+ exec->zp2 = exec->zp0;
}
/* XXX: We reserve a little more elements on the stack to deal safely */
@@ -627,7 +620,7 @@
exec->instruction_trap = FALSE;
- return TT_Err_Ok;
+ return FT_Err_Ok;
}
@@ -645,22 +638,19 @@
/* <InOut> */
/* size :: A handle to the target size object. */
/* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
- FT_LOCAL_DEF( FT_Error )
+ FT_LOCAL_DEF( void )
TT_Save_Context( TT_ExecContext exec,
TT_Size size )
{
FT_Int i;
- /* XXXX: Will probably disappear soon with all the code range */
- /* management, which is now rather obsolete. */
- /* */
+ /* XXX: Will probably disappear soon with all the code range */
+ /* management, which is now rather obsolete. */
+ /* */
size->num_function_defs = exec->numFDefs;
size->num_instruction_defs = exec->numIDefs;
@@ -669,8 +659,6 @@
for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
size->codeRangeTable[i] = exec->codeRangeTable[i];
-
- return TT_Err_Ok;
}
@@ -702,12 +690,7 @@
TT_Run_Context( TT_ExecContext exec,
FT_Bool debug )
{
- FT_Error error;
-
-
- if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
- != TT_Err_Ok )
- return error;
+ TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
exec->zp0 = exec->pts;
exec->zp1 = exec->pts;
@@ -743,7 +726,7 @@
if ( !debug )
return TT_RunIns( exec );
else
- return TT_Err_Ok;
+ return FT_Err_Ok;
#endif
}
@@ -777,16 +760,18 @@
FT_EXPORT_DEF( TT_ExecContext )
TT_New_Context( TT_Driver driver )
{
- TT_ExecContext exec;
- FT_Memory memory;
+ FT_Memory memory;
+ if ( !driver )
+ goto Fail;
+
memory = driver->root.root.memory;
- exec = driver->context;
if ( !driver->context )
{
- FT_Error error;
+ FT_Error error;
+ TT_ExecContext exec;
/* allocate object */
@@ -805,7 +790,6 @@
return driver->context;
Fail:
- FT_FREE( exec );
return NULL;
}
@@ -980,8 +964,8 @@
/* INS_$83 */ PACK( 0, 0 ),
/* INS_$84 */ PACK( 0, 0 ),
/* ScanCTRL */ PACK( 1, 0 ),
- /* SDVPTL[0] */ PACK( 2, 0 ),
- /* SDVPTL[1] */ PACK( 2, 0 ),
+ /* SDPVTL[0] */ PACK( 2, 0 ),
+ /* SDPVTL[1] */ PACK( 2, 0 ),
/* GetINFO */ PACK( 1, 1 ),
/* IDEF */ PACK( 1, 0 ),
/* ROLL */ PACK( 3, 3 ),
@@ -1112,6 +1096,287 @@
};
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ static
+ const char* const opcode_name[256] =
+ {
+ "SVTCA y",
+ "SVTCA x",
+ "SPvTCA y",
+ "SPvTCA x",
+ "SFvTCA y",
+ "SFvTCA x",
+ "SPvTL ||",
+ "SPvTL +",
+ "SFvTL ||",
+ "SFvTL +",
+ "SPvFS",
+ "SFvFS",
+ "GPV",
+ "GFV",
+ "SFvTPv",
+ "ISECT",
+
+ "SRP0",
+ "SRP1",
+ "SRP2",
+ "SZP0",
+ "SZP1",
+ "SZP2",
+ "SZPS",
+ "SLOOP",
+ "RTG",
+ "RTHG",
+ "SMD",
+ "ELSE",
+ "JMPR",
+ "SCvTCi",
+ "SSwCi",
+ "SSW",
+
+ "DUP",
+ "POP",
+ "CLEAR",
+ "SWAP",
+ "DEPTH",
+ "CINDEX",
+ "MINDEX",
+ "AlignPTS",
+ "INS_$28",
+ "UTP",
+ "LOOPCALL",
+ "CALL",
+ "FDEF",
+ "ENDF",
+ "MDAP[0]",
+ "MDAP[1]",
+
+ "IUP[0]",
+ "IUP[1]",
+ "SHP[0]",
+ "SHP[1]",
+ "SHC[0]",
+ "SHC[1]",
+ "SHZ[0]",
+ "SHZ[1]",
+ "SHPIX",
+ "IP",
+ "MSIRP[0]",
+ "MSIRP[1]",
+ "AlignRP",
+ "RTDG",
+ "MIAP[0]",
+ "MIAP[1]",
+
+ "NPushB",
+ "NPushW",
+ "WS",
+ "RS",
+ "WCvtP",
+ "RCvt",
+ "GC[0]",
+ "GC[1]",
+ "SCFS",
+ "MD[0]",
+ "MD[1]",
+ "MPPEM",
+ "MPS",
+ "FlipON",
+ "FlipOFF",
+ "DEBUG",
+
+ "LT",
+ "LTEQ",
+ "GT",
+ "GTEQ",
+ "EQ",
+ "NEQ",
+ "ODD",
+ "EVEN",
+ "IF",
+ "EIF",
+ "AND",
+ "OR",
+ "NOT",
+ "DeltaP1",
+ "SDB",
+ "SDS",
+
+ "ADD",
+ "SUB",
+ "DIV",
+ "MUL",
+ "ABS",
+ "NEG",
+ "FLOOR",
+ "CEILING",
+ "ROUND[0]",
+ "ROUND[1]",
+ "ROUND[2]",
+ "ROUND[3]",
+ "NROUND[0]",
+ "NROUND[1]",
+ "NROUND[2]",
+ "NROUND[3]",
+
+ "WCvtF",
+ "DeltaP2",
+ "DeltaP3",
+ "DeltaCn[0]",
+ "DeltaCn[1]",
+ "DeltaCn[2]",
+ "SROUND",
+ "S45Round",
+ "JROT",
+ "JROF",
+ "ROFF",
+ "INS_$7B",
+ "RUTG",
+ "RDTG",
+ "SANGW",
+ "AA",
+
+ "FlipPT",
+ "FlipRgON",
+ "FlipRgOFF",
+ "INS_$83",
+ "INS_$84",
+ "ScanCTRL",
+ "SDVPTL[0]",
+ "SDVPTL[1]",
+ "GetINFO",
+ "IDEF",
+ "ROLL",
+ "MAX",
+ "MIN",
+ "ScanTYPE",
+ "InstCTRL",
+ "INS_$8F",
+
+ "INS_$90",
+ "INS_$91",
+ "INS_$92",
+ "INS_$93",
+ "INS_$94",
+ "INS_$95",
+ "INS_$96",
+ "INS_$97",
+ "INS_$98",
+ "INS_$99",
+ "INS_$9A",
+ "INS_$9B",
+ "INS_$9C",
+ "INS_$9D",
+ "INS_$9E",
+ "INS_$9F",
+
+ "INS_$A0",
+ "INS_$A1",
+ "INS_$A2",
+ "INS_$A3",
+ "INS_$A4",
+ "INS_$A5",
+ "INS_$A6",
+ "INS_$A7",
+ "INS_$A8",
+ "INS_$A9",
+ "INS_$AA",
+ "INS_$AB",
+ "INS_$AC",
+ "INS_$AD",
+ "INS_$AE",
+ "INS_$AF",
+
+ "PushB[0]",
+ "PushB[1]",
+ "PushB[2]",
+ "PushB[3]",
+ "PushB[4]",
+ "PushB[5]",
+ "PushB[6]",
+ "PushB[7]",
+ "PushW[0]",
+ "PushW[1]",
+ "PushW[2]",
+ "PushW[3]",
+ "PushW[4]",
+ "PushW[5]",
+ "PushW[6]",
+ "PushW[7]",
+
+ "MDRP[00]",
+ "MDRP[01]",
+ "MDRP[02]",
+ "MDRP[03]",
+ "MDRP[04]",
+ "MDRP[05]",
+ "MDRP[06]",
+ "MDRP[07]",
+ "MDRP[08]",
+ "MDRP[09]",
+ "MDRP[10]",
+ "MDRP[11]",
+ "MDRP[12]",
+ "MDRP[13]",
+ "MDRP[14]",
+ "MDRP[15]",
+
+ "MDRP[16]",
+ "MDRP[17]",
+ "MDRP[18]",
+ "MDRP[19]",
+ "MDRP[20]",
+ "MDRP[21]",
+ "MDRP[22]",
+ "MDRP[23]",
+ "MDRP[24]",
+ "MDRP[25]",
+ "MDRP[26]",
+ "MDRP[27]",
+ "MDRP[28]",
+ "MDRP[29]",
+ "MDRP[30]",
+ "MDRP[31]",
+
+ "MIRP[00]",
+ "MIRP[01]",
+ "MIRP[02]",
+ "MIRP[03]",
+ "MIRP[04]",
+ "MIRP[05]",
+ "MIRP[06]",
+ "MIRP[07]",
+ "MIRP[08]",
+ "MIRP[09]",
+ "MIRP[10]",
+ "MIRP[11]",
+ "MIRP[12]",
+ "MIRP[13]",
+ "MIRP[14]",
+ "MIRP[15]",
+
+ "MIRP[16]",
+ "MIRP[17]",
+ "MIRP[18]",
+ "MIRP[19]",
+ "MIRP[20]",
+ "MIRP[21]",
+ "MIRP[22]",
+ "MIRP[23]",
+ "MIRP[24]",
+ "MIRP[25]",
+ "MIRP[26]",
+ "MIRP[27]",
+ "MIRP[28]",
+ "MIRP[29]",
+ "MIRP[30]",
+ "MIRP[31]"
+ };
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+
static
const FT_Char opcode_length[256] =
{
@@ -1138,8 +1403,107 @@
#undef PACK
-#if 1
+#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER
+
+#if defined( __arm__ ) && \
+ ( defined( __thumb2__ ) || !defined( __thumb__ ) )
+
+#define TT_MulFix14 TT_MulFix14_arm
+
+ static FT_Int32
+ TT_MulFix14_arm( FT_Int32 a,
+ FT_Int b )
+ {
+ FT_Int32 t, t2;
+
+
+#if defined( __CC_ARM ) || defined( __ARMCC__ )
+
+ __asm
+ {
+ smull t2, t, b, a /* (lo=t2,hi=t) = a*b */
+ mov a, t, asr #31 /* a = (hi >> 31) */
+ add a, a, #0x2000 /* a += 0x2000 */
+ adds t2, t2, a /* t2 += a */
+ adc t, t, #0 /* t += carry */
+ mov a, t2, lsr #14 /* a = t2 >> 14 */
+ orr a, a, t, lsl #18 /* a |= t << 18 */
+ }
+
+#elif defined( __GNUC__ )
+
+ __asm__ __volatile__ (
+ "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */
+ "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */
+#if defined( __clang__ ) && defined( __thumb2__ )
+ "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
+#else
+ "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
+#endif
+ "adds %1, %1, %0\n\t" /* %1 += %0 */
+ "adc %2, %2, #0\n\t" /* %2 += carry */
+ "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */
+ "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */
+ : "=r"(a), "=&r"(t2), "=&r"(t)
+ : "r"(a), "r"(b)
+ : "cc" );
+
+#endif
+
+ return a;
+ }
+
+#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */
+
+#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
+
+
+#if defined( __GNUC__ ) && \
+ ( defined( __i386__ ) || defined( __x86_64__ ) )
+
+#define TT_MulFix14 TT_MulFix14_long_long
+
+ /* Temporarily disable the warning that C90 doesn't support `long long'. */
+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wlong-long"
+
+ /* This is declared `noinline' because inlining the function results */
+ /* in slower code. The `pure' attribute indicates that the result */
+ /* only depends on the parameters. */
+ static __attribute__(( noinline ))
+ __attribute__(( pure )) FT_Int32
+ TT_MulFix14_long_long( FT_Int32 a,
+ FT_Int b )
+ {
+
+ long long ret = (long long)a * b;
+
+ /* The following line assumes that right shifting of signed values */
+ /* will actually preserve the sign bit. The exact behaviour is */
+ /* undefined, but this is true on x86 and x86_64. */
+ long long tmp = ret >> 63;
+
+
+ ret += 0x2000 + tmp;
+
+ return (FT_Int32)( ret >> 14 );
+ }
+
+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
+#pragma GCC diagnostic pop
+#endif
+
+#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */
+
+
+#ifndef TT_MulFix14
+
+ /* Compute (a*b)/2^14 with maximum accuracy and rounding. */
+ /* This is optimized to be faster than calling FT_MulFix() */
+ /* for platforms where sizeof(int) == 2. */
static FT_Int32
TT_MulFix14( FT_Int32 a,
FT_Int b )
@@ -1171,39 +1535,52 @@
return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
}
-#else
+#endif /* !TT_MulFix14 */
- /* compute (a*b)/2^14 with maximal accuracy and rounding */
- static FT_Int32
- TT_MulFix14( FT_Int32 a,
- FT_Int b )
- {
- FT_Int32 m, s, hi;
- FT_UInt32 l, lo;
+#if defined( __GNUC__ ) && \
+ ( defined( __i386__ ) || \
+ defined( __x86_64__ ) || \
+ defined( __arm__ ) )
- /* compute ax*bx as 64-bit value */
- l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
- m = ( a >> 16 ) * b;
+#define TT_DotFix14 TT_DotFix14_long_long
+
+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wlong-long"
- lo = l + (FT_UInt32)( m << 16 );
- hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
+ static __attribute__(( pure )) FT_Int32
+ TT_DotFix14_long_long( FT_Int32 ax,
+ FT_Int32 ay,
+ FT_Int bx,
+ FT_Int by )
+ {
+ /* Temporarily disable the warning that C90 doesn't support */
+ /* `long long'. */
- /* divide the result by 2^14 with rounding */
- s = hi >> 31;
- l = lo + (FT_UInt32)s;
- hi += s + ( l < lo );
- lo = l;
+ long long temp1 = (long long)ax * bx;
+ long long temp2 = (long long)ay * by;
- l = lo + 0x2000U;
- hi += l < lo;
- return ( hi << 18 ) | ( l >> 14 );
+ temp1 += temp2;
+ temp2 = temp1 >> 63;
+ temp1 += 0x2000 + temp2;
+
+ return (FT_Int32)( temp1 >> 14 );
+
}
+
+#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
+#pragma GCC diagnostic pop
#endif
+#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */
+
- /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
+#ifndef TT_DotFix14
+
+ /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
static FT_Int32
TT_DotFix14( FT_Int32 ax,
FT_Int32 ay,
@@ -1218,14 +1595,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 */
@@ -1241,98 +1618,10 @@
l = lo + 0x2000U;
hi += ( l < lo );
- return ( 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;
- }
+ return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
}
-#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
+#endif /* TT_DotFix14 */
/*************************************************************************/
@@ -1371,14 +1660,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 );
}
}
}
@@ -1386,10 +1675,17 @@
}
- static FT_Long
+ FT_CALLBACK_DEF( FT_Long )
Current_Ppem( EXEC_OP )
{
- return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
+ return CUR.tt_metrics.ppem;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Long )
+ Current_Ppem_Stretched( EXEC_OP )
+ {
+ return FT_MulFix( CUR.tt_metrics.ppem, CURRENT_Ratio() );
}
@@ -1410,7 +1706,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() );
}
@@ -1496,7 +1792,7 @@
if ( aRange < 1 || aRange > 3 )
{
- CUR.error = TT_Err_Bad_Argument;
+ CUR.error = FT_THROW( Bad_Argument );
return FAILURE;
}
@@ -1504,17 +1800,17 @@
if ( range->base == NULL ) /* invalid coderange */
{
- CUR.error = TT_Err_Invalid_CodeRange;
+ CUR.error = FT_THROW( Invalid_CodeRange );
return FAILURE;
}
/* NOTE: Because the last instruction of a program may be a CALL */
/* which will return to the first byte *after* the code */
- /* range, we test for AIP <= Size, instead of AIP < Size. */
+ /* range, we test for aIP <= Size, instead of aIP < Size. */
if ( aIP > range->size )
{
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
return FAILURE;
}
@@ -1560,9 +1856,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;
}
@@ -1571,9 +1870,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;
}
@@ -1612,16 +1909,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 );
}
@@ -1642,7 +1935,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;
}
@@ -1725,10 +2023,11 @@
if ( distance >= 0 )
{
val = distance + compensation;
- if ( distance && val < 0 )
+ if ( val < 0 )
val = 0;
}
- else {
+ else
+ {
val = distance - compensation;
if ( val > 0 )
val = 0;
@@ -1764,10 +2063,8 @@
if ( distance >= 0 )
{
- val = distance + compensation + 32;
- if ( distance && val > 0 )
- val &= ~63;
- else
+ val = FT_PIX_ROUND( distance + compensation );
+ if ( val < 0 )
val = 0;
}
else
@@ -1809,14 +2106,14 @@
if ( distance >= 0 )
{
val = FT_PIX_FLOOR( distance + compensation ) + 32;
- if ( distance && val < 0 )
- val = 0;
+ if ( val < 0 )
+ val = 32;
}
else
{
val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
if ( val > 0 )
- val = 0;
+ val = -32;
}
return val;
@@ -1850,15 +2147,13 @@
if ( distance >= 0 )
{
- val = distance + compensation;
- if ( distance && val > 0 )
- val &= ~63;
- else
+ val = FT_PIX_FLOOR( distance + compensation );
+ if ( val < 0 )
val = 0;
}
else
{
- val = -( ( compensation - distance ) & -64 );
+ val = -FT_PIX_FLOOR( compensation - distance );
if ( val > 0 )
val = 0;
}
@@ -1894,15 +2189,13 @@
if ( distance >= 0 )
{
- val = distance + compensation + 63;
- if ( distance && val > 0 )
- val &= ~63;
- else
+ val = FT_PIX_CEIL( distance + compensation );
+ if ( val < 0 )
val = 0;
}
else
{
- val = - FT_PIX_CEIL( compensation - distance );
+ val = -FT_PIX_CEIL( compensation - distance );
if ( val > 0 )
val = 0;
}
@@ -1938,10 +2231,8 @@
if ( distance >= 0 )
{
- val = distance + compensation + 16;
- if ( distance && val > 0 )
- val &= ~31;
- else
+ val = FT_PAD_ROUND( distance + compensation, 32 );
+ if ( val < 0 )
val = 0;
}
else
@@ -1988,17 +2279,17 @@
{
val = ( distance - CUR.phase + CUR.threshold + compensation ) &
-CUR.period;
- if ( distance && val < 0 )
- val = 0;
val += CUR.phase;
+ if ( val < 0 )
+ val = CUR.phase;
}
else
{
val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
-CUR.period );
- if ( val > 0 )
- val = 0;
val -= CUR.phase;
+ if ( val > 0 )
+ val = -CUR.phase;
}
return val;
@@ -2036,17 +2327,17 @@
{
val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
CUR.period ) * CUR.period;
- if ( distance && val < 0 )
- val = 0;
val += CUR.phase;
+ if ( val < 0 )
+ val = CUR.phase;
}
else
{
val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
CUR.period ) * CUR.period );
- if ( val > 0 )
- val = 0;
val -= CUR.phase;
+ if ( val > 0 )
+ val = -CUR.phase;
}
return val;
@@ -2113,8 +2404,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,
@@ -2326,13 +2618,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;
@@ -2342,61 +2631,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;
@@ -2425,98 +2703,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;
- }
-
- 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;
-
- 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;
+ Vx *= 0x4000;
+ Vy *= 0x4000;
}
- 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;
+ W = FT_Hypot( Vx, Vy );
- 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;
}
@@ -2544,7 +2757,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;
}
@@ -2554,6 +2767,17 @@
A = p1->x - p2->x;
B = p1->y - p2->y;
+ /* If p1 == p2, SPVTL and SFVTL behave the same as */
+ /* SPVTCA[X] and SFVTCA[X], respectively. */
+ /* */
+ /* Confirmed by Greg Hitchcock. */
+
+ if ( A == 0 && B == 0 )
+ {
+ A = 0x4000;
+ aOpc = 0;
+ }
+
if ( ( aOpc & 1 ) != 0 )
{
C = B; /* counter clockwise rotation */
@@ -2789,10 +3013,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];
@@ -2808,14 +3032,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 \
@@ -2826,19 +3045,22 @@
CUR.GS.auto_flip = FALSE;
-#define DO_SDB \
- CUR.GS.delta_base = (FT_Short)args[0];
+#define DO_SDB \
+ CUR.GS.delta_base = (FT_UShort)args[0];
-#define DO_SDS \
- CUR.GS.delta_shift = (FT_Short)args[0];
+#define DO_SDS \
+ if ( (FT_ULong)args[0] > 6UL ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ else \
+ CUR.GS.delta_shift = (FT_UShort)args[0];
#define DO_MD /* nothing */
-#define DO_MPPEM \
- args[0] = CURRENT_Ppem();
+#define DO_MPPEM \
+ args[0] = CUR_Func_cur_ppem();
/* Note: The pointSize should be irrelevant in a given font program; */
@@ -2850,8 +3072,8 @@
#else
-#define DO_MPS \
- args[0] = CURRENT_Ppem();
+#define DO_MPS \
+ args[0] = CUR_Func_cur_ppem();
#endif /* 0 */
@@ -2879,38 +3101,60 @@
args[0] = CUR.top;
-#define DO_CINDEX \
- { \
- FT_Long L; \
- \
- \
- L = args[0]; \
- \
- if ( L <= 0 || L > CUR.args ) \
- CUR.error = TT_Err_Invalid_Reference; \
- else \
- args[0] = CUR.stack[CUR.args - L]; \
- }
-
-
-#define DO_JROT \
- if ( args[1] != 0 ) \
- { \
- CUR.IP += args[0]; \
- CUR.step_ins = FALSE; \
- }
-
-
-#define DO_JMPR \
- CUR.IP += args[0]; \
+#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]; \
+ }
+
+
+#define DO_JROT \
+ if ( args[1] != 0 ) \
+ { \
+ if ( args[0] == 0 && CUR.args == 0 ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ CUR.IP += args[0]; \
+ if ( CUR.IP < 0 || \
+ ( CUR.callTop > 0 && \
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_JMPR \
+ if ( args[0] == 0 && CUR.args == 0 ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ CUR.IP += args[0]; \
+ if ( CUR.IP < 0 || \
+ ( CUR.callTop > 0 && \
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
CUR.step_ins = FALSE;
-#define DO_JROF \
- if ( args[1] == 0 ) \
- { \
- CUR.IP += args[0]; \
- CUR.step_ins = FALSE; \
+#define DO_JROF \
+ if ( args[1] == 0 ) \
+ { \
+ if ( args[0] == 0 && CUR.args == 0 ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ CUR.IP += args[0]; \
+ if ( CUR.IP < 0 || \
+ ( CUR.callTop > 0 && \
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
+ CUR.error = FT_THROW( Bad_Argument ); \
+ CUR.step_ins = FALSE; \
}
@@ -2968,13 +3212,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 \
@@ -2992,40 +3236,81 @@
#define DO_CEILING \
args[0] = FT_PIX_CEIL( args[0] );
-
-#define DO_RS \
- { \
- FT_ULong I = (FT_ULong)args[0]; \
- \
- \
- if ( BOUNDS( I, CUR.storeSize ) ) \
- { \
- if ( CUR.pedantic_hinting ) \
- { \
- ARRAY_BOUND_ERROR; \
- } \
- else \
- args[0] = 0; \
- } \
- else \
- args[0] = CUR.storage[I]; \
+#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 \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDSL( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR.storage[I]; \
+ }
-#define DO_WS \
- { \
- FT_ULong I = (FT_ULong)args[0]; \
- \
- \
- if ( BOUNDS( I, CUR.storeSize ) ) \
- { \
- if ( CUR.pedantic_hinting ) \
- { \
- ARRAY_BOUND_ERROR; \
- } \
- } \
- else \
- CUR.storage[I] = args[1]; \
+#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+#define DO_WS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDSL( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.storage[I] = args[1]; \
}
@@ -3034,7 +3319,7 @@
FT_ULong I = (FT_ULong)args[0]; \
\
\
- if ( BOUNDS( I, CUR.cvtSize ) ) \
+ if ( BOUNDSL( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
@@ -3053,7 +3338,7 @@
FT_ULong I = (FT_ULong)args[0]; \
\
\
- if ( BOUNDS( I, CUR.cvtSize ) ) \
+ if ( BOUNDSL( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
@@ -3070,7 +3355,7 @@
FT_ULong I = (FT_ULong)args[0]; \
\
\
- if ( BOUNDS( I, CUR.cvtSize ) ) \
+ if ( BOUNDSL( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
@@ -3078,12 +3363,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 \
@@ -3111,10 +3396,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; \
}
@@ -4092,17 +4377,19 @@
if ( L <= 0 || L > CUR.args )
{
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Invalid_Reference );
}
+ else
+ {
+ K = CUR.stack[CUR.args - L];
- K = CUR.stack[CUR.args - L];
-
- FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
- &CUR.stack[CUR.args - L + 1],
- ( L - 1 ) );
+ FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
+ &CUR.stack[CUR.args - L + 1],
+ ( L - 1 ) );
- CUR.stack[CUR.args - 1] = K;
+ CUR.stack[CUR.args - 1] = K;
+ }
}
@@ -4151,7 +4438,7 @@
CUR.length = opcode_length[CUR.opcode];
if ( CUR.length < 0 )
{
- if ( CUR.IP + 1 > CUR.codeSize )
+ if ( CUR.IP + 1 >= CUR.codeSize )
goto Fail_Overflow;
CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
}
@@ -4161,7 +4448,7 @@
}
Fail_Overflow:
- CUR.error = TT_Err_Code_Overflow;
+ CUR.error = FT_THROW( Code_Overflow );
return FAILURE;
}
@@ -4266,6 +4553,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. */
@@ -4285,7 +4672,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++;
@@ -4295,31 +4682,153 @@
/* 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 */
+ rec->end = CUR.IP;
return;
}
}
@@ -4340,9 +4849,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;
}
@@ -4357,7 +4870,7 @@
if ( pRec->Cur_Count > 0 )
{
CUR.callTop++;
- CUR.IP = pRec->Cur_Restart;
+ CUR.IP = pRec->Def->start;
}
else
/* Loop through the current function */
@@ -4391,7 +4904,7 @@
/* first of all, check the index */
F = args[0];
- if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
goto Fail;
/* Except for some old Apple fonts, all functions in a TrueType */
@@ -4424,10 +4937,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;
}
@@ -4436,7 +4960,7 @@
pCrec->Caller_Range = CUR.curRange;
pCrec->Caller_IP = CUR.IP + 1;
pCrec->Cur_Count = 1;
- pCrec->Cur_Restart = def->start;
+ pCrec->Def = def;
CUR.callTop++;
@@ -4444,10 +4968,11 @@
def->start );
CUR.step_ins = FALSE;
+
return;
Fail:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
@@ -4467,7 +4992,7 @@
/* first of all, check the index */
F = args[1];
- if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
goto Fail;
/* Except for some old Apple fonts, all functions in a TrueType */
@@ -4500,10 +5025,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;
}
@@ -4514,7 +5048,7 @@
pCrec->Caller_Range = CUR.curRange;
pCrec->Caller_IP = CUR.IP + 1;
pCrec->Cur_Count = (FT_Int)args[0];
- pCrec->Cur_Restart = def->start;
+ pCrec->Def = def;
CUR.callTop++;
@@ -4522,10 +5056,11 @@
CUR.step_ins = FALSE;
}
+
return;
Fail:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
}
@@ -4556,7 +5091,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++;
@@ -4565,12 +5100,12 @@
/* 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;
}
def->opc = (FT_Byte)args[0];
- def->start = CUR.IP+1;
+ def->start = CUR.IP + 1;
def->range = CUR.curRange;
def->active = TRUE;
@@ -4586,7 +5121,7 @@
{
case 0x89: /* IDEF */
case 0x2C: /* FDEF */
- CUR.error = TT_Err_Nested_DEFS;
+ CUR.error = FT_THROW( Nested_DEFS );
return;
case 0x2D: /* ENDF */
return;
@@ -4620,7 +5155,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4647,7 +5182,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4677,7 +5212,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4702,7 +5237,7 @@
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
@@ -4730,8 +5265,8 @@
/* Opcode range: 0x46-0x47 */
/* Stack: uint32 --> f26.6 */
/* */
- /* BULLSHIT: Measures from the original glyph must be taken along the */
- /* dual projection vector! */
+ /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
+ /* along the dual projection vector! */
/* */
static void
Ins_GC( INS_ARG )
@@ -4742,15 +5277,11 @@
L = (FT_ULong)args[0];
- if ( BOUNDS( L, CUR.zp2.n_points ) )
+ if ( BOUNDSL( L, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
- else
- R = 0;
+ CUR.error = FT_THROW( Invalid_Reference );
+ R = 0;
}
else
{
@@ -4786,7 +5317,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;
}
@@ -4794,8 +5325,8 @@
CUR_Func_move( &CUR.zp2, L, args[1] - K );
- /* not part of the specs, but here for safety */
-
+ /* UNDOCUMENTED! The MS rasterizer does that with */
+ /* twilight points (confirmed by Greg Hitchcock) */
if ( CUR.GS.gep2 == 0 )
CUR.zp2.org[L] = CUR.zp2.cur[L];
}
@@ -4807,14 +5338,14 @@
/* Opcode range: 0x49-0x4A */
/* Stack: uint32 uint32 --> f26.6 */
/* */
- /* BULLSHIT: Measure taken in the original glyph must be along the dual */
- /* projection vector. */
+ /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
+ /* the dual projection vector. */
/* */
- /* Second BULLSHIT: Flag attributes are inverted! */
- /* 0 => measure distance in original outline */
- /* 1 => measure distance in grid-fitted outline */
+ /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
+ /* 0 => measure distance in original outline */
+ /* 1 => measure distance in grid-fitted outline */
/* */
- /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
+ /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
/* */
static void
Ins_MD( INS_ARG )
@@ -4826,14 +5357,11 @@
K = (FT_UShort)args[1];
L = (FT_UShort)args[0];
- if( BOUNDS( L, CUR.zp0.n_points ) ||
- BOUNDS( K, CUR.zp1.n_points ) )
+ if ( BOUNDS( L, CUR.zp0.n_points ) ||
+ BOUNDS( K, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
+ CUR.error = FT_THROW( Invalid_Reference );
D = 0;
}
else
@@ -4842,29 +5370,49 @@
D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
else
{
- FT_Vector* vec1 = CUR.zp0.orus + L;
- FT_Vector* vec2 = CUR.zp1.orus + K;
-
+ /* XXX: UNDOCUMENTED: twilight zone special case */
- if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
{
- /* this should be faster */
+ FT_Vector* vec1 = CUR.zp0.org + L;
+ FT_Vector* vec2 = CUR.zp1.org + K;
+
+
D = CUR_Func_dualproj( vec1, vec2 );
- D = TT_MULFIX( D, CUR.metrics.x_scale );
}
else
{
- FT_Vector vec;
+ FT_Vector* vec1 = CUR.zp0.orus + L;
+ FT_Vector* vec2 = CUR.zp1.orus + K;
+
+
+ if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
+ {
+ /* this should be faster */
+ D = CUR_Func_dualproj( vec1, vec2 );
+ 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 );
+ D = CUR_fast_dualproj( &vec );
+ }
}
}
}
+#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;
}
@@ -4879,7 +5427,8 @@
Ins_SDPVTL( INS_ARG )
{
FT_Long A, B, C;
- FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
+ FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
+ FT_Int aOpc = CUR.opcode;
p1 = (FT_UShort)args[1];
@@ -4889,7 +5438,7 @@
BOUNDS( p1, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -4900,9 +5449,20 @@
A = v1->x - v2->x;
B = v1->y - v2->y;
+
+ /* If v1 == v2, SDPVTL behaves the same as */
+ /* SVTCA[X], respectively. */
+ /* */
+ /* Confirmed by Greg Hitchcock. */
+
+ if ( A == 0 && B == 0 )
+ {
+ A = 0x4000;
+ aOpc = 0;
+ }
}
- if ( ( CUR.opcode & 1 ) != 0 )
+ if ( ( aOpc & 1 ) != 0 )
{
C = B; /* counter clockwise rotation */
B = A;
@@ -4918,9 +5478,15 @@
A = v1->x - v2->x;
B = v1->y - v2->y;
+
+ if ( A == 0 && B == 0 )
+ {
+ A = 0x4000;
+ aOpc = 0;
+ }
}
- if ( ( CUR.opcode & 1 ) != 0 )
+ if ( ( aOpc & 1 ) != 0 )
{
C = B; /* counter clockwise rotation */
B = A;
@@ -4956,7 +5522,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -4985,7 +5551,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5014,7 +5580,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5043,7 +5609,7 @@
default:
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5059,7 +5625,7 @@
/*************************************************************************/
/* */
/* INSTCTRL[]: INSTruction ConTRoL */
- /* Opcode range: 0x8e */
+ /* Opcode range: 0x8E */
/* Stack: int32 int32 --> */
/* */
static void
@@ -5074,7 +5640,7 @@
if ( K < 1 || K > 2 )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5171,8 +5737,9 @@
if ( CUR.top < CUR.GS.loop )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ goto Fail;
}
while ( CUR.GS.loop > 0 )
@@ -5185,7 +5752,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -5195,6 +5762,7 @@
CUR.GS.loop--;
}
+ Fail:
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
@@ -5219,7 +5787,7 @@
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5247,7 +5815,7 @@
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5281,7 +5849,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;
}
@@ -5308,12 +5876,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;
@@ -5382,8 +5946,9 @@
if ( CUR.top < CUR.GS.loop )
{
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
@@ -5398,17 +5963,24 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
else
- /* XXX: UNDOCUMENTED! SHP touches the points */
+#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--;
}
+ Fail:
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
@@ -5420,24 +5992,28 @@
/* Opcode range: 0x34-35 */
/* Stack: uint32 --> */
/* */
+ /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
+ /* contour in the twilight zone, namely contour number */
+ /* zero which includes all points of it. */
+ /* */
static void
Ins_SHC( INS_ARG )
{
- TT_GlyphZoneRec zp;
- FT_UShort refp;
- FT_F26Dot6 dx,
- dy;
+ TT_GlyphZoneRec zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx, dy;
- FT_Short contour;
- FT_UShort first_point, last_point, i;
+ FT_Short contour, bounds;
+ FT_UShort start, limit, i;
contour = (FT_UShort)args[0];
+ bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours;
- if ( BOUNDS( contour, CUR.pts.n_contours ) )
+ if ( BOUNDS( contour, bounds ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -5445,26 +6021,19 @@
return;
if ( contour == 0 )
- first_point = 0;
+ start = 0;
else
- first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
- CUR.pts.first_point );
+ start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 -
+ CUR.zp2.first_point );
- last_point = (FT_UShort)( CUR.pts.contours[contour] -
- CUR.pts.first_point );
-
- /* XXX: this is probably wrong... at least it prevents memory */
- /* corruption when zp2 is the twilight zone */
- if ( BOUNDS( last_point, CUR.zp2.n_points ) )
- {
- if ( CUR.zp2.n_points > 0 )
- last_point = (FT_UShort)(CUR.zp2.n_points - 1);
- else
- last_point = 0;
- }
+ /* we use the number of points if in the twilight zone */
+ if ( CUR.GS.gep2 == 0 )
+ limit = CUR.zp2.n_points;
+ else
+ limit = (FT_UShort)( CUR.zp2.contours[contour] -
+ CUR.zp2.first_point + 1 );
- /* XXX: UNDOCUMENTED! SHC touches the points */
- for ( i = first_point; i <= last_point; i++ )
+ for ( i = start; i < limit; i++ )
{
if ( zp.cur != CUR.zp2.cur || refp != i )
MOVE_Zp2_Point( i, dx, dy, TRUE );
@@ -5481,37 +6050,37 @@
static void
Ins_SHZ( INS_ARG )
{
- TT_GlyphZoneRec zp;
- FT_UShort refp;
- FT_F26Dot6 dx,
- dy;
+ TT_GlyphZoneRec zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx,
+ dy;
- FT_UShort last_point, i;
+ FT_UShort limit, i;
if ( BOUNDS( args[0], 2 ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
return;
- /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
- /* Twilight zone has no contours, so use `n_points'. */
- /* Normal zone's `n_points' includes phantoms, so must */
- /* use end of last contour. */
- if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
- last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
+ /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
+ /* Twilight zone has no real contours, so use `n_points'. */
+ /* Normal zone's `n_points' includes phantoms, so must */
+ /* use end of last contour. */
+ if ( CUR.GS.gep2 == 0 )
+ limit = (FT_UShort)CUR.zp2.n_points;
else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
- last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
+ limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 );
else
- last_point = 0;
+ limit = 0;
/* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
- for ( i = 0; i <= last_point; i++ )
+ for ( i = 0; i < limit; i++ )
{
if ( zp.cur != CUR.zp2.cur || refp != i )
MOVE_Zp2_Point( i, dx, dy, FALSE );
@@ -5530,12 +6099,16 @@
{
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 )
{
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
@@ -5543,13 +6116,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
@@ -5569,16 +6142,99 @@
{
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--;
}
+ Fail:
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
@@ -5596,6 +6252,21 @@
FT_UShort point;
FT_F26Dot6 distance;
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ FT_F26Dot6 control_value_cutin = 0; /* pacify compiler */
+
+
+ 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];
@@ -5603,13 +6274,13 @@
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;
}
- /* XXX: UNDOCUMENTED! behaviour */
- if ( CUR.GS.gep1 == 0 ) /* if the point that is to be moved */
- /* is in twilight zone */
+ /* UNDOCUMENTED! The MS rasterizer does that with */
+ /* twilight points (confirmed by Greg Hitchcock) */
+ if ( CUR.GS.gep1 == 0 )
{
CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
CUR_Func_move_orig( &CUR.zp1, point, args[1] );
@@ -5619,6 +6290,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;
@@ -5639,8 +6319,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];
@@ -5648,17 +6328,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;
}
- /* XXX: Is there some undocumented feature while in the */
- /* twilight zone? ? */
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;
@@ -5681,64 +6369,100 @@
{
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];
- if ( BOUNDS( point, CUR.zp0.n_points ) ||
- BOUNDS( cvtEntry, CUR.cvtSize ) )
+#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;
- return;
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
- /* XXX: UNDOCUMENTED! */
- /* */
- /* The behaviour of an MIAP instruction is quite */
- /* different when used in the twilight zone. */
- /* */
- /* First, no control value cut-in test is performed */
- /* as it would fail anyway. Second, the original */
- /* point, i.e. (org_x,org_y) of zp0.point, is set */
- /* to the absolute, unrounded distance found in */
- /* the CVT. */
- /* */
- /* This is used in the CVT programs of the Microsoft */
- /* fonts Arial, Times, etc., in order to re-adjust */
- /* some key font heights. It allows the use of the */
- /* IP instruction in the twilight zone, which */
- /* otherwise would be `illegal' according to the */
- /* specification. */
- /* */
- /* We implement it with a special sequence for the */
- /* twilight zone. This is a bad hack, but it seems */
- /* to work. */
+ /* UNDOCUMENTED! */
+ /* */
+ /* The behaviour of an MIAP instruction is quite different when used */
+ /* in the twilight zone. */
+ /* */
+ /* First, no control value cut-in test is performed as it would fail */
+ /* anyway. Second, the original point, i.e. (org_x,org_y) of */
+ /* zp0.point, is set to the absolute, unrounded distance found in the */
+ /* CVT. */
+ /* */
+ /* This is used in the CVT programs of the Microsoft fonts Arial, */
+ /* Times, etc., in order to re-adjust some key font heights. It */
+ /* allows the use of the IP instruction in the twilight zone, which */
+ /* otherwise would be invalid according to the specification. */
+ /* */
+ /* We implement it with a special sequence for the twilight zone. */
+ /* This is a bad hack, but it seems to work. */
+ /* */
+ /* Confirmed by Greg Hitchcock. */
distance = CUR_Func_read_cvt( cvtEntry );
if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
{
- 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 ),
+#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 );
+ Fail:
CUR.GS.rp0 = point;
CUR.GS.rp1 = point;
}
@@ -5754,8 +6478,18 @@
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];
@@ -5763,8 +6497,8 @@
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
/* XXX: Is there some undocumented feature while in the */
@@ -5790,15 +6524,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 );
}
@@ -5818,9 +6552,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,
@@ -5832,13 +6577,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;
}
}
@@ -5849,6 +6594,7 @@
CUR_Func_move( &CUR.zp1, point, distance - org_dist );
+ Fail:
CUR.GS.rp1 = CUR.GS.rp0;
CUR.GS.rp2 = point;
@@ -5872,21 +6618,38 @@
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 = 0; /* pacify compiler */
+ FT_Int B2 = 0;
+ 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 */
if ( BOUNDS( point, CUR.zp1.n_points ) ||
- BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
+ BOUNDSL( cvtEntry, CUR.cvtSize + 1 ) ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
if ( !cvtEntry )
@@ -5905,19 +6668,17 @@
cvt_dist = -CUR.GS.single_width_value;
}
- /* XXX: UNDOCUMENTED! -- twilight zone */
-
+ /* UNDOCUMENTED! The MS rasterizer does that with */
+ /* twilight points (confirmed by Greg Hitchcock) */
if ( CUR.GS.gep1 == 0 )
{
CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
TT_MulFix14( (FT_UInt32)cvt_dist,
CUR.GS.freeVector.x );
-
CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
TT_MulFix14( (FT_UInt32)cvt_dist,
CUR.GS.freeVector.y );
-
- CUR.zp1.cur[point] = CUR.zp0.cur[point];
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
}
org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
@@ -5933,7 +6694,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 )
{
@@ -5941,17 +6715,45 @@
/* refer to the same zone. */
if ( CUR.GS.gep0 == CUR.GS.gep1 )
- if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
+ {
+ /* XXX: According to Greg Hitchcock, the following wording is */
+ /* the right one: */
+ /* */
+ /* When the absolute difference between the value in */
+ /* the table [CVT] and the measurement directly from */
+ /* the outline is _greater_ than the cut_in value, the */
+ /* outline measurement is used. */
+ /* */
+ /* This is from `instgly.doc'. The description in */
+ /* `ttinst2.doc', version 1.66, is thus incorrect since */
+ /* it implies `>=' instead of `>'. */
+
+ if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
cvt_dist = org_dist;
+ }
distance = CUR_Func_round(
cvt_dist,
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 */
@@ -5959,24 +6761,71 @@
{
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;
if ( ( CUR.opcode & 16 ) != 0 )
CUR.GS.rp0 = point;
- /* XXX: UNDOCUMENTED! */
CUR.GS.rp2 = point;
}
@@ -5996,12 +6845,23 @@
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;
- return;
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
while ( CUR.GS.loop > 0 )
@@ -6014,7 +6874,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -6029,6 +6889,7 @@
CUR.GS.loop--;
}
+ Fail:
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
@@ -6047,7 +6908,7 @@
a0, a1,
b0, b1;
- FT_F26Dot6 discriminant;
+ FT_F26Dot6 discriminant, dotproduct;
FT_F26Dot6 dx, dy,
dax, day,
@@ -6072,10 +6933,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;
@@ -6087,15 +6950,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;
@@ -6132,11 +7005,11 @@
p1 = (FT_UShort)args[0];
p2 = (FT_UShort)args[1];
- if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
- BOUNDS( args[1], CUR.zp0.n_points ) )
+ if ( BOUNDS( p1, CUR.zp1.n_points ) ||
+ BOUNDS( p2, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
@@ -6170,8 +7043,9 @@
if ( CUR.top < CUR.GS.loop )
{
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
/*
@@ -6184,8 +7058,8 @@
if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
- return;
+ CUR.error = FT_THROW( Invalid_Reference );
+ goto Fail;
}
if ( twilight )
@@ -6210,9 +7084,21 @@
if ( twilight )
old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
orus_base );
- else
+ else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
orus_base );
+ else
+ {
+ FT_Vector vec;
+
+
+ vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
+ CUR.metrics.x_scale );
+ vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
+ CUR.metrics.y_scale );
+
+ old_range = CUR_fast_dualproj( &vec );
+ }
cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
}
@@ -6228,7 +7114,7 @@
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
continue;
@@ -6236,20 +7122,55 @@
if ( twilight )
org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
- else
+ else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
+ else
+ {
+ FT_Vector vec;
- cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
+
+ vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x,
+ CUR.metrics.x_scale );
+ vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y,
+ CUR.metrics.y_scale );
+
+ org_dist = CUR_fast_dualproj( &vec );
+ }
+
+ 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: */
+ /* */
+ /* delta = org_dist - cur_dist . */
+ /* */
+ /* We move `point' by `new_dist - cur_dist' after leaving */
+ /* this block, thus we have */
+ /* */
+ /* new_dist - cur_dist = delta , */
+ /* new_dist - cur_dist = org_dist - cur_dist , */
+ /* new_dist = org_dist . */
+
+ new_dist = org_dist;
+ }
+ }
else
new_dist = 0;
CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
}
+
+ Fail:
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
@@ -6273,7 +7194,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;
}
@@ -6402,12 +7323,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;
}
@@ -6462,13 +7383,23 @@
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;
first_point = point;
- if ( CUR.pts.n_points <= end_point )
- end_point = CUR.pts.n_points;
+ if ( BOUNDS ( end_point, CUR.pts.n_points ) )
+ end_point = CUR.pts.n_points - 1;
while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
point++;
@@ -6484,12 +7415,11 @@
{
if ( ( CUR.pts.tags[point] & mask ) != 0 )
{
- if ( point > 0 )
- _iup_worker_interpolate( &V,
- cur_touched + 1,
- point - 1,
- cur_touched,
- point );
+ _iup_worker_interpolate( &V,
+ cur_touched + 1,
+ point - 1,
+ cur_touched,
+ point );
cur_touched = point;
}
@@ -6528,10 +7458,20 @@
static void
Ins_DELTAP( INS_ARG )
{
- FT_ULong k, nump;
+ FT_ULong nump, k;
FT_UShort A;
- FT_ULong C;
+ FT_ULong C, P;
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
@@ -6543,8 +7483,9 @@
if ( CUR.args < n )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ n = CUR.args;
}
CUR.args -= n;
@@ -6553,6 +7494,7 @@
}
#endif
+ P = (FT_ULong)CUR_Func_cur_ppem();
nump = (FT_ULong)args[0]; /* some points theoretically may occur more
than once, thus UShort isn't enough */
@@ -6560,8 +7502,10 @@
{
if ( CUR.args < 2 )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ CUR.args = 0;
+ goto Fail;
}
CUR.args -= 2;
@@ -6595,21 +7539,83 @@
C += CUR.GS.delta_base;
- if ( CURRENT_Ppem() == (FT_Long)C )
+ if ( P == C )
{
B = ( (FT_ULong)B & 0xF ) - 8;
if ( B >= 0 )
B++;
- B = B * 64 / ( 1L << CUR.GS.delta_shift );
+ B *= 1L << ( 6 - 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, or
+ * - glyph is composite and freedom vector is not in subpixel
+ * direction.
+ */
+ 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, always skipping deltas in subpixel direction. */
+ else if ( CUR.ignore_x_mode && CUR.GS.freeVector.y != 0 )
+ {
+ /* save the y value of the point now; compare after move */
+ B1 = (FT_UShort)CUR.zp0.cur[A].y;
+
+ /* Standard subpixel hinting: Allow y move for y-touched */
+ /* points. This messes up DejaVu ... */
+ if ( !CUR.face->sph_compatibility_mode &&
+ ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
+ CUR_Func_move( &CUR.zp0, A, B );
+
+ /* compatibility mode */
+ else if ( CUR.face->sph_compatibility_mode &&
+ !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
+ {
+ 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 = (FT_UShort)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:
CUR.new_top = CUR.args;
}
@@ -6624,7 +7630,7 @@
Ins_DELTAC( INS_ARG )
{
FT_ULong nump, k;
- FT_ULong A, C;
+ FT_ULong A, C, P;
FT_Long B;
@@ -6637,8 +7643,9 @@
if ( CUR.args < n )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ n = CUR.args;
}
CUR.args -= n;
@@ -6647,14 +7654,17 @@
}
#endif
+ P = (FT_ULong)CUR_Func_cur_ppem();
nump = (FT_ULong)args[0];
for ( k = 1; k <= nump; k++ )
{
if ( CUR.args < 2 )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
+ if ( CUR.pedantic_hinting )
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ CUR.args = 0;
+ goto Fail;
}
CUR.args -= 2;
@@ -6662,11 +7672,11 @@
A = (FT_ULong)CUR.stack[CUR.args + 1];
B = CUR.stack[CUR.args];
- if ( BOUNDS( A, CUR.cvtSize ) )
+ if ( BOUNDSL( A, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
return;
}
}
@@ -6690,18 +7700,19 @@
C += CUR.GS.delta_base;
- if ( CURRENT_Ppem() == (FT_Long)C )
+ if ( P == C )
{
B = ( (FT_ULong)B & 0xF ) - 8;
if ( B >= 0 )
B++;
- B = B * 64 / ( 1L << CUR.GS.delta_shift );
+ B *= 1L << ( 6 - CUR.GS.delta_shift );
CUR_Func_move_cvt( A, B );
}
}
}
+ Fail:
CUR.new_top = CUR.args;
}
@@ -6727,22 +7738,109 @@
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 )
+ {
+
+ if ( CUR.rasterizer_version >= 37 )
+ {
+ /********************************/
+ /* HINTING FOR SUBPIXEL */
+ /* Selector Bit: 6 */
+ /* Return Bit(s): 13 */
+ /* */
+ if ( ( args[0] & 64 ) != 0 && CUR.subpixel )
+ K |= 1 << 13;
+
+ /********************************/
+ /* 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;
}
@@ -6765,16 +7863,16 @@
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Stack_Overflow;
+ CUR.error = FT_THROW( Stack_Overflow );
return;
}
call = CUR.callStack + CUR.callTop++;
call->Caller_Range = CUR.curRange;
- call->Caller_IP = CUR.IP+1;
+ call->Caller_IP = CUR.IP + 1;
call->Cur_Count = 1;
- call->Cur_Restart = def->start;
+ call->Def = def;
INS_Goto_CodeRange( def->range, def->start );
@@ -6783,7 +7881,7 @@
}
}
- CUR.error = TT_Err_Invalid_Opcode;
+ CUR.error = FT_THROW( Invalid_Opcode );
}
@@ -7110,18 +8208,40 @@
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
+ if ( !exc )
+ return FT_THROW( Invalid_Argument );
+
cur = *exc;
#endif
- /* set CVT functions */
+#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
+ CUR.iup_called = FALSE;
+#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+ /* set PPEM and CVT functions */
CUR.tt_metrics.ratio = 0;
if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
{
/* non-square pixels, use the stretched routines */
+ CUR.func_cur_ppem = Current_Ppem_Stretched;
CUR.func_read_cvt = Read_CVT_Stretched;
CUR.func_write_cvt = Write_CVT_Stretched;
CUR.func_move_cvt = Move_CVT_Stretched;
@@ -7129,6 +8249,7 @@
else
{
/* square pixels, use normal routines */
+ CUR.func_cur_ppem = Current_Ppem;
CUR.func_read_cvt = Read_CVT;
CUR.func_write_cvt = Write_CVT;
CUR.func_move_cvt = Move_CVT;
@@ -7141,9 +8262,13 @@
{
CUR.opcode = CUR.code[CUR.IP];
+ FT_TRACE7(( " " ));
+ FT_TRACE7(( opcode_name[CUR.opcode] ));
+ FT_TRACE7(( "\n" ));
+
if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
{
- if ( CUR.IP + 1 > CUR.codeSize )
+ if ( CUR.IP + 1 >= CUR.codeSize )
goto LErrorCodeOverflow_;
CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
@@ -7159,8 +8284,16 @@
/* One can also interpret it as the index of the last argument. */
if ( CUR.args < 0 )
{
- CUR.error = TT_Err_Too_Few_Arguments;
- goto LErrorLabel_;
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = FT_THROW( Too_Few_Arguments );
+ goto LErrorLabel_;
+ }
+
+ /* push zeroes onto the stack */
+ for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ )
+ CUR.stack[i] = 0;
+ CUR.args = 0;
}
CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
@@ -7170,12 +8303,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
@@ -7197,7 +8363,7 @@
case 0x04: /* SFvTCA y */
case 0x05: /* SFvTCA x */
{
- FT_Short AA, BB;
+ FT_Short AA, BB;
AA = (FT_Short)( ( opcode & 1 ) << 14 );
@@ -7389,7 +8555,6 @@
Ins_MDAP( EXEC_ARG_ args );
break;
-
case 0x30: /* IUP */
case 0x31: /* IUP */
Ins_IUP( EXEC_ARG_ args );
@@ -7449,7 +8614,7 @@
break;
Set_Invalid_Ref:
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
break;
case 0x43: /* RS */
@@ -7739,11 +8904,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;
@@ -7758,7 +8924,7 @@
if ( CUR.callTop >= CUR.callSize )
{
- CUR.error = TT_Err_Invalid_Reference;
+ CUR.error = FT_THROW( Invalid_Reference );
goto LErrorLabel_;
}
@@ -7767,7 +8933,7 @@
callrec->Caller_Range = CUR.curRange;
callrec->Caller_IP = CUR.IP + 1;
callrec->Cur_Count = 1;
- callrec->Cur_Restart = def->start;
+ callrec->Def = def;
if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
goto LErrorLabel_;
@@ -7777,7 +8943,7 @@
}
}
- CUR.error = TT_Err_Invalid_Opcode;
+ CUR.error = FT_THROW( Invalid_Opcode );
goto LErrorLabel_;
#if 0
@@ -7803,14 +8969,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
@@ -7824,10 +8990,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_:
@@ -7835,6 +9001,18 @@
*exc = cur;
#endif
+ /* If any errors have occurred, function tables may be broken. */
+ /* Force a re-execution of `prep' and `fpgm' tables if no */
+ /* bytecode debugger is run. */
+ if ( CUR.error &&
+ !CUR.instruction_trap &&
+ CUR.curRange == tt_coderange_glyph )
+ {
+ FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error ));
+ exc->size->bytecode_ready = -1;
+ exc->size->cvt_ready = -1;
+ }
+
return CUR.error;
}