[sfnt] Rewrite `tt_cmap4_char_map_linear' (#46078).

* src/sfnt/ttcmap.c (tt_cmap4_char_map_linear): Add code to better
skip invalid segments.
If searching the next character, provide a more efficient logic to
speed up the code.
This commit is contained in:
Werner Lemberg 2015-09-30 14:44:29 +02:00
parent 8651f37ad5
commit 2ff83a5c99
2 changed files with 102 additions and 49 deletions

View File

@ -1,3 +1,12 @@
2015-09-30 Werner Lemberg <wl@gnu.org>
[sfnt] Rewrite `tt_cmap4_char_map_linear' (#46078).
* src/sfnt/ttcmap.c (tt_cmap4_char_map_linear): Add code to better
skip invalid segments.
If searching the next character, provide a more efficient logic to
speed up the code.
2015-09-30 Werner Lemberg <wl@gnu.org>
[truetype] Adjust number of glyphs for malformed `loca' tables.

View File

@ -1035,12 +1035,17 @@
FT_UInt32* pcharcode,
FT_Bool next )
{
TT_Face face = (TT_Face)cmap->cmap.charmap.face;
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt i, num_segs;
FT_UInt32 charcode = *pcharcode;
FT_UInt gindex = 0;
FT_Byte* p;
FT_Byte* q;
p = cmap->data + 6;
@ -1054,65 +1059,104 @@
if ( next )
charcode++;
if ( charcode > 0xFFFFU )
return 0;
/* linear search */
for ( ; charcode <= 0xFFFFU; charcode++ )
p = cmap->data + 14; /* ends table */
q = cmap->data + 16 + num_segs2; /* starts table */
for ( i = 0; i < num_segs; i++ )
{
FT_Byte* q;
end = TT_NEXT_USHORT( p );
start = TT_NEXT_USHORT( q );
p = cmap->data + 14; /* ends table */
q = cmap->data + 16 + num_segs2; /* starts table */
for ( i = 0; i < num_segs; i++ )
if ( charcode < start )
{
end = TT_NEXT_USHORT( p );
start = TT_NEXT_USHORT( q );
if ( charcode >= start && charcode <= end )
{
p = q - 2 + num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
/* some fonts have an incorrect last segment; */
/* we have to catch it */
if ( i >= num_segs - 1 &&
start == 0xFFFFU && end == 0xFFFFU )
{
TT_Face face = (TT_Face)cmap->cmap.charmap.face;
FT_Byte* limit = face->cmap_table + face->cmap_size;
if ( offset && p + offset + 2 > limit )
{
delta = 1;
offset = 0;
}
}
if ( offset == 0xFFFFU )
continue;
if ( offset )
{
p += offset + ( charcode - start ) * 2;
gindex = TT_PEEK_USHORT( p );
if ( gindex != 0 )
gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
}
else
gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
if ( next )
charcode = start;
else
break;
}
}
if ( !next || gindex )
Again:
if ( charcode <= end )
{
FT_Byte* r;
r = q - 2 + num_segs2;
delta = TT_PEEK_SHORT( r );
r += num_segs2;
offset = TT_PEEK_USHORT( r );
/* some fonts have an incorrect last segment; */
/* we have to catch it */
if ( i >= num_segs - 1 &&
start == 0xFFFFU && end == 0xFFFFU )
{
if ( offset && r + offset + 2 > limit )
{
delta = 1;
offset = 0;
}
}
if ( offset == 0xFFFFU )
continue;
if ( offset )
{
r += offset + ( charcode - start ) * 2;
/* if r > limit, the whole segment is invalid */
if ( next && r > limit )
continue;
gindex = TT_PEEK_USHORT( r );
if ( gindex )
gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
}
else
{
gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
if ( next && gindex >= (FT_UInt)face->root.num_glyphs )
{
/* we have an invalid glyph index; if there is an overflow, */
/* we can adjust `charcode', otherwise the whole segment is */
/* invalid */
if ( (FT_Int)charcode + delta < 0 &&
(FT_Int)end + delta >= 0 )
{
charcode = (FT_UInt)( -delta );
gindex = 0;
}
else if ( (FT_Int)charcode + delta < 0x10000L &&
(FT_Int)end + delta >= 0x10000L )
{
charcode = (FT_UInt)( 0x10000L - delta );
gindex = 0;
}
else
continue;
}
}
if ( next && !gindex )
{
if ( charcode >= 0xFFFFU )
break;
charcode++;
goto Again;
}
break;
}
}
if ( next && gindex )
if ( next )
*pcharcode = charcode;
return gindex;