1 /***************************************************************************/
5 /* TrueType character mapping table (cmap) support (body). */
7 /* Copyright 1996-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
27 /*************************************************************************/
29 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
30 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
31 /* messages during execution. */
34 #define FT_COMPONENT trace_ttcmap
37 FT_CALLBACK_DEF( FT_UInt )
38 code_to_index0( TT_CMapTable* charmap,
41 FT_CALLBACK_DEF( FT_UInt )
42 code_to_index2( TT_CMapTable* charmap,
45 FT_CALLBACK_DEF( FT_UInt )
46 code_to_index4( TT_CMapTable* charmap,
49 FT_CALLBACK_DEF( FT_UInt )
50 code_to_index6( TT_CMapTable* charmap,
53 FT_CALLBACK_DEF( FT_UInt )
54 code_to_index8_12( TT_CMapTable* charmap,
57 FT_CALLBACK_DEF( FT_UInt )
58 code_to_index10( TT_CMapTable* charmap,
62 /*************************************************************************/
68 /* Loads a given TrueType character map into memory. */
71 /* face :: A handle to the parent face object. */
72 /* stream :: A handle to the current stream object. */
75 /* table :: A pointer to a cmap object. */
78 /* FreeType error code. 0 means success. */
81 /* The function assumes that the stream is already in use (i.e., */
82 /* opened). In case of error, all partially allocated tables are */
86 TT_CharMap_Load( TT_Face face,
92 FT_UShort num_SH, num_Seg, i;
101 TT_CMap8_12* cmap8_12;
104 TT_CMap2SubHeader* cmap2sub;
105 TT_CMap4Segment* segments;
106 TT_CMapGroup* groups;
112 memory = stream->memory;
114 if ( FILE_Seek( cmap->offset ) )
117 switch ( cmap->format )
120 cmap0 = &cmap->c.cmap0;
122 if ( READ_UShort( cmap0->language ) ||
123 ALLOC( cmap0->glyphIdArray, 256L ) ||
124 FILE_Read( cmap0->glyphIdArray, 256L ) )
127 cmap->get_index = code_to_index0;
132 cmap2 = &cmap->c.cmap2;
134 /* allocate subheader keys */
136 if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
137 ACCESS_Frame( 2L + 512L ) )
140 cmap2->language = GET_UShort();
142 for ( i = 0; i < 256; i++ )
144 u = (FT_UShort)( GET_UShort() / 8 );
145 cmap2->subHeaderKeys[i] = u;
153 /* load subheaders */
155 cmap2->numGlyphId = l = (FT_UShort)(
156 ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2 );
158 if ( ALLOC_ARRAY( cmap2->subHeaders,
160 TT_CMap2SubHeader ) ||
161 ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
163 FREE( cmap2->subHeaderKeys );
167 cmap2sub = cmap2->subHeaders;
169 for ( i = 0; i <= num_SH; i++ )
171 cmap2sub->firstCode = GET_UShort();
172 cmap2sub->entryCount = GET_UShort();
173 cmap2sub->idDelta = GET_Short();
174 /* we apply the location offset immediately */
175 cmap2sub->idRangeOffset = (FT_UShort)(
176 GET_UShort() - ( num_SH - i ) * 8 - 2 );
185 if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
186 ACCESS_Frame( l * 2L ) )
188 FREE( cmap2->subHeaders );
189 FREE( cmap2->subHeaderKeys );
193 for ( i = 0; i < l; i++ )
194 cmap2->glyphIdArray[i] = GET_UShort();
198 cmap->get_index = code_to_index2;
202 cmap4 = &cmap->c.cmap4;
206 if ( ACCESS_Frame( 10L ) )
209 cmap4->language = GET_UShort();
210 cmap4->segCountX2 = GET_UShort();
211 cmap4->searchRange = GET_UShort();
212 cmap4->entrySelector = GET_UShort();
213 cmap4->rangeShift = GET_UShort();
215 num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
221 if ( ALLOC_ARRAY( cmap4->segments,
224 ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
227 segments = cmap4->segments;
229 for ( i = 0; i < num_Seg; i++ )
230 segments[i].endCount = GET_UShort();
234 for ( i = 0; i < num_Seg; i++ )
235 segments[i].startCount = GET_UShort();
237 for ( i = 0; i < num_Seg; i++ )
238 segments[i].idDelta = GET_Short();
240 for ( i = 0; i < num_Seg; i++ )
241 segments[i].idRangeOffset = GET_UShort();
245 cmap4->numGlyphId = l = (FT_UShort)(
246 ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2 );
250 if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
251 ACCESS_Frame( l * 2L ) )
253 FREE( cmap4->segments );
257 for ( i = 0; i < l; i++ )
258 cmap4->glyphIdArray[i] = GET_UShort();
262 cmap4->last_segment = cmap4->segments;
264 cmap->get_index = code_to_index4;
268 cmap6 = &cmap->c.cmap6;
270 if ( ACCESS_Frame( 6L ) )
273 cmap6->language = GET_UShort();
274 cmap6->firstCode = GET_UShort();
275 cmap6->entryCount = GET_UShort();
279 l = cmap6->entryCount;
281 if ( ALLOC_ARRAY( cmap6->glyphIdArray, l, FT_Short ) ||
282 ACCESS_Frame( l * 2L ) )
285 for ( i = 0; i < l; i++ )
286 cmap6->glyphIdArray[i] = GET_UShort();
289 cmap->get_index = code_to_index6;
294 cmap8_12 = &cmap->c.cmap8_12;
296 if ( ACCESS_Frame( 8L ) )
299 cmap->length = GET_ULong();
300 cmap8_12->language = GET_ULong();
304 if ( cmap->format == 8 )
305 if ( FILE_Skip( 8192L ) )
308 if ( READ_ULong( cmap8_12->nGroups ) )
311 n = cmap8_12->nGroups;
313 if ( ALLOC_ARRAY( cmap8_12->groups, n, TT_CMapGroup ) ||
314 ACCESS_Frame( n * 3 * 4L ) )
317 groups = cmap8_12->groups;
319 for ( j = 0; j < n; j++ )
321 groups[j].startCharCode = GET_ULong();
322 groups[j].endCharCode = GET_ULong();
323 groups[j].startGlyphID = GET_ULong();
328 cmap8_12->last_group = cmap8_12->groups;
330 cmap->get_index = code_to_index8_12;
334 cmap10 = &cmap->c.cmap10;
336 if ( ACCESS_Frame( 16L ) )
339 cmap->length = GET_ULong();
340 cmap10->language = GET_ULong();
341 cmap10->startCharCode = GET_ULong();
342 cmap10->numChars = GET_ULong();
346 n = cmap10->numChars;
348 if ( ALLOC_ARRAY( cmap10->glyphs, n, FT_Short ) ||
349 ACCESS_Frame( n * 2L ) )
352 for ( j = 0; j < n; j++ )
353 cmap10->glyphs[j] = GET_UShort();
356 cmap->get_index = code_to_index10;
359 default: /* corrupt character mapping table */
360 return SFNT_Err_Invalid_CharMap_Format;
367 TT_CharMap_Free( face, cmap );
372 /*************************************************************************/
375 /* TT_CharMap_Free */
378 /* Destroys a character mapping table. */
381 /* face :: A handle to the parent face object. */
382 /* cmap :: A handle to a cmap object. */
385 /* FreeType error code. 0 means success. */
387 FT_LOCAL_DEF FT_Error
388 TT_CharMap_Free( TT_Face face,
397 memory = face->root.driver->root.memory;
399 switch ( cmap->format )
402 FREE( cmap->c.cmap0.glyphIdArray );
406 FREE( cmap->c.cmap2.subHeaderKeys );
407 FREE( cmap->c.cmap2.subHeaders );
408 FREE( cmap->c.cmap2.glyphIdArray );
412 FREE( cmap->c.cmap4.segments );
413 FREE( cmap->c.cmap4.glyphIdArray );
414 cmap->c.cmap4.segCountX2 = 0;
418 FREE( cmap->c.cmap6.glyphIdArray );
419 cmap->c.cmap6.entryCount = 0;
424 FREE( cmap->c.cmap8_12.groups );
425 cmap->c.cmap8_12.nGroups = 0;
429 FREE( cmap->c.cmap10.glyphs );
430 cmap->c.cmap10.numChars = 0;
434 /* invalid table format, do nothing */
438 cmap->loaded = FALSE;
443 /*************************************************************************/
449 /* Converts the character code into a glyph index. Uses format 0. */
450 /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */
454 /* charCode :: The wanted character code. */
455 /* cmap0 :: A pointer to a cmap table in format 0. */
458 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
460 FT_CALLBACK_DEF( FT_UInt )
461 code_to_index0( TT_CMapTable* cmap,
464 TT_CMap0* cmap0 = &cmap->c.cmap0;
467 return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
471 /*************************************************************************/
477 /* Converts the character code into a glyph index. Uses format 2. */
480 /* charCode :: The wanted character code. */
481 /* cmap2 :: A pointer to a cmap table in format 2. */
484 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
486 FT_CALLBACK_DEF( FT_UInt )
487 code_to_index2( TT_CMapTable* cmap,
490 FT_UInt result, index1, offset;
493 TT_CMap2SubHeader* sh2;
497 cmap2 = &cmap->c.cmap2;
499 char_lo = (FT_UInt)( charCode & 0xFF );
500 char_hi = charCode >> 8;
504 /* an 8-bit character code -- we use the subHeader 0 in this case */
505 /* to test whether the character code is in the charmap */
506 index1 = cmap2->subHeaderKeys[char_lo];
512 /* a 16-bit character code */
513 index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
518 sh2 = cmap2->subHeaders + index1;
519 char_lo -= sh2->firstCode;
521 if ( char_lo < (FT_UInt)sh2->entryCount )
523 offset = sh2->idRangeOffset / 2 + char_lo;
524 if ( offset < (FT_UInt)cmap2->numGlyphId )
526 result = cmap2->glyphIdArray[offset];
528 result = ( result + sh2->idDelta ) & 0xFFFF;
536 /*************************************************************************/
542 /* Converts the character code into a glyph index. Uses format 4. */
545 /* charCode :: The wanted character code. */
546 /* cmap4 :: A pointer to a cmap table in format 4. */
549 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
551 FT_CALLBACK_DEF( FT_UInt )
552 code_to_index4( TT_CMapTable* cmap,
555 FT_UInt result, index1, segCount;
557 TT_CMap4Segment *seg4, *limit;
560 cmap4 = &cmap->c.cmap4;
562 segCount = cmap4->segCountX2 / 2;
563 limit = cmap4->segments + segCount;
565 /* first, check against the last used segment */
567 seg4 = cmap4->last_segment;
569 /* the following is equivalent to performing two tests, as in */
571 /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
573 /* This is a bit strange, but it is faster, and the idea behind the */
574 /* cache is to significantly speed up charcode to glyph index */
577 if ( (FT_ULong)( charCode - seg4->startCount ) <
578 (FT_ULong)( seg4->endCount - seg4->startCount ) )
581 for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
583 /* the ranges are sorted in increasing order. If we are out of */
584 /* the range here, the char code isn't in the charmap, so exit. */
586 if ( charCode > (FT_UInt)seg4->endCount )
589 if ( charCode >= (FT_UInt)seg4->startCount )
595 cmap4->last_segment = seg4;
598 /* if the idRangeOffset is 0, we can compute the glyph index */
601 if ( seg4->idRangeOffset == 0 )
602 result = ( charCode + seg4->idDelta ) & 0xFFFF;
605 /* otherwise, we must use the glyphIdArray to do it */
606 index1 = (FT_UInt)( seg4->idRangeOffset / 2
607 + ( charCode - seg4->startCount )
608 + ( seg4 - cmap4->segments )
611 if ( index1 < (FT_UInt)cmap4->numGlyphId &&
612 cmap4->glyphIdArray[index1] != 0 )
613 result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF;
620 /*************************************************************************/
626 /* Converts the character code into a glyph index. Uses format 6. */
629 /* charCode :: The wanted character code. */
630 /* cmap6 :: A pointer to a cmap table in format 6. */
633 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
635 FT_CALLBACK_DEF( FT_UInt )
636 code_to_index6( TT_CMapTable* cmap,
643 cmap6 = &cmap->c.cmap6;
644 charCode -= cmap6->firstCode;
646 if ( charCode < (FT_UInt)cmap6->entryCount )
647 result = cmap6->glyphIdArray[charCode];
653 /*************************************************************************/
656 /* code_to_index8_12 */
659 /* Converts the (possibly 32bit) character code into a glyph index. */
660 /* Uses format 8 or 12. */
663 /* charCode :: The wanted character code. */
664 /* cmap8_12 :: A pointer to a cmap table in format 8 or 12. */
667 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
669 FT_CALLBACK_DEF( FT_UInt )
670 code_to_index8_12( TT_CMapTable* cmap,
673 TT_CMap8_12* cmap8_12;
674 TT_CMapGroup *group, *limit;
677 cmap8_12 = &cmap->c.cmap8_12;
678 limit = cmap8_12->groups + cmap8_12->nGroups;
680 /* first, check against the last used group */
682 group = cmap8_12->last_group;
684 /* the following is equivalent to performing two tests, as in */
686 /* if ( charCode >= group->startCharCode && */
687 /* charCode <= group->endCharCode ) */
689 /* This is a bit strange, but it is faster, and the idea behind the */
690 /* cache is to significantly speed up charcode to glyph index */
693 if ( (FT_ULong)( charCode - group->startCharCode ) <
694 (FT_ULong)( group->endCharCode - group->startCharCode ) )
697 for ( group = cmap8_12->groups; group < limit; group++ )
699 /* the ranges are sorted in increasing order. If we are out of */
700 /* the range here, the char code isn't in the charmap, so exit. */
702 if ( charCode > group->endCharCode )
705 if ( charCode >= group->startCharCode )
711 cmap8_12->last_group = group;
714 return group->startGlyphID + (FT_UInt)( charCode - group->startCharCode );
718 /*************************************************************************/
721 /* code_to_index10 */
724 /* Converts the (possibly 32bit) character code into a glyph index. */
725 /* Uses format 10. */
728 /* charCode :: The wanted character code. */
729 /* cmap10 :: A pointer to a cmap table in format 10. */
732 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
734 FT_CALLBACK_DEF( FT_UInt )
735 code_to_index10( TT_CMapTable* cmap,
742 cmap10 = &cmap->c.cmap10;
743 charCode -= cmap10->startCharCode;
745 /* the overflow trick for comparison works here also since the number */
746 /* of glyphs (even if numChars is specified as ULong in the specs) in */
747 /* an OpenType font is limited to 64k */
749 if ( charCode < cmap10->numChars )
750 result = cmap10->glyphs[charCode];