summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Arnold <darnold@adobe.com>2016-09-14 01:14:29 +0200
committerWerner Lemberg <wl@gnu.org>2016-09-14 01:14:29 +0200
commitd1908a107d46388bc5ddcd657fe739181f73a3ac (patch)
tree9077900fa8958fa5143e126538517cb3d386e3b8
parent053943a757dda08a4df9f5fa934f59fb9dab80c1 (diff)
downloadfreetype2-d1908a107d46388bc5ddcd657fe739181f73a3ac.tar.gz
Preliminary OpenType 1.8 support.
-rw-r--r--README9
-rw-r--r--include/freetype/ftmm.h10
-rw-r--r--include/freetype/internal/fttrace.h1
-rw-r--r--include/freetype/internal/services/svmm.h25
-rw-r--r--include/freetype/internal/tttypes.h1
-rw-r--r--include/freetype/tttags.h2
-rw-r--r--src/base/ftmm.c55
-rw-r--r--src/cff/cf2fixed.h4
-rw-r--r--src/cff/cf2font.c192
-rw-r--r--src/cff/cf2font.h10
-rw-r--r--src/cff/cf2ft.c41
-rw-r--r--src/cff/cf2ft.h8
-rw-r--r--src/cff/cf2intrp.c40
-rw-r--r--src/cff/cf2stack.c28
-rw-r--r--src/cff/cf2stack.h9
-rw-r--r--src/cff/cffdrivr.c32
-rw-r--r--src/cff/cffload.c176
-rw-r--r--src/cff/cffload.h3
-rw-r--r--src/cff/cffobjs.c23
-rw-r--r--src/cff/cffparse.c50
-rw-r--r--src/cff/cffparse.h3
-rw-r--r--src/cff/cffpic.h1
-rw-r--r--src/cff/cfftoken.h4
-rw-r--r--src/cff/cfftypes.h39
-rw-r--r--src/sfnt/sfobjs.c9
-rw-r--r--src/sfnt/ttmtx.c10
-rw-r--r--src/truetype/ttdriver.c4
-rw-r--r--src/truetype/ttgxvar.c537
-rw-r--r--src/truetype/ttgxvar.h82
29 files changed, 1364 insertions, 44 deletions
diff --git a/README b/README
index 23c10abb1..1a975e69b 100644
--- a/README
+++ b/README
@@ -1,3 +1,12 @@
+ Branch of FreeType to support OpenType 1.8
+ ==========================================
+
+ This branch contains changes for supporting OpenType 1.8.
+ The changes will be merged back upstream in September 2016,
+ when the specification for OpenType 1.8 is final and has
+ been published.
+
+
FreeType 2.6.5
==============
diff --git a/include/freetype/ftmm.h b/include/freetype/ftmm.h
index 6c05f0c39..c447f1cce 100644
--- a/include/freetype/ftmm.h
+++ b/include/freetype/ftmm.h
@@ -171,6 +171,7 @@ FT_BEGIN_HEADER
{
FT_Fixed* coords;
FT_UInt strid;
+ FT_UInt psid;
} FT_Var_Named_Style;
@@ -329,6 +330,10 @@ FT_BEGIN_HEADER
FT_UInt num_coords,
FT_Fixed* coords );
+ FT_EXPORT( FT_Error )
+ FT_Get_Var_Design_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
/*************************************************************************/
/* */
@@ -375,6 +380,11 @@ FT_BEGIN_HEADER
/* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Var_Blend_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
FT_END_HEADER
diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h
index efb335595..54ca595bb 100644
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -90,6 +90,7 @@ FT_TRACE_DEF( cffparse )
FT_TRACE_DEF( cf2blues )
FT_TRACE_DEF( cf2hints )
+FT_TRACE_DEF( cf2font )
FT_TRACE_DEF( cf2interp )
/* Type 42 driver component */
diff --git a/include/freetype/internal/services/svmm.h b/include/freetype/internal/services/svmm.h
index b78a19f8e..6a1254d00 100644
--- a/include/freetype/internal/services/svmm.h
+++ b/include/freetype/internal/services/svmm.h
@@ -58,6 +58,16 @@ FT_BEGIN_HEADER
FT_UInt num_coords,
FT_Long* coords );
+ typedef FT_Error
+ (*FT_Get_Var_Design_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+ typedef FT_Error
+ (*FT_Get_Var_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
FT_DEFINE_SERVICE( MultiMasters )
{
@@ -66,6 +76,8 @@ FT_BEGIN_HEADER
FT_Set_MM_Blend_Func set_mm_blend;
FT_Get_MM_Var_Func get_mm_var;
FT_Set_Var_Design_Func set_var_design;
+ FT_Get_Var_Design_Func get_var_design;
+ FT_Get_Var_Blend_Func get_var_blend;
};
@@ -76,10 +88,13 @@ FT_BEGIN_HEADER
set_mm_design_, \
set_mm_blend_, \
get_mm_var_, \
- set_var_design_ ) \
+ set_var_design_, \
+ get_var_design_, \
+ get_var_blend_ ) \
static const FT_Service_MultiMastersRec class_ = \
{ \
- get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \
+ get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_, \
+ get_var_design_, get_var_blend_ \
};
#else /* FT_CONFIG_OPTION_PIC */
@@ -89,7 +104,9 @@ FT_BEGIN_HEADER
set_mm_design_, \
set_mm_blend_, \
get_mm_var_, \
- set_var_design_ ) \
+ set_var_design_, \
+ get_var_design_, \
+ get_var_blend_ ) \
void \
FT_Init_Class_ ## class_( FT_Service_MultiMastersRec* clazz ) \
{ \
@@ -98,6 +115,8 @@ FT_BEGIN_HEADER
clazz->set_mm_blend = set_mm_blend_; \
clazz->get_mm_var = get_mm_var_; \
clazz->set_var_design = set_var_design_; \
+ clazz->get_var_design = get_var_design_; \
+ clazz->get_var_blend = get_var_blend_; \
}
#endif /* FT_CONFIG_OPTION_PIC */
diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h
index 4110d5028..efade9547 100644
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1346,6 +1346,7 @@ FT_BEGIN_HEADER
FT_ULong glyf_len;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ FT_Bool isCFF2;
FT_Bool doblend;
GX_Blend blend;
#endif
diff --git a/include/freetype/tttags.h b/include/freetype/tttags.h
index f3c9aa5fc..49eecd2e9 100644
--- a/include/freetype/tttags.h
+++ b/include/freetype/tttags.h
@@ -43,6 +43,7 @@ FT_BEGIN_HEADER
#define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' )
#define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' )
#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' )
+#define TTAG_CFF2 FT_MAKE_TAG( 'C', 'F', 'F', '2' )
#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' )
#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' )
@@ -61,6 +62,7 @@ FT_BEGIN_HEADER
#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' )
+#define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' )
#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' )
#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' )
#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' )
diff --git a/src/base/ftmm.c b/src/base/ftmm.c
index 6b759ca46..b6bc3c506 100644
--- a/src/base/ftmm.c
+++ b/src/base/ftmm.c
@@ -175,6 +175,34 @@
/* documentation is in ftmm.h */
FT_EXPORT_DEF( FT_Error )
+ FT_Get_Var_Design_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error;
+ FT_Service_MultiMasters service;
+
+
+ /* check of `face' delayed to `ft_face_get_mm_service' */
+
+ if ( !coords )
+ return FT_THROW( Invalid_Argument );
+
+ error = ft_face_get_mm_service( face, &service );
+ if ( !error )
+ {
+ error = FT_ERR( Invalid_Argument );
+ if ( service->get_var_design )
+ error = service->get_var_design( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Blend_Coordinates( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords )
@@ -230,5 +258,32 @@
return error;
}
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Var_Blend_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error;
+ FT_Service_MultiMasters service;
+
+
+ /* check of `face' delayed to `ft_face_get_mm_service' */
+
+ if ( !coords )
+ return FT_THROW( Invalid_Argument );
+
+ error = ft_face_get_mm_service( face, &service );
+ if ( !error )
+ {
+ error = FT_ERR( Invalid_Argument );
+ if ( service->get_var_blend )
+ error = service->get_var_blend( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
/* END */
diff --git a/src/cff/cf2fixed.h b/src/cff/cf2fixed.h
index 74af37708..2e4b5032f 100644
--- a/src/cff/cf2fixed.h
+++ b/src/cff/cf2fixed.h
@@ -51,8 +51,8 @@ FT_BEGIN_HEADER
#define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL )
#define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L )
-#define CF2_FIXED_ONE 0x10000L
-#define CF2_FIXED_EPSILON 0x0001
+#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L )
+#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 )
/* in C 89, left and right shift of negative numbers is */
/* implementation specific behaviour in the general case */
diff --git a/src/cff/cf2font.c b/src/cff/cf2font.c
index 83fd348f2..9fd1531a4 100644
--- a/src/cff/cf2font.c
+++ b/src/cff/cf2font.c
@@ -38,6 +38,7 @@
#include <ft2build.h>
#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_DEBUG_H
#include "cf2ft.h"
@@ -46,6 +47,8 @@
#include "cf2error.h"
#include "cf2intrp.h"
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cf2font
/* Compute a stem darkening amount in character space. */
static void
@@ -233,25 +236,155 @@
*darkenAmount += boldenAmount / 2;
}
+ /* compute a blend vector from variation store index and normalized vector */
+ /* return size of blend vector and allocated storage for it */
+ /* caller must free this */
+ /* lenNormalizedVector == 0 produces a default blend vector */
+ /* Note: normalizedVector uses FT_Fixed, not CF2_Fixed */
+ static void
+ cf2_buildBlendVector( CF2_Font font, CF2_UInt vsindex,
+ CF2_UInt lenNormalizedVector, FT_Fixed * normalizedVector,
+ CF2_UInt * lenBlendVector, CF2_Fixed ** blendVector )
+ {
+ FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
+ FT_Memory memory = font->memory; /* for FT_REALLOC */
+ CF2_UInt len;
+ CFF_VStore vs;
+ CFF_VarData* varData;
+ CF2_UInt master;
+
+ FT_UNUSED( lenNormalizedVector );
+ FT_UNUSED( vsindex );
+
+ FT_ASSERT( lenBlendVector && blendVector );
+ FT_ASSERT( lenNormalizedVector == 0 || normalizedVector );
+ FT_TRACE4(( "cf2_buildBlendVector\n" ));
+
+ vs = cf2_getVStore( font->decoder );
+
+ /* VStore and fvar must be consistent */
+ if ( lenNormalizedVector != 0 && lenNormalizedVector != vs->axisCount )
+ {
+ FT_TRACE4(( "cf2_buildBlendVector: Axis count mismatch\n" ));
+ CF2_SET_ERROR( &font->error, Invalid_File_Format );
+ goto Exit;
+ }
+ if ( vsindex >= vs->dataCount )
+ {
+ FT_TRACE4(( "cf2_buildBlendVector: vsindex out of range\n" ));
+ CF2_SET_ERROR( &font->error, Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* select the item variation data structure */
+ varData = &vs->varData[vsindex];
+
+ /* prepare an output buffer for the blend vector */
+ len = varData->regionIdxCount + 1; /* add 1 for default */
+ if ( FT_REALLOC( *blendVector, *lenBlendVector, len * sizeof( **blendVector )) )
+ return;
+ *lenBlendVector = len;
+
+ /* outer loop steps through master designs to be blended */
+ for ( master=0; master<len; master++ )
+ {
+ CF2_UInt j;
+ CF2_UInt idx;
+ CFF_VarRegion* varRegion;
+
+ /* default factor is always one */
+ if ( master == 0 )
+ {
+ *blendVector[master] = CF2_FIXED_ONE;
+ FT_TRACE4(( "blend vector len %d\n [ %f ", len, (double)(*blendVector)[master] / 65536 ));
+ continue;
+ }
+
+ /* VStore array does not include default master, so subtract one */
+ idx = varData->regionIndices[master-1];
+ varRegion = &vs->varRegionList[idx];
+
+ if ( idx >= vs->regionCount )
+ {
+ FT_TRACE4(( "cf2_buildBlendVector: region index out of range\n" ));
+ CF2_SET_ERROR( &font->error, Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Note: lenNormalizedVector could be zero */
+ /* In that case, build default blend vector */
+ if ( lenNormalizedVector != 0 )
+ (*blendVector)[master] = CF2_FIXED_ONE; /* default */
+
+ /* inner loop steps through axes in this region */
+ for ( j=0; j<lenNormalizedVector; j++ )
+ {
+ CFF_AxisCoords* axis = &varRegion->axisList[j];
+ CF2_Fixed axisScalar;
+
+ /* compute the scalar contribution of this axis */
+ /* ignore invalid ranges */
+ if ( axis->startCoord > axis->peakCoord || axis->peakCoord > axis->endCoord )
+ axisScalar = CF2_FIXED_ONE;
+ else if ( axis->startCoord < 0 && axis->endCoord > 0 && axis->peakCoord != 0 )
+ axisScalar = CF2_FIXED_ONE;
+ /* peak of 0 means ignore this axis */
+ else if ( axis->peakCoord == 0 )
+ axisScalar = CF2_FIXED_ONE;
+ /* ignore this region if coords are out of range */
+ else if ( normalizedVector[j] < axis->startCoord || normalizedVector[j] > axis->endCoord )
+ axisScalar = 0;
+ /* calculate a proportional factor */
+ else
+ {
+ if ( normalizedVector[j] == axis->peakCoord )
+ axisScalar = CF2_FIXED_ONE;
+ else if ( normalizedVector[j] < axis->peakCoord )
+ axisScalar = FT_DivFix( normalizedVector[j] - axis->startCoord,
+ axis->peakCoord - axis->startCoord );
+ else
+ axisScalar = FT_DivFix( axis->endCoord - normalizedVector[j],
+ axis->endCoord - axis->peakCoord );
+ }
+ /* take product of all the axis scalars */
+ (*blendVector)[master] = FT_MulFix( (*blendVector)[master], axisScalar );
+ }
+ FT_TRACE4(( ", %f ", (double)(*blendVector)[master] / 65536 ));
+ }
+ FT_TRACE4(( "]\n" ));
+
+ Exit:
+ return;
+ }
+
/* set up values for the current FontDict and matrix */
+ /* called for each glyph to be rendered */
/* caller's transform is adjusted for subpixel positioning */
static void
cf2_font_setup( CF2_Font font,
const CF2_Matrix* transform )
{
+ FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
+ FT_Memory memory = font->memory; /* for FT_REALLOC */
+
/* pointer to parsed font object */
CFF_Decoder* decoder = font->decoder;
FT_Bool needExtraSetup = FALSE;
+ CFF_VStoreRec* vstore;
+ FT_Bool hasVariations = FALSE;
+
/* character space units */
CF2_Fixed boldenX = font->syntheticEmboldeningAmountX;
CF2_Fixed boldenY = font->syntheticEmboldeningAmountY;
CFF_SubFont subFont;
CF2_Fixed ppem;
+ CF2_UInt lenNormalizedV = 0;
+ FT_Fixed * normalizedV = NULL;
/* clear previous error */
@@ -266,6 +399,33 @@
needExtraSetup = TRUE;
}
+ /* check for variation vectors */
+ vstore = cf2_getVStore( decoder );
+ hasVariations = ( vstore->dataCount != 0 );
+
+ if ( hasVariations )
+ {
+ if ( font->lenBlendVector == 0 )
+ needExtraSetup = TRUE; /* a blend vector is required */
+
+ /* Note: lenNormalizedVector is zero until FT_Get_MM_Var() is called */
+ cf2_getNormalizedVector( decoder, &lenNormalizedV, &normalizedV );
+
+ /* determine if blend vector needs to be recomputed */
+ if ( font->lastVsindex != subFont->font_dict.vsindex ||
+ lenNormalizedV == 0 ||
+ font->lenNormalizedVector != lenNormalizedV ||
+ ( lenNormalizedV &&
+ memcmp( normalizedV,
+ &font->lastNormalizedVector,
+ lenNormalizedV * sizeof( *normalizedV ) ) != 0 ) )
+ {
+ font->lastVsindex = subFont->font_dict.vsindex;
+ /* vectors will be copied below, during ExtraSetup */
+ needExtraSetup = TRUE;
+ }
+ }
+
/* if ppem has changed, we need to recompute some cached data */
/* note: because of CID font matrix concatenation, ppem and transform */
/* do not necessarily track. */
@@ -423,7 +583,37 @@
/* compute blue zones for this instance */
cf2_blues_init( &font->blues, font );
- }
+
+ /* copy normalized vector used to compute blend vector */
+ if ( hasVariations )
+ {
+ /* if user has set a normalized vector, use it */
+ /* otherwise, assume default */
+ if ( lenNormalizedV != 0 )
+ {
+ /* user has set a normalized vector */
+ if ( FT_REALLOC( font->lastNormalizedVector,
+ font->lenNormalizedVector,
+ lenNormalizedV * sizeof( *normalizedV )) )
+ {
+ CF2_SET_ERROR( &font->error, Out_Of_Memory );
+ return;
+ }
+ font->lenNormalizedVector = lenNormalizedV;
+ FT_MEM_COPY( font->lastNormalizedVector,
+ normalizedV,
+ lenNormalizedV * sizeof( *normalizedV ));
+ }
+
+ /* build blend vector for this instance */
+ cf2_buildBlendVector( font, font->lastVsindex,
+ font->lenNormalizedVector,
+ font->lastNormalizedVector,
+ &font->lenBlendVector,
+ &font->blendVector );
+ }
+
+ } /* needExtraSetup */
}
diff --git a/src/cff/cf2font.h b/src/cff/cf2font.h
index bd05e69e7..a6fa31076 100644
--- a/src/cff/cf2font.h
+++ b/src/cff/cf2font.h
@@ -47,7 +47,7 @@
FT_BEGIN_HEADER
-#define CF2_OPERAND_STACK_SIZE 48
+#define CF2_OPERAND_STACK_SIZE 193/* TODO: this is temporary for CFF2 */
#define CF2_MAX_SUBR 16 /* maximum subroutine nesting; */
/* only 10 are allowed but there exist */
/* fonts like `HiraKakuProN-W3.ttf' */
@@ -63,6 +63,7 @@ FT_BEGIN_HEADER
FT_Memory memory;
FT_Error error; /* shared error for this instance */
+ FT_Bool isCFF2;
CF2_RenderingFlags renderingFlags;
/* variables that depend on Transform: */
@@ -74,6 +75,13 @@ FT_BEGIN_HEADER
CF2_Matrix outerTransform; /* post hinting; includes rotations */
CF2_Fixed ppem; /* transform-dependent */
+ /* variation data */
+ CF2_UInt lastVsindex; /* last vsindex used */
+ CF2_UInt lenNormalizedVector; /* normDV length (aka numAxes) */
+ FT_Fixed * lastNormalizedVector;/* last normDV used */
+ CF2_UInt lenBlendVector; /* blendV length (aka numMasters) */
+ CF2_Fixed * blendVector; /* current blendV (per glyph) */
+
CF2_Int unitsPerEm;
CF2_Fixed syntheticEmboldeningAmountX; /* character space units */
diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c
index 55f3206ac..3f8334f5f 100644
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -102,9 +102,10 @@
if ( font )
{
FT_Memory memory = font->memory;
-
-
(void)memory;
+
+ FT_FREE( font->lastNormalizedVector );
+ FT_FREE( font->blendVector );
}
}
@@ -366,6 +367,9 @@
&hinted,
&scaled );
+ /* copy isCFF2 boolean from TT_Face to CF2_Font */
+ font->isCFF2 = builder->face->isCFF2;
+
font->renderingFlags = 0;
if ( hinted )
font->renderingFlags |= CF2_FlagsHinted;
@@ -412,6 +416,39 @@
return decoder->current_subfont;
}
+ /* get pointer to VStore structure */
+ FT_LOCAL_DEF( CFF_VStore )
+ cf2_getVStore( CFF_Decoder* decoder )
+ {
+ FT_ASSERT( decoder && decoder->cff );
+
+ return &decoder->cff->vstore;
+ }
+
+ /* get normalized design vector for current render request */
+ /* returns pointer and length */
+ /* if blend struct is not initialized, return length zero */
+ /* Note: use FT_Fixed not CF2_Fixed for the vector */
+ FT_LOCAL_DEF( void )
+ cf2_getNormalizedVector( CFF_Decoder* decoder, CF2_UInt * len, FT_Fixed ** vec )
+ {
+ GX_Blend blend;
+
+ FT_ASSERT( decoder && decoder->builder.face );
+ FT_ASSERT( vec && len );
+
+ blend = decoder->builder.face->blend;
+ if ( blend )
+ {
+ *vec = blend->normalizedcoords;
+ *len = blend->num_axis;
+ }
+ else
+ {
+ *vec = NULL;
+ *len = 0;
+ }
+ }
/* get `y_ppem' from `CFF_Size' */
FT_LOCAL_DEF( CF2_Fixed )
diff --git a/src/cff/cf2ft.h b/src/cff/cf2ft.h
index 8e55e841a..7c1311aab 100644
--- a/src/cff/cf2ft.h
+++ b/src/cff/cf2ft.h
@@ -64,6 +64,14 @@ FT_BEGIN_HEADER
FT_LOCAL( CFF_SubFont )
cf2_getSubfont( CFF_Decoder* decoder );
+ FT_LOCAL( CFF_VStore )
+ cf2_getVStore( CFF_Decoder* decoder );
+
+
+ FT_LOCAL_DEF( void )
+ cf2_getNormalizedVector( CFF_Decoder* decoder,
+ CF2_UInt * len,
+ FT_Fixed ** vec );
FT_LOCAL( CF2_Fixed )
cf2_getPpemY( CFF_Decoder* decoder );
diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c
index 7d663dd0e..a011e288a 100644
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -216,7 +216,7 @@
cf2_cmdRESERVED_13, /* 13 */
cf2_cmdENDCHAR, /* 14 */
cf2_cmdRESERVED_15, /* 15 */
- cf2_cmdRESERVED_16, /* 16 */
+ cf2_cmdBLEND, /* 16 */
cf2_cmdRESERVED_17, /* 17 */
cf2_cmdHSTEMHM, /* 18 */
cf2_cmdHINTMASK, /* 19 */
@@ -402,6 +402,34 @@
*curY = vals[13];
}
+ /* Blend numOperands on the stack, */
+ /* store results into the first numBlends values, */
+ /* then pop remaining arguments. */
+ static void
+ cf2_doBlend( const CF2_Font font,
+ CF2_Stack opStack,
+ CF2_UInt numBlends )
+ {
+ CF2_UInt delta;
+ CF2_UInt base;
+ CF2_UInt i, j;
+ CF2_UInt numOperands = (CF2_UInt)(numBlends * font->lenBlendVector);
+
+ base = cf2_stack_count( opStack ) - numOperands;
+ delta = base + numBlends;
+ for ( i = 0; i < numBlends; i++ )
+ {
+ const CF2_Fixed * weight = &font->blendVector[1];
+ CF2_Fixed sum = cf2_stack_getReal( opStack, i+base ); /* start with first term */
+ for ( j = 1; j < font->lenBlendVector; j++ )
+ {
+ sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ));
+ }
+ cf2_stack_setReal( opStack, i+base, sum ); /* store blended result */
+ }
+ /* leave only numBlends results on stack */
+ cf2_stack_pop( opStack, numOperands - numBlends );
+}
/*
* `error' is a shared error code used by many objects in this
@@ -585,12 +613,20 @@
case cf2_cmdRESERVED_9:
case cf2_cmdRESERVED_13:
case cf2_cmdRESERVED_15:
- case cf2_cmdRESERVED_16:
case cf2_cmdRESERVED_17:
/* we may get here if we have a prior error */
FT_TRACE4(( " unknown op (%d)\n", op1 ));
break;
+ case cf2_cmdBLEND:
+ {
+ FT_UInt numBlends = (FT_UInt)cf2_stack_popInt( opStack );
+ FT_TRACE4(( " blend\n" ));
+ cf2_doBlend( font, opStack, numBlends );
+ }
+ continue; /* do not clear the stack */
+
+
case cf2_cmdHSTEMHM:
case cf2_cmdHSTEM:
FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
diff --git a/src/cff/cf2stack.c b/src/cff/cf2stack.c
index 6fafd901f..5001b68cf 100644
--- a/src/cff/cf2stack.c
+++ b/src/cff/cf2stack.c
@@ -194,6 +194,34 @@
}
}
+ /* provide random access to stack */
+ FT_LOCAL_DEF( void )
+ cf2_stack_setReal( CF2_Stack stack,
+ CF2_UInt idx,
+ CF2_Fixed val )
+ {
+ if ( idx > cf2_stack_count( stack ) )
+ {
+ CF2_SET_ERROR( stack->error, Stack_Overflow );
+ return;
+ }
+
+ stack->buffer[idx].u.r = val;
+ stack->buffer[idx].type = CF2_NumberFixed;
+ }
+
+ /* discard (pop) num values from stack */
+ FT_LOCAL_DEF( void )
+ cf2_stack_pop( CF2_Stack stack,
+ CF2_UInt num )
+ {
+ if ( num > cf2_stack_count( stack ) )
+ {
+ CF2_SET_ERROR( stack->error, Stack_Underflow );
+ return;
+ }
+ stack->top -= num;
+ }
FT_LOCAL( void )
cf2_stack_roll( CF2_Stack stack,
diff --git a/src/cff/cf2stack.h b/src/cff/cf2stack.h
index e740a7ac4..acec07470 100644
--- a/src/cff/cf2stack.h
+++ b/src/cff/cf2stack.h
@@ -94,6 +94,15 @@ FT_BEGIN_HEADER
CF2_UInt idx );
FT_LOCAL( void )
+ cf2_stack_setReal( CF2_Stack stack,
+ CF2_UInt idx,
+ CF2_Fixed val );
+
+ FT_LOCAL( void )
+ cf2_stack_pop( CF2_Stack stack,
+ CF2_UInt num );
+
+ FT_LOCAL( void )
cf2_stack_roll( CF2_Stack stack,
CF2_Int count,
CF2_Int idx );
diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c
index 67bf09d8c..b03dacbd8 100644
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -32,6 +32,12 @@
#include "cffcmap.h"
#include "cffparse.h"
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include FT_MULTIPLE_MASTERS_H
+#include FT_SERVICE_MULTIPLE_MASTERS_H
+#include "../truetype/ttgxvar.h"
+#endif
+
#include "cfferrs.h"
#include "cffpic.h"
@@ -291,6 +297,14 @@
FT_Error error;
+ /* TODO: for testing: cff2 does not have glyph names */
+ /* will need to use post table method */
+ if ( font->version_major == 2 )
+ {
+ FT_STRCPYN( buffer, "noname", buffer_max );
+ return FT_Err_Ok;
+ }
+
if ( !font->psnames )
{
FT_ERROR(( "cff_get_glyph_name:"
@@ -871,15 +885,31 @@
/*************************************************************************/
/*************************************************************************/
+/* reuse some of the TT functions for the cff multi_master service */
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ FT_DEFINE_SERVICE_MULTIMASTERSREC(
+ cff_service_multi_masters,
+ (FT_Get_MM_Func) NULL, /* get_mm */
+ (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
+ (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
+ (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
+ (FT_Set_Var_Design_Func) TT_Set_Var_Design, /* set_var_design */
+ (FT_Get_Var_Design_Func) TT_Get_Var_Design, /* get_var_design */
+ (FT_Get_Var_Blend_Func) TT_Get_Var_Blend ) /* get_var_blend */
+
+#endif
+
+/* TODO: fix up ifdefs and we really need an 8-parameter FT_DEFINE_SERVICEDESCREC8 */
#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
FT_DEFINE_SERVICEDESCREC7(
cff_services,
FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF,
+ FT_SERVICE_ID_MULTI_MASTERS, &CFF_SERVICE_MULTI_MASTERS_GET,
FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET,
FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET,
FT_SERVICE_ID_GLYPH_DICT, &CFF_SERVICE_GLYPH_DICT_GET,
FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET,
- FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET,
+ /*FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET,*/
FT_SERVICE_ID_PROPERTIES, &CFF_SERVICE_PROPERTIES_GET
)
#else
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index 3d1bda97b..c357a1acb 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -589,12 +589,15 @@
FT_UInt element )
{
CFF_Index idx = &font->name_index;
- FT_Memory memory = idx->stream->memory;
+ FT_Memory memory;
FT_Byte* bytes;
FT_ULong byte_len;
FT_Error error;
FT_String* name = 0;
+ if ( !idx->stream ) /* CFF2 does not include a name index */
+ goto Exit;
+ memory = idx->stream->memory;
error = cff_index_access_element( idx, element, &bytes, &byte_len );
if ( error )
@@ -862,6 +865,32 @@
charset->offset = 0;
}
+ static void
+ cff_vstore_done( CFF_VStoreRec* vstore,
+ FT_Memory memory )
+ {
+ FT_UInt i;
+
+ /* free regionList and axisLists */
+ if ( vstore->varRegionList )
+ {
+ for ( i=0; i<vstore->regionCount; i++ )
+ {
+ FT_FREE( vstore->varRegionList[i].axisList );
+ }
+ }
+ FT_FREE( vstore->varRegionList );
+
+ /* free varData and indices */
+ if ( vstore->varData )
+ {
+ for ( i=0; i<vstore->dataCount; i++ )
+ {
+ FT_FREE( vstore->varData[i].regionIndices );
+ }
+ }
+ FT_FREE( vstore->varData );
+ }
static FT_Error
cff_charset_load( CFF_Charset charset,
@@ -1053,6 +1082,130 @@
}
+ /* convert 2.14 to Fixed */
+ #define FT_fdot14ToFixed( x ) \
+ (((FT_Fixed)((FT_Int16)(x))) << 2 )
+
+ static FT_Error
+ cff_vstore_load( CFF_VStoreRec* vstore,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error = FT_THROW( Invalid_File_Format );
+ FT_UInt i,j;
+
+ /* no offset means no vstore to parse */
+ if ( offset )
+ {
+ FT_UInt vsSize; /* currently unused */
+ FT_UInt vsOffset;
+ FT_UInt format;
+ FT_ULong regionListOffset;
+ FT_ULong dataOffsetArrayOffset;
+ FT_ULong varDataOffset;
+
+ /* we need to parse the table to determine its size */
+ if ( FT_STREAM_SEEK( base_offset + offset ) ||
+ FT_READ_USHORT( vsSize ) )
+ goto Exit;
+
+ /* actual variation store begins after the length */
+ vsOffset = FT_STREAM_POS();
+
+ /* check the header */
+ if ( FT_READ_USHORT( format ) )
+ goto Exit;
+ if ( format != 1 )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* read top level fields */
+ if ( FT_READ_ULONG( regionListOffset ) ||
+ FT_READ_USHORT( vstore->dataCount ) )
+ goto Exit;
+
+ /* save position of item variation data offsets */
+ /* we'll parse region list first, then come back */
+ dataOffsetArrayOffset = FT_STREAM_POS();
+
+ /* parse regionList and axisLists*/
+ if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) ||
+ FT_READ_USHORT( vstore->axisCount ) ||
+ FT_READ_USHORT( vstore->regionCount ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) )
+ goto Exit;
+
+ for ( i=0; i<vstore->regionCount; i++ )
+ {
+ CFF_VarRegion* region = &vstore->varRegionList[i];
+ if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) )
+ goto Exit;
+ for ( j=0; j<vstore->axisCount; j++ )
+ {
+ CFF_AxisCoords* axis = &region->axisList[j];
+ FT_Int16 start14, peak14, end14;
+ if ( FT_READ_SHORT( start14 ) ||
+ FT_READ_SHORT( peak14 ) ||
+ FT_READ_SHORT( end14 ) )
+ goto Exit;
+ axis->startCoord = FT_fdot14ToFixed( start14 );
+ axis->peakCoord = FT_fdot14ToFixed( peak14 );
+ axis->endCoord = FT_fdot14ToFixed( end14 );
+ }
+ }
+
+ /* re-position to parse varData and regionIndices */
+ if ( FT_STREAM_SEEK( dataOffsetArrayOffset ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) )
+ goto Exit;
+
+ for ( i=0; i<vstore->dataCount; i++ )
+ {
+ FT_UInt itemCount, shortDeltaCount;
+ CFF_VarData* data = &vstore->varData[i];
+
+ if ( FT_READ_ULONG( varDataOffset ) )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( vsOffset + varDataOffset ) )
+ goto Exit;
+
+ /* ignore these two values because CFF2 has no delta sets */
+ if ( FT_READ_USHORT( itemCount ) ||
+ FT_READ_USHORT( shortDeltaCount ) )
+ goto Exit;
+
+ /* Note: just record values; consistency is checked later */
+ /* by cf2_buildBlendVector when it consumes vstore */
+
+ if ( FT_READ_USHORT( data->regionIdxCount ) )
+ goto Exit;
+ if ( FT_NEW_ARRAY( data->regionIndices, data->regionIdxCount ) )
+ goto Exit;
+ for ( j=0; j<data->regionIdxCount; j++ )
+ {
+ if ( FT_READ_USHORT( data->regionIndices[j] ) )
+ goto Exit;
+ }
+ }
+
+ }
+ error = FT_Err_Ok;
+
+ Exit:
+ if ( error )
+ cff_vstore_done( vstore, memory );
+ return error;
+ }
+
static void
cff_encoding_done( CFF_Encoding encoding )
{
@@ -1442,7 +1595,8 @@
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
- FT_Bool pure_cff )
+ FT_Bool pure_cff,
+ FT_Bool cff2 )
{
static const FT_Frame_Field cff_header_fields[] =
{
@@ -1478,7 +1632,7 @@
goto Exit;
/* check format */
- if ( font->version_major != 1 ||
+ if ( font->version_major != ( cff2 ? 2 : 1 ) ||
font->header_size < 4 ||
font->absolute_offsize > 4 )
{
@@ -1492,8 +1646,9 @@
goto Exit;
/* read the name, top dict, string and global subrs index */
- if ( FT_SET_ERROR( cff_index_init( &font->name_index,
- stream, 0 ) ) ||
+ /* CFF2 does not contain a name index */
+ if ( ( !cff2 && FT_SET_ERROR( cff_index_init( &font->name_index,
+ stream, 0 ) ) ) ||
FT_SET_ERROR( cff_index_init( &font->font_dict_index,
stream, 0 ) ) ||
FT_SET_ERROR( cff_index_init( &string_index,
@@ -1636,7 +1791,7 @@
goto Exit;
/* read the Charset and Encoding tables if available */
- if ( font->num_glyphs > 0 )
+ if ( !cff2 && font->num_glyphs > 0 )
{
FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff );
@@ -1660,6 +1815,14 @@
}
}
+ /* read the Variation Store if available */
+ error = cff_vstore_load( &font->vstore,
+ stream,
+ base_offset,
+ dict->vstore_offset );
+ if ( error )
+ goto Exit;
+
/* get the font name (/CIDFontName for CID-keyed fonts, */
/* /FontName otherwise) */
font->font_name = cff_index_get_name( font, subfont_index );
@@ -1696,6 +1859,7 @@
cff_encoding_done( &font->encoding );
cff_charset_done( &font->charset, font->stream );
+ cff_vstore_done( &font->vstore, memory );
cff_subfont_done( memory, &font->top_font );
diff --git a/src/cff/cffload.h b/src/cff/cffload.h
index 1dd07baf1..992e5b5f5 100644
--- a/src/cff/cffload.h
+++ b/src/cff/cffload.h
@@ -64,7 +64,8 @@ FT_BEGIN_HEADER
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
- FT_Bool pure_cff );
+ FT_Bool pure_cff,
+ FT_Bool cff2 );
FT_LOCAL( void )
cff_font_done( CFF_Font font );
diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c
index 0f0769677..b246f753e 100644
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -491,6 +491,7 @@
FT_Service_PsCMaps psnames;
PSHinter_Service pshinter;
FT_Bool pure_cff = 1;
+ FT_Bool cff2 = 0;
FT_Bool sfnt_format = 0;
FT_Library library = cffface->driver->root.library;
@@ -554,9 +555,22 @@
}
/* now load the CFF part of the file */
- error = face->goto_table( face, TTAG_CFF, stream, 0 );
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ /* give priority to CFF2 */
+ error = face->goto_table( face, TTAG_CFF2, stream, 0 );
+ if ( !error )
+ {
+ cff2 = 1;
+ face->isCFF2 = cff2;
+ }
+ if ( FT_ERR_EQ( error, Table_Missing ) )
+#endif
+ {
+ error = face->goto_table( face, TTAG_CFF, stream, 0 );
+ }
if ( error )
goto Exit;
+
}
else
{
@@ -579,7 +593,7 @@
goto Exit;
face->extra.data = cff;
- error = cff_font_load( library, stream, face_index, cff, pure_cff );
+ error = cff_font_load( library, stream, face_index, cff, pure_cff, cff2 );
if ( error )
goto Exit;
@@ -1079,6 +1093,11 @@
FT_FREE( face->extra.data );
}
}
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ tt_done_blend( memory, face->blend );
+ face->blend = NULL;
+#endif
+
}
diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c
index a4f986b67..f007f858c 100644
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -782,6 +782,32 @@
return error;
}
+ /* TODO: replace this test code with doBlend */
+ static FT_Error
+ cff_parse_blend( CFF_Parser parser )
+ {
+ FT_UInt num_args = (FT_UInt)( parser->top - parser->stack );
+ FT_UInt numBlends;
+ FT_Error error;
+
+ error = FT_ERR( Stack_Underflow );
+ FT_TRACE1(( " cff_parse_blend\n" ));
+
+ if ( parser->top >= parser->stack + 1 ) /* at least one operand */
+ {
+ /* top of stack gives number of blends */
+ numBlends = (FT_UInt)cff_parse_num( parser->top - 1 );
+
+ if ( numBlends < num_args )
+ {
+ /* for testing, just reduce stack to first numBlends values */
+ parser->top = parser->stack + numBlends;
+
+ error = FT_Err_Ok;
+ }
+ }
+ return error;
+ }
#define CFF_FIELD_NUM( code, name, id ) \
CFF_FIELD( code, name, id, cff_kind_num )
@@ -817,6 +843,15 @@
0, 0 \
},
+#define CFF_FIELD_BLEND( code, id ) \
+ { \
+ cff_kind_blend, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_blend, \
+ 0, 0 \
+ },
+
#define CFF_FIELD( code, name, id, kind ) \
{ \
kind, \
@@ -860,6 +895,16 @@
id \
},
+#define CFF_FIELD_BLEND( code, id ) \
+ { \
+ cff_kind_blend, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_blend, \
+ 0, 0, \
+ id \
+ },
+
#define CFF_FIELD( code, name, id, kind ) \
{ \
kind, \
@@ -1386,7 +1431,7 @@
}
break;
- default: /* callback */
+ default: /* callback or blend */
error = field->reader( parser );
if ( error )
goto Exit;
@@ -1400,7 +1445,8 @@
Found:
/* clear stack */
- parser->top = parser->stack;
+ if ( field->kind != cff_kind_blend )
+ parser->top = parser->stack;
}
p++;
}
diff --git a/src/cff/cffparse.h b/src/cff/cffparse.h
index a95970edc..0134efbf0 100644
--- a/src/cff/cffparse.h
+++ b/src/cff/cffparse.h
@@ -28,7 +28,7 @@
FT_BEGIN_HEADER
-#define CFF_MAX_STACK_DEPTH 96
+#define CFF_MAX_STACK_DEPTH 193
#define CFF_CODE_TOPDICT 0x1000
#define CFF_CODE_PRIVATE 0x2000
@@ -77,6 +77,7 @@ FT_BEGIN_HEADER
cff_kind_bool,
cff_kind_delta,
cff_kind_callback,
+ cff_kind_blend,
cff_kind_max /* do not remove */
};
diff --git a/src/cff/cffpic.h b/src/cff/cffpic.h
index bed6b35a8..4737b9e38 100644
--- a/src/cff/cffpic.h
+++ b/src/cff/cffpic.h
@@ -32,6 +32,7 @@
#define CFF_SERVICE_CID_INFO_GET cff_service_cid_info
#define CFF_SERVICE_PROPERTIES_GET cff_service_properties
#define CFF_SERVICES_GET cff_services
+#define CFF_SERVICE_MULTI_MASTERS_GET cff_service_multi_masters
#define CFF_CMAP_ENCODING_CLASS_REC_GET cff_cmap_encoding_class_rec
#define CFF_CMAP_UNICODE_CLASS_REC_GET cff_cmap_unicode_class_rec
#define CFF_FIELD_HANDLERS_GET cff_field_handlers
diff --git a/src/cff/cfftoken.h b/src/cff/cfftoken.h
index 22637c780..77e93afb5 100644
--- a/src/cff/cfftoken.h
+++ b/src/cff/cfftoken.h
@@ -45,6 +45,9 @@
CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" )
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
+ CFF_FIELD_NUM ( 22, vsindex, "vsindex" )
+ CFF_FIELD_NUM ( 24, vstore_offset, "vstore" )
+ CFF_FIELD_NUM ( 25, maxstack, "maxstack" )
CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" )
CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" )
@@ -101,5 +104,6 @@
CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
+ CFF_FIELD_BLEND ( 31, "blend" )
/* END */
diff --git a/src/cff/cfftypes.h b/src/cff/cfftypes.h
index 4426c7e4f..d8fc1e9ab 100644
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -101,6 +101,38 @@ FT_BEGIN_HEADER
} CFF_CharsetRec, *CFF_Charset;
+ typedef struct CFF_VarData_
+ {
+ /* FT_UInt itemCount; not used; always zero */
+ /* FT_UInt shortDeltaCount; not used; always zero */
+ FT_UInt regionIdxCount; /* # regions in this var data */
+ FT_UInt* regionIndices; /* array of regionCount indices */
+ /* these index the varRegionList */
+ } CFF_VarData;
+
+ typedef struct CFF_AxisCoords_ /* contribution of one axis to a region */
+ {
+ FT_Fixed startCoord;
+ FT_Fixed peakCoord; /* zero peak means no effect (factor = 1) */
+ FT_Fixed endCoord;
+ } CFF_AxisCoords;
+
+ typedef struct CFF_VarRegion_
+ {
+ CFF_AxisCoords* axisList; /* array of axisCount records */
+ } CFF_VarRegion;
+
+ typedef struct CFF_VstoreRec_
+ {
+ FT_UInt dataCount;
+ CFF_VarData* varData; /* array of dataCount records */
+ /* vsindex indexes this array */
+ FT_UShort axisCount;
+ FT_UInt regionCount; /* total # regions defined */
+ CFF_VarRegion* varRegionList;
+
+ } CFF_VStoreRec, *CFF_VStore;
+
typedef struct CFF_FontRecDictRec_
{
@@ -151,6 +183,11 @@ FT_BEGIN_HEADER
FT_UShort num_designs;
FT_UShort num_axes;
+ /* fields for CFF2 */
+ FT_UInt vsindex;
+ FT_ULong vstore_offset;
+ FT_UInt maxstack;
+
} CFF_FontRecDictRec, *CFF_FontRecDict;
@@ -280,6 +317,8 @@ FT_BEGIN_HEADER
/* since version 2.4.12 */
FT_Generic cf2_instance;
+ CFF_VStoreRec vstore;
+
} CFF_FontRec, *CFF_Font;
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 4413bbcf2..4ca8cb7c6 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -1085,10 +1085,12 @@
#ifdef FT_CONFIG_OPTION_INCREMENTAL
has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
- tt_face_lookup_table( face, TTAG_CFF ) != 0 );
+ tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
+ tt_face_lookup_table( face, TTAG_CFF2 ));
#else
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
- tt_face_lookup_table( face, TTAG_CFF ) != 0 );
+ tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
+ tt_face_lookup_table( face, TTAG_CFF2 ));
#endif
is_apple_sbit = 0;
@@ -1331,6 +1333,9 @@
tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
tt_face_lookup_table( face, TTAG_gvar ) != 0 )
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+ if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 &&
+ tt_face_lookup_table( face, TTAG_fvar ) != 0 )
+ flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
#endif
root->face_flags = flags;
diff --git a/src/sfnt/ttmtx.c b/src/sfnt/ttmtx.c
index 186f873da..a54472842 100644
--- a/src/sfnt/ttmtx.c
+++ b/src/sfnt/ttmtx.c
@@ -22,6 +22,10 @@
#include FT_TRUETYPE_TAGS_H
#include "ttmtx.h"
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include "../truetype/ttgxvar.h"
+#endif
+
#include "sferrors.h"
@@ -274,6 +278,12 @@
*abearing = 0;
*aadvance = 0;
}
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ /* TODO: handle VVAR and LSB */
+ if ( !vertical )
+ tt_adjust_advance( face, gindex, aadvance );
+#endif
+
}
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index 2659b9c9b..ce0be7ffe 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -449,7 +449,9 @@
(FT_Set_MM_Design_Func) NULL, /* set_mm_design */
(FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
(FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
- (FT_Set_Var_Design_Func)TT_Set_Var_Design ) /* set_var_design */
+ (FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */
+ (FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */
+ (FT_Get_Var_Blend_Func) TT_Get_Var_Blend ) /* get_var_blend */
#endif
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 080e2ddce..504022ad7 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -392,6 +392,418 @@
FT_FRAME_EXIT();
}
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_var_load_hvar */
+ /* */
+ /* <Description> */
+ /* Parse the `HVAR' table if present. It need not be, so we return */
+ /* nothing. */
+ /* On success, blend->hvar_checked is TRUE */
+ /* Some memory may remain allocated on error (hvar_checked FALSE) */
+ /* Memory is always freed in tt_done_blend. */
+ /* */
+ /* <InOut> */
+ /* face :: The font face. */
+ /* */
+ /* */
+
+ /* some macros we need */
+ #define FT_fdot14ToFixed( x ) \
+ (((FT_Fixed)((FT_Int16)(x))) << 2 )
+
+ #define FT_FIXED_ONE ((FT_Fixed)0x10000)
+ #define FT_intToFixed( i ) \
+ ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
+ #define FT_fixedToInt( x ) \
+ ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
+
+ static void
+ ft_var_load_hvar( TT_Face face )
+ {
+ FT_Stream stream = FT_FACE_STREAM( face );
+ FT_Memory memory = stream->memory;
+ GX_Blend blend = face->blend;
+ FT_Error error;
+ FT_UShort majorVersion;
+ FT_UShort minorVersion;
+ FT_ULong table_len;
+ FT_ULong table_offset;
+ FT_ULong store_offset;
+ FT_ULong map_offset;
+
+ FT_TRACE2(( "HVAR " ));
+
+ /* if we allocated the table, assume we've already tried to parse it */
+ if ( face->blend->hvar_table )
+ return;
+
+ error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing\n" ));
+ return;
+ }
+
+ table_offset = FT_STREAM_POS();
+
+ if ( FT_READ_USHORT( majorVersion ) ||
+ FT_READ_USHORT( minorVersion ) )
+ goto Exit;
+ if ( majorVersion != 1 )
+ {
+ FT_TRACE2(( "bad table version %d\n", majorVersion ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( FT_READ_ULONG( store_offset ) ||
+ FT_READ_ULONG( map_offset ) )
+ goto Exit;
+
+ /* parse item variation store */
+ {
+ FT_UShort format;
+ FT_ULong data_offset_array_offset;
+ FT_ULong data_offset;
+ FT_ULong region_offset;
+ GX_HVStore itemStore;
+ FT_UInt i, j, k;
+ FT_UInt shortDeltaCount;
+ GX_HVarTable hvarTable;
+ GX_HVarData hvarData;
+
+ if ( FT_STREAM_SEEK( table_offset + store_offset ) ||
+ FT_READ_USHORT( format ) )
+ goto Exit;
+ if ( format != 1 )
+ {
+ FT_TRACE2(( "bad store format %d\n", format ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( FT_NEW( blend->hvar_table ) ) /* allocate table at top level */
+ goto Exit;
+
+ hvarTable = blend->hvar_table;
+ itemStore = &hvarTable->itemStore;
+
+ if ( FT_READ_ULONG( region_offset ) ||
+ FT_READ_USHORT( itemStore->dataCount ) )
+ goto Exit;
+
+ /* save position of item variation data offsets */
+ /* we'll parse region list first, then come back */
+ data_offset_array_offset = FT_STREAM_POS();
+
+ /* parse array of region records (region list) */
+ if ( FT_STREAM_SEEK( table_offset + store_offset + region_offset ) )
+ goto Exit;
+
+ if ( FT_READ_USHORT( itemStore->axisCount ) ||
+ FT_READ_USHORT( itemStore->regionCount ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) )
+ goto Exit;
+
+ for ( i=0; i<itemStore->regionCount; i++ )
+ {
+ GX_AxisCoords axisCoords;
+
+ if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, itemStore->axisCount ) )
+ goto Exit;
+
+ axisCoords = itemStore->varRegionList[i].axisList;
+
+ for ( j=0; j<itemStore->axisCount; j++ )
+ {
+ FT_Short start, peak, end;
+
+ if ( FT_READ_SHORT( start ) ||
+ FT_READ_SHORT( peak ) ||
+ FT_READ_SHORT( end ) )
+ goto Exit;
+ axisCoords[j].startCoord = FT_fdot14ToFixed( start );
+ axisCoords[j].peakCoord = FT_fdot14ToFixed( peak );
+ axisCoords[j].endCoord = FT_fdot14ToFixed( end );
+ }
+ }
+ /* end of region list parse */
+
+ /* parse array of item variation data subtables */
+ if ( FT_STREAM_SEEK( data_offset_array_offset ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
+ goto Exit;
+
+ hvarData = itemStore->varData;
+ for ( i=0; i<itemStore->dataCount; i++ )
+ {
+ if ( FT_READ_ULONG( data_offset ) )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( table_offset + store_offset + data_offset ) ||
+ FT_READ_USHORT( hvarData->itemCount ) ||
+ FT_READ_USHORT( shortDeltaCount ) ||
+ FT_READ_USHORT( hvarData->regionCount ) )
+ goto Exit;
+
+ /* check some data consistency */
+ if ( shortDeltaCount > hvarData->regionCount )
+ {
+ FT_TRACE2(( "bad short count %d or region count %d\n",
+ shortDeltaCount, hvarData->regionCount ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ if ( hvarData->regionCount > itemStore->regionCount )
+ {
+ FT_TRACE2(( "inconsistent regionCount %d in varData[ %d ]\n",
+ hvarData->regionCount, i ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* parse region indices */
+ if ( FT_NEW_ARRAY( hvarData->regionIndices, hvarData->regionCount ) )
+ goto Exit;
+
+ for ( j=0; j<hvarData->regionCount; j++ )
+ {
+ if ( FT_READ_USHORT( hvarData->regionIndices[j] ) )
+ goto Exit;
+ if ( hvarData->regionIndices[j] >= hvarData->regionCount )
+ {
+ FT_TRACE2(( "bad region index %d\n", hvarData->regionIndices[j] ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ }
+
+ /* parse delta set */
+ /* on input, deltas are ( shortDeltaCount + regionCount ) bytes each */
+ /* on output, deltas are expanded to regionCount shorts each */
+ if ( FT_NEW_ARRAY( hvarData->deltaSet, hvarData->regionCount * hvarData->itemCount ) )
+ goto Exit;
+
+ /* the delta set is stored as a 2-dimensional array of shorts */
+ /* sign-extend signed bytes to signed shorts */
+ for ( j=0; j<hvarData->itemCount * hvarData->regionCount; )
+ {
+ for ( k=0; k<shortDeltaCount; k++,j++ )
+ {
+ /* read the short deltas */
+ FT_Short delta;
+ if ( FT_READ_SHORT( delta ) )
+ goto Exit;
+ hvarData->deltaSet[j] = delta;
+ }
+ for ( ; k<hvarData->regionCount; k++,j++ )
+ {
+ /* read the (signed) byte deltas */
+ FT_Char delta;
+ if ( FT_READ_CHAR( delta ) )
+ goto Exit;
+ hvarData->deltaSet[j] = delta;
+ }
+ }
+ }
+ }
+ /* end parse item variation store */
+
+ {
+ /* parse width map */
+ GX_WidthMap widthMap;
+ FT_UShort format;
+ FT_UInt entrySize;
+ FT_UInt innerBitCount;
+ FT_UInt innerIndexMask;
+ FT_UInt outerBitCount;
+ FT_UInt i, j;
+
+ widthMap = &blend->hvar_table->widthMap;
+ if ( FT_READ_USHORT( format ) ||
+ FT_READ_USHORT( widthMap->mapCount ) )
+ goto Exit;
+
+ if ( format & 0xFFC0 )
+ {
+ FT_TRACE2(( "bad map format %d\n", format ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ entrySize = ( ( format & 0x0030 ) >> 4 ) + 1; /* bytes per entry, 1,2,3 or 4 */
+ innerBitCount = ( format & 0x000F ) + 1;
+ innerIndexMask = ( 1 << innerBitCount ) - 1;
+ outerBitCount = 8 * entrySize - innerBitCount;
+
+ if ( FT_NEW_ARRAY( widthMap->innerIndex, widthMap->mapCount ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( widthMap->outerIndex, widthMap->mapCount ) )
+ goto Exit;
+
+ for ( i=0; i<widthMap->mapCount; i++ )
+ {
+ FT_UInt mapData = 0;
+ FT_UInt outerIndex, innerIndex;
+
+ /* read map data one unsigned byte at a time, big endian */
+ for ( j=0; j<entrySize; j++ )
+ {
+ FT_Byte data;
+
+ if ( FT_READ_BYTE( data ) )
+ goto Exit;
+ mapData = ( mapData << 8 ) | data;
+ }
+
+ outerIndex = mapData >> innerBitCount;
+ if ( outerIndex >= blend->hvar_table->itemStore.dataCount )
+ {
+ FT_TRACE2(( "outerIndex[ %d ] == %d out of range\n",
+ i, outerIndex ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ widthMap->outerIndex[i] = outerIndex;
+
+ innerIndex = mapData & innerIndexMask;
+
+ if ( innerIndex >= blend->hvar_table->itemStore.varData[ outerIndex ].itemCount )
+ {
+ FT_TRACE2(( "innerIndex[ %d ] == %d out of range\n",
+ i, innerIndex ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ widthMap->innerIndex[i] = innerIndex;
+ }
+
+ } /* end parse width map */
+
+ FT_TRACE2(( "loaded\n" ));
+ error = FT_Err_Ok;
+
+ Exit:
+ if ( error == FT_Err_Ok )
+ blend->hvar_checked = TRUE;
+ }
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_adjust_advance */
+ /* */
+ /* <Description> */
+ /* Apply HVAR adjustment to advance width of gindex */
+ /* */
+ /* <In> */
+ /* gindex :: The glyph */
+ /* <InOut> */
+ /* face :: The font face. */
+ /* aadvance :: points to width value */
+ /* */
+ FT_EXPORT( void )
+ tt_adjust_advance( TT_Face face,
+ FT_UInt gindex,
+ FT_UShort *aadvance )
+ {
+ FT_UInt innerIndex, outerIndex;
+ GX_HVarData varData;
+ FT_UInt master, j;
+ FT_Fixed netAdjustment = 0; /* accumulated adjustment */
+ FT_Fixed scaledDelta;
+ FT_Short* deltaSet;
+ FT_Fixed delta;
+
+ if ( !face->blend )
+ return;
+
+ if ( !face->blend->hvar_checked )
+ {
+ /* initialize hvar table */
+ ft_var_load_hvar( face );
+ }
+ if ( !face->blend->hvar_checked )
+ return; /* HVAR parse failed */
+
+ if ( gindex >= face->blend->hvar_table->widthMap.mapCount )
+ {
+ FT_TRACE2(( "gindex %d out of range\n", gindex ));
+ goto Exit;
+ }
+
+ /* trust that HVAR parser has checked indices */
+ outerIndex = face->blend->hvar_table->widthMap.outerIndex[ gindex ];
+ innerIndex = face->blend->hvar_table->widthMap.innerIndex[ gindex ];
+ varData = &face->blend->hvar_table->itemStore.varData[ outerIndex ];
+ deltaSet = &varData->deltaSet[ face->blend->hvar_table->itemStore.regionCount * innerIndex ];
+
+ /* see pseudo code from Font Variations Overview */
+ /* outer loop steps through master designs to be blended */
+ for ( master=0; master<varData->regionCount; master++ )
+ {
+ FT_UInt regionIndex = varData->regionIndices[ master ];
+ GX_AxisCoords axis = face->blend->hvar_table->itemStore.varRegionList[ regionIndex ].axisList;
+ FT_Fixed scalar = FT_FIXED_ONE;
+
+ /* inner loop steps through axes in this region */
+ for ( j=0; j<face->blend->hvar_table->itemStore.axisCount; j++, axis++ )
+ {
+ FT_Fixed axisScalar;
+
+ /* compute the scalar contribution of this axis */
+ /* ignore invalid ranges */
+ if ( axis->startCoord > axis->peakCoord || axis->peakCoord > axis->endCoord )
+ axisScalar = FT_FIXED_ONE;
+ else if ( axis->startCoord < 0 && axis->endCoord > 0 && axis->peakCoord != 0 )
+ axisScalar = FT_FIXED_ONE;
+ /* peak of 0 means ignore this axis */
+ else if ( axis->peakCoord == 0 )
+ axisScalar = FT_FIXED_ONE;
+ /* ignore this region if coords are out of range */
+ else if ( face->blend->normalizedcoords[j] < axis->startCoord || face->blend->normalizedcoords[j] > axis->endCoord )
+ axisScalar = 0;
+ /* calculate a proportional factor */
+ else
+ {
+ if ( face->blend->normalizedcoords[j] == axis->peakCoord )
+ axisScalar = FT_FIXED_ONE;
+ else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
+ axisScalar = FT_DivFix( face->blend->normalizedcoords[j] - axis->startCoord,
+ axis->peakCoord - axis->startCoord );
+ else
+ axisScalar = FT_DivFix( axis->endCoord - face->blend->normalizedcoords[j],
+ axis->endCoord - axis->peakCoord );
+ }
+ /* take product of all the axis scalars */
+ scalar = FT_MulFix( scalar, axisScalar );
+ } /* per-axis loop */
+ FT_TRACE4(( ", %f ", (double)scalar / 65536 ));
+
+ /* get the scaled delta for this region */
+ delta = FT_intToFixed( deltaSet[master] );
+ scaledDelta = FT_MulFix( scalar, delta );
+
+ /* accumulate the adjustments from each region */
+ netAdjustment = netAdjustment + scaledDelta;
+
+ } /* per-region loop */
+ FT_TRACE4(( "]\n" ));
+
+ /* apply the accumulated adjustment to the default to derive the interpolated value */
+ /* TODO check rounding: *aadvance is short */
+ *aadvance += FT_fixedToInt( netAdjustment );
+
+Exit:
+ return;
+ }
+
typedef struct GX_GVar_Head_
{
@@ -762,7 +1174,7 @@
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
- FT_LOCAL_DEF( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Get_MM_Var( TT_Face face,
FT_MM_Var* *master )
{
@@ -778,6 +1190,7 @@
FT_Var_Axis* a;
FT_Var_Named_Style* ns;
GX_FVar_Head fvar_head;
+ FT_Bool usePsName;
static const FT_Frame_Field fvar_fields[] =
{
@@ -824,9 +1237,14 @@
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;
+ /* CFF2 is an alternate to gvar here */
+ if ( ( error = face->goto_table( face, TTAG_CFF2,
+ stream, &table_len ) ) != 0 )
+ {
+ FT_TRACE1(( "\n"
+ "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" ));
+ goto Exit;
+ }
}
if ( ( error = face->goto_table( face, TTAG_fvar,
@@ -851,8 +1269,6 @@
fvar_head.axisSize != 20 ||
/* axisCount limit implied by 16-bit instanceSize */
fvar_head.axisCount > 0x3FFE ||
- fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount ||
- /* instanceCount limit implied by limited range of name IDs */
fvar_head.instanceCount > 0x7EFF ||
fvar_head.offsetToData + fvar_head.axisCount * 20U +
fvar_head.instanceCount * fvar_head.instanceSize > table_len )
@@ -862,7 +1278,21 @@
error = FT_THROW( Invalid_Table );
goto Exit;
}
-
+ if ( fvar_head.instanceSize == 4 + 4 * fvar_head.axisCount )
+ {
+ usePsName = FALSE;
+ }
+ else if ( fvar_head.instanceSize == 6 + 4 * fvar_head.axisCount )
+ {
+ usePsName = TRUE;
+ }
+ else
+ {
+ 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 ));
@@ -952,8 +1382,17 @@
ns = mmvar->namedstyle;
for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
{
- if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
- goto Exit;
+ /* PostScript names add 2 bytes to the instance record size */
+ if ( usePsName )
+ {
+ if ( FT_FRAME_ENTER( 6L + 4L * fvar_head.axisCount ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
+ goto Exit;
+ }
ns->strid = FT_GET_USHORT();
(void) /* flags = */ FT_GET_USHORT();
@@ -961,6 +1400,9 @@
for ( j = 0; j < fvar_head.axisCount; j++ )
ns->coords[j] = FT_GET_LONG();
+ if ( usePsName )
+ ns->psid = FT_GET_USHORT();
+
FT_FRAME_EXIT();
}
}
@@ -1042,7 +1484,7 @@
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
- FT_LOCAL_DEF( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Set_MM_Blend( TT_Face face,
FT_UInt num_coords,
FT_Fixed* coords )
@@ -1097,7 +1539,7 @@
FT_TRACE5(( "\n" ));
- if ( blend->glyphoffsets == NULL )
+ if ( !face->isCFF2 && blend->glyphoffsets == NULL )
if ( ( error = ft_var_load_gvar( face ) ) != 0 )
goto Exit;
@@ -1202,7 +1644,7 @@
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
- FT_LOCAL_DEF( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Set_Var_Design( TT_Face face,
FT_UInt num_coords,
FT_Fixed* coords )
@@ -1310,6 +1752,50 @@
}
+ FT_EXPORT( FT_Error )
+ TT_Get_Var_Blend( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error = FT_Err_Ok;
+ GX_Blend blend;
+ FT_UInt i;
+
+ face->doblend = FALSE;
+
+ if ( face->blend == NULL )
+ {
+ if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 )
+ return error;
+ }
+
+ blend = face->blend;
+
+ if ( num_coords > blend->num_axis )
+ {
+ FT_TRACE2(( "TT_Get_MM_Blend: only using first %d of %d coordinates\n",
+ blend->num_axis, num_coords ));
+ num_coords = blend->num_axis;
+ }
+
+ for (i = 0; i < num_coords; ++i)
+ {
+ coords[i] = blend->normalizedcoords[i];
+ }
+
+ return FT_Err_Ok;
+ }
+
+ FT_EXPORT( FT_Error )
+ TT_Get_Var_Design( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ /* TODO: Implement this function. */
+ return FT_THROW( Unimplemented_Feature );
+ }
+
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -2153,7 +2639,7 @@
/* <Description> */
/* Free the blend internal data structure. */
/* */
- FT_LOCAL_DEF( void )
+ FT_EXPORT( void )
tt_done_blend( FT_Memory memory,
GX_Blend blend )
{
@@ -2172,6 +2658,31 @@
FT_FREE( blend->avar_segment );
}
+ if ( blend->hvar_table != NULL )
+ {
+ FT_UInt i;
+ if ( blend->hvar_table->itemStore.varData )
+ {
+ for ( i=0; i<blend->hvar_table->itemStore.dataCount; i++ )
+ {
+ FT_FREE( blend->hvar_table->itemStore.varData[i].regionIndices );
+ FT_FREE( blend->hvar_table->itemStore.varData[i].deltaSet );
+ }
+ FT_FREE( blend->hvar_table->itemStore.varData );
+ }
+ if ( blend->hvar_table->itemStore.varRegionList )
+ {
+ for ( i=0; i<blend->hvar_table->itemStore.regionCount; i++ )
+ {
+ FT_FREE( blend->hvar_table->itemStore.varRegionList[i].axisList );
+ }
+ FT_FREE( blend->hvar_table->itemStore.varRegionList );
+ }
+ FT_FREE( blend->hvar_table->widthMap.innerIndex );
+ FT_FREE( blend->hvar_table->widthMap.outerIndex );
+ FT_FREE( blend->hvar_table );
+ }
+
FT_FREE( blend->tuplecoords );
FT_FREE( blend->glyphoffsets );
FT_FREE( blend );
diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h
index aa8f6ea59..956000c76 100644
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -64,6 +64,64 @@ FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* <Struct> */
+ /* GX_HVarRec */
+ /* */
+ /* <Description> */
+ /* Data from the `HVAR' table. */
+ /* */
+ /* See similar variation store structures in cfftypes.h */
+ /* */
+ typedef struct GX_HVarData_
+ {
+ FT_UInt itemCount; /* # delta sets per item */
+ FT_UInt regionCount; /* # regions in this var data */
+ FT_UInt* regionIndices; /* array of regionCount indices */
+ /* these index the varRegionList */
+ FT_Short* deltaSet; /* array of itemCount deltas */
+ /* use innerIndex for this array */
+ } GX_HVarDataRec, *GX_HVarData;
+
+ typedef struct GX_AxisCoords_ /* contribution of one axis to a region */
+ {
+ FT_Fixed startCoord;
+ FT_Fixed peakCoord; /* zero means no effect (factor = 1) */
+ FT_Fixed endCoord;
+ } GX_AxisCoordsRec, *GX_AxisCoords;
+
+ typedef struct GX_HVarRegion_
+ {
+ GX_AxisCoords axisList; /* array of axisCount records */
+ } GX_HVarRegionRec, *GX_HVarRegion;
+
+ typedef struct GX_HVStoreRec_ /* HVAR item variation store */
+ {
+ FT_UInt dataCount;
+ GX_HVarData varData; /* array of dataCount records */
+ /* use outerIndex for this array */
+ FT_UShort axisCount;
+ FT_UInt regionCount; /* total # regions defined */
+ GX_HVarRegion varRegionList;
+
+ } GX_HVStoreRec, *GX_HVStore;
+
+ typedef struct GX_WidthMapRec_
+ {
+ FT_UInt mapCount;
+ FT_UInt* outerIndex; /* indices to item var data */
+ FT_UInt* innerIndex; /* indices to delta set */
+ } GX_WidthMapRec, *GX_WidthMap;
+
+ typedef struct GX_HVarRec_
+ {
+ GX_HVStoreRec itemStore; /* Item Variation Store */
+ GX_WidthMapRec widthMap; /* Advance Width Mapping */
+ /* GX_LSBMap LsbMap; Not implemented */
+ /* GX_RSBMap RsbMap; Not implemented */
+ } GX_HVarTableRec, *GX_HVarTable;
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
/* GX_BlendRec */
/* */
/* <Description> */
@@ -89,6 +147,9 @@ FT_BEGIN_HEADER
FT_Bool avar_checked;
GX_AVarSegment avar_segment;
+ FT_Bool hvar_checked;
+ GX_HVarTable hvar_table;
+
FT_UInt tuplecount; /* shared tuples in `gvar' */
FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */
@@ -143,20 +204,29 @@ FT_BEGIN_HEADER
#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' )
- FT_LOCAL( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Set_MM_Blend( TT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
- FT_LOCAL( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Set_Var_Design( TT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
- FT_LOCAL( FT_Error )
+ FT_EXPORT( FT_Error )
TT_Get_MM_Var( TT_Face face,
FT_MM_Var* *master );
+ FT_EXPORT( FT_Error )
+ TT_Get_Var_Design( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+ FT_EXPORT( FT_Error )
+ TT_Get_Var_Blend( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
FT_LOCAL( FT_Error )
tt_face_vary_cvt( TT_Face face,
@@ -169,8 +239,12 @@ FT_BEGIN_HEADER
FT_Outline* outline,
FT_UInt n_points );
+ FT_EXPORT( void )
+ tt_adjust_advance( TT_Face face,
+ FT_UInt gindex,
+ FT_UShort *aadvance );
- FT_LOCAL( void )
+ FT_EXPORT( void )
tt_done_blend( FT_Memory memory,
GX_Blend blend );