Use unsigned point and contour indexing in `FT_Outline`.

This doubles the number or allowed points, see
    https://github.com/harfbuzz/harfbuzz/issues/4752

Although it is hardly practical to use more than 32767 points,
other font engines seem to support it.

* docs/CHANGES: Announce it.
* include/freetype/ftimage.h (FT_Outline): Do it and update limits.
* src/*: Update `FT_Outline` users.
This commit is contained in:
Alexei Podtelezhnikov 2024-06-20 20:49:56 -04:00
parent 2b9fdec5fa
commit 2a7bb4596f
16 changed files with 65 additions and 58 deletions

View File

@ -1,13 +1,21 @@
CHANGES BETWEEN 2.13.2 and 2.13.3 (2024-Mmm-DD)
I. IMPORTANT BUG FIXES
I. IMPORTANT CHANGES
- Some fields in the `FT_Outline` structure have been changed
from signed to unsigned type, which better reflects the actual
usage. It is also an additional means to protect against
malformed input.
II. IMPORTANT BUG FIXES
- Rare double-free crashes in the cache subsystem have been fixed.
- Excessive stack allocation in the autohinter has been fixed.
II. MISCELLANEOUS
III. MISCELLANEOUS
- The B/W rasterizer has received a major upkeep that resulted in
large performance improvement. The rendering speed has increased

View File

@ -345,14 +345,14 @@ FT_BEGIN_HEADER
*/
typedef struct FT_Outline_
{
short n_contours; /* number of contours in glyph */
short n_points; /* number of points in the glyph */
unsigned short n_contours; /* number of contours in glyph */
unsigned short n_points; /* number of points in the glyph */
FT_Vector* points; /* the outline's points */
char* tags; /* the points flags */
short* contours; /* the contour end points */
FT_Vector* points; /* the outline's points */
char* tags; /* the points flags */
unsigned short* contours; /* the contour end points */
int flags; /* outline masks */
int flags; /* outline masks */
} FT_Outline;
@ -360,8 +360,8 @@ FT_BEGIN_HEADER
/* Following limits must be consistent with */
/* FT_Outline.{n_contours,n_points} */
#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX
#define FT_OUTLINE_POINTS_MAX SHRT_MAX
#define FT_OUTLINE_CONTOURS_MAX USHRT_MAX
#define FT_OUTLINE_POINTS_MAX USHRT_MAX
/**************************************************************************

View File

@ -1655,9 +1655,9 @@ FT_BEGIN_HEADER
{
FT_Memory memory;
FT_UShort max_points;
FT_Short max_contours;
FT_UShort max_contours;
FT_UShort n_points; /* number of points in zone */
FT_Short n_contours; /* number of contours */
FT_UShort n_contours; /* number of contours */
FT_Vector* org; /* original point coordinates */
FT_Vector* cur; /* current point coordinates */

View File

