misc fixes to get rrdtool working without included libraries.
[rrdtool.git] / libraries / freetype-2.0.5 / ttcmap.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttcmap.c                                                               */
4 /*                                                                         */
5 /*    TrueType character mapping table (cmap) support (body).              */
6 /*                                                                         */
7 /*  Copyright 1996-2001 by                                                 */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
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.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include "ttload.h"
22 #include "ttcmap.h"
23
24 #include "sferrors.h"
25
26
27   /*************************************************************************/
28   /*                                                                       */
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.                                            */
32   /*                                                                       */
33 #undef  FT_COMPONENT
34 #define FT_COMPONENT  trace_ttcmap
35
36
37   FT_CALLBACK_DEF( FT_UInt )
38   code_to_index0( TT_CMapTable*  charmap,
39                   FT_ULong       char_code );
40
41   FT_CALLBACK_DEF( FT_UInt )
42   code_to_index2( TT_CMapTable*  charmap,
43                   FT_ULong       char_code );
44
45   FT_CALLBACK_DEF( FT_UInt )
46   code_to_index4( TT_CMapTable*  charmap,
47                   FT_ULong       char_code );
48
49   FT_CALLBACK_DEF( FT_UInt )
50   code_to_index6( TT_CMapTable*  charmap,
51                   FT_ULong       char_code );
52
53   FT_CALLBACK_DEF( FT_UInt )
54   code_to_index8_12( TT_CMapTable*  charmap,
55                      FT_ULong       char_code );
56
57   FT_CALLBACK_DEF( FT_UInt )
58   code_to_index10( TT_CMapTable*  charmap,
59                    FT_ULong       char_code );
60
61
62   /*************************************************************************/
63   /*                                                                       */
64   /* <Function>                                                            */
65   /*    TT_CharMap_Load                                                    */
66   /*                                                                       */
67   /* <Description>                                                         */
68   /*    Loads a given TrueType character map into memory.                  */
69   /*                                                                       */
70   /* <Input>                                                               */
71   /*    face   :: A handle to the parent face object.                      */
72   /*    stream :: A handle to the current stream object.                   */
73   /*                                                                       */
74   /* <InOut>                                                               */
75   /*    table  :: A pointer to a cmap object.                              */
76   /*                                                                       */
77   /* <Return>                                                              */
78   /*    FreeType error code.  0 means success.                             */
79   /*                                                                       */
80   /* <Note>                                                                */
81   /*    The function assumes that the stream is already in use (i.e.,      */
82   /*    opened).  In case of error, all partially allocated tables are     */
83   /*    released.                                                          */
84   /*                                                                       */
85   FT_LOCAL_DEF FT_Error
86   TT_CharMap_Load( TT_Face        face,
87                    TT_CMapTable*  cmap,
88                    FT_Stream      stream )
89   {
90     FT_Error      error;
91     FT_Memory     memory;
92     FT_UShort     num_SH, num_Seg, i;
93     FT_ULong      j, n;
94
95     FT_UShort     u, l;
96
97     TT_CMap0*     cmap0;
98     TT_CMap2*     cmap2;
99     TT_CMap4*     cmap4;
100     TT_CMap6*     cmap6;
101     TT_CMap8_12*  cmap8_12;
102     TT_CMap10*    cmap10;
103
104     TT_CMap2SubHeader*  cmap2sub;
105     TT_CMap4Segment*    segments;
106     TT_CMapGroup*       groups;
107
108
109     if ( cmap->loaded )
110       return SFNT_Err_Ok;
111
112     memory = stream->memory;
113
114     if ( FILE_Seek( cmap->offset ) )
115       return error;
116
117     switch ( cmap->format )
118     {
119     case 0:
120       cmap0 = &cmap->c.cmap0;
121
122       if ( READ_UShort( cmap0->language )         ||
123            ALLOC( cmap0->glyphIdArray, 256L )     ||
124            FILE_Read( cmap0->glyphIdArray, 256L ) )
125         goto Fail;
126
127       cmap->get_index = code_to_index0;
128       break;
129
130     case 2:
131       num_SH = 0;
132       cmap2  = &cmap->c.cmap2;
133
134       /* allocate subheader keys */
135
136       if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
137            ACCESS_Frame( 2L + 512L )                           )
138         goto Fail;
139
140       cmap2->language = GET_UShort();
141
142       for ( i = 0; i < 256; i++ )
143       {
144         u = (FT_UShort)( GET_UShort() / 8 );
145         cmap2->subHeaderKeys[i] = u;
146
147         if ( num_SH < u )
148           num_SH = u;
149       }
150
151       FORGET_Frame();
152
153       /* load subheaders */
154
155       cmap2->numGlyphId = l = (FT_UShort)(
156         ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2 );
157
158       if ( ALLOC_ARRAY( cmap2->subHeaders,
159                         num_SH + 1,
160                         TT_CMap2SubHeader )    ||
161            ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
162       {
163         FREE( cmap2->subHeaderKeys );
164         goto Fail;
165       }
166
167       cmap2sub = cmap2->subHeaders;
168
169       for ( i = 0; i <= num_SH; i++ )
170       {
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 );
177
178         cmap2sub++;
179       }
180
181       FORGET_Frame();
182
183       /* load glyph IDs */
184
185       if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
186            ACCESS_Frame( l * 2L )                           )
187       {
188         FREE( cmap2->subHeaders );
189         FREE( cmap2->subHeaderKeys );
190         goto Fail;
191       }
192
193       for ( i = 0; i < l; i++ )
194         cmap2->glyphIdArray[i] = GET_UShort();
195
196       FORGET_Frame();
197
198       cmap->get_index = code_to_index2;
199       break;
200
201     case 4:
202       cmap4 = &cmap->c.cmap4;
203
204       /* load header */
205
206       if ( ACCESS_Frame( 10L ) )
207         goto Fail;
208
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();
214
215       num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
216
217       FORGET_Frame();
218
219       /* load segments */
220
221       if ( ALLOC_ARRAY( cmap4->segments,
222                         num_Seg,
223                         TT_CMap4Segment )           ||
224            ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
225         goto Fail;
226
227       segments = cmap4->segments;
228
229       for ( i = 0; i < num_Seg; i++ )
230         segments[i].endCount      = GET_UShort();
231
232       (void)GET_UShort();
233
234       for ( i = 0; i < num_Seg; i++ )
235         segments[i].startCount    = GET_UShort();
236
237       for ( i = 0; i < num_Seg; i++ )
238         segments[i].idDelta       = GET_Short();
239
240       for ( i = 0; i < num_Seg; i++ )
241         segments[i].idRangeOffset = GET_UShort();
242
243       FORGET_Frame();
244
245       cmap4->numGlyphId = l = (FT_UShort)(
246         ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2 );
247
248       /* load IDs */
249
250       if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
251            ACCESS_Frame( l * 2L )                           )
252       {
253         FREE( cmap4->segments );
254         goto Fail;
255       }
256
257       for ( i = 0; i < l; i++ )
258         cmap4->glyphIdArray[i] = GET_UShort();
259
260       FORGET_Frame();
261
262       cmap4->last_segment = cmap4->segments;
263
264       cmap->get_index = code_to_index4;
265       break;
266
267     case 6:
268       cmap6 = &cmap->c.cmap6;
269
270       if ( ACCESS_Frame( 6L ) )
271         goto Fail;
272
273       cmap6->language   = GET_UShort();
274       cmap6->firstCode  = GET_UShort();
275       cmap6->entryCount = GET_UShort();
276
277       FORGET_Frame();
278
279       l = cmap6->entryCount;
280
281       if ( ALLOC_ARRAY( cmap6->glyphIdArray, l, FT_Short ) ||
282            ACCESS_Frame( l * 2L )                          )
283         goto Fail;
284
285       for ( i = 0; i < l; i++ )
286         cmap6->glyphIdArray[i] = GET_UShort();
287
288       FORGET_Frame();
289       cmap->get_index = code_to_index6;
290       break;
291
292     case 8:
293     case 12:
294       cmap8_12 = &cmap->c.cmap8_12;
295
296       if ( ACCESS_Frame( 8L ) )
297         goto Fail;
298
299       cmap->length       = GET_ULong();
300       cmap8_12->language = GET_ULong();
301
302       FORGET_Frame();
303
304       if ( cmap->format == 8 )
305         if ( FILE_Skip( 8192L ) )
306           goto Fail;
307
308       if ( READ_ULong( cmap8_12->nGroups ) )
309         goto Fail;
310
311       n = cmap8_12->nGroups;
312
313       if ( ALLOC_ARRAY( cmap8_12->groups, n, TT_CMapGroup ) ||
314            ACCESS_Frame( n * 3 * 4L )                       )
315         goto Fail;
316
317       groups = cmap8_12->groups;
318
319       for ( j = 0; j < n; j++ )
320       {
321         groups[j].startCharCode = GET_ULong();
322         groups[j].endCharCode   = GET_ULong();
323         groups[j].startGlyphID  = GET_ULong();
324       }
325
326       FORGET_Frame();
327
328       cmap8_12->last_group = cmap8_12->groups;
329
330       cmap->get_index = code_to_index8_12;
331       break;
332
333     case 10:
334       cmap10 = &cmap->c.cmap10;
335
336       if ( ACCESS_Frame( 16L ) )
337         goto Fail;
338
339       cmap->length          = GET_ULong();
340       cmap10->language      = GET_ULong();
341       cmap10->startCharCode = GET_ULong();
342       cmap10->numChars      = GET_ULong();
343
344       FORGET_Frame();
345
346       n = cmap10->numChars;
347
348       if ( ALLOC_ARRAY( cmap10->glyphs, n, FT_Short ) ||
349            ACCESS_Frame( n * 2L )                     )
350         goto Fail;
351
352       for ( j = 0; j < n; j++ )
353         cmap10->glyphs[j] = GET_UShort();
354
355       FORGET_Frame();
356       cmap->get_index = code_to_index10;
357       break;
358
359     default:   /* corrupt character mapping table */
360       return SFNT_Err_Invalid_CharMap_Format;
361
362     }
363
364     return SFNT_Err_Ok;
365
366   Fail:
367     TT_CharMap_Free( face, cmap );
368     return error;
369   }
370
371
372   /*************************************************************************/
373   /*                                                                       */
374   /* <Function>                                                            */
375   /*    TT_CharMap_Free                                                    */
376   /*                                                                       */
377   /* <Description>                                                         */
378   /*    Destroys a character mapping table.                                */
379   /*                                                                       */
380   /* <Input>                                                               */
381   /*    face :: A handle to the parent face object.                        */
382   /*    cmap :: A handle to a cmap object.                                 */
383   /*                                                                       */
384   /* <Return>                                                              */
385   /*    FreeType error code.  0 means success.                             */
386   /*                                                                       */
387   FT_LOCAL_DEF FT_Error
388   TT_CharMap_Free( TT_Face        face,
389                    TT_CMapTable*  cmap )
390   {
391     FT_Memory  memory;
392
393
394     if ( !cmap )
395       return SFNT_Err_Ok;
396
397     memory = face->root.driver->root.memory;
398
399     switch ( cmap->format )
400     {
401     case 0:
402       FREE( cmap->c.cmap0.glyphIdArray );
403       break;
404
405     case 2:
406       FREE( cmap->c.cmap2.subHeaderKeys );
407       FREE( cmap->c.cmap2.subHeaders );
408       FREE( cmap->c.cmap2.glyphIdArray );
409       break;
410
411     case 4:
412       FREE( cmap->c.cmap4.segments );
413       FREE( cmap->c.cmap4.glyphIdArray );
414       cmap->c.cmap4.segCountX2 = 0;
415       break;
416
417     case 6:
418       FREE( cmap->c.cmap6.glyphIdArray );
419       cmap->c.cmap6.entryCount = 0;
420       break;
421
422     case 8:
423     case 12:
424       FREE( cmap->c.cmap8_12.groups );
425       cmap->c.cmap8_12.nGroups = 0;
426       break;
427
428     case 10:
429       FREE( cmap->c.cmap10.glyphs );
430       cmap->c.cmap10.numChars = 0;
431       break;
432
433     default:
434       /* invalid table format, do nothing */
435       ;
436     }
437
438     cmap->loaded = FALSE;
439     return SFNT_Err_Ok;
440   }
441
442
443   /*************************************************************************/
444   /*                                                                       */
445   /* <Function>                                                            */
446   /*    code_to_index0                                                     */
447   /*                                                                       */
448   /* <Description>                                                         */
449   /*    Converts the character code into a glyph index.  Uses format 0.    */
450   /*    `charCode' must be in the range 0x00-0xFF (otherwise 0 is          */
451   /*    returned).                                                         */
452   /*                                                                       */
453   /* <Input>                                                               */
454   /*    charCode :: The wanted character code.                             */
455   /*    cmap0    :: A pointer to a cmap table in format 0.                 */
456   /*                                                                       */
457   /* <Return>                                                              */
458   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
459   /*                                                                       */
460   FT_CALLBACK_DEF( FT_UInt )
461   code_to_index0( TT_CMapTable*  cmap,
462                   FT_ULong       charCode )
463   {
464     TT_CMap0*  cmap0 = &cmap->c.cmap0;
465
466
467     return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
468   }
469
470
471   /*************************************************************************/
472   /*                                                                       */
473   /* <Function>                                                            */
474   /*    code_to_index2                                                     */
475   /*                                                                       */
476   /* <Description>                                                         */
477   /*    Converts the character code into a glyph index.  Uses format 2.    */
478   /*                                                                       */
479   /* <Input>                                                               */
480   /*    charCode :: The wanted character code.                             */
481   /*    cmap2    :: A pointer to a cmap table in format 2.                 */
482   /*                                                                       */
483   /* <Return>                                                              */
484   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
485   /*                                                                       */
486   FT_CALLBACK_DEF( FT_UInt )
487   code_to_index2( TT_CMapTable*  cmap,
488                   FT_ULong       charCode )
489   {
490     FT_UInt             result, index1, offset;
491     FT_UInt             char_lo;
492     FT_ULong            char_hi;
493     TT_CMap2SubHeader*  sh2;
494     TT_CMap2*           cmap2;
495
496
497     cmap2   = &cmap->c.cmap2;
498     result  = 0;
499     char_lo = (FT_UInt)( charCode & 0xFF );
500     char_hi = charCode >> 8;
501
502     if ( char_hi == 0 )
503     {
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];
507       if ( index1 != 0 )
508         return 0;
509     }
510     else
511     {
512       /* a 16-bit character code */
513       index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
514       if ( index1 == 0 )
515         return 0;
516     }
517
518     sh2      = cmap2->subHeaders + index1;
519     char_lo -= sh2->firstCode;
520
521     if ( char_lo < (FT_UInt)sh2->entryCount )
522     {
523       offset = sh2->idRangeOffset / 2 + char_lo;
524       if ( offset < (FT_UInt)cmap2->numGlyphId )
525       {
526         result = cmap2->glyphIdArray[offset];
527         if ( result )
528           result = ( result + sh2->idDelta ) & 0xFFFF;
529       }
530     }
531
532     return result;
533   }
534
535
536   /*************************************************************************/
537   /*                                                                       */
538   /* <Function>                                                            */
539   /*    code_to_index4                                                     */
540   /*                                                                       */
541   /* <Description>                                                         */
542   /*    Converts the character code into a glyph index.  Uses format 4.    */
543   /*                                                                       */
544   /* <Input>                                                               */
545   /*    charCode :: The wanted character code.                             */
546   /*    cmap4    :: A pointer to a cmap table in format 4.                 */
547   /*                                                                       */
548   /* <Return>                                                              */
549   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
550   /*                                                                       */
551   FT_CALLBACK_DEF( FT_UInt )
552   code_to_index4( TT_CMapTable*  cmap,
553                   FT_ULong       charCode )
554   {
555     FT_UInt          result, index1, segCount;
556     TT_CMap4*        cmap4;
557     TT_CMap4Segment  *seg4, *limit;
558
559
560     cmap4    = &cmap->c.cmap4;
561     result   = 0;
562     segCount = cmap4->segCountX2 / 2;
563     limit    = cmap4->segments + segCount;
564
565     /* first, check against the last used segment */
566
567     seg4 = cmap4->last_segment;
568
569     /* the following is equivalent to performing two tests, as in         */
570     /*                                                                    */
571     /*  if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
572     /*                                                                    */
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         */
575     /* conversion.                                                        */
576
577     if ( (FT_ULong)( charCode       - seg4->startCount ) <
578          (FT_ULong)( seg4->endCount - seg4->startCount ) )
579       goto Found1;
580
581     for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
582     {
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. */
585
586       if ( charCode > (FT_UInt)seg4->endCount )
587         continue;
588
589       if ( charCode >= (FT_UInt)seg4->startCount )
590         goto Found;
591     }
592     return 0;
593
594   Found:
595     cmap4->last_segment = seg4;
596
597   Found1:
598     /* if the idRangeOffset is 0, we can compute the glyph index */
599     /* directly                                                  */
600
601     if ( seg4->idRangeOffset == 0 )
602       result = ( charCode + seg4->idDelta ) & 0xFFFF;
603     else
604     {
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 )
609                           - segCount );
610
611       if ( index1 < (FT_UInt)cmap4->numGlyphId &&
612            cmap4->glyphIdArray[index1] != 0    )
613         result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF;
614     }
615
616     return result;
617   }
618
619
620   /*************************************************************************/
621   /*                                                                       */
622   /* <Function>                                                            */
623   /*    code_to_index6                                                     */
624   /*                                                                       */
625   /* <Description>                                                         */
626   /*    Converts the character code into a glyph index.  Uses format 6.    */
627   /*                                                                       */
628   /* <Input>                                                               */
629   /*    charCode :: The wanted character code.                             */
630   /*    cmap6    :: A pointer to a cmap table in format 6.                 */
631   /*                                                                       */
632   /* <Return>                                                              */
633   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
634   /*                                                                       */
635   FT_CALLBACK_DEF( FT_UInt )
636   code_to_index6( TT_CMapTable*  cmap,
637                   FT_ULong       charCode )
638   {
639     TT_CMap6*  cmap6;
640     FT_UInt    result = 0;
641
642
643     cmap6     = &cmap->c.cmap6;
644     charCode -= cmap6->firstCode;
645
646     if ( charCode < (FT_UInt)cmap6->entryCount )
647       result = cmap6->glyphIdArray[charCode];
648
649     return result;
650   }
651
652
653   /*************************************************************************/
654   /*                                                                       */
655   /* <Function>                                                            */
656   /*    code_to_index8_12                                                  */
657   /*                                                                       */
658   /* <Description>                                                         */
659   /*    Converts the (possibly 32bit) character code into a glyph index.   */
660   /*    Uses format 8 or 12.                                               */
661   /*                                                                       */
662   /* <Input>                                                               */
663   /*    charCode :: The wanted character code.                             */
664   /*    cmap8_12 :: A pointer to a cmap table in format 8 or 12.           */
665   /*                                                                       */
666   /* <Return>                                                              */
667   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
668   /*                                                                       */
669   FT_CALLBACK_DEF( FT_UInt )
670   code_to_index8_12( TT_CMapTable*  cmap,
671                      FT_ULong       charCode )
672   {
673     TT_CMap8_12*  cmap8_12;
674     TT_CMapGroup  *group, *limit;
675
676
677     cmap8_12 = &cmap->c.cmap8_12;
678     limit    = cmap8_12->groups + cmap8_12->nGroups;
679
680     /* first, check against the last used group */
681
682     group = cmap8_12->last_group;
683
684     /* the following is equivalent to performing two tests, as in       */
685     /*                                                                  */
686     /*  if ( charCode >= group->startCharCode &&                        */
687     /*       charCode <= group->endCharCode   )                         */
688     /*                                                                  */
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       */
691     /* conversion.                                                      */
692
693     if ( (FT_ULong)( charCode           - group->startCharCode ) <
694          (FT_ULong)( group->endCharCode - group->startCharCode ) )
695       goto Found1;
696
697     for ( group = cmap8_12->groups; group < limit; group++ )
698     {
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. */
701
702       if ( charCode > group->endCharCode )
703         continue;
704
705       if ( charCode >= group->startCharCode )
706         goto Found;
707     }
708     return 0;
709
710   Found:
711     cmap8_12->last_group = group;
712
713   Found1:
714     return group->startGlyphID + (FT_UInt)( charCode - group->startCharCode );
715   }
716
717
718   /*************************************************************************/
719   /*                                                                       */
720   /* <Function>                                                            */
721   /*    code_to_index10                                                    */
722   /*                                                                       */
723   /* <Description>                                                         */
724   /*    Converts the (possibly 32bit) character code into a glyph index.   */
725   /*    Uses format 10.                                                    */
726   /*                                                                       */
727   /* <Input>                                                               */
728   /*    charCode :: The wanted character code.                             */
729   /*    cmap10   :: A pointer to a cmap table in format 10.                */
730   /*                                                                       */
731   /* <Return>                                                              */
732   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
733   /*                                                                       */
734   FT_CALLBACK_DEF( FT_UInt )
735   code_to_index10( TT_CMapTable*  cmap,
736                    FT_ULong       charCode )
737   {
738     TT_CMap10*  cmap10;
739     FT_UInt     result = 0;
740
741
742     cmap10    = &cmap->c.cmap10;
743     charCode -= cmap10->startCharCode;
744
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                                 */
748
749     if ( charCode < cmap10->numChars )
750       result = cmap10->glyphs[charCode];
751
752     return result;
753   }
754
755
756 /* END */