ref: 07bee1c2ea89752e608d881dde2e2a4a1e738516
dir: /libfreetype/ttcmap.c/
/***************************************************************************/ /* */ /* ttcmap.c */ /* */ /* TrueType character mapping table (cmap) support (body). */ /* */ /* Copyright 1996-2001, 2002 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 "ttload.h" #include "ttcmap.h" #include "sferrors.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 FT_CALLBACK_DEF( FT_UInt ) code_to_index0( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next0( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_UInt ) code_to_index2( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next2( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_UInt ) code_to_index4( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next4( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_UInt ) code_to_index6( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next6( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_UInt ) code_to_index8_12( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next8_12( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_UInt ) code_to_index10( TT_CMapTable charmap, FT_ULong char_code ); FT_CALLBACK_DEF( FT_ULong ) code_to_next10( TT_CMapTable charmap, FT_ULong char_code ); /*************************************************************************/ /* */ /* <Function> */ /* tt_face_load_charmap */ /* */ /* <Description> */ /* Loads a given TrueType character map into memory. */ /* */ /* <Input> */ /* face :: A handle to the parent face object. */ /* */ /* stream :: A handle to the current stream object. */ /* */ /* <InOut> */ /* table :: A pointer to a cmap object. */ /* */ /* <Return> */ /* FreeType error code. 0 means success. */ /* */ /* <Note> */ /* The function assumes that the stream is already in use (i.e., */ /* opened). In case of error, all partially allocated tables are */ /* released. */ /* */ FT_LOCAL_DEF( FT_Error ) tt_face_load_charmap( TT_Face face, TT_CMapTable cmap, FT_Stream stream ) { FT_Error error; FT_Memory memory; FT_UShort num_SH, num_Seg, i; FT_ULong j, n; FT_UShort u, l; TT_CMap0 cmap0; TT_CMap2 cmap2; TT_CMap4 cmap4; TT_CMap6 cmap6; TT_CMap8_12 cmap8_12; TT_CMap10 cmap10; TT_CMap2SubHeader cmap2sub; TT_CMap4Segment segments; TT_CMapGroup groups; if ( cmap->loaded ) return SFNT_Err_Ok; memory = stream->memory; if ( FT_STREAM_SEEK( cmap->offset ) ) return error; switch ( cmap->format ) { case 0: cmap0 = &cmap->c.cmap0; if ( FT_READ_USHORT( cmap0->language ) || FT_ALLOC( cmap0->glyphIdArray, 256L ) || FT_STREAM_READ( cmap0->glyphIdArray, 256L ) ) goto Fail; cmap->get_index = code_to_index0; cmap->get_next_char = code_to_next0; break; case 2: num_SH = 0; cmap2 = &cmap->c.cmap2; /* allocate subheader keys */ if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) || FT_FRAME_ENTER( 2L + 512L ) ) goto Fail; cmap2->language = FT_GET_USHORT(); for ( i = 0; i < 256; i++ ) { u = (FT_UShort)( FT_GET_USHORT() / 8 ); cmap2->subHeaderKeys[i] = u; if ( num_SH < u ) num_SH = u; } FT_FRAME_EXIT(); /* load subheaders */ cmap2->numGlyphId = l = (FT_UShort)( ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 ); if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) || FT_FRAME_ENTER( ( num_SH + 1 ) * 8L ) ) { FT_FREE( cmap2->subHeaderKeys ); goto Fail; } cmap2sub = cmap2->subHeaders; for ( i = 0; i <= num_SH; i++ ) { cmap2sub->firstCode = FT_GET_USHORT(); cmap2sub->entryCount = FT_GET_USHORT(); cmap2sub->idDelta = FT_GET_SHORT(); /* we apply the location offset immediately */ cmap2sub->idRangeOffset = (FT_UShort)( FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 ); cmap2sub++; } FT_FRAME_EXIT(); /* load glyph IDs */ if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap2->subHeaders ); FT_FREE( cmap2->subHeaderKeys ); goto Fail; } for ( i = 0; i < l; i++ ) cmap2->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index2; cmap->get_next_char = code_to_next2; break; case 4: cmap4 = &cmap->c.cmap4; /* load header */ if ( FT_FRAME_ENTER( 10L ) ) goto Fail; cmap4->language = FT_GET_USHORT(); cmap4->segCountX2 = FT_GET_USHORT(); cmap4->searchRange = FT_GET_USHORT(); cmap4->entrySelector = FT_GET_USHORT(); cmap4->rangeShift = FT_GET_USHORT(); num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 ); FT_FRAME_EXIT(); /* load segments */ if ( FT_NEW_ARRAY( cmap4->segments, num_Seg ) || FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) ) goto Fail; segments = cmap4->segments; for ( i = 0; i < num_Seg; i++ ) segments[i].endCount = FT_GET_USHORT(); (void)FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].startCount = FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idDelta = FT_GET_SHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idRangeOffset = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->numGlyphId = l = (FT_UShort)( ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 ); /* load IDs */ if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap4->segments ); goto Fail; } for ( i = 0; i < l; i++ ) cmap4->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->last_segment = cmap4->segments; cmap->get_index = code_to_index4; cmap->get_next_char = code_to_next4; break; case 6: cmap6 = &cmap->c.cmap6; if ( FT_FRAME_ENTER( 6L ) ) goto Fail; cmap6->language = FT_GET_USHORT(); cmap6->firstCode = FT_GET_USHORT(); cmap6->entryCount = FT_GET_USHORT(); FT_FRAME_EXIT(); l = cmap6->entryCount; if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) goto Fail; for ( i = 0; i < l; i++ ) cmap6->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index6; cmap->get_next_char = code_to_next6; break; case 8: case 12: cmap8_12 = &cmap->c.cmap8_12; if ( FT_FRAME_ENTER( 8L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap8_12->language = FT_GET_ULONG(); FT_FRAME_EXIT(); if ( cmap->format == 8 ) if ( FT_STREAM_SKIP( 8192L ) ) goto Fail; if ( FT_READ_ULONG( cmap8_12->nGroups ) ) goto Fail; n = cmap8_12->nGroups; if ( FT_NEW_ARRAY( cmap8_12->groups, n ) || FT_FRAME_ENTER( n * 3 * 4L ) ) goto Fail; groups = cmap8_12->groups; for ( j = 0; j < n; j++ ) { groups[j].startCharCode = FT_GET_ULONG(); groups[j].endCharCode = FT_GET_ULONG(); groups[j].startGlyphID = FT_GET_ULONG(); } FT_FRAME_EXIT(); cmap8_12->last_group = cmap8_12->groups; cmap->get_index = code_to_index8_12; cmap->get_next_char = code_to_next8_12; break; case 10: cmap10 = &cmap->c.cmap10; if ( FT_FRAME_ENTER( 16L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap10->language = FT_GET_ULONG(); cmap10->startCharCode = FT_GET_ULONG(); cmap10->numChars = FT_GET_ULONG(); FT_FRAME_EXIT(); n = cmap10->numChars; if ( FT_NEW_ARRAY( cmap10->glyphs, n ) || FT_FRAME_ENTER( n * 2L ) ) goto Fail; for ( j = 0; j < n; j++ ) cmap10->glyphs[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index10; cmap->get_next_char = code_to_next10; break; default: /* corrupt character mapping table */ return SFNT_Err_Invalid_CharMap_Format; } return SFNT_Err_Ok; Fail: tt_face_free_charmap( face, cmap ); return error; } /*************************************************************************/ /* */ /* <Function> */ /* tt_face_free_charmap */ /* */ /* <Description> */ /* Destroys a character mapping table. */ /* */ /* <Input> */ /* face :: A handle to the parent face object. */ /* */ /* cmap :: A handle to a cmap object. */ /* */ /* <Return> */ /* FreeType error code. 0 means success. */ /* */ FT_LOCAL_DEF( FT_Error ) tt_face_free_charmap( TT_Face face, TT_CMapTable cmap ) { FT_Memory memory; if ( !cmap ) return SFNT_Err_Ok; memory = face->root.driver->root.memory; switch ( cmap->format ) { case 0: FT_FREE( cmap->c.cmap0.glyphIdArray ); break; case 2: FT_FREE( cmap->c.cmap2.subHeaderKeys ); FT_FREE( cmap->c.cmap2.subHeaders ); FT_FREE( cmap->c.cmap2.glyphIdArray ); break; case 4: FT_FREE( cmap->c.cmap4.segments ); FT_FREE( cmap->c.cmap4.glyphIdArray ); cmap->c.cmap4.segCountX2 = 0; break; case 6: FT_FREE( cmap->c.cmap6.glyphIdArray ); cmap->c.cmap6.entryCount = 0; break; case 8: case 12: FT_FREE( cmap->c.cmap8_12.groups ); cmap->c.cmap8_12.nGroups = 0; break; case 10: FT_FREE( cmap->c.cmap10.glyphs ); cmap->c.cmap10.numChars = 0; break; default: /* invalid table format, do nothing */ ; } cmap->loaded = FALSE; return SFNT_Err_Ok; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index0 */ /* */ /* <Description> */ /* Converts the character code into a glyph index. Uses format 0. */ /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */ /* returned). */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap0 :: A pointer to a cmap table in format 0. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index0( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap0 cmap0 = &cmap->c.cmap0; return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 ); } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next0 */ /* */ /* <Description> */ /* Finds the next encoded character after the given one. Uses */ /* format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0 */ /* is returned). */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap0 :: A pointer to a cmap table in format 0. */ /* */ /* <Return> */ /* Next char code. 0 if no higher one is encoded. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next0( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap0 cmap0 = &cmap->c.cmap0; while ( ++charCode <= 0xFF ) if ( cmap0->glyphIdArray[charCode] ) return ( charCode ); return ( 0 ); } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index2 */ /* */ /* <Description> */ /* Converts the character code into a glyph index. Uses format 2. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap2 :: A pointer to a cmap table in format 2. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index2( TT_CMapTable cmap, FT_ULong charCode ) { FT_UInt result, index1, offset; FT_UInt char_lo; FT_ULong char_hi; TT_CMap2SubHeader sh2; TT_CMap2 cmap2; cmap2 = &cmap->c.cmap2; result = 0; char_lo = (FT_UInt)( charCode & 0xFF ); char_hi = charCode >> 8; if ( char_hi == 0 ) { /* an 8-bit character code -- we use the subHeader 0 in this case */ /* to test whether the character code is in the charmap */ index1 = cmap2->subHeaderKeys[char_lo]; if ( index1 != 0 ) return 0; } else { /* a 16-bit character code */ index1 = cmap2->subHeaderKeys[char_hi & 0xFF]; if ( index1 == 0 ) return 0; } sh2 = cmap2->subHeaders + index1; char_lo -= sh2->firstCode; if ( char_lo < (FT_UInt)sh2->entryCount ) { offset = sh2->idRangeOffset / 2 + char_lo; if ( offset < (FT_UInt)cmap2->numGlyphId ) { result = cmap2->glyphIdArray[offset]; if ( result ) result = ( result + sh2->idDelta ) & 0xFFFFU; } } return result; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next2 */ /* */ /* <Description> */ /* Find the next encoded character. Uses format 2. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap2 :: A pointer to a cmap table in format 2. */ /* */ /* <Return> */ /* Next encoded character. 0 if none exists. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next2( TT_CMapTable cmap, FT_ULong charCode ) { FT_UInt index1, offset; FT_UInt char_lo; FT_ULong char_hi; TT_CMap2SubHeader sh2; TT_CMap2 cmap2; cmap2 = &cmap->c.cmap2; charCode++; /* * This is relatively simplistic -- look for a subHeader containing * glyphs and then walk to the first glyph in that subHeader. */ while ( charCode < 0x10000L ) { char_lo = (FT_UInt)( charCode & 0xFF ); char_hi = charCode >> 8; if ( char_hi == 0 ) { /* an 8-bit character code -- we use the subHeader 0 in this case */ /* to test whether the character code is in the charmap */ index1 = cmap2->subHeaderKeys[char_lo]; if ( index1 != 0 ) { charCode++; continue; } } else { /* a 16-bit character code */ index1 = cmap2->subHeaderKeys[char_hi & 0xFF]; if ( index1 == 0 ) { charCode = ( char_hi + 1 ) << 8; continue; } } sh2 = cmap2->subHeaders + index1; char_lo -= sh2->firstCode; if ( char_lo > (FT_UInt)sh2->entryCount ) { charCode = ( char_hi + 1 ) << 8; continue; } offset = sh2->idRangeOffset / 2 + char_lo; if ( offset >= (FT_UInt)cmap2->numGlyphId || cmap2->glyphIdArray[offset] == 0 ) { charCode++; continue; } return charCode; } return 0; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index4 */ /* */ /* <Description> */ /* Converts the character code into a glyph index. Uses format 4. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap4 :: A pointer to a cmap table in format 4. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index4( TT_CMapTable cmap, FT_ULong charCode ) { FT_UInt result, index1, segCount; TT_CMap4 cmap4; TT_CMap4SegmentRec *seg4, *limit; cmap4 = &cmap->c.cmap4; result = 0; segCount = cmap4->segCountX2 / 2; limit = cmap4->segments + segCount; /* first, check against the last used segment */ seg4 = cmap4->last_segment; /* the following is equivalent to performing two tests, as in */ /* */ /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */ /* */ /* This is a bit strange, but it is faster, and the idea behind the */ /* cache is to significantly speed up charcode to glyph index */ /* conversion. */ if ( (FT_ULong)( charCode - seg4->startCount ) < (FT_ULong)( seg4->endCount - seg4->startCount ) ) goto Found1; for ( seg4 = cmap4->segments; seg4 < limit; seg4++ ) { /* the ranges are sorted in increasing order. If we are out of */ /* the range here, the char code isn't in the charmap, so exit. */ if ( charCode > (FT_UInt)seg4->endCount ) continue; if ( charCode >= (FT_UInt)seg4->startCount ) goto Found; } return 0; Found: cmap4->last_segment = seg4; Found1: /* if the idRangeOffset is 0, we can compute the glyph index */ /* directly */ if ( seg4->idRangeOffset == 0 ) result = (FT_UInt)( charCode + seg4->idDelta ) & 0xFFFFU; else { /* otherwise, we must use the glyphIdArray to do it */ index1 = (FT_UInt)( seg4->idRangeOffset / 2 + ( charCode - seg4->startCount ) + ( seg4 - cmap4->segments ) - segCount ); if ( index1 < (FT_UInt)cmap4->numGlyphId && cmap4->glyphIdArray[index1] != 0 ) result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFFU; } return result; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next4 */ /* */ /* <Description> */ /* Find the next encoded character. Uses format 4. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap :: A pointer to a cmap table in format 4. */ /* */ /* <Return> */ /* Next encoded character. 0 if none exists. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next4( TT_CMapTable cmap, FT_ULong charCode ) { FT_UInt index1, segCount; TT_CMap4 cmap4; TT_CMap4SegmentRec *seg4, *limit; cmap4 = &cmap->c.cmap4; segCount = cmap4->segCountX2 / 2; limit = cmap4->segments + segCount; charCode++; for ( seg4 = cmap4->segments; seg4 < limit; seg4++ ) { /* The ranges are sorted in increasing order. If we are out of */ /* the range here, the char code isn't in the charmap, so exit. */ if ( charCode <= (FT_UInt)seg4->endCount ) goto Found; } return 0; Found: if ( charCode < (FT_ULong) seg4->startCount ) charCode = seg4->startCount; /* if the idRangeOffset is 0, all chars in the map exist */ if ( seg4->idRangeOffset == 0 ) return ( charCode ); while ( charCode <= (FT_UInt) seg4->endCount ) { /* otherwise, we must use the glyphIdArray to do it */ index1 = (FT_UInt)( seg4->idRangeOffset / 2 + ( charCode - seg4->startCount ) + ( seg4 - cmap4->segments ) - segCount ); if ( index1 < (FT_UInt)cmap4->numGlyphId && cmap4->glyphIdArray[index1] != 0 ) return ( charCode ); charCode++; } return 0; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index6 */ /* */ /* <Description> */ /* Converts the character code into a glyph index. Uses format 6. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap6 :: A pointer to a cmap table in format 6. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index6( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap6 cmap6; FT_UInt result = 0; cmap6 = &cmap->c.cmap6; charCode -= cmap6->firstCode; if ( charCode < (FT_UInt)cmap6->entryCount ) result = cmap6->glyphIdArray[charCode]; return result; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next6 */ /* */ /* <Description> */ /* Find the next encoded character. Uses format 6. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap :: A pointer to a cmap table in format 6. */ /* */ /* <Return> */ /* Next encoded character. 0 if none exists. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next6( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap6 cmap6; charCode++; cmap6 = &cmap->c.cmap6; if ( charCode < (FT_ULong) cmap6->firstCode ) charCode = cmap6->firstCode; charCode -= cmap6->firstCode; while ( charCode < (FT_UInt)cmap6->entryCount ) { if ( cmap6->glyphIdArray[charCode] != 0 ) return charCode + cmap6->firstCode; charCode++; } return 0; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index8_12 */ /* */ /* <Description> */ /* Converts the (possibly 32bit) character code into a glyph index. */ /* Uses format 8 or 12. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap8_12 :: A pointer to a cmap table in format 8 or 12. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index8_12( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap8_12 cmap8_12; TT_CMapGroupRec *group, *limit; cmap8_12 = &cmap->c.cmap8_12; limit = cmap8_12->groups + cmap8_12->nGroups; /* first, check against the last used group */ group = cmap8_12->last_group; /* the following is equivalent to performing two tests, as in */ /* */ /* if ( charCode >= group->startCharCode && */ /* charCode <= group->endCharCode ) */ /* */ /* This is a bit strange, but it is faster, and the idea behind the */ /* cache is to significantly speed up charcode to glyph index */ /* conversion. */ if ( (FT_ULong)( charCode - group->startCharCode ) < (FT_ULong)( group->endCharCode - group->startCharCode ) ) goto Found1; for ( group = cmap8_12->groups; group < limit; group++ ) { /* the ranges are sorted in increasing order. If we are out of */ /* the range here, the char code isn't in the charmap, so exit. */ if ( charCode > group->endCharCode ) continue; if ( charCode >= group->startCharCode ) goto Found; } return 0; Found: cmap8_12->last_group = group; Found1: return (FT_UInt)( group->startGlyphID + ( charCode - group->startCharCode ) ); } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next8_12 */ /* */ /* <Description> */ /* Find the next encoded character. Uses format 8 or 12. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap :: A pointer to a cmap table in format 8 or 12. */ /* */ /* <Return> */ /* Next encoded character. 0 if none exists. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next8_12( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap8_12 cmap8_12; TT_CMapGroupRec *group, *limit; charCode++; cmap8_12 = &cmap->c.cmap8_12; limit = cmap8_12->groups + cmap8_12->nGroups; for ( group = cmap8_12->groups; group < limit; group++ ) { /* the ranges are sorted in increasing order. If we are out of */ /* the range here, the char code isn't in the charmap, so exit. */ if ( charCode <= group->endCharCode ) goto Found; } return 0; Found: if ( charCode < group->startCharCode ) charCode = group->startCharCode; return charCode; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_index10 */ /* */ /* <Description> */ /* Converts the (possibly 32bit) character code into a glyph index. */ /* Uses format 10. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap10 :: A pointer to a cmap table in format 10. */ /* */ /* <Return> */ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ /* */ FT_CALLBACK_DEF( FT_UInt ) code_to_index10( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap10 cmap10; FT_UInt result = 0; cmap10 = &cmap->c.cmap10; charCode -= cmap10->startCharCode; /* the overflow trick for comparison works here also since the number */ /* of glyphs (even if numChars is specified as ULong in the specs) in */ /* an OpenType font is limited to 64k */ if ( charCode < cmap10->numChars ) result = cmap10->glyphs[charCode]; return result; } /*************************************************************************/ /* */ /* <Function> */ /* code_to_next10 */ /* */ /* <Description> */ /* Find the next encoded character. Uses format 10. */ /* */ /* <Input> */ /* charCode :: The wanted character code. */ /* */ /* cmap :: A pointer to a cmap table in format 10. */ /* */ /* <Return> */ /* Next encoded character. 0 if none exists. */ /* */ FT_CALLBACK_DEF( FT_ULong ) code_to_next10( TT_CMapTable cmap, FT_ULong charCode ) { TT_CMap10 cmap10; charCode++; cmap10 = &cmap->c.cmap10; if ( charCode < cmap10->startCharCode ) charCode = cmap10->startCharCode; charCode -= cmap10->startCharCode; /* the overflow trick for comparison works here also since the number */ /* of glyphs (even if numChars is specified as ULong in the specs) in */ /* an OpenType font is limited to 64k */ while ( charCode < cmap10->numChars ) { if ( cmap10->glyphs[charCode] ) return ( charCode + cmap10->startCharCode ); charCode++; } return 0; } /* END */