ref: 2ff83a5c99abf3d72d6e7bf4db179b671c7d59cb
parent: 8651f37ad5d64fa2122e42a212ba4eac4d99b8c9
author: Werner Lemberg <[email protected]>
date: Wed Sep 30 10:44:29 EDT 2015
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2015-09-30 Werner Lemberg <[email protected]>
+ [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 <[email protected]>
+
[truetype] Adjust number of glyphs for malformed `loca' tables.
* src/truetype/ttpload.c (tt_face_load_loca): Implement it.
--- a/src/sfnt/ttcmap.c
+++ b/src/sfnt/ttcmap.c
@@ -1035,6 +1035,10 @@
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;
@@ -1041,6 +1045,7 @@
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 );
+ if ( charcode < start )
+ {
+ if ( next )
+ charcode = start;
+ else
+ break;
+ }
- p = cmap->data + 14; /* ends table */
- q = cmap->data + 16 + num_segs2; /* starts table */
-
- for ( i = 0; i < num_segs; i++ )
+ Again:
+ if ( charcode <= end )
{
- end = TT_NEXT_USHORT( p );
- start = TT_NEXT_USHORT( q );
+ FT_Byte* r;
- 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 )
+ 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 )
{
- TT_Face face = (TT_Face)cmap->cmap.charmap.face;
- FT_Byte* limit = face->cmap_table + face->cmap_size;
+ delta = 1;
+ offset = 0;
+ }
+ }
+ if ( offset == 0xFFFFU )
+ continue;
- if ( offset && p + offset + 2 > limit )
- {
- delta = 1;
- offset = 0;
- }
- }
+ if ( offset )
+ {
+ r += offset + ( charcode - start ) * 2;
- if ( offset == 0xFFFFU )
+ /* if r > limit, the whole segment is invalid */
+ if ( next && r > limit )
continue;
- if ( offset )
+ 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 )
{
- p += offset + ( charcode - start ) * 2;
- gindex = TT_PEEK_USHORT( p );
- if ( gindex != 0 )
- gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
+ /* 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;
}
- else
- gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
+ }
- break;
+ if ( next && !gindex )
+ {
+ if ( charcode >= 0xFFFFU )
+ break;
+
+ charcode++;
+ goto Again;
}
- }
- if ( !next || gindex )
break;
+ }
}
- if ( next && gindex )
+ if ( next )
*pcharcode = charcode;
return gindex;