@ -980,7 +980,7 @@
{
FT_Vector* vec = outline->points;
char* tag = outline->tags;
FT_Short endpoint = outline->contours[0];
FT_UShort endpoint = outline->contours[0];
AF_Point end = points + endpoint;
AF_Point prev = end;
FT_Int contour_index = 0;
@ -1046,10 +1046,10 @@
/* set up the contours array */
{
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
short* end = outline->contours;
FT_Int idx = 0;
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
FT_UShort* end = outline->contours;
FT_Int idx = 0;
for ( ; contour < contour_limit; contour++, end++ )

View File

@ -489,7 +489,7 @@
return FT_THROW( Invalid_Outline );
/* if outline is empty, return (0,0,0,0) */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
if ( outline->n_points == 0 || outline->n_contours == 0 )
{
abbox->xMin = abbox->xMax = 0;
abbox->yMin = abbox->yMax = 0;

View File

@ -332,8 +332,8 @@
FT_NEW_ARRAY( anoutline->contours, numContours ) )
goto Fail;
anoutline->n_points = (FT_Short)numPoints;
anoutline->n_contours = (FT_Short)numContours;
anoutline->n_points = (FT_UShort)numPoints;
anoutline->n_contours = (FT_UShort)numContours;
anoutline->flags |= FT_OUTLINE_OWNER;
return FT_Err_Ok;
@ -359,12 +359,14 @@
FT_Int n;
FT_TRACE5(( "FT_Outline_Check: contours = %d, points = %d\n",
n_contours, n_points ));
/* empty glyph? */
if ( n_points == 0 && n_contours == 0 )
return FT_Err_Ok;
/* check point and contour counts */
if ( n_points <= 0 || n_contours <= 0 )
if ( n_points == 0 || n_contours == 0 )
goto Bad;
end0 = -1;

View File

@ -727,10 +727,10 @@
/* copy contours */
{
FT_UInt count = border->num_points;
FT_Byte* tags = border->tags;
FT_Short* write = outline->contours + outline->n_contours;
FT_Short idx = (FT_Short)outline->n_points;
FT_UInt count = border->num_points;
FT_Byte* tags = border->tags;
FT_UShort* write = outline->contours + outline->n_contours;
FT_UShort idx = outline->n_points;
for ( ; count > 0; count--, tags++, idx++ )
@ -743,7 +743,7 @@
}
}
outline->n_points += (short)border->num_points;
outline->n_points += (FT_UShort)border->num_points;
FT_ASSERT( FT_Outline_Check( outline ) == 0 );
}

View File

@ -108,7 +108,7 @@
/* don't add empty contours */
if ( last >= first )
outline->contours[outline->n_contours++] = (short)last;
outline->contours[outline->n_contours++] = (FT_UShort)last;
glyph->path_begun = 0;
}

View File

@ -1171,8 +1171,8 @@
FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) )
goto Exit;
glyph->num_points = (FT_UInt)outline->n_points;
glyph->num_contours = (FT_UInt)outline->n_contours;
glyph->num_points = outline->n_points;
glyph->num_contours = outline->n_contours;
{
FT_UInt first = 0, next, n;
@ -1186,7 +1186,7 @@
PSH_Point point;
next = (FT_UInt)outline->contours[n] + 1;
next = outline->contours[n] + 1;
count = next - first;
contour->start = points + first;

View File

@ -2683,7 +2683,7 @@
return FT_THROW( Invalid_Outline );
/* return immediately if the outline is empty */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
if ( outline->n_points == 0 || outline->n_contours == 0 )
return Raster_Err_Ok;
if ( !outline->contours || !outline->points )

View File

@ -3837,7 +3837,7 @@
}
/* if the outline is empty, return */
if ( outline->n_points <= 0 || outline->n_contours <= 0 )
if ( outline->n_points == 0 || outline->n_contours == 0 )
goto Exit;
/* check whether the outline has valid fields */

View File

@ -1981,7 +1981,7 @@ typedef ptrdiff_t FT_PtrDist;
return FT_THROW( Invalid_Outline );
/* return immediately if the outline is empty */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
if ( outline->n_points == 0 || outline->n_contours == 0 )
return Smooth_Err_Ok;
if ( !outline->contours || !outline->points )

View File

