Index: third_party/freetype/src/truetype/ttgxvar.c |
diff --git a/third_party/freetype/src/truetype/ttgxvar.c b/third_party/freetype/src/truetype/ttgxvar.c |
index 1b35539fe1371eee9e938a7792438371abae7729..dd9e250c9419b0127789f4bbc8cd220b86518967 100644 |
--- a/third_party/freetype/src/truetype/ttgxvar.c |
+++ b/third_party/freetype/src/truetype/ttgxvar.c |
@@ -4,7 +4,7 @@ |
/* */ |
/* TrueType GX Font Variation loader */ |
/* */ |
-/* Copyright 2004-2014 by */ |
+/* Copyright 2004-2015 by */ |
/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ |
/* */ |
/* This file is part of the FreeType project, and may only be used, */ |
@@ -20,7 +20,7 @@ |
/* */ |
/* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ |
/* */ |
- /* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ |
+ /* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html */ |
/* */ |
/* The documentation for `fvar' is inconsistent. At one point it says */ |
/* that `countSizePairs' should be 3, at another point 2. It should */ |
@@ -60,9 +60,9 @@ |
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT |
-#define FT_Stream_FTell( stream ) \ |
+#define FT_Stream_FTell( stream ) \ |
(FT_ULong)( (stream)->cursor - (stream)->base ) |
-#define FT_Stream_SeekSet( stream, off ) \ |
+#define FT_Stream_SeekSet( stream, off ) \ |
( (stream)->cursor = (stream)->base + (off) ) |
@@ -96,8 +96,8 @@ |
#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 |
-#define GX_PT_POINTS_ARE_WORDS 0x80 |
-#define GX_PT_POINT_RUN_COUNT_MASK 0x7F |
+#define GX_PT_POINTS_ARE_WORDS 0x80U |
+#define GX_PT_POINT_RUN_COUNT_MASK 0x7FU |
/*************************************************************************/ |
@@ -126,52 +126,67 @@ |
FT_UInt *point_cnt ) |
{ |
FT_UShort *points = NULL; |
- FT_Int n; |
- FT_Int runcnt; |
- FT_Int i; |
- FT_Int j; |
- FT_Int first; |
+ FT_UInt n; |
+ FT_UInt runcnt; |
+ FT_UInt i, j; |
+ FT_UShort first; |
FT_Memory memory = stream->memory; |
FT_Error error = FT_Err_Ok; |
FT_UNUSED( error ); |
- *point_cnt = n = FT_GET_BYTE(); |
+ *point_cnt = 0; |
+ |
+ n = FT_GET_BYTE(); |
if ( n == 0 ) |
return ALL_POINTS; |
if ( n & GX_PT_POINTS_ARE_WORDS ) |
- n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); |
+ { |
+ n &= GX_PT_POINT_RUN_COUNT_MASK; |
+ n <<= 8; |
+ n |= FT_GET_BYTE(); |
+ } |
if ( FT_NEW_ARRAY( points, n ) ) |
return NULL; |
+ *point_cnt = n; |
+ |
i = 0; |
while ( i < n ) |
{ |
runcnt = FT_GET_BYTE(); |
if ( runcnt & GX_PT_POINTS_ARE_WORDS ) |
{ |
- runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; |
- first = points[i++] = FT_GET_USHORT(); |
+ runcnt &= GX_PT_POINT_RUN_COUNT_MASK; |
+ first = FT_GET_USHORT(); |
+ points[i++] = first; |
- if ( runcnt < 1 || i + runcnt >= n ) |
+ if ( runcnt < 1 || i + runcnt > n ) |
goto Exit; |
- /* first point not included in runcount */ |
- for ( j = 0; j < runcnt; ++j ) |
- points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); |
+ /* first point not included in run count */ |
+ for ( j = 0; j < runcnt; j++ ) |
+ { |
+ first += FT_GET_USHORT(); |
+ points[i++] = first; |
+ } |
} |
else |
{ |
- first = points[i++] = FT_GET_BYTE(); |
+ first = FT_GET_BYTE(); |
+ points[i++] = first; |
- if ( runcnt < 1 || i + runcnt >= n ) |
+ if ( runcnt < 1 || i + runcnt > n ) |
goto Exit; |
- for ( j = 0; j < runcnt; ++j ) |
- points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); |
+ for ( j = 0; j < runcnt; j++ ) |
+ { |
+ first += FT_GET_BYTE(); |
+ points[i++] = first; |
+ } |
} |
} |
@@ -180,12 +195,9 @@ |
} |
- enum |
- { |
- GX_DT_DELTAS_ARE_ZERO = 0x80, |
- GX_DT_DELTAS_ARE_WORDS = 0x40, |
- GX_DT_DELTA_RUN_COUNT_MASK = 0x3F |
- }; |
+#define GX_DT_DELTAS_ARE_ZERO 0x80U |
+#define GX_DT_DELTAS_ARE_WORDS 0x40U |
+#define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU |
/*************************************************************************/ |
@@ -200,7 +212,7 @@ |
/* <Input> */ |
/* stream :: The data stream. */ |
/* */ |
- /* delta_cnt :: The number of to be read. */ |
+ /* delta_cnt :: The number of deltas to be read. */ |
/* */ |
/* <Return> */ |
/* An array of FT_Short containing the deltas for the affected */ |
@@ -210,12 +222,11 @@ |
/* */ |
static FT_Short* |
ft_var_readpackeddeltas( FT_Stream stream, |
- FT_Offset delta_cnt ) |
+ FT_UInt delta_cnt ) |
{ |
FT_Short *deltas = NULL; |
- FT_UInt runcnt; |
- FT_Offset i; |
- FT_UInt j; |
+ FT_UInt runcnt, cnt; |
+ FT_UInt i, j; |
FT_Memory memory = stream->memory; |
FT_Error error = FT_Err_Ok; |
@@ -229,34 +240,30 @@ |
while ( i < delta_cnt ) |
{ |
runcnt = FT_GET_BYTE(); |
+ cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; |
+ |
if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) |
{ |
- /* runcnt zeroes get added */ |
- for ( j = 0; |
- j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; |
- ++j ) |
+ /* `runcnt' zeroes get added */ |
+ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
deltas[i++] = 0; |
} |
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) |
{ |
- /* runcnt shorts from the stack */ |
- for ( j = 0; |
- j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; |
- ++j ) |
+ /* `runcnt' shorts from the stack */ |
+ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
deltas[i++] = FT_GET_SHORT(); |
} |
else |
{ |
- /* runcnt signed bytes from the stack */ |
- for ( j = 0; |
- j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; |
- ++j ) |
+ /* `runcnt' signed bytes from the stack */ |
+ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
deltas[i++] = FT_GET_CHAR(); |
} |
- if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) |
+ if ( j <= cnt ) |
{ |
- /* Bad format */ |
+ /* bad format */ |
FT_FREE( deltas ); |
return NULL; |
} |
@@ -281,12 +288,12 @@ |
static void |
ft_var_load_avar( TT_Face face ) |
{ |
- FT_Stream stream = FT_FACE_STREAM(face); |
+ FT_Stream stream = FT_FACE_STREAM( face ); |
FT_Memory memory = stream->memory; |
GX_Blend blend = face->blend; |
GX_AVarSegment segment; |
FT_Error error = FT_Err_Ok; |
- FT_ULong version; |
+ FT_Long version; |
FT_Long axisCount; |
FT_Int i, j; |
FT_ULong table_len; |
@@ -294,9 +301,15 @@ |
FT_UNUSED( error ); |
+ FT_TRACE2(( "AVAR " )); |
+ |
blend->avar_checked = TRUE; |
- if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 ) |
+ error = face->goto_table( face, TTAG_avar, stream, &table_len ); |
+ if ( error ) |
+ { |
+ FT_TRACE2(( "is missing\n" )); |
return; |
+ } |
if ( FT_FRAME_ENTER( table_len ) ) |
return; |
@@ -304,23 +317,36 @@ |
version = FT_GET_LONG(); |
axisCount = FT_GET_LONG(); |
- if ( version != 0x00010000L || |
- axisCount != (FT_Long)blend->mmvar->num_axis ) |
+ if ( version != 0x00010000L ) |
+ { |
+ FT_TRACE2(( "bad table version\n" )); |
+ goto Exit; |
+ } |
+ |
+ FT_TRACE2(( "loaded\n" )); |
+ |
+ if ( axisCount != (FT_Long)blend->mmvar->num_axis ) |
+ { |
+ FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `cvar'\n" |
+ " table are different\n" )); |
goto Exit; |
+ } |
if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) |
goto Exit; |
segment = &blend->avar_segment[0]; |
- for ( i = 0; i < axisCount; ++i, ++segment ) |
+ for ( i = 0; i < axisCount; i++, segment++ ) |
{ |
+ FT_TRACE5(( " axis %d:\n", i )); |
+ |
segment->pairCount = FT_GET_USHORT(); |
if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) |
{ |
/* Failure. Free everything we have done so far. We must do */ |
/* it right now since loading the `avar' table is optional. */ |
- for ( j = i - 1; j >= 0; --j ) |
+ for ( j = i - 1; j >= 0; j-- ) |
FT_FREE( blend->avar_segment[j].correspondence ); |
FT_FREE( blend->avar_segment ); |
@@ -328,13 +354,18 @@ |
goto Exit; |
} |
- for ( j = 0; j < segment->pairCount; ++j ) |
+ for ( j = 0; j < segment->pairCount; j++ ) |
{ |
- segment->correspondence[j].fromCoord = |
- FT_GET_SHORT() << 2; /* convert to Fixed */ |
- segment->correspondence[j].toCoord = |
- FT_GET_SHORT()<<2; /* convert to Fixed */ |
+ /* convert to Fixed */ |
+ segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4; |
+ segment->correspondence[j].toCoord = FT_GET_SHORT() * 4; |
+ |
+ FT_TRACE5(( " mapping %.4f to %.4f\n", |
+ segment->correspondence[j].fromCoord / 65536.0, |
+ segment->correspondence[j].toCoord / 65536.0 )); |
} |
+ |
+ FT_TRACE5(( "\n" )); |
} |
Exit: |
@@ -361,8 +392,8 @@ |
/* ft_var_load_gvar */ |
/* */ |
/* <Description> */ |
- /* Parses the `gvar' table if present. If `fvar' is there, `gvar' */ |
- /* had better be there too. */ |
+ /* Parse the `gvar' table if present. If `fvar' is there, `gvar' had */ |
+ /* better be there too. */ |
/* */ |
/* <InOut> */ |
/* face :: The font face. */ |
@@ -373,7 +404,7 @@ |
static FT_Error |
ft_var_load_gvar( TT_Face face ) |
{ |
- FT_Stream stream = FT_FACE_STREAM(face); |
+ FT_Stream stream = FT_FACE_STREAM( face ); |
FT_Memory memory = stream->memory; |
GX_Blend blend = face->blend; |
FT_Error error; |
@@ -400,8 +431,17 @@ |
FT_FRAME_END |
}; |
- if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) |
+ |
+ FT_TRACE2(( "GVAR " )); |
+ |
+ if ( ( error = face->goto_table( face, |
+ TTAG_gvar, |
+ stream, |
+ &table_len ) ) != 0 ) |
+ { |
+ FT_TRACE2(( "is missing\n" )); |
goto Exit; |
+ } |
gvar_start = FT_STREAM_POS( ); |
if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) |
@@ -411,13 +451,26 @@ |
blend->gv_glyphcnt = gvar_head.glyphCount; |
offsetToData = gvar_start + gvar_head.offsetToData; |
- if ( gvar_head.version != (FT_Long)0x00010000L || |
- gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) |
+ if ( gvar_head.version != 0x00010000L ) |
+ { |
+ FT_TRACE1(( "bad table version\n" )); |
+ error = FT_THROW( Invalid_Table ); |
+ goto Exit; |
+ } |
+ |
+ FT_TRACE2(( "loaded\n" )); |
+ |
+ if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) |
{ |
+ FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" |
+ " table are different\n" )); |
error = FT_THROW( Invalid_Table ); |
goto Exit; |
} |
+ FT_TRACE5(( "gvar: there are %d shared coordinates:\n", |
+ blend->tuplecount )); |
+ |
if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) |
goto Exit; |
@@ -427,8 +480,8 @@ |
if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) |
goto Exit; |
- for ( i = 0; i <= blend->gv_glyphcnt; ++i ) |
- blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); |
+ for ( i = 0; i <= blend->gv_glyphcnt; i++ ) |
+ blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); |
FT_FRAME_EXIT(); |
} |
@@ -438,9 +491,9 @@ |
if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) |
goto Exit; |
- for ( i = 0; i <= blend->gv_glyphcnt; ++i ) |
+ for ( i = 0; i <= blend->gv_glyphcnt; i++ ) |
blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; |
- /* XXX: Undocumented: `*2'! */ |
+ /* XXX: Undocumented: `*2'! */ |
FT_FRAME_EXIT(); |
} |
@@ -451,14 +504,24 @@ |
gvar_head.axisCount * blend->tuplecount ) ) |
goto Exit; |
- if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || |
- FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) |
+ if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || |
+ FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) |
goto Exit; |
- for ( i = 0; i < blend->tuplecount; ++i ) |
- for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) |
+ for ( i = 0; i < blend->tuplecount; i++ ) |
+ { |
+ FT_TRACE5(( " [ " )); |
+ for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; j++ ) |
+ { |
blend->tuplecoords[i * gvar_head.axisCount + j] = |
- FT_GET_SHORT() << 2; /* convert to FT_Fixed */ |
+ FT_GET_SHORT() * 4; /* convert to FT_Fixed */ |
+ FT_TRACE5(( "%.4f ", |
+ blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); |
+ } |
+ FT_TRACE5(( "]\n" )); |
+ } |
+ |
+ FT_TRACE5(( "\n" )); |
FT_FRAME_EXIT(); |
} |
@@ -506,48 +569,83 @@ |
FT_Fixed apply = 0x10000L; |
- for ( i = 0; i < blend->num_axis; ++i ) |
+ for ( i = 0; i < blend->num_axis; i++ ) |
{ |
+ FT_TRACE6(( " axis coordinate %d (%.4f):\n", |
+ i, blend->normalizedcoords[i] / 65536.0 )); |
+ |
+ /* It's not clear why (for intermediate tuples) we don't need */ |
+ /* to check against start/end -- the documentation says we don't. */ |
+ /* Similarly, it's unclear why we don't need to scale along the */ |
+ /* axis. */ |
+ |
if ( tuple_coords[i] == 0 ) |
- /* It's not clear why (for intermediate tuples) we don't need */ |
- /* to check against start/end -- the documentation says we don't. */ |
- /* Similarly, it's unclear why we don't need to scale along the */ |
- /* axis. */ |
+ { |
+ FT_TRACE6(( " tuple coordinate is zero, ignored\n", i )); |
continue; |
+ } |
+ |
+ else if ( blend->normalizedcoords[i] == 0 ) |
+ { |
+ FT_TRACE6(( " axis coordinate is zero, stop\n" )); |
+ apply = 0; |
+ break; |
+ } |
- else if ( blend->normalizedcoords[i] == 0 || |
- ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || |
+ else if ( ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || |
( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) |
{ |
+ FT_TRACE6(( " tuple coordinate value %.4f is exceeded, stop\n", |
+ tuple_coords[i] / 65536.0 )); |
apply = 0; |
break; |
} |
else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) |
+ { |
+ FT_TRACE6(( " tuple coordinate value %.4f fits\n", |
+ tuple_coords[i] / 65536.0 )); |
/* not an intermediate tuple */ |
apply = FT_MulFix( apply, |
blend->normalizedcoords[i] > 0 |
? blend->normalizedcoords[i] |
: -blend->normalizedcoords[i] ); |
+ } |
- else if ( blend->normalizedcoords[i] <= im_start_coords[i] || |
- blend->normalizedcoords[i] >= im_end_coords[i] ) |
+ else if ( blend->normalizedcoords[i] < im_start_coords[i] || |
+ blend->normalizedcoords[i] > im_end_coords[i] ) |
{ |
+ FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] is exceeded," |
+ " stop\n", |
+ im_start_coords[i] / 65536.0, |
+ im_end_coords[i] / 65536.0 )); |
apply = 0; |
break; |
} |
else if ( blend->normalizedcoords[i] < tuple_coords[i] ) |
+ { |
+ FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", |
+ im_start_coords[i] / 65536.0, |
+ im_end_coords[i] / 65536.0 )); |
apply = FT_MulDiv( apply, |
blend->normalizedcoords[i] - im_start_coords[i], |
tuple_coords[i] - im_start_coords[i] ); |
+ } |
else |
+ { |
+ FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", |
+ im_start_coords[i] / 65536.0, |
+ im_end_coords[i] / 65536.0 )); |
apply = FT_MulDiv( apply, |
im_end_coords[i] - blend->normalizedcoords[i], |
im_end_coords[i] - tuple_coords[i] ); |
+ } |
} |
+ FT_TRACE6(( " apply factor is %.4f\n", apply / 65536.0 )); |
+ |
return apply; |
} |
@@ -577,9 +675,9 @@ |
typedef struct fvar_axis_ |
{ |
FT_ULong axisTag; |
- FT_ULong minValue; |
- FT_ULong defaultValue; |
- FT_ULong maxValue; |
+ FT_Fixed minValue; |
+ FT_Fixed defaultValue; |
+ FT_Fixed maxValue; |
FT_UShort flags; |
FT_UShort nameID; |
@@ -600,7 +698,8 @@ |
/* TT_Get_MM_Var initializes the blend structure. */ |
/* */ |
/* <Output> */ |
- /* master :: The `fvar' data (must be freed by caller). */ |
+ /* master :: The `fvar' data (must be freed by caller). Can be NULL, */ |
+ /* which makes this function simply load MM support. */ |
/* */ |
/* <Return> */ |
/* FreeType error code. 0 means success. */ |
@@ -647,25 +746,37 @@ |
FT_FRAME_START( 20 ), |
FT_FRAME_ULONG ( axisTag ), |
- FT_FRAME_ULONG ( minValue ), |
- FT_FRAME_ULONG ( defaultValue ), |
- FT_FRAME_ULONG ( maxValue ), |
+ FT_FRAME_LONG ( minValue ), |
+ FT_FRAME_LONG ( defaultValue ), |
+ FT_FRAME_LONG ( maxValue ), |
FT_FRAME_USHORT( flags ), |
FT_FRAME_USHORT( nameID ), |
FT_FRAME_END |
}; |
+ /* read the font data and set up the internal representation */ |
+ /* if not already done */ |
+ |
if ( face->blend == NULL ) |
{ |
+ FT_TRACE2(( "FVAR " )); |
+ |
/* both `fvar' and `gvar' must be present */ |
- if ( (error = face->goto_table( face, TTAG_gvar, |
- stream, &table_len )) != 0 ) |
+ if ( ( error = face->goto_table( face, TTAG_gvar, |
+ stream, &table_len ) ) != 0 ) |
+ { |
+ FT_TRACE1(( "\n" |
+ "TT_Get_MM_Var: `gvar' table is missing\n" )); |
goto Exit; |
+ } |
- if ( (error = face->goto_table( face, TTAG_fvar, |
- stream, &table_len )) != 0 ) |
+ if ( ( error = face->goto_table( face, TTAG_fvar, |
+ stream, &table_len ) ) != 0 ) |
+ { |
+ FT_TRACE1(( "is missing\n" )); |
goto Exit; |
+ } |
fvar_start = FT_STREAM_POS( ); |
@@ -673,7 +784,12 @@ |
goto Exit; |
if ( fvar_head.version != (FT_Long)0x00010000L || |
+#if 0 |
+ /* fonts like `JamRegular.ttf' have an incorrect value for */ |
+ /* `countSizePairs'; since value 2 is hard-coded in `fvar' */ |
+ /* version 1.0, we simply ignore it */ |
fvar_head.countSizePairs != 2 || |
+#endif |
fvar_head.axisSize != 20 || |
/* axisCount limit implied by 16-bit instanceSize */ |
fvar_head.axisCount > 0x3FFE || |
@@ -683,10 +799,16 @@ |
fvar_head.offsetToData + fvar_head.axisCount * 20U + |
fvar_head.instanceCount * fvar_head.instanceSize > table_len ) |
{ |
+ FT_TRACE1(( "\n" |
+ "TT_Get_MM_Var: invalid `fvar' header\n" )); |
error = FT_THROW( Invalid_Table ); |
goto Exit; |
} |
+ FT_TRACE2(( "loaded\n" )); |
+ |
+ FT_TRACE5(( "number of GX style axes: %d\n", fvar_head.axisCount )); |
+ |
if ( FT_NEW( face->blend ) ) |
goto Exit; |
@@ -702,6 +824,9 @@ |
goto Exit; |
face->blend->mmvar = mmvar; |
+ /* set up pointers and offsets into the `mmvar' array; */ |
+ /* the data gets filled in later on */ |
+ |
mmvar->num_axis = |
fvar_head.axisCount; |
mmvar->num_designs = |
@@ -711,30 +836,32 @@ |
mmvar->num_namedstyles = |
fvar_head.instanceCount; |
mmvar->axis = |
- (FT_Var_Axis*)&(mmvar[1]); |
+ (FT_Var_Axis*)&( mmvar[1] ); |
mmvar->namedstyle = |
- (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); |
+ (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] ); |
next_coords = |
- (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); |
- for ( i = 0; i < fvar_head.instanceCount; ++i ) |
+ (FT_Fixed*)&( mmvar->namedstyle[fvar_head.instanceCount] ); |
+ for ( i = 0; i < fvar_head.instanceCount; i++ ) |
{ |
mmvar->namedstyle[i].coords = next_coords; |
next_coords += fvar_head.axisCount; |
} |
next_name = (FT_String*)next_coords; |
- for ( i = 0; i < fvar_head.axisCount; ++i ) |
+ for ( i = 0; i < fvar_head.axisCount; i++ ) |
{ |
mmvar->axis[i].name = next_name; |
next_name += 5; |
} |
+ /* now fill in the data */ |
+ |
if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) |
goto Exit; |
a = mmvar->axis; |
- for ( i = 0; i < fvar_head.axisCount; ++i ) |
+ for ( i = 0; i < fvar_head.axisCount; i++ ) |
{ |
GX_FVar_Axis axis_rec; |
@@ -742,22 +869,30 @@ |
if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) |
goto Exit; |
a->tag = axis_rec.axisTag; |
- a->minimum = axis_rec.minValue; /* A Fixed */ |
- a->def = axis_rec.defaultValue; /* A Fixed */ |
- a->maximum = axis_rec.maxValue; /* A Fixed */ |
+ a->minimum = axis_rec.minValue; |
+ a->def = axis_rec.defaultValue; |
+ a->maximum = axis_rec.maxValue; |
a->strid = axis_rec.nameID; |
a->name[0] = (FT_String)( a->tag >> 24 ); |
a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); |
a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); |
a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); |
- a->name[4] = 0; |
+ a->name[4] = '\0'; |
- ++a; |
+ FT_TRACE5(( " \"%s\": minimum=%.4f, default=%.4f, maximum=%.4f\n", |
+ a->name, |
+ a->minimum / 65536.0, |
+ a->def / 65536.0, |
+ a->maximum / 65536.0 )); |
+ |
+ a++; |
} |
+ FT_TRACE5(( "\n" )); |
+ |
ns = mmvar->namedstyle; |
- for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns ) |
+ for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) |
{ |
if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) |
goto Exit; |
@@ -765,13 +900,15 @@ |
ns->strid = FT_GET_USHORT(); |
(void) /* flags = */ FT_GET_USHORT(); |
- for ( j = 0; j < fvar_head.axisCount; ++j ) |
- ns->coords[j] = FT_GET_ULONG(); /* A Fixed */ |
+ for ( j = 0; j < fvar_head.axisCount; j++ ) |
+ ns->coords[j] = FT_GET_LONG(); |
FT_FRAME_EXIT(); |
} |
} |
+ /* fill the output array if requested */ |
+ |
if ( master != NULL ) |
{ |
FT_UInt n; |
@@ -782,36 +919,36 @@ |
FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); |
mmvar->axis = |
- (FT_Var_Axis*)&(mmvar[1]); |
+ (FT_Var_Axis*)&( mmvar[1] ); |
mmvar->namedstyle = |
- (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); |
+ (FT_Var_Named_Style*)&( mmvar->axis[mmvar->num_axis] ); |
next_coords = |
- (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); |
+ (FT_Fixed*)&( mmvar->namedstyle[mmvar->num_namedstyles] ); |
- for ( n = 0; n < mmvar->num_namedstyles; ++n ) |
+ for ( n = 0; n < mmvar->num_namedstyles; n++ ) |
{ |
mmvar->namedstyle[n].coords = next_coords; |
next_coords += mmvar->num_axis; |
} |
- a = mmvar->axis; |
+ a = mmvar->axis; |
next_name = (FT_String*)next_coords; |
- for ( n = 0; n < mmvar->num_axis; ++n ) |
+ for ( n = 0; n < mmvar->num_axis; n++ ) |
{ |
a->name = next_name; |
/* standard PostScript names for some standard apple tags */ |
if ( a->tag == TTAG_wght ) |
- a->name = (char *)"Weight"; |
+ a->name = (char*)"Weight"; |
else if ( a->tag == TTAG_wdth ) |
- a->name = (char *)"Width"; |
+ a->name = (char*)"Width"; |
else if ( a->tag == TTAG_opsz ) |
- a->name = (char *)"OpticalSize"; |
+ a->name = (char*)"OpticalSize"; |
else if ( a->tag == TTAG_slnt ) |
- a->name = (char *)"Slant"; |
+ a->name = (char*)"Slant"; |
next_name += 5; |
- ++a; |
+ a++; |
} |
*master = mmvar; |
@@ -837,9 +974,12 @@ |
/* Initialize the blend structure with `gvar' data. */ |
/* */ |
/* <Input> */ |
- /* num_coords :: Must be the axis count of the font. */ |
+ /* num_coords :: The number of available coordinates. If it is */ |
+ /* larger than the number of axes, ignore the excess */ |
+ /* values. If it is smaller than the number of axes, */ |
+ /* use the default value (0) for the remaining axes. */ |
/* */ |
- /* coords :: An array of num_coords, each between [-1,1]. */ |
+ /* coords :: An array of `num_coords', each between [-1,1]. */ |
/* */ |
/* <Return> */ |
/* FreeType error code. 0 means success. */ |
@@ -868,33 +1008,44 @@ |
if ( face->blend == NULL ) |
{ |
- if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) |
+ if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) |
goto Exit; |
} |
blend = face->blend; |
mmvar = blend->mmvar; |
- if ( num_coords != mmvar->num_axis ) |
+ if ( num_coords > mmvar->num_axis ) |
{ |
- error = FT_THROW( Invalid_Argument ); |
- goto Exit; |
+ FT_TRACE2(( "TT_Set_MM_Blend: only using first %d of %d coordinates\n", |
+ mmvar->num_axis, num_coords )); |
+ num_coords = mmvar->num_axis; |
} |
- for ( i = 0; i < num_coords; ++i ) |
+ FT_TRACE5(( "normalized design coordinates:\n" )); |
+ |
+ for ( i = 0; i < num_coords; i++ ) |
+ { |
+ FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); |
if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) |
{ |
+ FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.4f\n" |
+ " is out of range [-1;1]\n", |
+ coords[i] / 65536.0 )); |
error = FT_THROW( Invalid_Argument ); |
goto Exit; |
} |
+ } |
+ |
+ FT_TRACE5(( "\n" )); |
if ( blend->glyphoffsets == NULL ) |
- if ( (error = ft_var_load_gvar( face )) != 0 ) |
+ if ( ( error = ft_var_load_gvar( face ) ) != 0 ) |
goto Exit; |
if ( blend->normalizedcoords == NULL ) |
{ |
- if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) |
+ if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) |
goto Exit; |
manageCvt = mcvt_modify; |
@@ -906,7 +1057,8 @@ |
else |
{ |
manageCvt = mcvt_retain; |
- for ( i = 0; i < num_coords; ++i ) |
+ |
+ for ( i = 0; i < num_coords; i++ ) |
{ |
if ( blend->normalizedcoords[i] != coords[i] ) |
{ |
@@ -915,13 +1067,22 @@ |
} |
} |
+ for ( ; i < mmvar->num_axis; i++ ) |
+ { |
+ if ( blend->normalizedcoords[i] != 0 ) |
+ { |
+ manageCvt = mcvt_load; |
+ break; |
+ } |
+ } |
+ |
/* If we don't change the blend coords then we don't need to do */ |
/* anything to the cvt table. It will be correct. Otherwise we */ |
/* no longer have the original cvt (it was modified when we set */ |
/* the blend last time), so we must reload and then modify it. */ |
} |
- blend->num_axis = num_coords; |
+ blend->num_axis = mmvar->num_axis; |
FT_MEM_COPY( blend->normalizedcoords, |
coords, |
num_coords * sizeof ( FT_Fixed ) ); |
@@ -973,7 +1134,10 @@ |
/* Initialize the blend struct with `gvar' data. */ |
/* */ |
/* <Input> */ |
- /* num_coords :: This must be the axis count of the font. */ |
+ /* num_coords :: The number of available coordinates. If it is */ |
+ /* larger than the number of axes, ignore the excess */ |
+ /* values. If it is smaller than the number of axes, */ |
+ /* use the default values for the remaining axes. */ |
/* */ |
/* coords :: A coordinate array with `num_coords' elements. */ |
/* */ |
@@ -997,17 +1161,19 @@ |
if ( face->blend == NULL ) |
{ |
- if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) |
+ if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) |
goto Exit; |
} |
blend = face->blend; |
mmvar = blend->mmvar; |
- if ( num_coords != mmvar->num_axis ) |
+ if ( num_coords > mmvar->num_axis ) |
{ |
- error = FT_THROW( Invalid_Argument ); |
- goto Exit; |
+ FT_TRACE2(( "TT_Set_Var_Design:" |
+ " only using first %d of %d coordinates\n", |
+ mmvar->num_axis, num_coords )); |
+ num_coords = mmvar->num_axis; |
} |
/* Axis normalization is a two stage process. First we normalize */ |
@@ -1017,32 +1183,52 @@ |
if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) |
goto Exit; |
+ FT_TRACE5(( "design coordinates:\n" )); |
+ |
a = mmvar->axis; |
- for ( i = 0; i < mmvar->num_axis; ++i, ++a ) |
+ for ( i = 0; i < num_coords; i++, a++ ) |
{ |
+ FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); |
if ( coords[i] > a->maximum || coords[i] < a->minimum ) |
{ |
+ FT_TRACE1(( "TT_Set_Var_Design: normalized design coordinate %.4f\n" |
+ " is out of range [%.4f;%.4f]\n", |
+ coords[i] / 65536.0, |
+ a->minimum / 65536.0, |
+ a->maximum / 65536.0 )); |
error = FT_THROW( Invalid_Argument ); |
goto Exit; |
} |
if ( coords[i] < a->def ) |
- normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def ); |
+ normalized[i] = -FT_DivFix( coords[i] - a->def, |
+ a->minimum - a->def ); |
else if ( a->maximum == a->def ) |
normalized[i] = 0; |
else |
- normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def ); |
+ normalized[i] = FT_DivFix( coords[i] - a->def, |
+ a->maximum - a->def ); |
} |
+ FT_TRACE5(( "\n" )); |
+ |
+ for ( ; i < mmvar->num_axis; i++ ) |
+ normalized[i] = 0; |
+ |
if ( !blend->avar_checked ) |
ft_var_load_avar( face ); |
if ( blend->avar_segment != NULL ) |
{ |
+ FT_TRACE5(( "normalized design coordinates" |
+ " before applying `avar' data:\n" )); |
+ |
av = blend->avar_segment; |
- for ( i = 0; i < mmvar->num_axis; ++i, ++av ) |
+ for ( i = 0; i < mmvar->num_axis; i++, av++ ) |
{ |
- for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) |
+ for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) |
+ { |
+ FT_TRACE5(( " %.4f\n", normalized[i] / 65536.0 )); |
if ( normalized[i] < av->correspondence[j].fromCoord ) |
{ |
normalized[i] = |
@@ -1054,10 +1240,11 @@ |
av->correspondence[j - 1].toCoord; |
break; |
} |
+ } |
} |
} |
- error = TT_Set_MM_Blend( face, num_coords, normalized ); |
+ error = TT_Set_MM_Blend( face, mmvar->num_axis, normalized ); |
Exit: |
FT_FREE( normalized ); |
@@ -1120,16 +1307,16 @@ |
if ( blend == NULL ) |
{ |
- FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); |
- |
+ FT_TRACE2(( "\n" |
+ "tt_face_vary_cvt: no blend specified\n" )); |
error = FT_Err_Ok; |
goto Exit; |
} |
if ( face->cvt == NULL ) |
{ |
- FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); |
- |
+ FT_TRACE2(( "\n" |
+ "tt_face_vary_cvt: no `cvt ' table\n" )); |
error = FT_Err_Ok; |
goto Exit; |
} |
@@ -1158,6 +1345,8 @@ |
goto FExit; |
} |
+ FT_TRACE2(( "loaded\n" )); |
+ |
if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || |
FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || |
FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) |
@@ -1170,13 +1359,17 @@ |
/* tuplecount, but John Jenkins says that shared points don't apply */ |
/* to `cvar', and no other flags are defined. */ |
- for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) |
+ FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount )); |
+ |
+ for ( i = 0; i < ( tupleCount & 0xFFF ); i++ ) |
{ |
FT_UInt tupleDataSize; |
FT_UInt tupleIndex; |
FT_Fixed apply; |
+ FT_TRACE6(( " tuple %d:\n", i )); |
+ |
tupleDataSize = FT_GET_USHORT(); |
tupleIndex = FT_GET_USHORT(); |
@@ -1185,8 +1378,8 @@ |
if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) |
{ |
- for ( j = 0; j < blend->num_axis; ++j ) |
- tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ |
/* short frac to fixed */ |
} |
else |
@@ -1194,7 +1387,7 @@ |
/* skip this tuple; it makes no sense */ |
if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
- for ( j = 0; j < 2 * blend->num_axis; ++j ) |
+ for ( j = 0; j < 2 * blend->num_axis; j++ ) |
(void)FT_GET_SHORT(); |
offsetToData += tupleDataSize; |
@@ -1203,10 +1396,10 @@ |
if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
{ |
- for ( j = 0; j < blend->num_axis; ++j ) |
- im_start_coords[j] = FT_GET_SHORT() << 2; |
- for ( j = 0; j < blend->num_axis; ++j ) |
- im_end_coords[j] = FT_GET_SHORT() << 2; |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ im_start_coords[j] = FT_GET_SHORT() * 4; |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ im_end_coords[j] = FT_GET_SHORT() * 4; |
} |
apply = ft_var_apply_tuple( blend, |
@@ -1233,25 +1426,74 @@ |
point_count == 0 ? face->cvt_size |
: point_count ); |
if ( localpoints == NULL || deltas == NULL ) |
- /* failure, ignore it */; |
+ ; /* failure, ignore it */ |
else if ( localpoints == ALL_POINTS ) |
{ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ int count = 0; |
+#endif |
+ |
+ |
+ FT_TRACE7(( " CVT deltas:\n" )); |
+ |
/* this means that there are deltas for every entry in cvt */ |
- for ( j = 0; j < face->cvt_size; ++j ) |
- face->cvt[j] = (FT_Short)( face->cvt[j] + |
+ for ( j = 0; j < face->cvt_size; j++ ) |
+ { |
+ FT_Long orig_cvt = face->cvt[j]; |
+ |
+ |
+ face->cvt[j] = (FT_Short)( orig_cvt + |
FT_MulFix( deltas[j], apply ) ); |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( orig_cvt != face->cvt[j] ) |
+ { |
+ FT_TRACE7(( " %d: %d -> %d\n", |
+ j, orig_cvt, face->cvt[j] )); |
+ count++; |
+ } |
+#endif |
+ } |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( !count ) |
+ FT_TRACE7(( " none\n" )); |
+#endif |
} |
else |
{ |
- for ( j = 0; j < point_count; ++j ) |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ int count = 0; |
+#endif |
+ |
+ |
+ FT_TRACE7(( " CVT deltas:\n" )); |
+ |
+ for ( j = 0; j < point_count; j++ ) |
{ |
- int pindex = localpoints[j]; |
+ int pindex = localpoints[j]; |
+ FT_Long orig_cvt = face->cvt[pindex]; |
+ |
- face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + |
+ face->cvt[pindex] = (FT_Short)( orig_cvt + |
FT_MulFix( deltas[j], apply ) ); |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( orig_cvt != face->cvt[pindex] ) |
+ { |
+ FT_TRACE7(( " %d: %d -> %d\n", |
+ pindex, orig_cvt, face->cvt[pindex] )); |
+ count++; |
+ } |
+#endif |
} |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( !count ) |
+ FT_TRACE7(( " none\n" )); |
+#endif |
} |
if ( localpoints != ALL_POINTS ) |
@@ -1263,6 +1505,8 @@ |
FT_Stream_SeekSet( stream, here ); |
} |
+ FT_TRACE5(( "\n" )); |
+ |
FExit: |
FT_FRAME_EXIT(); |
@@ -1275,13 +1519,230 @@ |
} |
+ /* Shift the original coordinates of all points between indices `p1' */ |
+ /* and `p2', using the same difference as given by index `ref'. */ |
+ |
+ /* modeled after `af_iup_shift' */ |
+ |
+ static void |
+ tt_delta_shift( int p1, |
+ int p2, |
+ int ref, |
+ FT_Vector* in_points, |
+ FT_Vector* out_points ) |
+ { |
+ int p; |
+ FT_Vector delta; |
+ |
+ |
+ delta.x = out_points[ref].x - in_points[ref].x; |
+ delta.y = out_points[ref].y - in_points[ref].y; |
+ |
+ if ( delta.x == 0 && delta.y == 0 ) |
+ return; |
+ |
+ for ( p = p1; p < ref; p++ ) |
+ { |
+ out_points[p].x += delta.x; |
+ out_points[p].y += delta.y; |
+ } |
+ |
+ for ( p = ref + 1; p <= p2; p++ ) |
+ { |
+ out_points[p].x += delta.x; |
+ out_points[p].y += delta.y; |
+ } |
+ } |
+ |
+ |
+ /* Interpolate the original coordinates of all points with indices */ |
+ /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ |
+ /* point indices. */ |
+ |
+ /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ |
+ /* `Ins_IUP' */ |
+ |
+ static void |
+ tt_delta_interpolate( int p1, |
+ int p2, |
+ int ref1, |
+ int ref2, |
+ FT_Vector* in_points, |
+ FT_Vector* out_points ) |
+ { |
+ int p, i; |
+ |
+ FT_Pos out, in1, in2, out1, out2, d1, d2; |
+ |
+ |
+ if ( p1 > p2 ) |
+ return; |
+ |
+ /* handle both horizontal and vertical coordinates */ |
+ for ( i = 0; i <= 1; i++ ) |
+ { |
+ /* shift array pointers so that we can access `foo.y' as `foo.x' */ |
+ in_points = (FT_Vector*)( (FT_Pos*)in_points + i ); |
+ out_points = (FT_Vector*)( (FT_Pos*)out_points + i ); |
+ |
+ if ( in_points[ref1].x > in_points[ref2].x ) |
+ { |
+ p = ref1; |
+ ref1 = ref2; |
+ ref2 = p; |
+ } |
+ |
+ in1 = in_points[ref1].x; |
+ in2 = in_points[ref2].x; |
+ out1 = out_points[ref1].x; |
+ out2 = out_points[ref2].x; |
+ d1 = out1 - in1; |
+ d2 = out2 - in2; |
+ |
+ if ( out1 == out2 || in1 == in2 ) |
+ { |
+ for ( p = p1; p <= p2; p++ ) |
+ { |
+ out = in_points[p].x; |
+ |
+ if ( out <= in1 ) |
+ out += d1; |
+ else if ( out >= in2 ) |
+ out += d2; |
+ else |
+ out = out1; |
+ |
+ out_points[p].x = out; |
+ } |
+ } |
+ else |
+ { |
+ FT_Fixed scale = FT_DivFix( out2 - out1, in2 - in1 ); |
+ |
+ |
+ for ( p = p1; p <= p2; p++ ) |
+ { |
+ out = in_points[p].x; |
+ |
+ if ( out <= in1 ) |
+ out += d1; |
+ else if ( out >= in2 ) |
+ out += d2; |
+ else |
+ out = out1 + FT_MulFix( out - in1, scale ); |
+ |
+ out_points[p].x = out; |
+ } |
+ } |
+ } |
+ } |
+ |
+ |
+ /* Interpolate points without delta values, similar to */ |
+ /* the `IUP' hinting instruction. */ |
+ |
+ /* modeled after `Ins_IUP */ |
+ |
+ static void |
+ tt_handle_deltas( FT_Outline* outline, |
+ FT_Vector* in_points, |
+ FT_Bool* has_delta ) |
+ { |
+ FT_Vector* out_points; |
+ |
+ FT_Int first_point; |
+ FT_Int end_point; |
+ |
+ FT_Int first_delta; |
+ FT_Int cur_delta; |
+ |
+ FT_Int point; |
+ FT_Short contour; |
+ |
+ |
+ /* ignore empty outlines */ |
+ if ( !outline->n_contours ) |
+ return; |
+ |
+ out_points = outline->points; |
+ |
+ contour = 0; |
+ point = 0; |
+ |
+ do |
+ { |
+ end_point = outline->contours[contour]; |
+ first_point = point; |
+ |
+ /* search first point that has a delta */ |
+ while ( point <= end_point && !has_delta[point] ) |
+ point++; |
+ |
+ if ( point <= end_point ) |
+ { |
+ first_delta = point; |
+ cur_delta = point; |
+ |
+ point++; |
+ |
+ while ( point <= end_point ) |
+ { |
+ /* search next point that has a delta */ |
+ /* and interpolate intermediate points */ |
+ if ( has_delta[point] ) |
+ { |
+ tt_delta_interpolate( cur_delta + 1, |
+ point - 1, |
+ cur_delta, |
+ point, |
+ in_points, |
+ out_points ); |
+ cur_delta = point; |
+ } |
+ |
+ point++; |
+ } |
+ |
+ /* shift contour if we only have a single delta */ |
+ if ( cur_delta == first_delta ) |
+ tt_delta_shift( first_point, |
+ end_point, |
+ cur_delta, |
+ in_points, |
+ out_points ); |
+ else |
+ { |
+ /* otherwise handle remaining points */ |
+ /* at the end and beginning of the contour */ |
+ tt_delta_interpolate( cur_delta + 1, |
+ end_point, |
+ cur_delta, |
+ first_delta, |
+ in_points, |
+ out_points ); |
+ |
+ if ( first_delta > 0 ) |
+ tt_delta_interpolate( first_point, |
+ first_delta - 1, |
+ cur_delta, |
+ first_delta, |
+ in_points, |
+ out_points ); |
+ } |
+ } |
+ contour++; |
+ |
+ } while ( contour < outline->n_contours ); |
+ } |
+ |
+ |
/*************************************************************************/ |
/* */ |
/* <Function> */ |
- /* TT_Vary_Get_Glyph_Deltas */ |
+ /* TT_Vary_Apply_Glyph_Deltas */ |
/* */ |
/* <Description> */ |
- /* Load the appropriate deltas for the current glyph. */ |
+ /* Apply the appropriate deltas to the current glyph. */ |
/* */ |
/* <Input> */ |
/* face :: A handle to the target face object. */ |
@@ -1291,22 +1752,24 @@ |
/* n_points :: The number of the points in the glyph, including */ |
/* phantom points. */ |
/* */ |
- /* <Output> */ |
- /* deltas :: The array of points to change. */ |
+ /* <InOut> */ |
+ /* outline :: The outline to change. */ |
/* */ |
/* <Return> */ |
/* FreeType error code. 0 means success. */ |
/* */ |
FT_LOCAL_DEF( FT_Error ) |
- TT_Vary_Get_Glyph_Deltas( TT_Face face, |
- FT_UInt glyph_index, |
- FT_Vector* *deltas, |
- FT_UInt n_points ) |
+ TT_Vary_Apply_Glyph_Deltas( TT_Face face, |
+ FT_UInt glyph_index, |
+ FT_Outline* outline, |
+ FT_UInt n_points ) |
{ |
FT_Stream stream = face->root.stream; |
FT_Memory memory = stream->memory; |
GX_Blend blend = face->blend; |
- FT_Vector* delta_xy = NULL; |
+ |
+ FT_Vector* points_org = NULL; |
+ FT_Bool* has_delta = NULL; |
FT_Error error; |
FT_ULong glyph_start; |
@@ -1327,15 +1790,18 @@ |
if ( !face->doblend || blend == NULL ) |
return FT_THROW( Invalid_Argument ); |
- /* to be freed by the caller */ |
- if ( FT_NEW_ARRAY( delta_xy, n_points ) ) |
- goto Exit; |
- *deltas = delta_xy; |
- |
if ( glyph_index >= blend->gv_glyphcnt || |
blend->glyphoffsets[glyph_index] == |
blend->glyphoffsets[glyph_index + 1] ) |
- return FT_Err_Ok; /* no variation data for this glyph */ |
+ { |
+ FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" |
+ " no variation data for this glyph\n" )); |
+ return FT_Err_Ok; |
+ } |
+ |
+ if ( FT_NEW_ARRAY( points_org, n_points ) || |
+ FT_NEW_ARRAY( has_delta, n_points ) ) |
+ goto Fail1; |
if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || |
FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - |
@@ -1367,41 +1833,43 @@ |
FT_Stream_SeekSet( stream, here ); |
} |
- for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) |
+ FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount )); |
+ |
+ for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) |
{ |
FT_UInt tupleDataSize; |
FT_UInt tupleIndex; |
FT_Fixed apply; |
+ FT_TRACE6(( " tuple %d:\n", i )); |
+ |
tupleDataSize = FT_GET_USHORT(); |
tupleIndex = FT_GET_USHORT(); |
if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) |
{ |
- for ( j = 0; j < blend->num_axis; ++j ) |
- tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ |
/* short frac to fixed */ |
} |
else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) |
{ |
error = FT_THROW( Invalid_Table ); |
- goto Fail3; |
+ goto Fail2; |
} |
else |
- { |
FT_MEM_COPY( |
tuple_coords, |
- &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], |
+ &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], |
blend->num_axis * sizeof ( FT_Fixed ) ); |
- } |
if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
{ |
- for ( j = 0; j < blend->num_axis; ++j ) |
- im_start_coords[j] = FT_GET_SHORT() << 2; |
- for ( j = 0; j < blend->num_axis; ++j ) |
- im_end_coords[j] = FT_GET_SHORT() << 2; |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ im_start_coords[j] = FT_GET_SHORT() * 4; |
+ for ( j = 0; j < blend->num_axis; j++ ) |
+ im_end_coords[j] = FT_GET_SHORT() * 4; |
} |
apply = ft_var_apply_tuple( blend, |
@@ -1443,24 +1911,101 @@ |
else if ( points == ALL_POINTS ) |
{ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ int count = 0; |
+#endif |
+ |
+ |
+ FT_TRACE7(( " point deltas:\n" )); |
+ |
/* this means that there are deltas for every point in the glyph */ |
- for ( j = 0; j < n_points; ++j ) |
+ for ( j = 0; j < n_points; j++ ) |
{ |
- delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); |
- delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ FT_Vector point_org = outline->points[j]; |
+#endif |
+ |
+ |
+ outline->points[j].x += FT_MulFix( deltas_x[j], apply ); |
+ outline->points[j].y += FT_MulFix( deltas_y[j], apply ); |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( ( point_org.x != outline->points[j].x ) || |
+ ( point_org.y != outline->points[j].y ) ) |
+ { |
+ FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", |
+ j, |
+ point_org.x, |
+ point_org.y, |
+ outline->points[j].x, |
+ outline->points[j].y )); |
+ count++; |
+ } |
+#endif |
} |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ if ( !count ) |
+ FT_TRACE7(( " none\n" )); |
+#endif |
} |
else |
{ |
- for ( j = 0; j < point_count; ++j ) |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ int count = 0; |
+#endif |
+ |
+ |
+ /* we have to interpolate the missing deltas similar to the */ |
+ /* IUP bytecode instruction */ |
+ for ( j = 0; j < n_points; j++ ) |
+ { |
+ points_org[j] = outline->points[j]; |
+ has_delta[j] = FALSE; |
+ } |
+ |
+ for ( j = 0; j < point_count; j++ ) |
{ |
- if ( localpoints[j] >= n_points ) |
+ FT_UShort idx = localpoints[j]; |
+ |
+ |
+ if ( idx >= n_points ) |
continue; |
- delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); |
- delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); |
+ has_delta[idx] = TRUE; |
+ |
+ outline->points[idx].x += FT_MulFix( deltas_x[j], apply ); |
+ outline->points[idx].y += FT_MulFix( deltas_y[j], apply ); |
} |
+ |
+ /* no need to handle phantom points here, */ |
+ /* since solitary points can't be interpolated */ |
+ tt_handle_deltas( outline, |
+ points_org, |
+ has_delta ); |
+ |
+#ifdef FT_DEBUG_LEVEL_TRACE |
+ FT_TRACE7(( " point deltas:\n" )); |
+ |
+ for ( j = 0; j < n_points; j++) |
+ { |
+ if ( ( points_org[j].x != outline->points[j].x ) || |
+ ( points_org[j].y != outline->points[j].y ) ) |
+ { |
+ FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", |
+ j, |
+ points_org[j].x, |
+ points_org[j].y, |
+ outline->points[j].x, |
+ outline->points[j].y )); |
+ count++; |
+ } |
+ } |
+ |
+ if ( !count ) |
+ FT_TRACE7(( " none\n" )); |
+#endif |
} |
if ( localpoints != ALL_POINTS ) |
@@ -1473,22 +2018,19 @@ |
FT_Stream_SeekSet( stream, here ); |
} |
- Fail3: |
+ FT_TRACE5(( "\n" )); |
+ |
+ Fail2: |
FT_FREE( tuple_coords ); |
FT_FREE( im_start_coords ); |
FT_FREE( im_end_coords ); |
- Fail2: |
FT_FRAME_EXIT(); |
Fail1: |
- if ( error ) |
- { |
- FT_FREE( delta_xy ); |
- *deltas = NULL; |
- } |
+ FT_FREE( points_org ); |
+ FT_FREE( has_delta ); |
- Exit: |
return error; |
} |
@@ -1499,7 +2041,7 @@ |
/* tt_done_blend */ |
/* */ |
/* <Description> */ |
- /* Frees the blend internal data structure. */ |
+ /* Free the blend internal data structure. */ |
/* */ |
FT_LOCAL_DEF( void ) |
tt_done_blend( FT_Memory memory, |
@@ -1515,7 +2057,7 @@ |
if ( blend->avar_segment != NULL ) |
{ |
- for ( i = 0; i < blend->num_axis; ++i ) |
+ for ( i = 0; i < blend->num_axis; i++ ) |
FT_FREE( blend->avar_segment[i].correspondence ); |
FT_FREE( blend->avar_segment ); |
} |