summaryrefslogtreecommitdiff
path: root/src/sfnt/ttcmap.c
diff options
context:
space:
mode:
authorWerner Lemberg <wl@gnu.org>2015-09-30 14:44:29 +0200
committerWerner Lemberg <wl@gnu.org>2015-09-30 14:44:29 +0200
commit2ff83a5c99abf3d72d6e7bf4db179b671c7d59cb (patch)
tree54ca524cc5897d911047cac74874cf67e591ceaa /src/sfnt/ttcmap.c
parent8651f37ad5d64fa2122e42a212ba4eac4d99b8c9 (diff)
downloadfreetype2-2ff83a5c99abf3d72d6e7bf4db179b671c7d59cb.tar.gz
[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.
Diffstat (limited to 'src/sfnt/ttcmap.c')
-rw-r--r--src/sfnt/ttcmap.c120
1 files changed, 82 insertions, 38 deletions
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;