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) 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. - Rare double-free crashes in the cache subsystem have been fixed.
- Excessive stack allocation in the autohinter has 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 - The B/W rasterizer has received a major upkeep that resulted in
large performance improvement. The rendering speed has increased large performance improvement. The rendering speed has increased

View File

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

View File

@ -1655,9 +1655,9 @@ FT_BEGIN_HEADER
{ {
FT_Memory memory; FT_Memory memory;
FT_UShort max_points; FT_UShort max_points;
FT_Short max_contours; FT_UShort max_contours;
FT_UShort n_points; /* number of points in zone */ 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* org; /* original point coordinates */
FT_Vector* cur; /* current point coordinates */ FT_Vector* cur; /* current point coordinates */

View File

@ -980,7 +980,7 @@
{ {
FT_Vector* vec = outline->points; FT_Vector* vec = outline->points;
char* tag = outline->tags; char* tag = outline->tags;
FT_Short endpoint = outline->contours[0]; FT_UShort endpoint = outline->contours[0];
AF_Point end = points + endpoint; AF_Point end = points + endpoint;
AF_Point prev = end; AF_Point prev = end;
FT_Int contour_index = 0; FT_Int contour_index = 0;
@ -1048,7 +1048,7 @@
{ {
AF_Point* contour = hints->contours; AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours; AF_Point* contour_limit = contour + hints->num_contours;
short* end = outline->contours; FT_UShort* end = outline->contours;
FT_Int idx = 0; FT_Int idx = 0;

View File

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

View File

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

View File

@ -729,8 +729,8 @@
{ {
FT_UInt count = border->num_points; FT_UInt count = border->num_points;
FT_Byte* tags = border->tags; FT_Byte* tags = border->tags;
FT_Short* write = outline->contours + outline->n_contours; FT_UShort* write = outline->contours + outline->n_contours;
FT_Short idx = (FT_Short)outline->n_points; FT_UShort idx = outline->n_points;
for ( ; count > 0; count--, tags++, idx++ ) 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 ); FT_ASSERT( FT_Outline_Check( outline ) == 0 );
} }

View File

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

View File

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

View File

@ -2683,7 +2683,7 @@
return FT_THROW( Invalid_Outline ); return FT_THROW( Invalid_Outline );
/* return immediately if the outline is empty */ /* 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; return Raster_Err_Ok;
if ( !outline->contours || !outline->points ) if ( !outline->contours || !outline->points )

View File

@ -3837,7 +3837,7 @@
} }
/* if the outline is empty, return */ /* 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; goto Exit;
/* check whether the outline has valid fields */ /* check whether the outline has valid fields */

View File

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

View File

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

View File

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

View File

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

View File

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