@ -353,7 +353,8 @@
FT_Byte c, count;
FT_Vector *vec, *vec_limit;
FT_Pos x, y;
FT_Short *cont, *cont_limit, last;
FT_UShort *cont, *cont_limit;
FT_Int last;
/* check that we can add the contours to the glyph */
@ -372,7 +373,7 @@
last = -1;
for ( ; cont < cont_limit; cont++ )
{
*cont = FT_NEXT_SHORT( p );
*cont = FT_NEXT_USHORT( p );
if ( *cont <= last )
goto Invalid_Outline;
@ -530,8 +531,8 @@
*flag = (FT_Byte)( f & ON_CURVE_POINT );
}
outline->n_points = (FT_Short)n_points;
outline->n_contours = (FT_Short)n_contours;
outline->n_points = (FT_UShort)n_points;
outline->n_contours = (FT_UShort)n_contours;
load->cursor = p;
@ -752,10 +753,8 @@
FT_UInt start_point,
FT_UInt start_contour )
{
zone->n_points = (FT_UShort)load->outline.n_points + 4 -
(FT_UShort)start_point;
zone->n_contours = load->outline.n_contours -
(FT_Short)start_contour;
zone->n_points = load->outline.n_points + 4 - (FT_UShort)start_point;
zone->n_contours = load->outline.n_contours - (FT_UShort)start_contour;
zone->org = load->extra_points + start_point;
zone->cur = load->outline.points + start_point;
zone->orus = load->extra_points2 + start_point;
@ -1044,7 +1043,7 @@
current.points = gloader->base.outline.points +
num_base_points;
current.n_points = gloader->base.outline.n_points -
(short)num_base_points;
(FT_UShort)num_base_points;
have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE |
WE_HAVE_AN_XY_SCALE |
@ -1057,7 +1056,7 @@
/* get offset */
if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
{
FT_UInt num_points = (FT_UInt)gloader->base.outline.n_points;
FT_UInt num_points = gloader->base.outline.n_points;
FT_UInt k = (FT_UInt)subglyph->arg1;
FT_UInt l = (FT_UInt)subglyph->arg2;
FT_Vector* p1;
@ -1719,8 +1718,8 @@
FT_List_Add( &loader->composites, node );
}
start_point = (FT_UInt)gloader->base.outline.n_points;
start_contour = (FT_UInt)gloader->base.outline.n_contours;
start_point = gloader->base.outline.n_points;
start_contour = gloader->base.outline.n_contours;
/* for each subglyph, read composite header */
error = face->read_composite_glyph( loader );
@ -1872,7 +1871,7 @@
linear_hadvance = loader->linear;
linear_vadvance = loader->vadvance;
num_base_points = (FT_UInt)gloader->base.outline.n_points;
num_base_points = gloader->base.outline.n_points;
error = load_truetype_glyph( loader,
(FT_UInt)subglyph->index,
@ -1896,7 +1895,7 @@
loader->vadvance = linear_vadvance;
}
num_points = (FT_UInt)gloader->base.outline.n_points;
num_points = gloader->base.outline.n_points;
if ( num_points == num_base_points )
continue;
@ -2717,7 +2716,7 @@
size->metrics->y_ppem < 24 )
glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
FT_TRACE1(( " subglyphs = %u, contours = %hd, points = %hd,"
FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu,"
" flags = 0x%.3x\n",
loader.gloader->base.num_subglyphs,
glyph->outline.n_contours,

View File

@ -5270,11 +5270,11 @@
FT_UShort refp;
FT_F26Dot6 dx, dy;
FT_Short contour, bounds;
FT_UShort contour, bounds;
FT_UShort start, limit, i;
contour = (FT_Short)args[0];
contour = (FT_UShort)args[0];
bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;
if ( BOUNDS( contour, bounds ) )
@ -5290,15 +5290,13 @@
if ( contour == 0 )
start = 0;
else
start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
exc->zp2.first_point );
start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point;
/* we use the number of points if in the twilight zone */
if ( exc->GS.gep2 == 0 )
limit = exc->zp2.n_points;
else
limit = (FT_UShort)( exc->zp2.contours[contour] -
exc->zp2.first_point + 1 );
limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point;
for ( i = start; i < limit; i++ )
{
@ -5341,9 +5339,9 @@
/* Normal zone's `n_points' includes phantoms, so must */
/* use end of last contour. */
if ( exc->GS.gep2 == 0 )
limit = (FT_UShort)exc->zp2.n_points;
limit = exc->zp2.n_points;
else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )
limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 );
limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1;
else
limit = 0;

View File

@ -115,7 +115,7 @@
FT_LOCAL_DEF( FT_Error )
tt_glyphzone_new( FT_Memory memory,
FT_UShort maxPoints,
FT_Short maxContours,
FT_UShort maxContours,
TT_GlyphZone zone )
{
FT_Error error;

View File

@ -105,7 +105,7 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
tt_glyphzone_new( FT_Memory memory,
FT_UShort maxPoints,
FT_Short maxContours,
FT_UShort maxContours,
TT_GlyphZone zone );
#endif /* TT_USE_BYTECODE_INTERPRETER */