From 2ff83a5c99abf3d72d6e7bf4db179b671c7d59cb Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Wed, 30 Sep 2015 14:44:29 +0200 Subject: [PATCH] [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. --- ChangeLog | 9 ++++ src/sfnt/ttcmap.c | 120 +++++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index de7421360..278675433 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2015-09-30 Werner Lemberg + + [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 [truetype] Adjust number of glyphs for malformed `loca' tables. diff --git a/src/sfnt/ttcmap.c b/src/sfnt/ttcmap.c index 6acba732d..e80fc54e7 100644 --- a/src/sfnt/ttcmap.c +++ b/src/sfnt/ttcmap.c @@ -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++ ) - { - FT_Byte* q; + p = cmap->data + 14; /* ends table */ + q = cmap->data + 16 + num_segs2; /* starts table */ + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); - p = cmap->data + 14; /* ends table */ - q = cmap->data + 16 + num_segs2; /* starts table */ + if ( charcode < start ) + { + if ( next ) + charcode = start; + else + break; + } - 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 ) + + 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 ) { - 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 ) + 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;