blob: f15963ead136fc629176b82515d8036eeed855da [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
3/* ttcmap.c */
4/* */
5/* TrueType character mapping table (cmap) support (body). */
6/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00007/* Copyright 1996-2000 by */
David Turnerd2b1f351999-12-16 23:11:37 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000010/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000012/* 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. */
15/* */
16/***************************************************************************/
17
18
David Turnerefce08d2000-05-11 18:23:52 +000019#include <freetype/internal/ftdebug.h>
20#include <freetype/internal/tterrors.h>
David Turnerd2b1f351999-12-16 23:11:37 +000021
22#include <ttload.h>
23#include <ttcmap.h>
David Turnerd2b1f351999-12-16 23:11:37 +000024
Werner Lemberg4e6dd852000-06-05 05:26:15 +000025
26 /*************************************************************************/
27 /* */
28 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
29 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
30 /* messages during execution. */
31 /* */
David Turnerd2b1f351999-12-16 23:11:37 +000032#undef FT_COMPONENT
Werner Lemberg4e6dd852000-06-05 05:26:15 +000033#define FT_COMPONENT trace_ttcmap
David Turnerd2b1f351999-12-16 23:11:37 +000034
35
David Turnerf9b8dec2000-06-16 19:34:52 +000036 static FT_UInt code_to_index0( TT_CMapTable* charmap,
37 FT_ULong char_code );
38 static FT_UInt code_to_index2( TT_CMapTable* charmap,
39 FT_ULong char_code );
40 static FT_UInt code_to_index4( TT_CMapTable* charmap,
41 FT_ULong char_code );
42 static FT_UInt code_to_index6( TT_CMapTable* charmap,
43 FT_ULong char_code );
Werner Lemberg4e6dd852000-06-05 05:26:15 +000044
David Turnerd2b1f351999-12-16 23:11:37 +000045
46 /*************************************************************************/
47 /* */
48 /* <Function> */
49 /* TT_CharMap_Load */
50 /* */
51 /* <Description> */
52 /* Loads a given TrueType character map into memory. */
53 /* */
54 /* <Input> */
55 /* face :: A handle to the parent face object. */
56 /* stream :: A handle to the current stream object. */
57 /* */
58 /* <InOut> */
59 /* table :: A pointer to a cmap object. */
60 /* */
61 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +000062 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +000063 /* */
64 /* <Note> */
65 /* The function assumes that the stream is already in use (i.e., */
66 /* opened). In case of error, all partially allocated tables are */
67 /* released. */
68 /* */
69 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +000070 FT_Error TT_CharMap_Load( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +000071 TT_CMapTable* cmap,
72 FT_Stream stream )
73 {
David Turnerf9b8dec2000-06-16 19:34:52 +000074 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +000075 FT_Memory memory;
David Turnerf9b8dec2000-06-16 19:34:52 +000076 FT_UShort num_SH, num_Seg, i;
David Turnerd2b1f351999-12-16 23:11:37 +000077
David Turnerf9b8dec2000-06-16 19:34:52 +000078 FT_UShort u, l;
David Turnerd2b1f351999-12-16 23:11:37 +000079
80 TT_CMap0* cmap0;
81 TT_CMap2* cmap2;
82 TT_CMap4* cmap4;
83 TT_CMap6* cmap6;
84
Werner Lembergbd5ae402000-07-05 04:32:02 +000085 TT_CMap2SubHeader* cmap2sub;
86 TT_CMap4Segment* segments;
David Turnerd2b1f351999-12-16 23:11:37 +000087
88
89 if ( cmap->loaded )
90 return TT_Err_Ok;
91
92 memory = stream->memory;
93
94 if ( FILE_Seek( cmap->offset ) )
95 return error;
96
97 switch ( cmap->format )
98 {
99 case 0:
100 cmap0 = &cmap->c.cmap0;
101
102 if ( ALLOC( cmap0->glyphIdArray, 256L ) ||
Werner Lembergbd5ae402000-07-05 04:32:02 +0000103 FILE_Read( cmap0->glyphIdArray, 256L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000104 goto Fail;
105
106 cmap->get_index = code_to_index0;
107 break;
108
109 case 2:
110 num_SH = 0;
111 cmap2 = &cmap->c.cmap2;
112
113 /* allocate subheader keys */
114
David Turnerf9b8dec2000-06-16 19:34:52 +0000115 if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000116 ACCESS_Frame( 512L ) )
117 goto Fail;
118
119 for ( i = 0; i < 256; i++ )
120 {
121 u = GET_UShort() / 8;
122 cmap2->subHeaderKeys[i] = u;
123
124 if ( num_SH < u )
125 num_SH = u;
126 }
127
128 FORGET_Frame();
129
130 /* load subheaders */
131
132 cmap2->numGlyphId = l =
Werner Lemberg61bd4b92000-06-07 00:00:08 +0000133 ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000134
135 if ( ALLOC_ARRAY( cmap2->subHeaders,
136 num_SH + 1,
137 TT_CMap2SubHeader ) ||
138 ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
139 goto Fail;
140
141 cmap2sub = cmap2->subHeaders;
142
143 for ( i = 0; i <= num_SH; i++ )
144 {
145 cmap2sub->firstCode = GET_UShort();
146 cmap2sub->entryCount = GET_UShort();
147 cmap2sub->idDelta = GET_Short();
148 /* we apply the location offset immediately */
149 cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
150
151 cmap2sub++;
152 }
153
154 FORGET_Frame();
155
156 /* load glyph IDs */
157
David Turnerf9b8dec2000-06-16 19:34:52 +0000158 if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000159 ACCESS_Frame( l * 2L ) )
160 goto Fail;
161
162 for ( i = 0; i < l; i++ )
163 cmap2->glyphIdArray[i] = GET_UShort();
164
165 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +0000166
David Turnerd2b1f351999-12-16 23:11:37 +0000167 cmap->get_index = code_to_index2;
168 break;
169
170 case 4:
171 cmap4 = &cmap->c.cmap4;
172
173 /* load header */
174
175 if ( ACCESS_Frame( 8L ) )
176 goto Fail;
177
178 cmap4->segCountX2 = GET_UShort();
179 cmap4->searchRange = GET_UShort();
180 cmap4->entrySelector = GET_UShort();
181 cmap4->rangeShift = GET_UShort();
182
183 num_Seg = cmap4->segCountX2 / 2;
184
185 FORGET_Frame();
186
187 /* load segments */
188
189 if ( ALLOC_ARRAY( cmap4->segments,
190 num_Seg,
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000191 TT_CMap4Segment ) ||
192 ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000193 goto Fail;
194
195 segments = cmap4->segments;
196
197 for ( i = 0; i < num_Seg; i++ )
198 segments[i].endCount = GET_UShort();
199
200 (void)GET_UShort();
201
202 for ( i = 0; i < num_Seg; i++ )
203 segments[i].startCount = GET_UShort();
204
205 for ( i = 0; i < num_Seg; i++ )
206 segments[i].idDelta = GET_Short();
207
208 for ( i = 0; i < num_Seg; i++ )
209 segments[i].idRangeOffset = GET_UShort();
210
211 FORGET_Frame();
212
213 cmap4->numGlyphId = l =
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000214 ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000215
216 /* load IDs */
217
David Turnerf9b8dec2000-06-16 19:34:52 +0000218 if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000219 ACCESS_Frame( l * 2L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000220 goto Fail;
221
222 for ( i = 0; i < l; i++ )
223 cmap4->glyphIdArray[i] = GET_UShort();
224
225 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +0000226
David Turnerd2b1f351999-12-16 23:11:37 +0000227 cmap->get_index = code_to_index4;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000228
David Turner2e421312000-05-26 22:13:17 +0000229 cmap4->last_segment = cmap4->segments;
David Turnerd2b1f351999-12-16 23:11:37 +0000230 break;
231
232 case 6:
233 cmap6 = &cmap->c.cmap6;
234
235 if ( ACCESS_Frame( 4L ) )
236 goto Fail;
237
238 cmap6->firstCode = GET_UShort();
239 cmap6->entryCount = GET_UShort();
240
241 FORGET_Frame();
242
243 l = cmap6->entryCount;
244
245 if ( ALLOC_ARRAY( cmap6->glyphIdArray,
246 cmap6->entryCount,
David Turnerf9b8dec2000-06-16 19:34:52 +0000247 FT_Short ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000248 ACCESS_Frame( l * 2L ) )
249 goto Fail;
250
251 for ( i = 0; i < l; i++ )
252 cmap6->glyphIdArray[i] = GET_UShort();
253
254 FORGET_Frame();
255 cmap->get_index = code_to_index6;
256 break;
257
258 default: /* corrupt character mapping table */
259 return TT_Err_Invalid_CharMap_Format;
260
261 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000262
David Turnerd2b1f351999-12-16 23:11:37 +0000263 return TT_Err_Ok;
264
265 Fail:
266 TT_CharMap_Free( face, cmap );
267 return error;
268 }
269
270
271 /*************************************************************************/
272 /* */
273 /* <Function> */
274 /* TT_CharMap_Free */
275 /* */
276 /* <Description> */
277 /* Destroys a character mapping table. */
278 /* */
279 /* <Input> */
280 /* face :: A handle to the parent face object. */
281 /* cmap :: A handle to a cmap object. */
282 /* */
283 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000284 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000285 /* */
286 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +0000287 FT_Error TT_CharMap_Free( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +0000288 TT_CMapTable* cmap )
289 {
290 FT_Memory memory;
291
292
293 if ( !cmap )
294 return TT_Err_Ok;
295
David Turnerf0df85b2000-06-22 00:17:42 +0000296 memory = face->root.driver->root.memory;
David Turnerd2b1f351999-12-16 23:11:37 +0000297
298 switch ( cmap->format )
299 {
300 case 0:
301 FREE( cmap->c.cmap0.glyphIdArray );
302 break;
303
304 case 2:
305 FREE( cmap->c.cmap2.subHeaderKeys );
306 FREE( cmap->c.cmap2.subHeaders );
307 FREE( cmap->c.cmap2.glyphIdArray );
308 break;
309
310 case 4:
311 FREE( cmap->c.cmap4.segments );
312 FREE( cmap->c.cmap4.glyphIdArray );
313 cmap->c.cmap4.segCountX2 = 0;
314 break;
315
316 case 6:
317 FREE( cmap->c.cmap6.glyphIdArray );
318 cmap->c.cmap6.entryCount = 0;
319 break;
320
321 default:
322 /* invalid table format, do nothing */
323 ;
324 }
325
326 cmap->loaded = FALSE;
327 return TT_Err_Ok;
328 }
329
330
David Turnerd2b1f351999-12-16 23:11:37 +0000331 /*************************************************************************/
332 /* */
333 /* <Function> */
334 /* code_to_index0 */
335 /* */
336 /* <Description> */
337 /* Converts the character code into a glyph index. Uses format 0. */
338 /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */
339 /* returned). */
340 /* */
341 /* <Input> */
342 /* charCode :: The wanted character code. */
343 /* cmap0 :: A pointer to a cmap table in format 0. */
344 /* */
345 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000346 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
David Turnerd2b1f351999-12-16 23:11:37 +0000347 /* */
348 static
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000349 FT_UInt code_to_index0( TT_CMapTable* cmap,
350 FT_ULong charCode )
David Turnerd2b1f351999-12-16 23:11:37 +0000351 {
352 TT_CMap0* cmap0 = &cmap->c.cmap0;
David Turnere49ab252000-05-16 23:44:38 +0000353
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000354
David Turnerd2b1f351999-12-16 23:11:37 +0000355 return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
356 }
357
358
359 /*************************************************************************/
360 /* */
361 /* <Function> */
362 /* code_to_index2 */
363 /* */
364 /* <Description> */
365 /* Converts the character code into a glyph index. Uses format 2. */
366 /* */
367 /* <Input> */
368 /* charCode :: The wanted character code. */
369 /* cmap2 :: A pointer to a cmap table in format 2. */
370 /* */
371 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000372 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
David Turnerd2b1f351999-12-16 23:11:37 +0000373 /* */
374 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000375 FT_UInt code_to_index2( TT_CMapTable* cmap,
376 FT_ULong charCode )
David Turnerd2b1f351999-12-16 23:11:37 +0000377 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000378 FT_UInt result, index1, offset;
379 FT_UInt char_lo;
380 FT_ULong char_hi;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000381 TT_CMap2SubHeader* sh2;
382 TT_CMap2* cmap2;
383
David Turnerd2b1f351999-12-16 23:11:37 +0000384
385 cmap2 = &cmap->c.cmap2;
386 result = 0;
David Turnerf9b8dec2000-06-16 19:34:52 +0000387 char_lo = (FT_UInt)( charCode & 0xFF );
David Turnerd2b1f351999-12-16 23:11:37 +0000388 char_hi = charCode >> 8;
389
390 if ( char_hi == 0 )
391 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000392 /* an 8-bit character code -- we use the subHeader 0 in this case */
393 /* to test whether the character code is in the charmap */
David Turnerd2b1f351999-12-16 23:11:37 +0000394 if ( cmap2->subHeaderKeys[char_lo] == 0 )
David Turnerd2b1f351999-12-16 23:11:37 +0000395 result = cmap2->glyphIdArray[char_lo];
David Turnerd2b1f351999-12-16 23:11:37 +0000396 }
397 else
398 {
399 /* a 16-bit character code */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000400 index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
401 if ( index1 )
David Turnerd2b1f351999-12-16 23:11:37 +0000402 {
403 sh2 = cmap2->subHeaders + index1;
404 char_lo -= sh2->firstCode;
405
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000406 if ( char_lo < sh2->entryCount )
David Turnerd2b1f351999-12-16 23:11:37 +0000407 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000408 offset = sh2->idRangeOffset / 2 + char_lo;
409 if ( offset < cmap2->numGlyphId )
David Turnerd2b1f351999-12-16 23:11:37 +0000410 {
411 result = cmap2->glyphIdArray[offset];
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000412 if ( result )
413 result = ( result + sh2->idDelta ) & 0xFFFF;
David Turnerd2b1f351999-12-16 23:11:37 +0000414 }
415 }
416 }
417 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000418
David Turnerd2b1f351999-12-16 23:11:37 +0000419 return result;
420 }
421
422
423 /*************************************************************************/
424 /* */
425 /* <Function> */
426 /* code_to_index4 */
427 /* */
428 /* <Description> */
429 /* Converts the character code into a glyph index. Uses format 4. */
430 /* */
431 /* <Input> */
432 /* charCode :: The wanted character code. */
433 /* cmap4 :: A pointer to a cmap table in format 4. */
434 /* */
435 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000436 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
David Turnerd2b1f351999-12-16 23:11:37 +0000437 /* */
438 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000439 FT_UInt code_to_index4( TT_CMapTable* cmap,
440 FT_ULong charCode )
David Turnerd2b1f351999-12-16 23:11:37 +0000441 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000442 FT_UInt result, index1, segCount;
David Turnerd2b1f351999-12-16 23:11:37 +0000443 TT_CMap4* cmap4;
444 TT_CMap4Segment *seg4, *limit;
445
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000446
David Turnerd2b1f351999-12-16 23:11:37 +0000447 cmap4 = &cmap->c.cmap4;
448 result = 0;
449 segCount = cmap4->segCountX2 / 2;
450 seg4 = cmap4->segments;
451 limit = seg4 + segCount;
452
David Turner2e421312000-05-26 22:13:17 +0000453 /* check against the last segment */
454 seg4 = cmap4->last_segment;
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000455
Werner Lemberge35cac62000-06-11 03:46:57 +0000456 /* the following is equivalent to performing two tests, as in */
457 /* */
458 /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
459 /* */
460 /* Yes, that's a bit strange, but it's faster, and the idea behind */
461 /* the cache is to significantly speed up charcode to glyph index */
462 /* conversion. */
463
David Turnerf9b8dec2000-06-16 19:34:52 +0000464 if ( (FT_ULong)(charCode - seg4->startCount) <
465 (FT_ULong)(seg4->endCount - seg4->startCount) )
David Turner2e421312000-05-26 22:13:17 +0000466 goto Found;
467
David Turnerb770a4a2000-06-07 20:06:18 +0000468 for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000469 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000470 /* the ranges are sorted in increasing order. If we are out of */
471 /* the range here, the char code isn't in the charmap, so exit. */
Werner Lemberge35cac62000-06-11 03:46:57 +0000472
David Turner2e421312000-05-26 22:13:17 +0000473 if ( charCode > seg4->endCount )
David Turnerb1677a82000-05-29 20:37:41 +0000474 continue;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000475
David Turner2e421312000-05-26 22:13:17 +0000476 if ( charCode >= seg4->startCount )
477 goto Found;
478 }
479 return 0;
480
Werner Lemberg920d41e2000-06-05 14:32:32 +0000481 Found:
David Turner2e421312000-05-26 22:13:17 +0000482 cmap4->last_segment = seg4;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000483
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000484 /* if the idRangeOffset is 0, we can compute the glyph index */
485 /* directly */
Werner Lemberg920d41e2000-06-05 14:32:32 +0000486
David Turner2e421312000-05-26 22:13:17 +0000487 if ( seg4->idRangeOffset == 0 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000488 result = ( charCode + seg4->idDelta ) & 0xFFFF;
David Turner2e421312000-05-26 22:13:17 +0000489 else
David Turner2e421312000-05-26 22:13:17 +0000490 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000491 /* otherwise, we must use the glyphIdArray to do it */
492 index1 = seg4->idRangeOffset / 2
493 + ( charCode - seg4->startCount )
David Turnerb770a4a2000-06-07 20:06:18 +0000494 + ( seg4 - cmap4->segments )
David Turner2e421312000-05-26 22:13:17 +0000495 - segCount;
496
497 if ( index1 < cmap4->numGlyphId &&
498 cmap4->glyphIdArray[index1] != 0 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000499 result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF;
David Turnerd2b1f351999-12-16 23:11:37 +0000500 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000501
David Turnerd2b1f351999-12-16 23:11:37 +0000502 return result;
503 }
504
505
506 /*************************************************************************/
507 /* */
508 /* <Function> */
509 /* code_to_index6 */
510 /* */
511 /* <Description> */
512 /* Converts the character code into a glyph index. Uses format 6. */
513 /* */
514 /* <Input> */
515 /* charCode :: The wanted character code. */
516 /* cmap6 :: A pointer to a cmap table in format 6. */
517 /* */
518 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000519 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
David Turnerd2b1f351999-12-16 23:11:37 +0000520 /* */
521 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000522 FT_UInt code_to_index6( TT_CMapTable* cmap,
523 FT_ULong charCode )
David Turnerd2b1f351999-12-16 23:11:37 +0000524 {
525 TT_CMap6* cmap6;
David Turnerf9b8dec2000-06-16 19:34:52 +0000526 FT_UInt result = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000527
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000528
David Turnerd2b1f351999-12-16 23:11:37 +0000529 cmap6 = &cmap->c.cmap6;
530 result = 0;
531 charCode -= cmap6->firstCode;
532
533 if ( charCode < cmap6->entryCount )
534 result = cmap6->glyphIdArray[charCode];
535
536 return result;
537 }
538
539
540/* END */