summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src/sfnt/ttcmap.c
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/3rdparty/freetype/src/sfnt/ttcmap.c
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/3rdparty/freetype/src/sfnt/ttcmap.c')
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcmap.c3187
1 files changed, 3187 insertions, 0 deletions
diff --git a/src/3rdparty/freetype/src/sfnt/ttcmap.c b/src/3rdparty/freetype/src/sfnt/ttcmap.c
new file mode 100644
index 0000000000..683039153b
--- /dev/null
+++ b/src/3rdparty/freetype/src/sfnt/ttcmap.c
@@ -0,0 +1,3187 @@
+/***************************************************************************/
+/* */
+/* ttcmap.c */
+/* */
+/* TrueType character mapping table (cmap) support (body). */
+/* */
+/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */
+
+#include FT_INTERNAL_VALIDATE_H
+#include FT_INTERNAL_STREAM_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttcmap
+
+
+#define TT_PEEK_SHORT FT_PEEK_SHORT
+#define TT_PEEK_USHORT FT_PEEK_USHORT
+#define TT_PEEK_UINT24 FT_PEEK_UOFF3
+#define TT_PEEK_LONG FT_PEEK_LONG
+#define TT_PEEK_ULONG FT_PEEK_ULONG
+
+#define TT_NEXT_SHORT FT_NEXT_SHORT
+#define TT_NEXT_USHORT FT_NEXT_USHORT
+#define TT_NEXT_UINT24 FT_NEXT_UOFF3
+#define TT_NEXT_LONG FT_NEXT_LONG
+#define TT_NEXT_ULONG FT_NEXT_ULONG
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap_init( TT_CMap cmap,
+ FT_Byte* table )
+ {
+ cmap->data = table;
+ return SFNT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 0 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 0 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* glyph_ids 6 BYTE[256] array of glyph indices */
+ /* 262 */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap0_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2;
+ FT_UInt length = TT_NEXT_USHORT( p );
+
+
+ if ( table + length > valid->limit || length < 262 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices whenever necessary */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt n, idx;
+
+
+ p = table + 6;
+ for ( n = 0; n < 256; n++ )
+ {
+ idx = *p++;
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+
+
+ return char_code < 256 ? table[6 + char_code] : 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 charcode = *pchar_code;
+ FT_UInt32 result = 0;
+ FT_UInt gindex = 0;
+
+
+ table += 6; /* go to glyph IDs */
+ while ( ++charcode < 256 )
+ {
+ gindex = table[charcode];
+ if ( gindex != 0 )
+ {
+ result = charcode;
+ break;
+ }
+ }
+
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap0_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 4;
+
+
+ cmap_info->format = 0;
+ cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap0_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap0_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 0,
+ (TT_CMap_ValidateFunc) tt_cmap0_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap0_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 2 *****/
+ /***** *****/
+ /***** This is used for certain CJK encodings that encode text in a *****/
+ /***** mixed 8/16 bits encoding along the following lines: *****/
+ /***** *****/
+ /***** * Certain byte values correspond to an 8-bit character code *****/
+ /***** (typically in the range 0..127 for ASCII compatibility). *****/
+ /***** *****/
+ /***** * Certain byte values signal the first byte of a 2-byte *****/
+ /***** character code (but these values are also valid as the *****/
+ /***** second byte of a 2-byte character). *****/
+ /***** *****/
+ /***** The following charmap lookup and iteration functions all *****/
+ /***** assume that the value "charcode" correspond to following: *****/
+ /***** *****/
+ /***** - For one byte characters, "charcode" is simply the *****/
+ /***** character code. *****/
+ /***** *****/
+ /***** - For two byte characters, "charcode" is the 2-byte *****/
+ /***** character code in big endian format. More exactly: *****/
+ /***** *****/
+ /***** (charcode >> 8) is the first byte value *****/
+ /***** (charcode & 0xFF) is the second byte value *****/
+ /***** *****/
+ /***** Note that not all values of "charcode" are valid according *****/
+ /***** to these rules, and the function moderately check the *****/
+ /***** arguments. *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 2 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* keys 6 USHORT[256] sub-header keys */
+ /* subs 518 SUBHEAD[NSUBS] sub-headers array */
+ /* glyph_ids 518+NSUB*8 USHORT[] glyph ID array */
+ /* */
+ /* The `keys' table is used to map charcode high-bytes to sub-headers. */
+ /* The value of `NSUBS' is the number of sub-headers defined in the */
+ /* table and is computed by finding the maximum of the `keys' table. */
+ /* */
+ /* Note that for any n, `keys[n]' is a byte offset within the `subs' */
+ /* table, i.e., it is the corresponding sub-header index multiplied */
+ /* by 8. */
+ /* */
+ /* Each sub-header has the following format: */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* first 0 USHORT first valid low-byte */
+ /* count 2 USHORT number of valid low-bytes */
+ /* delta 4 SHORT see below */
+ /* offset 6 USHORT see below */
+ /* */
+ /* A sub-header defines, for each high-byte, the range of valid */
+ /* low-bytes within the charmap. Note that the range defined by `first' */
+ /* and `count' must be completely included in the interval [0..255] */
+ /* according to the specification. */
+ /* */
+ /* If a character code is contained within a given sub-header, then */
+ /* mapping it to a glyph index is done as follows: */
+ /* */
+ /* * The value of `offset' is read. This is a _byte_ distance from the */
+ /* location of the `offset' field itself into a slice of the */
+ /* `glyph_ids' table. Let's call it `slice' (it is a USHORT[] too). */
+ /* */
+ /* * The value `slice[char.lo - first]' is read. If it is 0, there is */
+ /* no glyph for the charcode. Otherwise, the value of `delta' is */
+ /* added to it (modulo 65536) to form a new glyph index. */
+ /* */
+ /* It is up to the validation routine to check that all offsets fall */
+ /* within the glyph IDs table (and not within the `subs' table itself or */
+ /* outside of the CMap). */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap2_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2; /* skip format */
+ FT_UInt length = TT_PEEK_USHORT( p );
+ FT_UInt n, max_subs;
+ FT_Byte* keys; /* keys table */
+ FT_Byte* subs; /* sub-headers */
+ FT_Byte* glyph_ids; /* glyph ID array */
+
+
+ if ( table + length > valid->limit || length < 6 + 512 )
+ FT_INVALID_TOO_SHORT;
+
+ keys = table + 6;
+
+ /* parse keys to compute sub-headers count */
+ p = keys;
+ max_subs = 0;
+ for ( n = 0; n < 256; n++ )
+ {
+ FT_UInt idx = TT_NEXT_USHORT( p );
+
+
+ /* value must be multiple of 8 */
+ if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
+ FT_INVALID_DATA;
+
+ idx >>= 3;
+
+ if ( idx > max_subs )
+ max_subs = idx;
+ }
+
+ FT_ASSERT( p == table + 518 );
+
+ subs = p;
+ glyph_ids = subs + (max_subs + 1) * 8;
+ if ( glyph_ids > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ /* parse sub-headers */
+ for ( n = 0; n <= max_subs; n++ )
+ {
+ FT_UInt first_code, code_count, offset;
+ FT_Int delta;
+ FT_Byte* ids;
+
+
+ first_code = TT_NEXT_USHORT( p );
+ code_count = TT_NEXT_USHORT( p );
+ delta = TT_NEXT_SHORT( p );
+ offset = TT_NEXT_USHORT( p );
+
+ /* many Dynalab fonts have empty sub-headers */
+ if ( code_count == 0 )
+ continue;
+
+ /* check range within 0..255 */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ if ( first_code >= 256 || first_code + code_count > 256 )
+ FT_INVALID_DATA;
+ }
+
+ /* check offset */
+ if ( offset != 0 )
+ {
+ ids = p - 2 + offset;
+ if ( ids < glyph_ids || ids + code_count*2 > table + length )
+ FT_INVALID_OFFSET;
+
+ /* check glyph IDs */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_Byte* limit = p + code_count * 2;
+ FT_UInt idx;
+
+
+ for ( ; p < limit; )
+ {
+ idx = TT_NEXT_USHORT( p );
+ if ( idx != 0 )
+ {
+ idx = ( idx + delta ) & 0xFFFFU;
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ /* return sub header corresponding to a given character code */
+ /* NULL on invalid charcode */
+ static FT_Byte*
+ tt_cmap2_get_subheader( FT_Byte* table,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* result = NULL;
+
+
+ if ( char_code < 0x10000UL )
+ {
+ FT_UInt char_lo = (FT_UInt)( char_code & 0xFF );
+ FT_UInt char_hi = (FT_UInt)( char_code >> 8 );
+ FT_Byte* p = table + 6; /* keys table */
+ FT_Byte* subs = table + 518; /* subheaders table */
+ FT_Byte* sub;
+
+
+ if ( char_hi == 0 )
+ {
+ /* an 8-bit character code -- we use subHeader 0 in this case */
+ /* to test whether the character code is in the charmap */
+ /* */
+ sub = subs; /* jump to first sub-header */
+
+ /* check that the sub-header for this byte is 0, which */
+ /* indicates that it is really a valid one-byte value */
+ /* Otherwise, return 0 */
+ /* */
+ p += char_lo * 2;
+ if ( TT_PEEK_USHORT( p ) != 0 )
+ goto Exit;
+ }
+ else
+ {
+ /* a 16-bit character code */
+
+ /* jump to key entry */
+ p += char_hi * 2;
+ /* jump to sub-header */
+ sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) );
+
+ /* check that the high byte isn't a valid one-byte value */
+ if ( sub == subs )
+ goto Exit;
+ }
+ result = sub;
+ }
+ Exit:
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* subheader;
+
+
+ subheader = tt_cmap2_get_subheader( table, char_code );
+ if ( subheader )
+ {
+ FT_Byte* p = subheader;
+ FT_UInt idx = (FT_UInt)(char_code & 0xFF);
+ FT_UInt start, count;
+ FT_Int delta;
+ FT_UInt offset;
+
+
+ start = TT_NEXT_USHORT( p );
+ count = TT_NEXT_USHORT( p );
+ delta = TT_NEXT_SHORT ( p );
+ offset = TT_PEEK_USHORT( p );
+
+ idx -= start;
+ if ( idx < count && offset != 0 )
+ {
+ p += offset + 2 * idx;
+ idx = TT_PEEK_USHORT( p );
+
+ if ( idx != 0 )
+ result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_next( TT_CMap cmap,
+ FT_UInt32 *pcharcode )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt gindex = 0;
+ FT_UInt32 result = 0;
+ FT_UInt32 charcode = *pcharcode + 1;
+ FT_Byte* subheader;
+
+
+ while ( charcode < 0x10000UL )
+ {
+ subheader = tt_cmap2_get_subheader( table, charcode );
+ if ( subheader )
+ {
+ FT_Byte* p = subheader;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_Int delta = TT_NEXT_SHORT ( p );
+ FT_UInt offset = TT_PEEK_USHORT( p );
+ FT_UInt char_lo = (FT_UInt)( charcode & 0xFF );
+ FT_UInt pos, idx;
+
+
+ if ( offset == 0 )
+ goto Next_SubHeader;
+
+ if ( char_lo < start )
+ {
+ char_lo = start;
+ pos = 0;
+ }
+ else
+ pos = (FT_UInt)( char_lo - start );
+
+ p += offset + pos * 2;
+ charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo;
+
+ for ( ; pos < count; pos++, charcode++ )
+ {
+ idx = TT_NEXT_USHORT( p );
+
+ if ( idx != 0 )
+ {
+ gindex = ( idx + delta ) & 0xFFFFU;
+ if ( gindex != 0 )
+ {
+ result = charcode;
+ goto Exit;
+ }
+ }
+ }
+ }
+
+ /* jump to next sub-header, i.e. higher byte value */
+ Next_SubHeader:
+ charcode = FT_PAD_FLOOR( charcode, 256 ) + 256;
+ }
+
+ Exit:
+ *pcharcode = result;
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap2_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 4;
+
+
+ cmap_info->format = 2;
+ cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap2_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap2_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 2,
+ (TT_CMap_ValidateFunc) tt_cmap2_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap2_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_2 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 4 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 4 */
+ /* length 2 USHORT table length */
+ /* in bytes */
+ /* language 4 USHORT Mac language code */
+ /* */
+ /* segCountX2 6 USHORT 2*NUM_SEGS */
+ /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */
+ /* entrySelector 10 USHORT LOG_SEGS */
+ /* rangeShift 12 USHORT segCountX2 - */
+ /* searchRange */
+ /* */
+ /* endCount 14 USHORT[NUM_SEGS] end charcode for */
+ /* each segment; last */
+ /* is 0xFFFF */
+ /* */
+ /* pad 14+NUM_SEGS*2 USHORT padding */
+ /* */
+ /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */
+ /* each segment */
+ /* */
+ /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */
+ /* segment */
+ /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */
+ /* each segment; can be */
+ /* zero */
+ /* */
+ /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph ID */
+ /* ranges */
+ /* */
+ /* Character codes are modelled by a series of ordered (increasing) */
+ /* intervals called segments. Each segment has start and end codes, */
+ /* provided by the `startCount' and `endCount' arrays. Segments must */
+ /* not overlap, and the last segment should always contain the value */
+ /* 0xFFFF for `endCount'. */
+ /* */
+ /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
+ /* ignored (they are traces of over-engineering in the TrueType */
+ /* specification). */
+ /* */
+ /* Each segment also has a signed `delta', as well as an optional offset */
+ /* within the `glyphIds' table. */
+ /* */
+ /* If a segment's idOffset is 0, the glyph index corresponding to any */
+ /* charcode within the segment is obtained by adding the value of */
+ /* `idDelta' directly to the charcode, modulo 65536. */
+ /* */
+ /* Otherwise, a glyph index is taken from the glyph IDs sub-array for */
+ /* the segment, and the value of `idDelta' is added to it. */
+ /* */
+ /* */
+ /* Finally, note that a lot of fonts contain an invalid last segment, */
+ /* where `start' and `end' are correctly set to 0xFFFF but both `delta' */
+ /* and `offset' are incorrect (e.g., `opens___.ttf' which comes with */
+ /* OpenOffice.org). We need special code to deal with them correctly. */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+
+ typedef struct TT_CMap4Rec_
+ {
+ TT_CMapRec cmap;
+ FT_UInt32 cur_charcode; /* current charcode */
+ FT_UInt cur_gindex; /* current glyph index */
+
+ FT_UInt num_ranges;
+ FT_UInt cur_range;
+ FT_UInt cur_start;
+ FT_UInt cur_end;
+ FT_Int cur_delta;
+ FT_Byte* cur_values;
+
+ } TT_CMap4Rec, *TT_CMap4;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap4_init( TT_CMap4 cmap,
+ FT_Byte* table )
+ {
+ FT_Byte* p;
+
+
+ cmap->cmap.data = table;
+
+ p = table + 6;
+ cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1;
+ cmap->cur_charcode = 0xFFFFFFFFUL;
+ cmap->cur_gindex = 0;
+
+ return SFNT_Err_Ok;
+ }
+
+
+ static FT_Int
+ tt_cmap4_set_range( TT_CMap4 cmap,
+ FT_UInt range_index )
+ {
+ FT_Byte* table = cmap->cmap.data;
+ FT_Byte* p;
+ FT_UInt num_ranges = cmap->num_ranges;
+
+
+ while ( range_index < num_ranges )
+ {
+ FT_UInt offset;
+
+
+ p = table + 14 + range_index * 2;
+ cmap->cur_end = FT_PEEK_USHORT( p );
+
+ p += 2 + num_ranges * 2;
+ cmap->cur_start = FT_PEEK_USHORT( p );
+
+ p += num_ranges * 2;
+ cmap->cur_delta = FT_PEEK_SHORT( p );
+
+ p += num_ranges * 2;
+ offset = FT_PEEK_USHORT( p );
+
+ /* some fonts have an incorrect last segment; */
+ /* we have to catch it */
+ if ( range_index >= num_ranges - 1 &&
+ cmap->cur_start == 0xFFFFU &&
+ cmap->cur_end == 0xFFFFU )
+ {
+ TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face;
+ FT_Byte* limit = face->cmap_table + face->cmap_size;
+
+
+ if ( offset && p + offset + 2 > limit )
+ {
+ cmap->cur_delta = 1;
+ offset = 0;
+ }
+ }
+
+ if ( offset != 0xFFFFU )
+ {
+ cmap->cur_values = offset ? p + offset : NULL;
+ cmap->cur_range = range_index;
+ return 0;
+ }
+
+ /* we skip empty segments */
+ range_index++;
+ }
+
+ return -1;
+ }
+
+
+ /* search the index of the charcode next to cmap->cur_charcode; */
+ /* caller should call tt_cmap4_set_range with proper range */
+ /* before calling this function */
+ /* */
+ static void
+ tt_cmap4_next( TT_CMap4 cmap )
+ {
+ FT_UInt charcode;
+
+
+ if ( cmap->cur_charcode >= 0xFFFFUL )
+ goto Fail;
+
+ charcode = cmap->cur_charcode + 1;
+
+ if ( charcode < cmap->cur_start )
+ charcode = cmap->cur_start;
+
+ for ( ;; )
+ {
+ FT_Byte* values = cmap->cur_values;
+ FT_UInt end = cmap->cur_end;
+ FT_Int delta = cmap->cur_delta;
+
+
+ if ( charcode <= end )
+ {
+ if ( values )
+ {
+ FT_Byte* p = values + 2 * ( charcode - cmap->cur_start );
+
+
+ do
+ {
+ FT_UInt gindex = FT_NEXT_USHORT( p );
+
+
+ if ( gindex != 0 )
+ {
+ gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU );
+ if ( gindex != 0 )
+ {
+ cmap->cur_charcode = charcode;
+ cmap->cur_gindex = gindex;
+ return;
+ }
+ }
+ } while ( ++charcode <= end );
+ }
+ else
+ {
+ do
+ {
+ FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU );
+
+
+ if ( gindex != 0 )
+ {
+ cmap->cur_charcode = charcode;
+ cmap->cur_gindex = gindex;
+ return;
+ }
+ } while ( ++charcode <= end );
+ }
+ }
+
+ /* we need to find another range */
+ if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 )
+ break;
+
+ if ( charcode < cmap->cur_start )
+ charcode = cmap->cur_start;
+ }
+
+ Fail:
+ cmap->cur_charcode = 0xFFFFFFFFUL;
+ cmap->cur_gindex = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap4_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2; /* skip format */
+ FT_UInt length = TT_NEXT_USHORT( p );
+ FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids;
+ FT_UInt num_segs;
+ FT_Error error = SFNT_Err_Ok;
+
+
+ if ( length < 16 )
+ FT_INVALID_TOO_SHORT;
+
+ /* in certain fonts, the `length' field is invalid and goes */
+ /* out of bound. We try to correct this here... */
+ if ( table + length > valid->limit )
+ {
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ FT_INVALID_TOO_SHORT;
+
+ length = (FT_UInt)( valid->limit - table );
+ }
+
+ p = table + 6;
+ num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */
+
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ /* check that we have an even value here */
+ if ( num_segs & 1 )
+ FT_INVALID_DATA;
+ }
+
+ num_segs /= 2;
+
+ if ( length < 16 + num_segs * 2 * 4 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check the search parameters - even though we never use them */
+ /* */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ /* check the values of `searchRange', `entrySelector', `rangeShift' */
+ FT_UInt search_range = TT_NEXT_USHORT( p );
+ FT_UInt entry_selector = TT_NEXT_USHORT( p );
+ FT_UInt range_shift = TT_NEXT_USHORT( p );
+
+
+ if ( ( search_range | range_shift ) & 1 ) /* must be even values */
+ FT_INVALID_DATA;
+
+ search_range /= 2;
+ range_shift /= 2;
+
+ /* `search range' is the greatest power of 2 that is <= num_segs */
+
+ if ( search_range > num_segs ||
+ search_range * 2 < num_segs ||
+ search_range + range_shift != num_segs ||
+ search_range != ( 1U << entry_selector ) )
+ FT_INVALID_DATA;
+ }
+
+ ends = table + 14;
+ starts = table + 16 + num_segs * 2;
+ deltas = starts + num_segs * 2;
+ offsets = deltas + num_segs * 2;
+ glyph_ids = offsets + num_segs * 2;
+
+ /* check last segment; its end count value must be 0xFFFF */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ p = ends + ( num_segs - 1 ) * 2;
+ if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
+ FT_INVALID_DATA;
+ }
+
+ {
+ FT_UInt start, end, offset, n;
+ FT_UInt last_start = 0, last_end = 0;
+ FT_Int delta;
+ FT_Byte* p_start = starts;
+ FT_Byte* p_end = ends;
+ FT_Byte* p_delta = deltas;
+ FT_Byte* p_offset = offsets;
+
+
+ for ( n = 0; n < num_segs; n++ )
+ {
+ p = p_offset;
+ start = TT_NEXT_USHORT( p_start );
+ end = TT_NEXT_USHORT( p_end );
+ delta = TT_NEXT_SHORT( p_delta );
+ offset = TT_NEXT_USHORT( p_offset );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ /* this test should be performed at default validation level; */
+ /* unfortunately, some popular Asian fonts have overlapping */
+ /* ranges in their charmaps */
+ /* */
+ if ( start <= last_end && n > 0 )
+ {
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ FT_INVALID_DATA;
+ else
+ {
+ /* allow overlapping segments, provided their start points */
+ /* and end points, respectively, are in ascending order */
+ /* */
+ if ( last_start > start || last_end > end )
+ error |= TT_CMAP_FLAG_UNSORTED;
+ else
+ error |= TT_CMAP_FLAG_OVERLAPPING;
+ }
+ }
+
+ if ( offset && offset != 0xFFFFU )
+ {
+ p += offset; /* start of glyph ID array */
+
+ /* check that we point within the glyph IDs table only */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( p < glyph_ids ||
+ p + ( end - start + 1 ) * 2 > table + length )
+ FT_INVALID_DATA;
+ }
+ /* Some fonts handle the last segment incorrectly. In */
+ /* theory, 0xFFFF might point to an ordinary glyph -- */
+ /* a cmap 4 is versatile and could be used for any */
+ /* encoding, not only Unicode. However, reality shows */
+ /* that far too many fonts are sloppy and incorrectly */
+ /* set all fields but `start' and `end' for the last */
+ /* segment if it contains only a single character. */
+ /* */
+ /* We thus omit the test here, delaying it to the */
+ /* routines which actually access the cmap. */
+ else if ( n != num_segs - 1 ||
+ !( start == 0xFFFFU && end == 0xFFFFU ) )
+ {
+ if ( p < glyph_ids ||
+ p + ( end - start + 1 ) * 2 > valid->limit )
+ FT_INVALID_DATA;
+ }
+
+ /* check glyph indices within the segment range */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt i, idx;
+
+
+ for ( i = start; i < end; i++ )
+ {
+ idx = FT_NEXT_USHORT( p );
+ if ( idx != 0 )
+ {
+ idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
+
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+ }
+ else if ( offset == 0xFFFFU )
+ {
+ /* some fonts (erroneously?) use a range offset of 0xFFFF */
+ /* to mean missing glyph in cmap table */
+ /* */
+ if ( valid->level >= FT_VALIDATE_PARANOID ||
+ n != num_segs - 1 ||
+ !( start == 0xFFFFU && end == 0xFFFFU ) )
+ FT_INVALID_DATA;
+ }
+
+ last_start = start;
+ last_end = end;
+ }
+ }
+
+ return error;
+ }
+
+
+ static FT_UInt
+ tt_cmap4_char_map_linear( TT_CMap cmap,
+ FT_UInt32* pcharcode,
+ FT_Bool next )
+ {
+ 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;
+
+
+ p = cmap->data + 6;
+ num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
+
+ num_segs = num_segs2 >> 1;
+
+ if ( !num_segs )
+ return 0;
+
+ if ( next )
+ charcode++;
+
+ /* 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 );
+
+ 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)( gindex + delta ) & 0xFFFFU;
+ }
+ else
+ gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
+
+ break;
+ }
+ }
+
+ if ( !next || gindex )
+ break;
+ }
+
+ if ( next && gindex )
+ *pcharcode = charcode;
+
+ return gindex;
+ }
+
+
+ static FT_UInt
+ tt_cmap4_char_map_binary( TT_CMap cmap,
+ FT_UInt32* pcharcode,
+ FT_Bool next )
+ {
+ FT_UInt num_segs2, start, end, offset;
+ FT_Int delta;
+ FT_UInt max, min, mid, num_segs;
+ FT_UInt charcode = *pcharcode;
+ FT_UInt gindex = 0;
+ FT_Byte* p;
+
+
+ p = cmap->data + 6;
+ num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
+
+ if ( !num_segs2 )
+ return 0;
+
+ num_segs = num_segs2 >> 1;
+
+ /* make compiler happy */
+ mid = num_segs;
+ end = 0xFFFFU;
+
+ if ( next )
+ charcode++;
+
+ min = 0;
+ max = num_segs;
+
+ /* binary search */
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = cmap->data + 14 + mid * 2;
+ end = TT_PEEK_USHORT( p );
+ p += 2 + num_segs2;
+ start = TT_PEEK_USHORT( p );
+
+ if ( charcode < start )
+ max = mid;
+ else if ( charcode > end )
+ min = mid + 1;
+ else
+ {
+ p += 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 ( mid >= 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;
+ }
+ }
+
+ /* search the first segment containing `charcode' */
+ if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING )
+ {
+ FT_UInt i;
+
+
+ /* call the current segment `max' */
+ max = mid;
+
+ if ( offset == 0xFFFFU )
+ mid = max + 1;
+
+ /* search in segments before the current segment */
+ for ( i = max ; i > 0; i-- )
+ {
+ FT_UInt prev_end;
+ FT_Byte* old_p;
+
+
+ old_p = p;
+ p = cmap->data + 14 + ( i - 1 ) * 2;
+ prev_end = TT_PEEK_USHORT( p );
+
+ if ( charcode > prev_end )
+ {
+ p = old_p;
+ break;
+ }
+
+ end = prev_end;
+ p += 2 + num_segs2;
+ start = TT_PEEK_USHORT( p );
+ p += num_segs2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( offset != 0xFFFFU )
+ mid = i - 1;
+ }
+
+ /* no luck */
+ if ( mid == max + 1 )
+ {
+ if ( i != max )
+ {
+ p = cmap->data + 14 + max * 2;
+ end = TT_PEEK_USHORT( p );
+ p += 2 + num_segs2;
+ start = TT_PEEK_USHORT( p );
+ p += num_segs2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+ }
+
+ mid = max;
+
+ /* search in segments after the current segment */
+ for ( i = max + 1; i < num_segs; i++ )
+ {
+ FT_UInt next_end, next_start;
+
+
+ p = cmap->data + 14 + i * 2;
+ next_end = TT_PEEK_USHORT( p );
+ p += 2 + num_segs2;
+ next_start = TT_PEEK_USHORT( p );
+
+ if ( charcode < next_start )
+ break;
+
+ end = next_end;
+ start = next_start;
+ p += num_segs2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( offset != 0xFFFFU )
+ mid = i;
+ }
+ i--;
+
+ /* still no luck */
+ if ( mid == max )
+ {
+ mid = i;
+
+ break;
+ }
+ }
+
+ /* end, start, delta, and offset are for the i'th segment */
+ if ( mid != i )
+ {
+ p = cmap->data + 14 + mid * 2;
+ end = TT_PEEK_USHORT( p );
+ p += 2 + num_segs2;
+ start = TT_PEEK_USHORT( p );
+ p += num_segs2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+ }
+ }
+ else
+ {
+ if ( offset == 0xFFFFU )
+ break;
+ }
+
+ if ( offset )
+ {
+ p += offset + ( charcode - start ) * 2;
+ gindex = TT_PEEK_USHORT( p );
+ if ( gindex != 0 )
+ gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
+ }
+ else
+ gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
+
+ break;
+ }
+ }
+
+ if ( next )
+ {
+ TT_CMap4 cmap4 = (TT_CMap4)cmap;
+
+
+ /* if `charcode' is not in any segment, then `mid' is */
+ /* the segment nearest to `charcode' */
+ /* */
+
+ if ( charcode > end )
+ {
+ mid++;
+ if ( mid == num_segs )
+ return 0;
+ }
+
+ if ( tt_cmap4_set_range( cmap4, mid ) )
+ {
+ if ( gindex )
+ *pcharcode = charcode;
+ }
+ else
+ {
+ cmap4->cur_charcode = charcode;
+
+ if ( gindex )
+ cmap4->cur_gindex = gindex;
+ else
+ {
+ cmap4->cur_charcode = charcode;
+ tt_cmap4_next( cmap4 );
+ gindex = cmap4->cur_gindex;
+ }
+
+ if ( gindex )
+ *pcharcode = cmap4->cur_charcode;
+ }
+ }
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ if ( char_code >= 0x10000UL )
+ return 0;
+
+ if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
+ return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
+ else
+ return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt gindex;
+
+
+ if ( *pchar_code >= 0xFFFFU )
+ return 0;
+
+ if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
+ gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
+ else
+ {
+ TT_CMap4 cmap4 = (TT_CMap4)cmap;
+
+
+ /* no need to search */
+ if ( *pchar_code == cmap4->cur_charcode )
+ {
+ tt_cmap4_next( cmap4 );
+ gindex = cmap4->cur_gindex;
+ if ( gindex )
+ *pchar_code = cmap4->cur_charcode;
+ }
+ else
+ gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
+ }
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap4_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 4;
+
+
+ cmap_info->format = 4;
+ cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap4_class_rec =
+ {
+ {
+ sizeof ( TT_CMap4Rec ),
+ (FT_CMap_InitFunc) tt_cmap4_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap4_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 4,
+ (TT_CMap_ValidateFunc) tt_cmap4_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap4_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_4 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 6 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 4 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* */
+ /* first 6 USHORT first segment code */
+ /* count 8 USHORT segment size in chars */
+ /* glyphIds 10 USHORT[count] glyph IDs */
+ /* */
+ /* A very simplified segment mapping. */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap6_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p;
+ FT_UInt length, count;
+
+
+ if ( table + 10 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ p = table + 2;
+ length = TT_NEXT_USHORT( p );
+
+ p = table + 8; /* skip language and start index */
+ count = TT_NEXT_USHORT( p );
+
+ if ( table + length > valid->limit || length < 10 + count * 2 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt gindex;
+
+
+ for ( ; count > 0; count-- )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 6;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_UInt idx = (FT_UInt)( char_code - start );
+
+
+ if ( idx < count )
+ {
+ p += 2 * idx;
+ result = TT_PEEK_USHORT( p );
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+
+ FT_Byte* p = table + 6;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_UInt idx;
+
+
+ if ( char_code >= 0x10000UL )
+ goto Exit;
+
+ if ( char_code < start )
+ char_code = start;
+
+ idx = (FT_UInt)( char_code - start );
+ p += 2 * idx;
+
+ for ( ; idx < count; idx++ )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ break;
+ }
+ char_code++;
+ }
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap6_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 4;
+
+
+ cmap_info->format = 6;
+ cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap6_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap6_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 6,
+ (TT_CMap_ValidateFunc) tt_cmap6_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap6_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_6 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 8 *****/
+ /***** *****/
+ /***** It is hard to completely understand what the OpenType spec *****/
+ /***** says about this format, but here is my conclusion. *****/
+ /***** *****/
+ /***** The purpose of this format is to easily map UTF-16 text to *****/
+ /***** glyph indices. Basically, the `char_code' must be in one of *****/
+ /***** the following formats: *****/
+ /***** *****/
+ /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/
+ /***** Area (i.e. U+D800-U+DFFF). *****/
+ /***** *****/
+ /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/
+ /***** `char_code = (char_hi << 16) | char_lo', then both *****/
+ /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/
+ /***** Area. *****/
+ /***** *****/
+ /***** The `is32' table embedded in the charmap indicates whether a *****/
+ /***** given 16-bit value is in the surrogates area or not. *****/
+ /***** *****/
+ /***** So, for any given `char_code', we can assert the following: *****/
+ /***** *****/
+ /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/
+ /***** *****/
+ /***** If `char_hi != 0' then we must have both *****/
+ /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 8 */
+ /* reserved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* is32 12 BYTE[8192] 32-bitness bitmap */
+ /* count 8204 ULONG number of groups */
+ /* */
+ /* This header is followed by `count' groups of the following format: */
+ /* */
+ /* start 0 ULONG first charcode */
+ /* end 4 ULONG last charcode */
+ /* startId 8 ULONG start glyph ID for the group */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap8_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 4;
+ FT_Byte* is32;
+ FT_UInt32 length;
+ FT_UInt32 num_groups;
+
+
+ if ( table + 16 + 8192 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ length = TT_NEXT_ULONG( p );
+ if ( table + length > valid->limit || length < 8208 )
+ FT_INVALID_TOO_SHORT;
+
+ is32 = table + 12;
+ p = is32 + 8192; /* skip `is32' array */
+ num_groups = TT_NEXT_ULONG( p );
+
+ if ( p + num_groups * 12 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ /* check groups, they must be in increasing order */
+ {
+ FT_UInt32 n, start, end, start_id, count, last = 0;
+
+
+ for ( n = 0; n < num_groups; n++ )
+ {
+ FT_UInt hi, lo;
+
+
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ if ( n > 0 && start <= last )
+ FT_INVALID_DATA;
+
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+
+ count = (FT_UInt32)( end - start + 1 );
+
+ if ( start & ~0xFFFFU )
+ {
+ /* start_hi != 0; check that is32[i] is 1 for each i in */
+ /* the `hi' and `lo' of the range [start..end] */
+ for ( ; count > 0; count--, start++ )
+ {
+ hi = (FT_UInt)( start >> 16 );
+ lo = (FT_UInt)( start & 0xFFFFU );
+
+ if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 )
+ FT_INVALID_DATA;
+
+ if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 )
+ FT_INVALID_DATA;
+ }
+ }
+ else
+ {
+ /* start_hi == 0; check that is32[i] is 0 for each i in */
+ /* the range [start..end] */
+
+ /* end_hi cannot be != 0! */
+ if ( end & ~0xFFFFU )
+ FT_INVALID_DATA;
+
+ for ( ; count > 0; count--, start++ )
+ {
+ lo = (FT_UInt)( start & 0xFFFFU );
+
+ if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 )
+ FT_INVALID_DATA;
+ }
+ }
+ }
+
+ last = end;
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 8204;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ break;
+
+ if ( char_code <= end )
+ {
+ result = (FT_UInt)( start_id + char_code - start );
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* table = cmap->data;
+ FT_Byte* p = table + 8204;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ p = table + 8208;
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ char_code = start;
+
+ if ( char_code <= end )
+ {
+ gindex = (FT_UInt)( char_code - start + start_id );
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ goto Exit;
+ }
+ }
+ }
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap8_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 8;
+
+
+ cmap_info->format = 8;
+ cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap8_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap8_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 8,
+ (TT_CMap_ValidateFunc) tt_cmap8_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap8_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_8 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 10 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 10 */
+ /* reserved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* */
+ /* start 12 ULONG first char in range */
+ /* count 16 ULONG number of chars in range */
+ /* glyphIds 20 USHORT[count] glyph indices covered */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap10_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 4;
+ FT_ULong length, count;
+
+
+ if ( table + 20 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ length = TT_NEXT_ULONG( p );
+ p = table + 16;
+ count = TT_NEXT_ULONG( p );
+
+ if ( table + length > valid->limit || length < 20 + count * 2 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt gindex;
+
+
+ for ( ; count > 0; count-- )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 12;
+ FT_UInt32 start = TT_NEXT_ULONG( p );
+ FT_UInt32 count = TT_NEXT_ULONG( p );
+ FT_UInt32 idx = (FT_ULong)( char_code - start );
+
+
+ if ( idx < count )
+ {
+ p += 2 * idx;
+ result = TT_PEEK_USHORT( p );
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* p = table + 12;
+ FT_UInt32 start = TT_NEXT_ULONG( p );
+ FT_UInt32 count = TT_NEXT_ULONG( p );
+ FT_UInt32 idx;
+
+
+ if ( char_code < start )
+ char_code = start;
+
+ idx = (FT_UInt32)( char_code - start );
+ p += 2 * idx;
+
+ for ( ; idx < count; idx++ )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex != 0 )
+ break;
+ char_code++;
+ }
+
+ *pchar_code = char_code;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap10_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 8;
+
+
+ cmap_info->format = 10;
+ cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap10_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap10_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 10,
+ (TT_CMap_ValidateFunc) tt_cmap10_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap10_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_10 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 12 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 12 */
+ /* reserved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* count 12 ULONG number of groups */
+ /* 16 */
+ /* */
+ /* This header is followed by `count' groups of the following format: */
+ /* */
+ /* start 0 ULONG first charcode */
+ /* end 4 ULONG last charcode */
+ /* startId 8 ULONG start glyph ID for the group */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+
+ typedef struct TT_CMap12Rec_
+ {
+ TT_CMapRec cmap;
+ FT_Bool valid;
+ FT_ULong cur_charcode;
+ FT_UInt cur_gindex;
+ FT_ULong cur_group;
+ FT_ULong num_groups;
+
+ } TT_CMap12Rec, *TT_CMap12;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap12_init( TT_CMap12 cmap,
+ FT_Byte* table )
+ {
+ cmap->cmap.data = table;
+
+ table += 12;
+ cmap->num_groups = FT_PEEK_ULONG( table );
+
+ cmap->valid = 0;
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap12_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p;
+ FT_ULong length;
+ FT_ULong num_groups;
+
+
+ if ( table + 16 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ p = table + 4;
+ length = TT_NEXT_ULONG( p );
+
+ p = table + 12;
+ num_groups = TT_NEXT_ULONG( p );
+
+ if ( table + length > valid->limit || length < 16 + 12 * num_groups )
+ FT_INVALID_TOO_SHORT;
+
+ /* check groups, they must be in increasing order */
+ {
+ FT_ULong n, start, end, start_id, last = 0;
+
+
+ for ( n = 0; n < num_groups; n++ )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ if ( n > 0 && start <= last )
+ FT_INVALID_DATA;
+
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+
+ last = end;
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ /* search the index of the charcode next to cmap->cur_charcode */
+ /* cmap->cur_group should be set up properly by caller */
+ /* */
+ static void
+ tt_cmap12_next( TT_CMap12 cmap )
+ {
+ FT_Byte* p;
+ FT_ULong start, end, start_id, char_code;
+ FT_ULong n;
+ FT_UInt gindex;
+
+
+ if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
+ goto Fail;
+
+ char_code = cmap->cur_charcode + 1;
+
+ n = cmap->cur_group;
+
+ for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+ {
+ p = cmap->cmap.data + 16 + 12 * n;
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_PEEK_ULONG( p );
+
+ if ( char_code < start )
+ char_code = start;
+
+ for ( ; char_code <= end; char_code++ )
+ {
+ gindex = (FT_UInt)( start_id + char_code - start );
+
+ if ( gindex )
+ {
+ cmap->cur_charcode = char_code;;
+ cmap->cur_gindex = gindex;
+ cmap->cur_group = n;
+
+ return;
+ }
+ }
+ }
+
+ Fail:
+ cmap->valid = 0;
+ }
+
+
+ static FT_UInt
+ tt_cmap12_char_map_binary( TT_CMap cmap,
+ FT_UInt32* pchar_code,
+ FT_Bool next )
+ {
+ FT_UInt gindex = 0;
+ FT_Byte* p = cmap->data + 12;
+ FT_UInt32 num_groups = TT_PEEK_ULONG( p );
+ FT_UInt32 char_code = *pchar_code;
+ FT_UInt32 start, end, start_id;
+ FT_UInt32 max, min, mid;
+
+
+ if ( !num_groups )
+ return 0;
+
+ /* make compiler happy */
+ mid = num_groups;
+ end = 0xFFFFFFFFUL;
+
+ if ( next )
+ char_code++;
+
+ min = 0;
+ max = num_groups;
+
+ /* binary search */
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = cmap->data + 16 + 12 * mid;
+
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ max = mid;
+ else if ( char_code > end )
+ min = mid + 1;
+ else
+ {
+ start_id = TT_PEEK_ULONG( p );
+ gindex = (FT_UInt)( start_id + char_code - start );
+
+ break;
+ }
+ }
+
+ if ( next )
+ {
+ TT_CMap12 cmap12 = (TT_CMap12)cmap;
+
+
+ /* if `char_code' is not in any group, then `mid' is */
+ /* the group nearest to `char_code' */
+ /* */
+
+ if ( char_code > end )
+ {
+ mid++;
+ if ( mid == num_groups )
+ return 0;
+ }
+
+ cmap12->valid = 1;
+ cmap12->cur_charcode = char_code;
+ cmap12->cur_group = mid;
+
+ if ( !gindex )
+ {
+ tt_cmap12_next( cmap12 );
+
+ if ( cmap12->valid )
+ gindex = cmap12->cur_gindex;
+ }
+ else
+ cmap12->cur_gindex = gindex;
+
+ if ( gindex )
+ *pchar_code = cmap12->cur_charcode;
+ }
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ TT_CMap12 cmap12 = (TT_CMap12)cmap;
+ FT_ULong gindex;
+
+
+ if ( cmap12->cur_charcode >= 0xFFFFFFFFUL )
+ return 0;
+
+ /* no need to search */
+ if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
+ {
+ tt_cmap12_next( cmap12 );
+ if ( cmap12->valid )
+ {
+ gindex = cmap12->cur_gindex;
+ if ( gindex )
+ *pchar_code = cmap12->cur_charcode;
+ }
+ else
+ gindex = 0;
+ }
+ else
+ gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap12_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_Byte* p = cmap->data + 8;
+
+
+ cmap_info->format = 12;
+ cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap12_class_rec =
+ {
+ {
+ sizeof ( TT_CMap12Rec ),
+
+ (FT_CMap_InitFunc) tt_cmap12_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap12_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ },
+ 12,
+ (TT_CMap_ValidateFunc) tt_cmap12_validate,
+ (TT_CMap_Info_GetFunc) tt_cmap12_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_12 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 14 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 14 */
+ /* length 2 ULONG table length in bytes */
+ /* numSelector 6 ULONG number of variation sel. records */
+ /* */
+ /* Followed by numSelector records, each of which looks like */
+ /* */
+ /* varSelector 0 UINT24 Unicode codepoint of sel. */
+ /* defaultOff 3 ULONG offset to a default UVS table */
+ /* describing any variants to be found in */
+ /* the normal Unicode subtable. */
+ /* nonDefOff 7 ULONG offset to a non-default UVS table */
+ /* describing any variants not in the */
+ /* standard cmap, with GIDs here */
+ /* (either offset may be 0 NULL) */
+ /* */
+ /* Selectors are sorted by code point. */
+ /* */
+ /* A default Unicode Variation Selector (UVS) subtable is just a list of */
+ /* ranges of code points which are to be found in the standard cmap. No */
+ /* glyph IDs (GIDs) here. */
+ /* */
+ /* numRanges 0 ULONG number of ranges following */
+ /* */
+ /* A range looks like */
+ /* */
+ /* uniStart 0 UINT24 code point of the first character in */
+ /* this range */
+ /* additionalCnt 3 UBYTE count of additional characters in this */
+ /* range (zero means a range of a single */
+ /* character) */
+ /* */
+ /* Ranges are sorted by `uniStart'. */
+ /* */
+ /* A non-default Unicode Variation Selector (UVS) subtable is a list of */
+ /* mappings from codepoint to GID. */
+ /* */
+ /* numMappings 0 ULONG number of mappings */
+ /* */
+ /* A range looks like */
+ /* */
+ /* uniStart 0 UINT24 code point of the first character in */
+ /* this range */
+ /* GID 3 USHORT and its GID */
+ /* */
+ /* Ranges are sorted by `uniStart'. */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_14
+
+ typedef struct TT_CMap14Rec_
+ {
+ TT_CMapRec cmap;
+ FT_ULong num_selectors;
+
+ /* This array is used to store the results of various
+ * cmap 14 query functions. The data is overwritten
+ * on each call to these functions.
+ */
+ FT_UInt max_results;
+ FT_UInt32* results;
+ FT_Memory memory;
+
+ } TT_CMap14Rec, *TT_CMap14;
+
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap14_done( TT_CMap14 cmap )
+ {
+ FT_Memory memory = cmap->memory;
+
+
+ cmap->max_results = 0;
+ if ( memory != NULL && cmap->results != NULL )
+ FT_FREE( cmap->results );
+ }
+
+
+ static FT_Error
+ tt_cmap14_ensure( TT_CMap14 cmap,
+ FT_UInt num_results,
+ FT_Memory memory )
+ {
+ FT_UInt old_max = cmap->max_results;
+ FT_Error error = 0;
+
+
+ if ( num_results > cmap->max_results )
+ {
+ cmap->memory = memory;
+
+ if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) )
+ return error;
+
+ cmap->max_results = num_results;
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap14_init( TT_CMap14 cmap,
+ FT_Byte* table )
+ {
+ cmap->cmap.data = table;
+
+ table += 6;
+ cmap->num_selectors = FT_PEEK_ULONG( table );
+ cmap->max_results = 0;
+ cmap->results = NULL;
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap14_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2;
+ FT_ULong length = TT_NEXT_ULONG( p );
+ FT_ULong num_selectors = TT_NEXT_ULONG( p );
+
+
+ if ( table + length > valid->limit || length < 10 + 11 * num_selectors )
+ FT_INVALID_TOO_SHORT;
+
+ /* check selectors, they must be in increasing order */
+ {
+ /* we start lastVarSel at 1 because a variant selector value of 0
+ * isn't valid.
+ */
+ FT_ULong n, lastVarSel = 1;
+
+
+ for ( n = 0; n < num_selectors; n++ )
+ {
+ FT_ULong varSel = TT_NEXT_UINT24( p );
+ FT_ULong defOff = TT_NEXT_ULONG( p );
+ FT_ULong nondefOff = TT_NEXT_ULONG( p );
+
+
+ if ( defOff >= length || nondefOff >= length )
+ FT_INVALID_TOO_SHORT;
+
+ if ( varSel < lastVarSel )
+ FT_INVALID_DATA;
+
+ lastVarSel = varSel + 1;
+
+ /* check the default table (these glyphs should be reached */
+ /* through the normal Unicode cmap, no GIDs, just check order) */
+ if ( defOff != 0 )
+ {
+ FT_Byte* defp = table + defOff;
+ FT_ULong numRanges = TT_NEXT_ULONG( defp );
+ FT_ULong i;
+ FT_ULong lastBase = 0;
+
+
+ if ( defp + numRanges * 4 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ for ( i = 0; i < numRanges; ++i )
+ {
+ FT_ULong base = TT_NEXT_UINT24( defp );
+ FT_ULong cnt = FT_NEXT_BYTE( defp );
+
+
+ if ( base + cnt >= 0x110000UL ) /* end of Unicode */
+ FT_INVALID_DATA;
+
+ if ( base < lastBase )
+ FT_INVALID_DATA;
+
+ lastBase = base + cnt + 1U;
+ }
+ }
+
+ /* and the non-default table (these glyphs are specified here) */
+ if ( nondefOff != 0 ) {
+ FT_Byte* ndp = table + nondefOff;
+ FT_ULong numMappings = TT_NEXT_ULONG( ndp );
+ FT_ULong i, lastUni = 0;
+
+
+ if ( ndp + numMappings * 4 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ for ( i = 0; i < numMappings; ++i )
+ {
+ FT_ULong uni = TT_NEXT_UINT24( ndp );
+ FT_ULong gid = TT_NEXT_USHORT( ndp );
+
+
+ if ( uni >= 0x110000UL ) /* end of Unicode */
+ FT_INVALID_DATA;
+
+ if ( uni < lastUni )
+ FT_INVALID_DATA;
+
+ lastUni = uni + 1U;
+
+ if ( valid->level >= FT_VALIDATE_TIGHT &&
+ gid >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap14_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UNUSED( cmap );
+ FT_UNUSED( char_code );
+
+ /* This can't happen */
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap14_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UNUSED( cmap );
+
+ /* This can't happen */
+ *pchar_code = 0;
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap14_get_info( TT_CMap cmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_UNUSED( cmap );
+
+ cmap_info->format = 14;
+ /* subtable 14 does not define a language field */
+ cmap_info->language = 0xFFFFFFFFUL;
+
+ return SFNT_Err_Ok;
+ }
+
+
+ static FT_UInt
+ tt_cmap14_char_map_def_binary( FT_Byte *base,
+ FT_UInt32 char_code )
+ {
+ FT_UInt32 numRanges = TT_PEEK_ULONG( base );
+ FT_UInt32 max, min;
+
+
+ min = 0;
+ max = numRanges;
+
+ base += 4;
+
+ /* binary search */
+ while ( min < max )
+ {
+ FT_UInt32 mid = ( min + max ) >> 1;
+ FT_Byte* p = base + 4 * mid;
+ FT_ULong start = TT_NEXT_UINT24( p );
+ FT_UInt cnt = FT_NEXT_BYTE( p );
+
+
+ if ( char_code < start )
+ max = mid;
+ else if ( char_code > start+cnt )
+ min = mid + 1;
+ else
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+ static FT_UInt
+ tt_cmap14_char_map_nondef_binary( FT_Byte *base,
+ FT_UInt32 char_code )
+ {
+ FT_UInt32 numMappings = TT_PEEK_ULONG( base );
+ FT_UInt32 max, min;
+
+
+ min = 0;
+ max = numMappings;
+
+ base += 4;
+
+ /* binary search */
+ while ( min < max )
+ {
+ FT_UInt32 mid = ( min + max ) >> 1;
+ FT_Byte* p = base + 5 * mid;
+ FT_UInt32 uni = TT_NEXT_UINT24( p );
+
+
+ if ( char_code < uni )
+ max = mid;
+ else if ( char_code > uni )
+ min = mid + 1;
+ else
+ return TT_PEEK_USHORT( p );
+ }
+
+ return 0;
+ }
+
+
+ static FT_Byte*
+ tt_cmap14_find_variant( FT_Byte *base,
+ FT_UInt32 variantCode )
+ {
+ FT_UInt32 numVar = TT_PEEK_ULONG( base );
+ FT_UInt32 max, min;
+
+
+ min = 0;
+ max = numVar;
+
+ base += 4;
+
+ /* binary search */
+ while ( min < max )
+ {
+ FT_UInt32 mid = ( min + max ) >> 1;
+ FT_Byte* p = base + 11 * mid;
+ FT_ULong varSel = TT_NEXT_UINT24( p );
+
+
+ if ( variantCode < varSel )
+ max = mid;
+ else if ( variantCode > varSel )
+ min = mid + 1;
+ else
+ return p;
+ }
+
+ return NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap14_char_var_index( TT_CMap cmap,
+ TT_CMap ucmap,
+ FT_ULong charcode,
+ FT_ULong variantSelector)
+ {
+ FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ FT_ULong defOff;
+ FT_ULong nondefOff;
+
+
+ if ( !p )
+ return 0;
+
+ defOff = TT_NEXT_ULONG( p );
+ nondefOff = TT_PEEK_ULONG( p );
+
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ {
+ /* This is the default variant of this charcode. GID not stored */
+ /* here; stored in the normal Unicode charmap instead. */
+ return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
+ }
+
+ if ( nondefOff != 0 )
+ return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+ charcode );
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Int )
+ tt_cmap14_char_var_isdefault( TT_CMap cmap,
+ FT_ULong charcode,
+ FT_ULong variantSelector )
+ {
+ FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ FT_ULong defOff;
+ FT_ULong nondefOff;
+
+
+ if ( !p )
+ return -1;
+
+ defOff = TT_NEXT_ULONG( p );
+ nondefOff = TT_NEXT_ULONG( p );
+
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ return 1;
+
+ if ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+ charcode ) != 0 )
+ return 0;
+
+ return -1;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt32* )
+ tt_cmap14_variants( TT_CMap cmap,
+ FT_Memory memory )
+ {
+ TT_CMap14 cmap14 = (TT_CMap14)cmap;
+ FT_UInt count = cmap14->num_selectors;
+ FT_Byte* p = cmap->data + 10;
+ FT_UInt32* result;
+ FT_UInt i;
+
+
+ if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) )
+ return NULL;
+
+ result = cmap14->results;
+ for ( i = 0; i < count; ++i )
+ {
+ result[i] = TT_NEXT_UINT24( p );
+ p += 8;
+ }
+ result[i] = 0;
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt32 * )
+ tt_cmap14_char_variants( TT_CMap cmap,
+ FT_Memory memory,
+ FT_ULong charCode )
+ {
+ TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ FT_UInt count = cmap14->num_selectors;
+ FT_Byte* p = cmap->data + 10;
+ FT_UInt32* q;
+
+
+ if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) )
+ return NULL;
+
+ for ( q = cmap14->results; count > 0; --count )
+ {
+ FT_UInt32 varSel = TT_NEXT_UINT24( p );
+ FT_ULong defOff = TT_NEXT_ULONG( p );
+ FT_ULong nondefOff = TT_NEXT_ULONG( p );
+
+
+ if ( ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( cmap->data + defOff,
+ charCode ) ) ||
+ ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+ charCode ) != 0 ) )
+ {
+ q[0] = varSel;
+ q++;
+ }
+ }
+ q[0] = 0;
+
+ return cmap14->results;
+ }
+
+
+ static FT_UInt
+ tt_cmap14_def_char_count( FT_Byte *p )
+ {
+ FT_UInt32 numRanges = TT_NEXT_ULONG( p );
+ FT_UInt tot = 0;
+
+
+ p += 3; /* point to the first `cnt' field */
+ for ( ; numRanges > 0; numRanges-- )
+ {
+ tot += 1 + p[0];
+ p += 4;
+ }
+
+ return tot;
+ }
+
+
+ static FT_UInt32*
+ tt_cmap14_get_def_chars( TT_CMap cmap,
+ FT_Byte* p,
+ FT_Memory memory )
+ {
+ TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ FT_UInt32 numRanges;
+ FT_UInt cnt;
+ FT_UInt32* q;
+
+
+ cnt = tt_cmap14_def_char_count( p );
+ numRanges = TT_NEXT_ULONG( p );
+
+ if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) )
+ return NULL;
+
+ for ( q = cmap14->results; numRanges > 0; --numRanges )
+ {
+ FT_UInt uni = TT_NEXT_UINT24( p );
+
+
+ cnt = FT_NEXT_BYTE( p ) + 1;
+ do
+ {
+ q[0] = uni;
+ uni += 1;
+ q += 1;
+ } while ( --cnt != 0 );
+ }
+ q[0] = 0;
+
+ return cmap14->results;
+ }
+
+
+ static FT_UInt32*
+ tt_cmap14_get_nondef_chars( TT_CMap cmap,
+ FT_Byte *p,
+ FT_Memory memory )
+ {
+ TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ FT_UInt32 numMappings;
+ FT_UInt i;
+ FT_UInt32 *ret;
+
+
+ numMappings = TT_NEXT_ULONG( p );
+
+ if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) )
+ return NULL;
+
+ ret = cmap14->results;
+ for ( i = 0; i < numMappings; ++i )
+ {
+ ret[i] = TT_NEXT_UINT24( p );
+ p += 2;
+ }
+ ret[i] = 0;
+
+ return ret;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt32 * )
+ tt_cmap14_variant_chars( TT_CMap cmap,
+ FT_Memory memory,
+ FT_ULong variantSelector )
+ {
+ FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6,
+ variantSelector );
+ FT_UInt32 *ret;
+ FT_Int i;
+ FT_ULong defOff;
+ FT_ULong nondefOff;
+
+
+ if ( !p )
+ return NULL;
+
+ defOff = TT_NEXT_ULONG( p );
+ nondefOff = TT_NEXT_ULONG( p );
+
+ if ( defOff == 0 && nondefOff == 0 )
+ return NULL;
+
+ if ( defOff == 0 )
+ return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ memory );
+ else if ( nondefOff == 0 )
+ return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ memory );
+ else
+ {
+ /* Both a default and a non-default glyph set? That's probably not */
+ /* good font design, but the spec allows for it... */
+ TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ FT_UInt32 numRanges;
+ FT_UInt32 numMappings;
+ FT_UInt32 duni;
+ FT_UInt32 dcnt;
+ FT_UInt32 nuni;
+ FT_Byte* dp;
+ FT_UInt di, ni, k;
+
+
+ p = cmap->data + nondefOff;
+ dp = cmap->data + defOff;
+
+ numMappings = TT_NEXT_ULONG( p );
+ dcnt = tt_cmap14_def_char_count( dp );
+ numRanges = TT_NEXT_ULONG( dp );
+
+ if ( numMappings == 0 )
+ return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ memory );
+ if ( dcnt == 0 )
+ return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ memory );
+
+ if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) )
+ return NULL;
+
+ ret = cmap14->results;
+ duni = TT_NEXT_UINT24( dp );
+ dcnt = FT_NEXT_BYTE( dp );
+ di = 1;
+ nuni = TT_NEXT_UINT24( p );
+ p += 2;
+ ni = 1;
+ i = 0;
+
+ for ( ;; )
+ {
+ if ( nuni > duni + dcnt )
+ {
+ for ( k = 0; k <= dcnt; ++k )
+ ret[i++] = duni + k;
+
+ ++di;
+
+ if ( di > numRanges )
+ break;
+
+ duni = TT_NEXT_UINT24( dp );
+ dcnt = FT_NEXT_BYTE( dp );
+ }
+ else
+ {
+ if ( nuni < duni )
+ ret[i++] = nuni;
+ /* If it is within the default range then ignore it -- */
+ /* that should not have happened */
+ ++ni;
+ if ( ni > numMappings )
+ break;
+
+ nuni = TT_NEXT_UINT24( p );
+ p += 2;
+ }
+ }
+
+ if ( ni <= numMappings )
+ {
+ /* If we get here then we have run out of all default ranges. */
+ /* We have read one non-default mapping which we haven't stored */
+ /* and there may be others that need to be read. */
+ ret[i++] = nuni;
+ while ( ni < numMappings )
+ {
+ ret[i++] = TT_NEXT_UINT24( p );
+ p += 2;
+ ++ni;
+ }
+ }
+ else if ( di <= numRanges )
+ {
+ /* If we get here then we have run out of all non-default */
+ /* mappings. We have read one default range which we haven't */
+ /* stored and there may be others that need to be read. */
+ for ( k = 0; k <= dcnt; ++k )
+ ret[i++] = duni + k;
+
+ while ( di < numRanges )
+ {
+ duni = TT_NEXT_UINT24( dp );
+ dcnt = FT_NEXT_BYTE( dp );
+
+ for ( k = 0; k <= dcnt; ++k )
+ ret[i++] = duni + k;
+ ++di;
+ }
+ }
+
+ ret[i] = 0;
+
+ return ret;
+ }
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap14_class_rec =
+ {
+ {
+ sizeof ( TT_CMap14Rec ),
+
+ (FT_CMap_InitFunc) tt_cmap14_init,
+ (FT_CMap_DoneFunc) tt_cmap14_done,
+ (FT_CMap_CharIndexFunc)tt_cmap14_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap14_char_next,
+
+ /* Format 14 extension functions */
+ (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index,
+ (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault,
+ (FT_CMap_VariantListFunc) tt_cmap14_variants,
+ (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants,
+ (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars
+ },
+ 14,
+ (TT_CMap_ValidateFunc)tt_cmap14_validate,
+ (TT_CMap_Info_GetFunc)tt_cmap14_get_info
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_14 */
+
+
+ static const TT_CMap_Class tt_cmap_classes[] =
+ {
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+ &tt_cmap0_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+ &tt_cmap2_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+ &tt_cmap4_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+ &tt_cmap6_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+ &tt_cmap8_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+ &tt_cmap10_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+ &tt_cmap12_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_14
+ &tt_cmap14_class_rec,
+#endif
+
+ NULL,
+ };
+
+
+ /* parse the `cmap' table and build the corresponding TT_CMap objects */
+ /* in the current face */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_build_cmaps( TT_Face face )
+ {
+ FT_Byte* table = face->cmap_table;
+ FT_Byte* limit = table + face->cmap_size;
+ FT_UInt volatile num_cmaps;
+ FT_Byte* volatile p = table;
+
+
+ if ( p + 4 > limit )
+ return SFNT_Err_Invalid_Table;
+
+ /* only recognize format 0 */
+ if ( TT_NEXT_USHORT( p ) != 0 )
+ {
+ p -= 2;
+ FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n",
+ TT_PEEK_USHORT( p ) ));
+ return SFNT_Err_Invalid_Table;
+ }
+
+ num_cmaps = TT_NEXT_USHORT( p );
+
+ for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
+ {
+ FT_CharMapRec charmap;
+ FT_UInt32 offset;
+
+
+ charmap.platform_id = TT_NEXT_USHORT( p );
+ charmap.encoding_id = TT_NEXT_USHORT( p );
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE; /* will be filled later */
+ offset = TT_NEXT_ULONG( p );
+
+ if ( offset && offset <= face->cmap_size - 2 )
+ {
+ FT_Byte* volatile cmap = table + offset;
+ volatile FT_UInt format = TT_PEEK_USHORT( cmap );
+ const TT_CMap_Class* volatile pclazz = tt_cmap_classes;
+ TT_CMap_Class volatile clazz;
+
+
+ for ( ; *pclazz; pclazz++ )
+ {
+ clazz = *pclazz;
+ if ( clazz->format == format )
+ {
+ volatile TT_ValidatorRec valid;
+ volatile FT_Error error = SFNT_Err_Ok;
+
+
+ ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit,
+ FT_VALIDATE_DEFAULT );
+
+ valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs;
+
+ if ( ft_setjmp(
+ *((ft_jmp_buf*)&FT_VALIDATOR( &valid )->jump_buffer) ) == 0 )
+ {
+ /* validate this cmap sub-table */
+ error = clazz->validate( cmap, FT_VALIDATOR( &valid ) );
+ }
+
+ if ( valid.validator.error == 0 )
+ {
+ FT_CMap ttcmap;
+
+
+ /* It might make sense to store the single variation selector */
+ /* cmap somewhere special. But it would have to be in the */
+ /* public FT_FaceRec, and we can't change that. */
+
+ if ( !FT_CMap_New( (FT_CMap_Class)clazz,
+ cmap, &charmap, &ttcmap ) )
+ {
+ /* it is simpler to directly set `flags' than adding */
+ /* a parameter to FT_CMap_New */
+ ((TT_CMap)ttcmap)->flags = (FT_Int)error;
+ }
+ }
+ else
+ {
+ FT_ERROR(( "tt_face_build_cmaps:" ));
+ FT_ERROR(( " broken cmap sub-table ignored!\n" ));
+ }
+ break;
+ }
+ }
+
+ if ( *pclazz == NULL )
+ {
+ FT_ERROR(( "tt_face_build_cmaps:" ));
+ FT_ERROR(( " unsupported cmap sub-table ignored!\n" ));
+ }
+ }
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+ FT_LOCAL( FT_Error )
+ tt_get_cmap_info( FT_CharMap charmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_CMap cmap = (FT_CMap)charmap;
+ TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz;
+
+
+ return clazz->get_cmap_info( charmap, cmap_info );
+ }
+
+
+/* END */