| Index: third_party/freetype/src/cff/cf2hints.c
|
| diff --git a/core/src/fxge/fx_freetype/fxft2.5.01/src/cff/cf2hints.c b/third_party/freetype/src/cff/cf2hints.c
|
| similarity index 88%
|
| rename from core/src/fxge/fx_freetype/fxft2.5.01/src/cff/cf2hints.c
|
| rename to third_party/freetype/src/cff/cf2hints.c
|
| index 70926299f3f1e5918a9becc855d58dbb34000775..040d193f3136b1a99628072c10a2c99158c04ab0 100644
|
| --- a/core/src/fxge/fx_freetype/fxft2.5.01/src/cff/cf2hints.c
|
| +++ b/third_party/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 */
|
| @@ -37,7 +37,7 @@
|
|
|
|
|
| #include "cf2ft.h"
|
| -#include "../../include/freetype/internal/ftdebug.h"
|
| +#include FT_INTERNAL_DEBUG_H
|
|
|
| #include "cf2glue.h"
|
| #include "cf2font.h"
|
| @@ -304,9 +304,6 @@
|
| cf2_hintmap_map( CF2_HintMap hintmap,
|
| CF2_Fixed csCoord )
|
| {
|
| - FT_ASSERT( hintmap->isValid ); /* must call Build before Map */
|
| - FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
|
| -
|
| if ( hintmap->count == 0 || ! hintmap->hinted )
|
| {
|
| /* there are no hints; use uniform scale and zero offset */
|
| @@ -317,6 +314,7 @@
|
| /* start linear search from last hit */
|
| CF2_UInt i = hintmap->lastIndex;
|
|
|
| + FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
|
|
|
| /* search up */
|
| while ( i < hintmap->count - 1 &&
|
| @@ -596,22 +594,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 +652,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 */
|
| @@ -725,7 +751,6 @@
|
| FT_Bool initialMap )
|
| {
|
| FT_Byte* maskPtr;
|
| - FT_Byte* maskEndPtr; // add by Xiaochuan_Liu
|
|
|
| CF2_Font font = hintmap->font;
|
| CF2_HintMaskRec tempHintMask;
|
| @@ -754,6 +779,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 */
|
| @@ -763,13 +790,14 @@
|
| /* make a copy of the hint mask so we can modify it */
|
| tempHintMask = *hintMask;
|
| maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
|
| - maskEndPtr = maskPtr + ( CF2_MAX_HINTS + 7 ) / 8;
|
| -
|
|
|
| /* use the hStem hints only, which are first in the mask */
|
| - /* TODO: compare this to cffhintmaskGetBitCount */
|
| bitCount = cf2_arrstack_size( hStemHintArray );
|
|
|
| + /* Defense-in-depth. Should never return here. */
|
| + if ( bitCount > hintMask->bitCount )
|
| + return;
|
| +
|
| /* synthetic embox hints get highest priority */
|
| if ( font->blues.doEmBoxHints )
|
| {
|
| @@ -830,11 +858,6 @@
|
| {
|
| /* move to next mask byte */
|
| maskPtr++;
|
| - if (maskPtr >= maskEndPtr)
|
| - {
|
| - break;
|
| - }
|
| -
|
| maskByte = 0x80;
|
| }
|
| else
|
| @@ -895,7 +918,6 @@
|
| /* insert remaining hints */
|
|
|
| maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
|
| - maskEndPtr = maskPtr + ( CF2_MAX_HINTS + 7 ) / 8;
|
|
|
| for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
|
| {
|
| @@ -926,10 +948,6 @@
|
| {
|
| /* move to next mask byte */
|
| maskPtr++;
|
| - if (maskPtr >= maskEndPtr)
|
| - {
|
| - break;
|
| - }
|
| maskByte = 0x80;
|
| }
|
| else
|
| @@ -1048,6 +1066,7 @@
|
|
|
| glyphpath->moveIsPending = TRUE;
|
| glyphpath->pathIsOpen = FALSE;
|
| + glyphpath->pathIsClosing = FALSE;
|
| glyphpath->elemIsQueued = FALSE;
|
| }
|
|
|
| @@ -1188,12 +1207,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:
|
| @@ -1263,16 +1286,32 @@
|
| params.op = CF2_PathOpLineTo;
|
|
|
| /* note: pt2 and pt3 are unused */
|
| - cf2_glyphpath_hintPoint( glyphpath,
|
| - hintmap,
|
| - ¶ms.pt1,
|
| - glyphpath->prevElemP1.x,
|
| - glyphpath->prevElemP1.y );
|
|
|
| - glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms );
|
| + if ( close )
|
| + {
|
| + /* use first hint map if closing */
|
| + cf2_glyphpath_hintPoint( glyphpath,
|
| + &glyphpath->firstHintMap,
|
| + ¶ms.pt1,
|
| + glyphpath->prevElemP1.x,
|
| + glyphpath->prevElemP1.y );
|
| + }
|
| + else
|
| + {
|
| + cf2_glyphpath_hintPoint( glyphpath,
|
| + hintmap,
|
| + ¶ms.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, ¶ms );
|
|
|
| + glyphpath->currentDS = params.pt1;
|
| + }
|
| break;
|
|
|
| case CF2_PathOpCubeTo:
|
| @@ -1309,11 +1348,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,
|
| - ¶ms.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,
|
| + ¶ms.pt1,
|
| + nextP0->x,
|
| + nextP0->y );
|
| + }
|
| + else
|
| + {
|
| + cf2_glyphpath_hintPoint( glyphpath,
|
| + hintmap,
|
| + ¶ms.pt1,
|
| + nextP0->x,
|
| + nextP0->y );
|
| + }
|
|
|
| if ( params.pt1.x != glyphpath->currentDS.x ||
|
| params.pt1.y != glyphpath->currentDS.y )
|
| @@ -1509,7 +1561,7 @@
|
| {
|
| /* -y */
|
| *x = -glyphpath->xOffset;
|
| - *y = glyphpath->xOffset;
|
| + *y = glyphpath->yOffset;
|
| }
|
| else
|
| {
|
| @@ -1524,6 +1576,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,
|
| @@ -1561,10 +1623,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).
|
| + */
|
|
|
| - /* can't compute offset of zero length line, so ignore them */
|
| - if ( glyphpath->currentCS.x == x && glyphpath->currentCS.y == y )
|
| + /* 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
|
| + *
|
| + */
|
| +
|
| + 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,
|
| @@ -1585,7 +1683,6 @@
|
| {
|
| /* emit offset 1st point as MoveTo */
|
| cf2_glyphpath_pushMove( glyphpath, P0 );
|
| - if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath->callbacks->error) return;
|
|
|
| glyphpath->moveIsPending = FALSE; /* adjust state machine */
|
| glyphpath->pathIsOpen = TRUE;
|
| @@ -1595,14 +1692,14 @@
|
|
|
| if ( glyphpath->elemIsQueued )
|
| {
|
| - FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) );
|
| + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
|
| + glyphpath->hintMap.count == 0 );
|
|
|
| cf2_glyphpath_pushPrevElem( glyphpath,
|
| &glyphpath->hintMap,
|
| &P0,
|
| P1,
|
| FALSE );
|
| - if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath->callbacks->error) return;
|
| }
|
|
|
| /* queue the current element with offset points */
|
| @@ -1612,7 +1709,7 @@
|
| glyphpath->prevElemP1 = P1;
|
|
|
| /* update current map */
|
| - if ( cf2_hintmask_isNew( glyphpath->hintMask ) )
|
| + if ( newHintMap )
|
| cf2_hintmap_build( &glyphpath->hintMap,
|
| glyphpath->hStemHintArray,
|
| glyphpath->vStemHintArray,
|
| @@ -1673,7 +1770,6 @@
|
| {
|
| /* emit offset 1st point as MoveTo */
|
| cf2_glyphpath_pushMove( glyphpath, P0 );
|
| - if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath->callbacks->error) return;
|
|
|
| glyphpath->moveIsPending = FALSE;
|
| glyphpath->pathIsOpen = TRUE;
|
| @@ -1683,14 +1779,14 @@
|
|
|
| if ( glyphpath->elemIsQueued )
|
| {
|
| - FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) );
|
| + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
|
| + glyphpath->hintMap.count == 0 );
|
|
|
| cf2_glyphpath_pushPrevElem( glyphpath,
|
| &glyphpath->hintMap,
|
| &P0,
|
| P1,
|
| FALSE );
|
| - if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath->callbacks->error) return;
|
| }
|
|
|
| /* queue the current element with offset points */
|
| @@ -1720,30 +1816,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 );
|
| - if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath->callbacks->error) return;
|
| -
|
| - /* 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;
|
| }
|
| }
|
|
|