update for HEAD-2003050101
[reactos.git] / lib / freetype / src / sfnt / ttcmap.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttcmap.c                                                               */
4 /*                                                                         */
5 /*    TrueType character mapping table (cmap) support (body).              */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002 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_ULong )
42   code_to_next0( TT_CMapTable  charmap,
43                  FT_ULong      char_code );
44
45   FT_CALLBACK_DEF( FT_UInt )
46   code_to_index2( TT_CMapTable  charmap,
47                   FT_ULong      char_code );
48
49   FT_CALLBACK_DEF( FT_ULong )
50   code_to_next2( TT_CMapTable  charmap,
51                  FT_ULong      char_code );
52
53   FT_CALLBACK_DEF( FT_UInt )
54   code_to_index4( TT_CMapTable  charmap,
55                   FT_ULong      char_code );
56
57   FT_CALLBACK_DEF( FT_ULong )
58   code_to_next4( TT_CMapTable  charmap,
59                  FT_ULong      char_code );
60
61   FT_CALLBACK_DEF( FT_UInt )
62   code_to_index6( TT_CMapTable  charmap,
63                   FT_ULong      char_code );
64
65   FT_CALLBACK_DEF( FT_ULong )
66   code_to_next6( TT_CMapTable  charmap,
67                  FT_ULong      char_code );
68
69   FT_CALLBACK_DEF( FT_UInt )
70   code_to_index8_12( TT_CMapTable  charmap,
71                      FT_ULong      char_code );
72
73   FT_CALLBACK_DEF( FT_ULong )
74   code_to_next8_12( TT_CMapTable  charmap,
75                     FT_ULong      char_code );
76
77   FT_CALLBACK_DEF( FT_UInt )
78   code_to_index10( TT_CMapTable  charmap,
79                    FT_ULong      char_code );
80
81   FT_CALLBACK_DEF( FT_ULong )
82   code_to_next10( TT_CMapTable  charmap,
83                   FT_ULong      char_code );
84
85
86   /*************************************************************************/
87   /*                                                                       */
88   /* <Function>                                                            */
89   /*    tt_face_load_charmap                                               */
90   /*                                                                       */
91   /* <Description>                                                         */
92   /*    Loads a given TrueType character map into memory.                  */
93   /*                                                                       */
94   /* <Input>                                                               */
95   /*    face   :: A handle to the parent face object.                      */
96   /*                                                                       */
97   /*    stream :: A handle to the current stream object.                   */
98   /*                                                                       */
99   /* <InOut>                                                               */
100   /*    table  :: A pointer to a cmap object.                              */
101   /*                                                                       */
102   /* <Return>                                                              */
103   /*    FreeType error code.  0 means success.                             */
104   /*                                                                       */
105   /* <Note>                                                                */
106   /*    The function assumes that the stream is already in use (i.e.,      */
107   /*    opened).  In case of error, all partially allocated tables are     */
108   /*    released.                                                          */
109   /*                                                                       */
110   FT_LOCAL_DEF( FT_Error )
111   tt_face_load_charmap( TT_Face       face,
112                         TT_CMapTable  cmap,
113                         FT_Stream     stream )
114   {
115     FT_Error     error;
116     FT_Memory    memory;
117     FT_UShort    num_SH, num_Seg, i;
118     FT_ULong     j, n;
119
120     FT_UShort    u, l;
121
122     TT_CMap0     cmap0;
123     TT_CMap2     cmap2;
124     TT_CMap4     cmap4;
125     TT_CMap6     cmap6;
126     TT_CMap8_12  cmap8_12;
127     TT_CMap10    cmap10;
128
129     TT_CMap2SubHeader  cmap2sub;
130     TT_CMap4Segment    segments;
131     TT_CMapGroup       groups;
132
133
134     if ( cmap->loaded )
135       return SFNT_Err_Ok;
136
137     memory = stream->memory;
138
139     if ( FT_STREAM_SEEK( cmap->offset ) )
140       return error;
141
142     switch ( cmap->format )
143     {
144     case 0:
145       cmap0 = &cmap->c.cmap0;
146
147       if ( FT_READ_USHORT( cmap0->language )           ||
148            FT_ALLOC( cmap0->glyphIdArray, 256L )       ||
149            FT_STREAM_READ( cmap0->glyphIdArray, 256L ) )
150         goto Fail;
151
152       cmap->get_index     = code_to_index0;
153       cmap->get_next_char = code_to_next0;
154       break;
155
156     case 2:
157       num_SH = 0;
158       cmap2  = &cmap->c.cmap2;
159
160       /* allocate subheader keys */
161
162       if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) ||
163            FT_FRAME_ENTER( 2L + 512L )               )
164         goto Fail;
165
166       cmap2->language = FT_GET_USHORT();
167
168       for ( i = 0; i < 256; i++ )
169       {
170         u = (FT_UShort)( FT_GET_USHORT() / 8 );
171         cmap2->subHeaderKeys[i] = u;
172
173         if ( num_SH < u )
174           num_SH = u;
175       }
176
177       FT_FRAME_EXIT();
178
179       /* load subheaders */
180
181       cmap2->numGlyphId = l = (FT_UShort)(
182         ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 );
183
184       if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) ||
185            FT_FRAME_ENTER( ( num_SH + 1 ) * 8L )         )
186       {
187         FT_FREE( cmap2->subHeaderKeys );
188         goto Fail;
189       }
190
191       cmap2sub = cmap2->subHeaders;
192
193       for ( i = 0; i <= num_SH; i++ )
194       {
195         cmap2sub->firstCode     = FT_GET_USHORT();
196         cmap2sub->entryCount    = FT_GET_USHORT();
197         cmap2sub->idDelta       = FT_GET_SHORT();
198         /* we apply the location offset immediately */
199         cmap2sub->idRangeOffset = (FT_UShort)(
200           FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 );
201
202         cmap2sub++;
203       }
204
205       FT_FRAME_EXIT();
206
207       /* load glyph IDs */
208
209       if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) ||
210            FT_FRAME_ENTER( l * 2L )               )
211       {
212         FT_FREE( cmap2->subHeaders );
213         FT_FREE( cmap2->subHeaderKeys );
214         goto Fail;
215       }
216
217       for ( i = 0; i < l; i++ )
218         cmap2->glyphIdArray[i] = FT_GET_USHORT();
219
220       FT_FRAME_EXIT();
221
222       cmap->get_index = code_to_index2;
223       cmap->get_next_char = code_to_next2;
224       break;
225
226     case 4:
227       cmap4 = &cmap->c.cmap4;
228
229       /* load header */
230
231       if ( FT_FRAME_ENTER( 10L ) )
232         goto Fail;
233
234       cmap4->language      = FT_GET_USHORT();
235       cmap4->segCountX2    = FT_GET_USHORT();
236       cmap4->searchRange   = FT_GET_USHORT();
237       cmap4->entrySelector = FT_GET_USHORT();
238       cmap4->rangeShift    = FT_GET_USHORT();
239
240       num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
241
242       FT_FRAME_EXIT();
243
244       /* load segments */
245
246       if ( FT_NEW_ARRAY( cmap4->segments, num_Seg )   ||
247            FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) )
248         goto Fail;
249
250       segments = cmap4->segments;
251
252       for ( i = 0; i < num_Seg; i++ )
253         segments[i].endCount = FT_GET_USHORT();
254
255       (void)FT_GET_USHORT();
256
257       for ( i = 0; i < num_Seg; i++ )
258         segments[i].startCount = FT_GET_USHORT();
259
260       for ( i = 0; i < num_Seg; i++ )
261         segments[i].idDelta = FT_GET_SHORT();
262
263       for ( i = 0; i < num_Seg; i++ )
264         segments[i].idRangeOffset = FT_GET_USHORT();
265
266       FT_FRAME_EXIT();
267
268       cmap4->numGlyphId = l = (FT_UShort)(
269         ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 );
270
271       /* load IDs */
272
273       if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) ||
274            FT_FRAME_ENTER( l * 2L )               )
275       {
276         FT_FREE( cmap4->segments );
277         goto Fail;
278       }
279
280       for ( i = 0; i < l; i++ )
281         cmap4->glyphIdArray[i] = FT_GET_USHORT();
282
283       FT_FRAME_EXIT();
284
285       cmap4->last_segment = cmap4->segments;
286
287       cmap->get_index     = code_to_index4;
288       cmap->get_next_char = code_to_next4;
289       break;
290
291     case 6:
292       cmap6 = &cmap->c.cmap6;
293
294       if ( FT_FRAME_ENTER( 6L ) )
295         goto Fail;
296
297       cmap6->language   = FT_GET_USHORT();
298       cmap6->firstCode  = FT_GET_USHORT();
299       cmap6->entryCount = FT_GET_USHORT();
300
301       FT_FRAME_EXIT();
302
303       l = cmap6->entryCount;
304
305       if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) ||
306            FT_FRAME_ENTER( l * 2L )               )
307         goto Fail;
308
309       for ( i = 0; i < l; i++ )
310         cmap6->glyphIdArray[i] = FT_GET_USHORT();
311
312       FT_FRAME_EXIT();
313       cmap->get_index     = code_to_index6;
314       cmap->get_next_char = code_to_next6;
315       break;
316
317     case 8:
318     case 12:
319       cmap8_12 = &cmap->c.cmap8_12;
320
321       if ( FT_FRAME_ENTER( 8L ) )
322         goto Fail;
323
324       cmap->length       = FT_GET_ULONG();
325       cmap8_12->language = FT_GET_ULONG();
326
327       FT_FRAME_EXIT();
328
329       if ( cmap->format == 8 )
330         if ( FT_STREAM_SKIP( 8192L ) )
331           goto Fail;
332
333       if ( FT_READ_ULONG( cmap8_12->nGroups ) )
334         goto Fail;
335
336       n = cmap8_12->nGroups;
337
338       if ( FT_NEW_ARRAY( cmap8_12->groups, n ) ||
339            FT_FRAME_ENTER( n * 3 * 4L )        )
340         goto Fail;
341
342       groups = cmap8_12->groups;
343
344       for ( j = 0; j < n; j++ )
345       {
346         groups[j].startCharCode = FT_GET_ULONG();
347         groups[j].endCharCode   = FT_GET_ULONG();
348         groups[j].startGlyphID  = FT_GET_ULONG();
349       }
350
351       FT_FRAME_EXIT();
352
353       cmap8_12->last_group = cmap8_12->groups;
354
355       cmap->get_index     = code_to_index8_12;
356       cmap->get_next_char = code_to_next8_12;
357       break;
358
359     case 10:
360       cmap10 = &cmap->c.cmap10;
361
362       if ( FT_FRAME_ENTER( 16L ) )
363         goto Fail;
364
365       cmap->length          = FT_GET_ULONG();
366       cmap10->language      = FT_GET_ULONG();
367       cmap10->startCharCode = FT_GET_ULONG();
368       cmap10->numChars      = FT_GET_ULONG();
369
370       FT_FRAME_EXIT();
371
372       n = cmap10->numChars;
373
374       if ( FT_NEW_ARRAY( cmap10->glyphs, n ) ||
375            FT_FRAME_ENTER( n * 2L )          )
376         goto Fail;
377
378       for ( j = 0; j < n; j++ )
379         cmap10->glyphs[j] = FT_GET_USHORT();
380
381       FT_FRAME_EXIT();
382       cmap->get_index     = code_to_index10;
383       cmap->get_next_char = code_to_next10;
384       break;
385
386     default:   /* corrupt character mapping table */
387       return SFNT_Err_Invalid_CharMap_Format;
388
389     }
390
391     return SFNT_Err_Ok;
392
393   Fail:
394     tt_face_free_charmap( face, cmap );
395     return error;
396   }
397
398
399   /*************************************************************************/
400   /*                                                                       */
401   /* <Function>                                                            */
402   /*    tt_face_free_charmap                                               */
403   /*                                                                       */
404   /* <Description>                                                         */
405   /*    Destroys a character mapping table.                                */
406   /*                                                                       */
407   /* <Input>                                                               */
408   /*    face :: A handle to the parent face object.                        */
409   /*                                                                       */
410   /*    cmap :: A handle to a cmap object.                                 */
411   /*                                                                       */
412   /* <Return>                                                              */
413   /*    FreeType error code.  0 means success.                             */
414   /*                                                                       */
415   FT_LOCAL_DEF( FT_Error )
416   tt_face_free_charmap( TT_Face       face,
417                         TT_CMapTable  cmap )
418   {
419     FT_Memory  memory;
420
421
422     if ( !cmap )
423       return SFNT_Err_Ok;
424
425     memory = face->root.driver->root.memory;
426
427     switch ( cmap->format )
428     {
429     case 0:
430       FT_FREE( cmap->c.cmap0.glyphIdArray );
431       break;
432
433     case 2:
434       FT_FREE( cmap->c.cmap2.subHeaderKeys );
435       FT_FREE( cmap->c.cmap2.subHeaders );
436       FT_FREE( cmap->c.cmap2.glyphIdArray );
437       break;
438
439     case 4:
440       FT_FREE( cmap->c.cmap4.segments );
441       FT_FREE( cmap->c.cmap4.glyphIdArray );
442       cmap->c.cmap4.segCountX2 = 0;
443       break;
444
445     case 6:
446       FT_FREE( cmap->c.cmap6.glyphIdArray );
447       cmap->c.cmap6.entryCount = 0;
448       break;
449
450     case 8:
451     case 12:
452       FT_FREE( cmap->c.cmap8_12.groups );
453       cmap->c.cmap8_12.nGroups = 0;
454       break;
455
456     case 10:
457       FT_FREE( cmap->c.cmap10.glyphs );
458       cmap->c.cmap10.numChars = 0;
459       break;
460
461     default:
462       /* invalid table format, do nothing */
463       ;
464     }
465
466     cmap->loaded = FALSE;
467     return SFNT_Err_Ok;
468   }
469
470
471   /*************************************************************************/
472   /*                                                                       */
473   /* <Function>                                                            */
474   /*    code_to_index0                                                     */
475   /*                                                                       */
476   /* <Description>                                                         */
477   /*    Converts the character code into a glyph index.  Uses format 0.    */
478   /*    `charCode' must be in the range 0x00-0xFF (otherwise 0 is          */
479   /*    returned).                                                         */
480   /*                                                                       */
481   /* <Input>                                                               */
482   /*    charCode :: The wanted character code.                             */
483   /*                                                                       */
484   /*    cmap0    :: A pointer to a cmap table in format 0.                 */
485   /*                                                                       */
486   /* <Return>                                                              */
487   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
488   /*                                                                       */
489   FT_CALLBACK_DEF( FT_UInt )
490   code_to_index0( TT_CMapTable  cmap,
491                   FT_ULong      charCode )
492   {
493     TT_CMap0  cmap0 = &cmap->c.cmap0;
494
495
496     return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
497   }
498
499
500   /*************************************************************************/
501   /*                                                                       */
502   /* <Function>                                                            */
503   /*    code_to_next0                                                      */
504   /*                                                                       */
505   /* <Description>                                                         */
506   /*    Finds the next encoded character after the given one.  Uses        */
507   /*    format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0   */
508   /*    is returned).                                                      */
509   /*                                                                       */
510   /* <Input>                                                               */
511   /*    charCode :: The wanted character code.                             */
512   /*                                                                       */
513   /*    cmap0    :: A pointer to a cmap table in format 0.                 */
514   /*                                                                       */
515   /* <Return>                                                              */
516   /*    Next char code.  0 if no higher one is encoded.                    */
517   /*                                                                       */
518   FT_CALLBACK_DEF( FT_ULong )
519   code_to_next0( TT_CMapTable  cmap,
520                  FT_ULong      charCode )
521   {
522     TT_CMap0  cmap0 = &cmap->c.cmap0;
523
524
525     while ( ++charCode <= 0xFF )
526       if ( cmap0->glyphIdArray[charCode] )
527         return ( charCode );
528     return ( 0 );
529   }
530
531
532   /*************************************************************************/
533   /*                                                                       */
534   /* <Function>                                                            */
535   /*    code_to_index2                                                     */
536   /*                                                                       */
537   /* <Description>                                                         */
538   /*    Converts the character code into a glyph index.  Uses format 2.    */
539   /*                                                                       */
540   /* <Input>                                                               */
541   /*    charCode :: The wanted character code.                             */
542   /*                                                                       */
543   /*    cmap2    :: A pointer to a cmap table in format 2.                 */
544   /*                                                                       */
545   /* <Return>                                                              */
546   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
547   /*                                                                       */
548   FT_CALLBACK_DEF( FT_UInt )
549   code_to_index2( TT_CMapTable  cmap,
550                   FT_ULong      charCode )
551   {
552     FT_UInt            result, index1, offset;
553     FT_UInt            char_lo;
554     FT_ULong           char_hi;
555     TT_CMap2SubHeader  sh2;
556     TT_CMap2           cmap2;
557
558
559     cmap2   = &cmap->c.cmap2;
560     result  = 0;
561     char_lo = (FT_UInt)( charCode & 0xFF );
562     char_hi = charCode >> 8;
563
564     if ( char_hi == 0 )
565     {
566       /* an 8-bit character code -- we use the subHeader 0 in this case */
567       /* to test whether the character code is in the charmap           */
568       index1 = cmap2->subHeaderKeys[char_lo];
569       if ( index1 != 0 )
570         return 0;
571     }
572     else
573     {
574       /* a 16-bit character code */
575       index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
576       if ( index1 == 0 )
577         return 0;
578     }
579
580     sh2      = cmap2->subHeaders + index1;
581     char_lo -= sh2->firstCode;
582
583     if ( char_lo < (FT_UInt)sh2->entryCount )
584     {
585       offset = sh2->idRangeOffset / 2 + char_lo;
586       if ( offset < (FT_UInt)cmap2->numGlyphId )
587       {
588         result = cmap2->glyphIdArray[offset];
589         if ( result )
590           result = ( result + sh2->idDelta ) & 0xFFFFU;
591       }
592     }
593
594     return result;
595   }
596
597
598   /*************************************************************************/
599   /*                                                                       */
600   /* <Function>                                                            */
601   /*    code_to_next2                                                      */
602   /*                                                                       */
603   /* <Description>                                                         */
604   /*    Find the next encoded character.  Uses format 2.                   */
605   /*                                                                       */
606   /* <Input>                                                               */
607   /*    charCode :: The wanted character code.                             */
608   /*                                                                       */
609   /*    cmap2    :: A pointer to a cmap table in format 2.                 */
610   /*                                                                       */
611   /* <Return>                                                              */
612   /*    Next encoded character.  0 if none exists.                         */
613   /*                                                                       */
614   FT_CALLBACK_DEF( FT_ULong )
615   code_to_next2( TT_CMapTable  cmap,
616                  FT_ULong      charCode )
617   {
618     FT_UInt            index1, offset;
619     FT_UInt            char_lo;
620     FT_ULong           char_hi;
621     TT_CMap2SubHeader  sh2;
622     TT_CMap2           cmap2;
623
624
625     cmap2 = &cmap->c.cmap2;
626     charCode++;
627
628     /*
629      * This is relatively simplistic -- look for a subHeader containing
630      * glyphs and then walk to the first glyph in that subHeader.
631      */
632     while ( charCode < 0x10000L )
633     {
634       char_lo = (FT_UInt)( charCode & 0xFF );
635       char_hi = charCode >> 8;
636
637       if ( char_hi == 0 )
638       {
639         /* an 8-bit character code -- we use the subHeader 0 in this case */
640         /* to test whether the character code is in the charmap           */
641         index1 = cmap2->subHeaderKeys[char_lo];
642         if ( index1 != 0 )
643         {
644           charCode++;
645           continue;
646         }
647       }
648       else
649       {
650         /* a 16-bit character code */
651         index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
652         if ( index1 == 0 )
653         {
654           charCode = ( char_hi + 1 ) << 8;
655           continue;
656         }
657       }
658
659       sh2      = cmap2->subHeaders + index1;
660       char_lo -= sh2->firstCode;
661
662       if ( char_lo > (FT_UInt)sh2->entryCount )
663       {
664         charCode = ( char_hi + 1 ) << 8;
665         continue;
666       }
667
668       offset = sh2->idRangeOffset / 2 + char_lo;
669       if ( offset >= (FT_UInt)cmap2->numGlyphId ||
670            cmap2->glyphIdArray[offset] == 0     )
671       {
672         charCode++;
673         continue;
674       }
675
676       return charCode;
677     }
678     return 0;
679   }
680
681
682   /*************************************************************************/
683   /*                                                                       */
684   /* <Function>                                                            */
685   /*    code_to_index4                                                     */
686   /*                                                                       */
687   /* <Description>                                                         */
688   /*    Converts the character code into a glyph index.  Uses format 4.    */
689   /*                                                                       */
690   /* <Input>                                                               */
691   /*    charCode :: The wanted character code.                             */
692   /*                                                                       */
693   /*    cmap4    :: A pointer to a cmap table in format 4.                 */
694   /*                                                                       */
695   /* <Return>                                                              */
696   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
697   /*                                                                       */
698   FT_CALLBACK_DEF( FT_UInt )
699   code_to_index4( TT_CMapTable  cmap,
700                   FT_ULong      charCode )
701   {
702     FT_UInt             result, index1, segCount;
703     TT_CMap4            cmap4;
704     TT_CMap4SegmentRec  *seg4, *limit;
705
706
707     cmap4    = &cmap->c.cmap4;
708     result   = 0;
709     segCount = cmap4->segCountX2 / 2;
710     limit    = cmap4->segments + segCount;
711
712     /* first, check against the last used segment */
713
714     seg4 = cmap4->last_segment;
715
716     /* the following is equivalent to performing two tests, as in         */
717     /*                                                                    */
718     /*  if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
719     /*                                                                    */
720     /* This is a bit strange, but it is faster, and the idea behind the   */
721     /* cache is to significantly speed up charcode to glyph index         */
722     /* conversion.                                                        */
723
724     if ( (FT_ULong)( charCode       - seg4->startCount ) <
725          (FT_ULong)( seg4->endCount - seg4->startCount ) )
726       goto Found1;
727
728     for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
729     {
730       /* the ranges are sorted in increasing order.  If we are out of */
731       /* the range here, the char code isn't in the charmap, so exit. */
732
733       if ( charCode > (FT_UInt)seg4->endCount )
734         continue;
735
736       if ( charCode >= (FT_UInt)seg4->startCount )
737         goto Found;
738     }
739     return 0;
740
741   Found:
742     cmap4->last_segment = seg4;
743
744   Found1:
745     /* if the idRangeOffset is 0, we can compute the glyph index */
746     /* directly                                                  */
747
748     if ( seg4->idRangeOffset == 0 )
749       result = (FT_UInt)( charCode + seg4->idDelta ) & 0xFFFFU;
750     else
751     {
752       /* otherwise, we must use the glyphIdArray to do it */
753       index1 = (FT_UInt)( seg4->idRangeOffset / 2
754                           + ( charCode - seg4->startCount )
755                           + ( seg4 - cmap4->segments )
756                           - segCount );
757
758       if ( index1 < (FT_UInt)cmap4->numGlyphId &&
759            cmap4->glyphIdArray[index1] != 0    )
760         result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFFU;
761     }
762
763     return result;
764   }
765
766
767   /*************************************************************************/
768   /*                                                                       */
769   /* <Function>                                                            */
770   /*    code_to_next4                                                      */
771   /*                                                                       */
772   /* <Description>                                                         */
773   /*    Find the next encoded character.  Uses format 4.                   */
774   /*                                                                       */
775   /* <Input>                                                               */
776   /*    charCode :: The wanted character code.                             */
777   /*                                                                       */
778   /*    cmap     :: A pointer to a cmap table in format 4.                 */
779   /*                                                                       */
780   /* <Return>                                                              */
781   /*    Next encoded character.  0 if none exists.                         */
782   /*                                                                       */
783   FT_CALLBACK_DEF( FT_ULong )
784   code_to_next4( TT_CMapTable  cmap,
785                  FT_ULong      charCode )
786   {
787     FT_UInt             index1, segCount;
788     TT_CMap4            cmap4;
789     TT_CMap4SegmentRec  *seg4, *limit;
790
791
792     cmap4    = &cmap->c.cmap4;
793     segCount = cmap4->segCountX2 / 2;
794     limit    = cmap4->segments + segCount;
795
796     charCode++;
797
798     for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
799     {
800       /* The ranges are sorted in increasing order.  If we are out of */
801       /* the range here, the char code isn't in the charmap, so exit. */
802
803       if ( charCode <= (FT_UInt)seg4->endCount )
804         goto Found;
805     }
806     return 0;
807
808   Found:
809     if ( charCode < (FT_ULong) seg4->startCount )
810       charCode = seg4->startCount;
811
812     /* if the idRangeOffset is 0, all chars in the map exist */
813
814     if ( seg4->idRangeOffset == 0 )
815       return ( charCode );
816
817     while ( charCode <= (FT_UInt) seg4->endCount )
818     {
819       /* otherwise, we must use the glyphIdArray to do it */
820       index1 = (FT_UInt)( seg4->idRangeOffset / 2
821                           + ( charCode - seg4->startCount )
822                           + ( seg4 - cmap4->segments )
823                           - segCount );
824
825       if ( index1 < (FT_UInt)cmap4->numGlyphId &&
826            cmap4->glyphIdArray[index1] != 0    )
827         return ( charCode );
828       charCode++;
829     }
830
831     return 0;
832   }
833
834
835   /*************************************************************************/
836   /*                                                                       */
837   /* <Function>                                                            */
838   /*    code_to_index6                                                     */
839   /*                                                                       */
840   /* <Description>                                                         */
841   /*    Converts the character code into a glyph index.  Uses format 6.    */
842   /*                                                                       */
843   /* <Input>                                                               */
844   /*    charCode :: The wanted character code.                             */
845   /*                                                                       */
846   /*    cmap6    :: A pointer to a cmap table in format 6.                 */
847   /*                                                                       */
848   /* <Return>                                                              */
849   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
850   /*                                                                       */
851   FT_CALLBACK_DEF( FT_UInt )
852   code_to_index6( TT_CMapTable  cmap,
853                   FT_ULong      charCode )
854   {
855     TT_CMap6  cmap6;
856     FT_UInt   result = 0;
857
858
859     cmap6     = &cmap->c.cmap6;
860     charCode -= cmap6->firstCode;
861
862     if ( charCode < (FT_UInt)cmap6->entryCount )
863       result = cmap6->glyphIdArray[charCode];
864
865     return result;
866   }
867
868
869   /*************************************************************************/
870   /*                                                                       */
871   /* <Function>                                                            */
872   /*    code_to_next6                                                      */
873   /*                                                                       */
874   /* <Description>                                                         */
875   /*    Find the next encoded character.  Uses format 6.                   */
876   /*                                                                       */
877   /* <Input>                                                               */
878   /*    charCode :: The wanted character code.                             */
879   /*                                                                       */
880   /*    cmap     :: A pointer to a cmap table in format 6.                 */
881   /*                                                                       */
882   /* <Return>                                                              */
883   /*    Next encoded character.  0 if none exists.                         */
884   /*                                                                       */
885   FT_CALLBACK_DEF( FT_ULong )
886   code_to_next6( TT_CMapTable  cmap,
887                  FT_ULong      charCode )
888   {
889     TT_CMap6  cmap6;
890
891
892     charCode++;
893
894     cmap6 = &cmap->c.cmap6;
895
896     if ( charCode < (FT_ULong) cmap6->firstCode )
897       charCode = cmap6->firstCode;
898
899     charCode -= cmap6->firstCode;
900
901     while ( charCode < (FT_UInt)cmap6->entryCount )
902     {
903       if ( cmap6->glyphIdArray[charCode] != 0 )
904         return charCode + cmap6->firstCode;
905       charCode++;
906     }
907
908     return 0;
909   }
910
911
912   /*************************************************************************/
913   /*                                                                       */
914   /* <Function>                                                            */
915   /*    code_to_index8_12                                                  */
916   /*                                                                       */
917   /* <Description>                                                         */
918   /*    Converts the (possibly 32bit) character code into a glyph index.   */
919   /*    Uses format 8 or 12.                                               */
920   /*                                                                       */
921   /* <Input>                                                               */
922   /*    charCode :: The wanted character code.                             */
923   /*                                                                       */
924   /*    cmap8_12 :: A pointer to a cmap table in format 8 or 12.           */
925   /*                                                                       */
926   /* <Return>                                                              */
927   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
928   /*                                                                       */
929   FT_CALLBACK_DEF( FT_UInt )
930   code_to_index8_12( TT_CMapTable  cmap,
931                      FT_ULong      charCode )
932   {
933     TT_CMap8_12      cmap8_12;
934     TT_CMapGroupRec  *group, *limit;
935
936
937     cmap8_12 = &cmap->c.cmap8_12;
938     limit    = cmap8_12->groups + cmap8_12->nGroups;
939
940     /* first, check against the last used group */
941
942     group = cmap8_12->last_group;
943
944     /* the following is equivalent to performing two tests, as in       */
945     /*                                                                  */
946     /*  if ( charCode >= group->startCharCode &&                        */
947     /*       charCode <= group->endCharCode   )                         */
948     /*                                                                  */
949     /* This is a bit strange, but it is faster, and the idea behind the */
950     /* cache is to significantly speed up charcode to glyph index       */
951     /* conversion.                                                      */
952
953     if ( (FT_ULong)( charCode           - group->startCharCode ) <
954          (FT_ULong)( group->endCharCode - group->startCharCode ) )
955       goto Found1;
956
957     for ( group = cmap8_12->groups; group < limit; group++ )
958     {
959       /* the ranges are sorted in increasing order.  If we are out of */
960       /* the range here, the char code isn't in the charmap, so exit. */
961
962       if ( charCode > group->endCharCode )
963         continue;
964
965       if ( charCode >= group->startCharCode )
966         goto Found;
967     }
968     return 0;
969
970   Found:
971     cmap8_12->last_group = group;
972
973   Found1:
974     return (FT_UInt)( group->startGlyphID +
975                       ( charCode - group->startCharCode ) );
976   }
977
978
979   /*************************************************************************/
980   /*                                                                       */
981   /* <Function>                                                            */
982   /*    code_to_next8_12                                                   */
983   /*                                                                       */
984   /* <Description>                                                         */
985   /*    Find the next encoded character.  Uses format 8 or 12.             */
986   /*                                                                       */
987   /* <Input>                                                               */
988   /*    charCode :: The wanted character code.                             */
989   /*                                                                       */
990   /*    cmap     :: A pointer to a cmap table in format 8 or 12.           */
991   /*                                                                       */
992   /* <Return>                                                              */
993   /*    Next encoded character.  0 if none exists.                         */
994   /*                                                                       */
995   FT_CALLBACK_DEF( FT_ULong )
996   code_to_next8_12( TT_CMapTable  cmap,
997                     FT_ULong      charCode )
998   {
999     TT_CMap8_12      cmap8_12;
1000     TT_CMapGroupRec  *group, *limit;
1001
1002
1003     charCode++;
1004     cmap8_12 = &cmap->c.cmap8_12;
1005     limit    = cmap8_12->groups + cmap8_12->nGroups;
1006
1007     for ( group = cmap8_12->groups; group < limit; group++ )
1008     {
1009       /* the ranges are sorted in increasing order.  If we are out of */
1010       /* the range here, the char code isn't in the charmap, so exit. */
1011
1012       if ( charCode <= group->endCharCode )
1013         goto Found;
1014     }
1015     return 0;
1016
1017   Found:
1018     if ( charCode < group->startCharCode )
1019       charCode = group->startCharCode;
1020
1021     return charCode;
1022   }
1023
1024
1025   /*************************************************************************/
1026   /*                                                                       */
1027   /* <Function>                                                            */
1028   /*    code_to_index10                                                    */
1029   /*                                                                       */
1030   /* <Description>                                                         */
1031   /*    Converts the (possibly 32bit) character code into a glyph index.   */
1032   /*    Uses format 10.                                                    */
1033   /*                                                                       */
1034   /* <Input>                                                               */
1035   /*    charCode :: The wanted character code.                             */
1036   /*                                                                       */
1037   /*    cmap10   :: A pointer to a cmap table in format 10.                */
1038   /*                                                                       */
1039   /* <Return>                                                              */
1040   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
1041   /*                                                                       */
1042   FT_CALLBACK_DEF( FT_UInt )
1043   code_to_index10( TT_CMapTable  cmap,
1044                    FT_ULong      charCode )
1045   {
1046     TT_CMap10  cmap10;
1047     FT_UInt    result = 0;
1048
1049
1050     cmap10    = &cmap->c.cmap10;
1051     charCode -= cmap10->startCharCode;
1052
1053     /* the overflow trick for comparison works here also since the number */
1054     /* of glyphs (even if numChars is specified as ULong in the specs) in */
1055     /* an OpenType font is limited to 64k                                 */
1056
1057     if ( charCode < cmap10->numChars )
1058       result = cmap10->glyphs[charCode];
1059
1060     return result;
1061   }
1062
1063
1064   /*************************************************************************/
1065   /*                                                                       */
1066   /* <Function>                                                            */
1067   /*    code_to_next10                                                     */
1068   /*                                                                       */
1069   /* <Description>                                                         */
1070   /*    Find the next encoded character.  Uses format 10.                  */
1071   /*                                                                       */
1072   /* <Input>                                                               */
1073   /*    charCode :: The wanted character code.                             */
1074   /*                                                                       */
1075   /*    cmap     :: A pointer to a cmap table in format 10.                */
1076   /*                                                                       */
1077   /* <Return>                                                              */
1078   /*    Next encoded character.  0 if none exists.                         */
1079   /*                                                                       */
1080   FT_CALLBACK_DEF( FT_ULong )
1081   code_to_next10( TT_CMapTable  cmap,
1082                   FT_ULong      charCode )
1083   {
1084     TT_CMap10  cmap10;
1085
1086
1087     charCode++;
1088     cmap10 = &cmap->c.cmap10;
1089
1090     if ( charCode < cmap10->startCharCode )
1091       charCode = cmap10->startCharCode;
1092
1093     charCode -= cmap10->startCharCode;
1094
1095     /* the overflow trick for comparison works here also since the number */
1096     /* of glyphs (even if numChars is specified as ULong in the specs) in */
1097     /* an OpenType font is limited to 64k                                 */
1098
1099     while ( charCode < cmap10->numChars )
1100     {
1101       if ( cmap10->glyphs[charCode] )
1102         return ( charCode + cmap10->startCharCode );
1103       charCode++;
1104     }
1105
1106     return 0;
1107   }
1108
1109
1110 /* END */