aboutsummaryrefslogtreecommitdiff
path: root/freetype/src/cff
diff options
context:
space:
mode:
Diffstat (limited to 'freetype/src/cff')
-rw-r--r--freetype/src/cff/cf2blues.c13
-rw-r--r--freetype/src/cff/cf2font.c182
-rw-r--r--freetype/src/cff/cf2font.h2
-rw-r--r--freetype/src/cff/cf2ft.c48
-rw-r--r--freetype/src/cff/cf2hints.c200
-rw-r--r--freetype/src/cff/cf2hints.h4
-rw-r--r--freetype/src/cff/cffdrivr.c61
-rw-r--r--freetype/src/cff/cffgload.c6
-rw-r--r--freetype/src/cff/cffload.c25
-rw-r--r--freetype/src/cff/cffobjs.c13
-rw-r--r--freetype/src/cff/cffobjs.h2
-rw-r--r--freetype/src/cff/cffparse.c6
12 files changed, 429 insertions, 133 deletions
diff --git a/freetype/src/cff/cf2blues.c b/freetype/src/cff/cf2blues.c
index 5b348398a..250f89e0d 100644
--- a/freetype/src/cff/cf2blues.c
+++ b/freetype/src/cff/cf2blues.c
@@ -4,7 +4,7 @@
/* */
/* Adobe's code for handling Blue Zones (body). */
/* */
-/* Copyright 2009-2013 Adobe Systems Incorporated. */
+/* Copyright 2009-2014 Adobe Systems Incorporated. */
/* */
/* This software, and all works of authorship, whether in source or */
/* object code form as indicated by the copyright notice(s) included */
@@ -86,11 +86,13 @@
size_t i;
CF2_Fixed emBoxBottom, emBoxTop;
+#if 0
CF2_Int unitsPerEm = font->unitsPerEm;
if ( unitsPerEm == 0 )
unitsPerEm = 1000;
+#endif
FT_ZERO( blues );
blues->scale = font->innerTransform.d;
@@ -406,11 +408,10 @@
/* Note: constant changed from 0.5 to 0.6 to avoid a problem with */
/* 10ppem Arial */
- blues->boost = FT_MulFix(
- cf2_floatToFixed( .6 ),
- ( cf2_intToFixed( 1 ) -
- FT_DivFix( blues->scale,
- blues->blueScale ) ) );
+ blues->boost = cf2_floatToFixed( .6 ) -
+ FT_MulDiv( cf2_floatToFixed ( .6 ),
+ blues->scale,
+ blues->blueScale );
if ( blues->boost > 0x7FFF )
{
/* boost must remain less than 0.5, or baseline could go negative */
diff --git a/freetype/src/cff/cf2font.c b/freetype/src/cff/cf2font.c
index 479d9125d..6e99dc2f0 100644
--- a/freetype/src/cff/cf2font.c
+++ b/freetype/src/cff/cf2font.c
@@ -4,7 +4,7 @@
/* */
/* Adobe's code for font instances (body). */
/* */
-/* Copyright 2007-2013 Adobe Systems Incorporated. */
+/* Copyright 2007-2014 Adobe Systems Incorporated. */
/* */
/* This software, and all works of authorship, whether in source or */
/* object code form as indicated by the copyright notice(s) included */
@@ -51,10 +51,59 @@
CF2_Fixed stemWidth,
CF2_Fixed* darkenAmount,
CF2_Fixed boldenAmount,
- FT_Bool stemDarkened )
+ FT_Bool stemDarkened,
+ FT_Int* darkenParams )
{
+ /*
+ * Total darkening amount is computed in 1000 unit character space
+ * using the modified 5 part curve as Adobe's Avalon rasterizer.
+ * The darkening amount is smaller for thicker stems.
+ * It becomes zero when the stem is thicker than 2.333 pixels.
+ *
+ * By default, we use
+ *
+ * darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels,
+ * darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
+ * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels,
+ *
+ * and piecewise linear in-between:
+ *
+ *
+ * darkening
+ * ^
+ * |
+ * | (x1,y1)
+ * |--------+
+ * | \
+ * | \
+ * | \ (x3,y3)
+ * | +----------+
+ * | (x2,y2) \
+ * | \
+ * | \
+ * | +-----------------
+ * | (x4,y4)
+ * +---------------------------------------------> stem
+ * thickness
+ *
+ *
+ * This corresponds to the following values for the
+ * `darkening-parameters' property:
+ *
+ * (x1, y1) = (500, 400)
+ * (x2, y2) = (1000, 275)
+ * (x3, y3) = (1667, 275)
+ * (x4, y4) = (2333, 0)
+ *
+ */
+
/* Internal calculations are done in units per thousand for */
- /* convenience. */
+ /* convenience. The x axis is scaled stem width in */
+ /* thousandths of a pixel. That is, 1000 is 1 pixel. */
+ /* The y axis is darkening amount in thousandths of a pixel.*/
+ /* In the code, below, dividing by ppem and */
+ /* adjusting for emRatio converts darkenAmount to character */
+ /* space (font units). */
CF2_Fixed stemWidthPer1000, scaledStem;
@@ -69,6 +118,16 @@
if ( stemDarkened )
{
+ FT_Int x1 = darkenParams[0];
+ FT_Int y1 = darkenParams[1];
+ FT_Int x2 = darkenParams[2];
+ FT_Int y2 = darkenParams[3];
+ FT_Int x3 = darkenParams[4];
+ FT_Int y3 = darkenParams[5];
+ FT_Int x4 = darkenParams[6];
+ FT_Int y4 = darkenParams[7];
+
+
/* convert from true character space to 1000 unit character space; */
/* add synthetic emboldening effect */
@@ -81,7 +140,7 @@
stemWidthPer1000 <= ( stemWidth + boldenAmount ) )
{
stemWidthPer1000 = 0; /* to pacify compiler */
- scaledStem = cf2_intToFixed( 2333 );
+ scaledStem = cf2_intToFixed( x4 );
}
else
{
@@ -89,39 +148,70 @@
if ( ppem > CF2_FIXED_ONE &&
scaledStem <= stemWidthPer1000 )
- scaledStem = cf2_intToFixed( 2333 );
+ scaledStem = cf2_intToFixed( x4 );
+ }
+
+ /* now apply the darkening parameters */
+
+ if ( scaledStem < cf2_intToFixed( x1 ) )
+ *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem );
+
+ else if ( scaledStem < cf2_intToFixed( x2 ) )
+ {
+ FT_Int xdelta = x2 - x1;
+ FT_Int ydelta = y2 - y1;
+ FT_Int x = stemWidthPer1000 -
+ FT_DivFix( cf2_intToFixed( x1 ), ppem );
+
+
+ if ( !xdelta )
+ goto Try_x3;
+
+ *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+ FT_DivFix( cf2_intToFixed( y1 ), ppem );
+ }
+
+ else if ( scaledStem < cf2_intToFixed( x3 ) )
+ {
+ Try_x3:
+ {
+ FT_Int xdelta = x3 - x2;
+ FT_Int ydelta = y3 - y2;
+ FT_Int x = stemWidthPer1000 -
+ FT_DivFix( cf2_intToFixed( x2 ), ppem );
+
+
+ if ( !xdelta )
+ goto Try_x4;
+
+ *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+ FT_DivFix( cf2_intToFixed( y2 ), ppem );
+ }
+ }
+
+ else if ( scaledStem < cf2_intToFixed( x4 ) )
+ {
+ Try_x4:
+ {
+ FT_Int xdelta = x4 - x3;
+ FT_Int ydelta = y4 - y3;
+ FT_Int x = stemWidthPer1000 -
+ FT_DivFix( cf2_intToFixed( x3 ), ppem );
+
+
+ if ( !xdelta )
+ goto Use_y4;
+
+ *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+ FT_DivFix( cf2_intToFixed( y3 ), ppem );
+ }
}
- /*
- * Total darkening amount is computed in 1000 unit character space
- * using the modified 5 part curve as Avalon rasterizer.
- * The darkening amount is smaller for thicker stems.
- * It becomes zero when the stem is thicker than 2.333 pixels.
- *
- * In Avalon rasterizer,
- *
- * darkenAmount = 0.5 pixels if scaledStem <= 0.5 pixels,
- * darkenAmount = 0.333 pixels if 1 <= scaledStem <= 1.667 pixels,
- * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels,
- *
- * and piecewise linear in-between.
- *
- */
- if ( scaledStem < cf2_intToFixed( 500 ) )
- *darkenAmount = FT_DivFix( cf2_intToFixed( 400 ), ppem );
-
- else if ( scaledStem < cf2_intToFixed( 1000 ) )
- *darkenAmount = FT_DivFix( cf2_intToFixed( 525 ), ppem ) -
- FT_MulFix( stemWidthPer1000,
- cf2_floatToFixed( .25 ) );
-
- else if ( scaledStem < cf2_intToFixed( 1667 ) )
- *darkenAmount = FT_DivFix( cf2_intToFixed( 275 ), ppem );
-
- else if ( scaledStem < cf2_intToFixed( 2333 ) )
- *darkenAmount = FT_DivFix( cf2_intToFixed( 963 ), ppem ) -
- FT_MulFix( stemWidthPer1000,
- cf2_floatToFixed( .413 ) );
+ else
+ {
+ Use_y4:
+ *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem );
+ }
/* use half the amount on each side and convert back to true */
/* character space */
@@ -143,13 +233,14 @@
/* pointer to parsed font object */
CFF_Decoder* decoder = font->decoder;
- FT_Bool needExtraSetup;
+ FT_Bool needExtraSetup = FALSE;
/* character space units */
CF2_Fixed boldenX = font->syntheticEmboldeningAmountX;
CF2_Fixed boldenY = font->syntheticEmboldeningAmountY;
- CF2_Fixed ppem;
+ CFF_SubFont subFont;
+ CF2_Fixed ppem;
/* clear previous error */
@@ -157,8 +248,12 @@
/* if a CID fontDict has changed, we need to recompute some cached */
/* data */
- needExtraSetup =
- (FT_Bool)( font->lastSubfont != cf2_getSubfont( decoder ) );
+ subFont = cf2_getSubfont( decoder );
+ if ( font->lastSubfont != subFont )
+ {
+ font->lastSubfont = subFont;
+ needExtraSetup = TRUE;
+ }
/* if ppem has changed, we need to recompute some cached data */
/* note: because of CID font matrix concatenation, ppem and transform */
@@ -268,7 +363,8 @@
font->stdVW,
&font->darkenX,
boldenX,
- FALSE );
+ FALSE,
+ font->darkenParams );
}
else
cf2_computeDarkening( emRatio,
@@ -276,7 +372,8 @@
font->stdVW,
&font->darkenX,
0,
- font->stemDarkened );
+ font->stemDarkened,
+ font->darkenParams );
#if 0
/* since hstem is measured in the y-direction, we use the `d' member */
@@ -303,7 +400,8 @@
font->stdHW,
&font->darkenY,
boldenY,
- font->stemDarkened );
+ font->stemDarkened,
+ font->darkenParams );
if ( font->darkenX != 0 || font->darkenY != 0 )
font->darkened = TRUE;
diff --git a/freetype/src/cff/cf2font.h b/freetype/src/cff/cf2font.h
index f9dd1bbd4..d8860ce8e 100644
--- a/freetype/src/cff/cf2font.h
+++ b/freetype/src/cff/cf2font.h
@@ -85,6 +85,8 @@ FT_BEGIN_HEADER
/* i.e. darkenX != 0 || darkenY != 0 */
FT_Bool stemDarkened;
+ FT_Int darkenParams[8]; /* 1000 unit character space */
+
/* variables that depend on both FontDict and Transform */
CF2_Fixed stdVW; /* in character space; depends on dict entry */
CF2_Fixed stdHW; /* in character space; depends on dict entry */
diff --git a/freetype/src/cff/cf2ft.c b/freetype/src/cff/cf2ft.c
index c09a0244a..cb8d31c53 100644
--- a/freetype/src/cff/cf2ft.c
+++ b/freetype/src/cff/cf2ft.c
@@ -4,7 +4,7 @@
/* */
/* FreeType Glue Component to Adobe's Interpreter (body). */
/* */
-/* Copyright 2013 Adobe Systems Incorporated. */
+/* Copyright 2013-2014 Adobe Systems Incorporated. */
/* */
/* This software, and all works of authorship, whether in source or */
/* object code form as indicated by the copyright notice(s) included */
@@ -61,7 +61,9 @@
FT_ASSERT( unitsPerEm > 0 );
- FT_ASSERT( transform->a > 0 && transform->d > 0 );
+ if ( transform->a <= 0 || transform->d <= 0 )
+ return FT_THROW( Invalid_Size_Handle );
+
FT_ASSERT( transform->b == 0 && transform->c == 0 );
FT_ASSERT( transform->tx == 0 && transform->ty == 0 );
@@ -236,10 +238,8 @@
if ( *hinted )
{
- *x_scale = FT_DivFix( decoder->builder.glyph->x_scale,
- cf2_intToFixed( 64 ) );
- *y_scale = FT_DivFix( decoder->builder.glyph->y_scale,
- cf2_intToFixed( 64 ) );
+ *x_scale = ( decoder->builder.glyph->x_scale + 32 ) / 64;
+ *y_scale = ( decoder->builder.glyph->y_scale + 32 ) / 64;
}
else
{
@@ -344,13 +344,25 @@
if ( scaled && !driver->no_stem_darkening )
font->renderingFlags |= CF2_FlagsDarkened;
+ font->darkenParams[0] = driver->darken_params[0];
+ font->darkenParams[1] = driver->darken_params[1];
+ font->darkenParams[2] = driver->darken_params[2];
+ font->darkenParams[3] = driver->darken_params[3];
+ font->darkenParams[4] = driver->darken_params[4];
+ font->darkenParams[5] = driver->darken_params[5];
+ font->darkenParams[6] = driver->darken_params[6];
+ font->darkenParams[7] = driver->darken_params[7];
+
/* now get an outline for this glyph; */
/* also get units per em to validate scale */
font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );
- error2 = cf2_checkTransform( &transform, font->unitsPerEm );
- if ( error2 )
- return error2;
+ if ( scaled )
+ {
+ error2 = cf2_checkTransform( &transform, font->unitsPerEm );
+ if ( error2 )
+ return error2;
+ }
error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth );
if ( error2 )
@@ -380,8 +392,16 @@
FT_ASSERT( decoder &&
decoder->builder.face &&
decoder->builder.face->root.size );
- FT_ASSERT( decoder->builder.face->root.size->metrics.y_ppem );
+ /*
+ * Note that `y_ppem' can be zero if there wasn't a call to
+ * `FT_Set_Char_Size' or something similar. However, this isn't a
+ * problem since we come to this place in the code only if
+ * FT_LOAD_NO_SCALE is set (the other case gets caught by
+ * `cf2_checkTransform'). The ppem value is needed to compute the stem
+ * darkening, which is disabled for getting the unscaled outline.
+ *
+ */
return cf2_intToFixed(
decoder->builder.face->root.size->metrics.y_ppem );
}
@@ -499,7 +519,7 @@
CF2_UInt idx,
CF2_Buffer buf )
{
- FT_ASSERT( decoder && decoder->globals );
+ FT_ASSERT( decoder );
FT_ZERO( buf );
@@ -507,6 +527,8 @@
if ( idx >= decoder->num_globals )
return TRUE; /* error */
+ FT_ASSERT( decoder->globals );
+
buf->start =
buf->ptr = decoder->globals[idx];
buf->end = decoder->globals[idx + 1];
@@ -572,7 +594,7 @@
CF2_UInt idx,
CF2_Buffer buf )
{
- FT_ASSERT( decoder && decoder->locals );
+ FT_ASSERT( decoder );
FT_ZERO( buf );
@@ -580,6 +602,8 @@
if ( idx >= decoder->num_locals )
return TRUE; /* error */
+ FT_ASSERT( decoder->locals );
+
buf->start =
buf->ptr = decoder->locals[idx];
buf->end = decoder->locals[idx + 1];
diff --git a/freetype/src/cff/cf2hints.c b/freetype/src/cff/cf2hints.c
index 96bd49f18..5853d7758 100644
--- a/freetype/src/cff/cf2hints.c
+++ b/freetype/src/cff/cf2hints.c
@@ -4,7 +4,7 @@
/* */
/* Adobe's code for handling CFF hints (body). */
/* */
-/* Copyright 2007-2013 Adobe Systems Incorporated. */
+/* Copyright 2007-2014 Adobe Systems Incorporated. */
/* */
/* This software, and all works of authorship, whether in source or */
/* object code form as indicated by the copyright notice(s) included */
@@ -596,22 +596,31 @@
indexInsert = 0;
for ( ; indexInsert < hintmap->count; indexInsert++ )
{
- if ( hintmap->edge[indexInsert].csCoord > firstHintEdge->csCoord )
+ if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord )
break;
}
/*
- * Discard any hints that overlap in character space. Most often,
- * this is while building the initial map, but in theory, it can also
- * occur because of darkening.
+ * Discard any hints that overlap in character space. Most often, this
+ * is while building the initial map, where captured hints from all
+ * zones are combined. Define overlap to include hints that `touch'
+ * (overlap zero). Hiragino Sans/Gothic fonts have numerous hints that
+ * touch. Some fonts have non-ideographic glyphs that overlap our
+ * synthetic hints.
+ *
+ * Overlap also occurs when darkening stem hints that are close.
*
*/
if ( indexInsert < hintmap->count )
{
- /* we are inserting before an existing edge: */
+ /* we are inserting before an existing edge: */
+ /* verify that an existing edge is not the same */
+ if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord )
+ return; /* ignore overlapping stem hint */
+
/* verify that a new pair does not straddle the next edge */
- if ( isPair &&
- hintmap->edge[indexInsert].csCoord < secondHintEdge->csCoord )
+ if ( isPair &&
+ hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord )
return; /* ignore overlapping stem hint */
/* verify that we are not inserting between paired edges */
@@ -645,8 +654,27 @@
firstHintEdge->csCoord );
}
- /* discard any hints that overlap in device space; this can occur */
- /* because locked hints have been moved to align with blue zones */
+ /*
+ * Discard any hints that overlap in device space; this can occur
+ * because locked hints have been moved to align with blue zones.
+ *
+ * TODO: Although we might correct this later during adjustment, we
+ * don't currently have a way to delete a conflicting hint once it has
+ * been inserted. See v2.030 MinionPro-Regular, 12 ppem darkened,
+ * initial hint map for second path, glyph 945 (the perispomeni (tilde)
+ * in U+1F6E, Greek omega with psili and perispomeni). Darkening is
+ * 25. Pair 667,747 initially conflicts in design space with top edge
+ * 660. This is because 667 maps to 7.87, and the top edge was
+ * captured by a zone at 8.0. The pair is later successfully inserted
+ * in a zone without the top edge. In this zone it is adjusted to 8.0,
+ * and no longer conflicts with the top edge in design space. This
+ * means it can be included in yet a later zone which does have the top
+ * edge hint. This produces a small mismatch between the first and
+ * last points of this path, even though the hint masks are the same.
+ * The density map difference is tiny (1/256).
+ *
+ */
+
if ( indexInsert > 0 )
{
/* we are inserting after an existing edge */
@@ -753,6 +781,8 @@
cf2_hintmask_setAll( hintMask,
cf2_arrstack_size( hStemHintArray ) +
cf2_arrstack_size( vStemHintArray ) );
+ if ( !cf2_hintmask_isValid( hintMask ) )
+ return; /* too many stem hints */
}
/* begin by clearing the map */
@@ -1035,6 +1065,7 @@
glyphpath->moveIsPending = TRUE;
glyphpath->pathIsOpen = FALSE;
+ glyphpath->pathIsClosing = FALSE;
glyphpath->elemIsQueued = FALSE;
}
@@ -1175,12 +1206,16 @@
/*
* Push the cached element (glyphpath->prevElem*) to the outline
* consumer. When a darkening offset is used, the end point of the
- * cached element may be adjusted to an intersection point or it may be
- * connected by a line to the current element. This calculation must
- * use a HintMap that was valid at the time the element was saved. For
- * the first point in a subpath, that is a saved HintMap. For most
- * elements, it just means the caller has delayed building a HintMap
- * from the current HintMask.
+ * cached element may be adjusted to an intersection point or we may
+ * synthesize a connecting line to the current element. If we are
+ * closing a subpath, we may also generate a connecting line to the start
+ * point.
+ *
+ * This is where Character Space (CS) is converted to Device Space (DS)
+ * using a hint map. This calculation must use a HintMap that was valid
+ * at the time the element was saved. For the first point in a subpath,
+ * that is a saved HintMap. For most elements, it just means the caller
+ * has delayed building a HintMap from the current HintMask.
*
* Transform each point with outerTransform and call the outline
* callbacks. This is a general 3x3 transform:
@@ -1250,16 +1285,32 @@
params.op = CF2_PathOpLineTo;
/* note: pt2 and pt3 are unused */
- cf2_glyphpath_hintPoint( glyphpath,
- hintmap,
- &params.pt1,
- glyphpath->prevElemP1.x,
- glyphpath->prevElemP1.y );
- glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
+ if ( close )
+ {
+ /* use first hint map if closing */
+ cf2_glyphpath_hintPoint( glyphpath,
+ &glyphpath->firstHintMap,
+ &params.pt1,
+ glyphpath->prevElemP1.x,
+ glyphpath->prevElemP1.y );
+ }
+ else
+ {
+ cf2_glyphpath_hintPoint( glyphpath,
+ hintmap,
+ &params.pt1,
+ glyphpath->prevElemP1.x,
+ glyphpath->prevElemP1.y );
+ }
- glyphpath->currentDS = params.pt1;
+ /* output only non-zero length lines */
+ if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y )
+ {
+ glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
+ glyphpath->currentDS = params.pt1;
+ }
break;
case CF2_PathOpCubeTo:
@@ -1296,11 +1347,24 @@
/* note: at the end of a subpath, we might do both, so use `nextP0' */
/* before we change it, below */
- cf2_glyphpath_hintPoint( glyphpath,
- hintmap,
- &params.pt1,
- nextP0->x,
- nextP0->y );
+ if ( close )
+ {
+ /* if we are closing the subpath, then nextP0 is in the first */
+ /* hint zone */
+ cf2_glyphpath_hintPoint( glyphpath,
+ &glyphpath->firstHintMap,
+ &params.pt1,
+ nextP0->x,
+ nextP0->y );
+ }
+ else
+ {
+ cf2_glyphpath_hintPoint( glyphpath,
+ hintmap,
+ &params.pt1,
+ nextP0->x,
+ nextP0->y );
+ }
if ( params.pt1.x != glyphpath->currentDS.x ||
params.pt1.y != glyphpath->currentDS.y )
@@ -1511,6 +1575,16 @@
}
+ /*
+ * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are
+ * called by the interpreter with Character Space (CS) coordinates. Each
+ * path element is placed into a queue of length one to await the
+ * calculation of the following element. At that time, the darkening
+ * offset of the following element is known and joins can be computed,
+ * including possible modification of this element, before mapping to
+ * Device Space (DS) and passing it on to the outline consumer.
+ *
+ */
FT_LOCAL_DEF( void )
cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath,
CF2_Fixed x,
@@ -1548,10 +1622,46 @@
{
CF2_Fixed xOffset, yOffset;
FT_Vector P0, P1;
+ FT_Bool newHintMap;
+
+ /*
+ * New hints will be applied after cf2_glyphpath_pushPrevElem has run.
+ * In case this is a synthesized closing line, any new hints should be
+ * delayed until this path is closed (`cf2_hintmask_isNew' will be
+ * called again before the next line or curve).
+ */
+
+ /* true if new hint map not on close */
+ newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) &&
+ !glyphpath->pathIsClosing;
+
+ /*
+ * Zero-length lines may occur in the charstring. Because we cannot
+ * compute darkening offsets or intersections from zero-length lines,
+ * it is best to remove them and avoid artifacts. However, zero-length
+ * lines in CS at the start of a new hint map can generate non-zero
+ * lines in DS due to hint substitution. We detect a change in hint
+ * map here and pass those zero-length lines along.
+ */
+ /*
+ * Note: Find explicitly closed paths here with a conditional
+ * breakpoint using
+ *
+ * !gp->pathIsClosing && gp->start.x == x && gp->start.y == y
+ *
+ */
- /* can't compute offset of zero length line, so ignore them */
- if ( glyphpath->currentCS.x == x && glyphpath->currentCS.y == y )
+ if ( glyphpath->currentCS.x == x &&
+ glyphpath->currentCS.y == y &&
+ !newHintMap )
+ /*
+ * Ignore zero-length lines in CS where the hint map is the same
+ * because the line in DS will also be zero length.
+ *
+ * Ignore zero-length lines when we synthesize a closing line because
+ * the close will be handled in cf2_glyphPath_pushPrevElem.
+ */
return;
cf2_glyphpath_computeOffset( glyphpath,
@@ -1597,7 +1707,7 @@
glyphpath->prevElemP1 = P1;
/* update current map */
- if ( cf2_hintmask_isNew( glyphpath->hintMask ) )
+ if ( newHintMap )
cf2_hintmap_build( &glyphpath->hintMap,
glyphpath->hStemHintArray,
glyphpath->vStemHintArray,
@@ -1703,29 +1813,29 @@
{
if ( glyphpath->pathIsOpen )
{
- FT_ASSERT( cf2_hintmap_isValid( &glyphpath->firstHintMap ) );
+ /*
+ * A closing line in Character Space line is always generated below
+ * with `cf2_glyphPath_lineTo'. It may be ignored later if it turns
+ * out to be zero length in Device Space.
+ */
+ glyphpath->pathIsClosing = TRUE;
- /* since we need to apply an offset to the implicit lineto, we make */
- /* it explicit here */
cf2_glyphpath_lineTo( glyphpath,
glyphpath->start.x,
glyphpath->start.y );
- /* Draw previous element (the explicit LineTo we just created, */
- /* above) and connect it to the start point, but with the offset we */
- /* saved from the first element. */
- /* Use the saved HintMap, too. */
- FT_ASSERT( glyphpath->elemIsQueued );
-
- cf2_glyphpath_pushPrevElem( glyphpath,
- &glyphpath->firstHintMap,
- &glyphpath->offsetStart0,
- glyphpath->offsetStart1,
- TRUE );
+ /* empty the final element from the queue and close the path */
+ if ( glyphpath->elemIsQueued )
+ cf2_glyphpath_pushPrevElem( glyphpath,
+ &glyphpath->hintMap,
+ &glyphpath->offsetStart0,
+ glyphpath->offsetStart1,
+ TRUE );
/* reset state machine */
glyphpath->moveIsPending = TRUE;
glyphpath->pathIsOpen = FALSE;
+ glyphpath->pathIsClosing = FALSE;
glyphpath->elemIsQueued = FALSE;
}
}
diff --git a/freetype/src/cff/cf2hints.h b/freetype/src/cff/cf2hints.h
index c4fa922a3..f25d91bf8 100644
--- a/freetype/src/cff/cf2hints.h
+++ b/freetype/src/cff/cf2hints.h
@@ -204,6 +204,7 @@ FT_BEGIN_HEADER
#endif
FT_Bool pathIsOpen; /* true after MoveTo */
+ FT_Bool pathIsClosing; /* true when synthesizing closepath line */
FT_Bool darken; /* true if stem darkening */
FT_Bool moveIsPending; /* true between MoveTo and offset MoveTo */
@@ -229,7 +230,8 @@ FT_BEGIN_HEADER
FT_Vector currentCS;
/* current point, device space */
FT_Vector currentDS;
- FT_Vector start; /* start point of subpath */
+ /* start point of subpath, character space */
+ FT_Vector start;
/* the following members constitute the `queue' of one element */
FT_Bool elemIsQueued;
diff --git a/freetype/src/cff/cffdrivr.c b/freetype/src/cff/cffdrivr.c
index c8ca96ba4..dde7d4488 100644
--- a/freetype/src/cff/cffdrivr.c
+++ b/freetype/src/cff/cffdrivr.c
@@ -164,6 +164,8 @@
if ( !slot )
return FT_THROW( Invalid_Slot_Handle );
+ FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
+
/* check whether we want a scaled outline or bitmap */
if ( !size )
load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
@@ -586,7 +588,38 @@
CFF_Driver driver = (CFF_Driver)module;
- if ( !ft_strcmp( property_name, "hinting-engine" ) )
+ if ( !ft_strcmp( property_name, "darkening-parameters" ) )
+ {
+ FT_Int* darken_params = (FT_Int*)value;
+
+ FT_Int x1 = darken_params[0];
+ FT_Int y1 = darken_params[1];
+ FT_Int x2 = darken_params[2];
+ FT_Int y2 = darken_params[3];
+ FT_Int x3 = darken_params[4];
+ FT_Int y3 = darken_params[5];
+ FT_Int x4 = darken_params[6];
+ FT_Int y4 = darken_params[7];
+
+
+ if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 ||
+ y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 ||
+ x1 > x2 || x2 > x3 || x3 > x4 ||
+ y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 )
+ return FT_THROW( Invalid_Argument );
+
+ driver->darken_params[0] = x1;
+ driver->darken_params[1] = y1;
+ driver->darken_params[2] = x2;
+ driver->darken_params[3] = y2;
+ driver->darken_params[4] = x3;
+ driver->darken_params[5] = y3;
+ driver->darken_params[6] = x4;
+ driver->darken_params[7] = y4;
+
+ return error;
+ }
+ else if ( !ft_strcmp( property_name, "hinting-engine" ) )
{
FT_UInt* hinting_engine = (FT_UInt*)value;
@@ -624,13 +657,28 @@
FT_Error error = FT_Err_Ok;
CFF_Driver driver = (CFF_Driver)module;
- FT_UInt hinting_engine = driver->hinting_engine;
- FT_Bool no_stem_darkening = driver->no_stem_darkening;
+ if ( !ft_strcmp( property_name, "darkening-parameters" ) )
+ {
+ FT_Int* darken_params = driver->darken_params;
+ FT_Int* val = (FT_Int*)value;
+
+
+ val[0] = darken_params[0];
+ val[1] = darken_params[1];
+ val[2] = darken_params[2];
+ val[3] = darken_params[3];
+ val[4] = darken_params[4];
+ val[5] = darken_params[5];
+ val[6] = darken_params[6];
+ val[7] = darken_params[7];
- if ( !ft_strcmp( property_name, "hinting-engine" ) )
+ return error;
+ }
+ else if ( !ft_strcmp( property_name, "hinting-engine" ) )
{
- FT_UInt* val = (FT_UInt*)value;
+ FT_UInt hinting_engine = driver->hinting_engine;
+ FT_UInt* val = (FT_UInt*)value;
*val = hinting_engine;
@@ -639,7 +687,8 @@
}
else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
{
- FT_Bool* val = (FT_Bool*)value;
+ FT_Bool no_stem_darkening = driver->no_stem_darkening;
+ FT_Bool* val = (FT_Bool*)value;
*val = no_stem_darkening;
diff --git a/freetype/src/cff/cffgload.c b/freetype/src/cff/cffgload.c
index 6a8494fa9..c8e9f9124 100644
--- a/freetype/src/cff/cffgload.c
+++ b/freetype/src/cff/cffgload.c
@@ -434,7 +434,7 @@
goto Exit;
}
- FT_TRACE3(( "glyph index %d (subfont %d):\n", glyph_index, fd_index ));
+ FT_TRACE3(( " in subfont %d:\n", fd_index ));
sub = cff->subfonts[fd_index];
@@ -447,10 +447,6 @@
builder->hints_globals = (void *)internal->subfonts[fd_index];
}
}
-#ifdef FT_DEBUG_LEVEL_TRACE
- else
- FT_TRACE3(( "glyph index %d:\n", glyph_index ));
-#endif
decoder->num_locals = sub->local_subrs_index.count;
decoder->locals = sub->local_subrs;
diff --git a/freetype/src/cff/cffload.c b/freetype/src/cff/cffload.c
index 64b497168..d9bec5966 100644
--- a/freetype/src/cff/cffload.c
+++ b/freetype/src/cff/cffload.c
@@ -4,7 +4,7 @@
/* */
/* OpenType and CFF data/program tables loader (body). */
/* */
-/* Copyright 1996-2013 by */
+/* Copyright 1996-2014 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -414,7 +414,7 @@
cur_offset = idx->offsets[0] - 1;
/* sanity check */
- if ( cur_offset >= idx->data_size )
+ if ( cur_offset != 0 )
{
FT_TRACE0(( "cff_index_get_pointers:"
" invalid first offset value %d set to zero\n",
@@ -432,11 +432,11 @@
FT_ULong next_offset = idx->offsets[n] - 1;
- /* empty slot + two sanity checks for invalid offset tables */
- if ( next_offset == 0 ||
- next_offset < cur_offset ||
- ( next_offset >= idx->data_size && n < idx->count ) )
+ /* two sanity checks for invalid offset tables */
+ if ( next_offset < cur_offset )
next_offset = cur_offset;
+ else if ( next_offset > idx->data_size )
+ next_offset = idx->data_size;
if ( !pool )
t[n] = org_bytes + next_offset;
@@ -689,6 +689,13 @@
if ( FT_READ_USHORT( num_ranges ) )
goto Exit;
+ if ( !num_ranges )
+ {
+ FT_TRACE0(( "CFF_Load_FD_Select: empty FDSelect array\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
fdselect->data_size = num_ranges * 3 + 2;
Load_Data:
@@ -719,7 +726,7 @@
break;
case 3:
- /* first, compare to cache */
+ /* first, compare to the cache */
if ( (FT_UInt)( glyph_index - fdselect->cache_first ) <
fdselect->cache_count )
{
@@ -727,7 +734,7 @@
break;
}
- /* then, lookup the ranges array */
+ /* then, look up the ranges array */
{
FT_Byte* p = fdselect->data;
FT_Byte* p_limit = p + fdselect->data_size;
@@ -750,7 +757,7 @@
/* update cache */
fdselect->cache_first = first;
- fdselect->cache_count = limit-first;
+ fdselect->cache_count = limit - first;
fdselect->cache_fd = fd2;
break;
}
diff --git a/freetype/src/cff/cffobjs.c b/freetype/src/cff/cffobjs.c
index dd750d104..cac4ac2bd 100644
--- a/freetype/src/cff/cffobjs.c
+++ b/freetype/src/cff/cffobjs.c
@@ -866,7 +866,7 @@
flags |= FT_FACE_FLAG_KERNING;
#endif
- cffface->face_flags = flags;
+ cffface->face_flags |= flags;
/*******************************************************************/
/* */
@@ -1055,7 +1055,7 @@
CFF_Driver driver = (CFF_Driver)module;
- /* set default property values */
+ /* set default property values, cf `ftcffdrv.h' */
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
driver->hinting_engine = FT_CFF_HINTING_FREETYPE;
#else
@@ -1063,6 +1063,15 @@
#endif
driver->no_stem_darkening = FALSE;
+ driver->darken_params[0] = 500;
+ driver->darken_params[1] = 400;
+ driver->darken_params[2] = 1000;
+ driver->darken_params[3] = 275;
+ driver->darken_params[4] = 1667;
+ driver->darken_params[5] = 275;
+ driver->darken_params[6] = 2333;
+ driver->darken_params[7] = 0;
+
return FT_Err_Ok;
}
diff --git a/freetype/src/cff/cffobjs.h b/freetype/src/cff/cffobjs.h
index b375c20c7..dfbf9a96b 100644
--- a/freetype/src/cff/cffobjs.h
+++ b/freetype/src/cff/cffobjs.h
@@ -121,6 +121,8 @@ FT_BEGIN_HEADER
FT_UInt hinting_engine;
FT_Bool no_stem_darkening;
+ FT_Int darken_params[8];
+
} CFF_DriverRec;
diff --git a/freetype/src/cff/cffparse.c b/freetype/src/cff/cffparse.c
index 96222120b..91bd5326c 100644
--- a/freetype/src/cff/cffparse.c
+++ b/freetype/src/cff/cffparse.c
@@ -4,7 +4,7 @@
/* */
/* CFF token stream parser (body) */
/* */
-/* Copyright 1996-2004, 2007-2013 by */
+/* Copyright 1996-2004, 2007-2014 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -66,7 +66,6 @@
goto Bad;
val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] );
- p += 2;
}
else if ( v == 29 )
{
@@ -77,7 +76,6 @@
( (FT_ULong)p[1] << 16 ) |
( (FT_ULong)p[2] << 8 ) |
(FT_ULong)p[3] );
- p += 4;
}
else if ( v < 247 )
{
@@ -89,7 +87,6 @@
goto Bad;
val = ( v - 247 ) * 256 + p[0] + 108;
- p++;
}
else
{
@@ -97,7 +94,6 @@
goto Bad;
val = -( v - 251 ) * 256 - p[0] - 108;
- p++;
}
Exit: