This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / subsys / win32k / freetype / src / sfnt / ttcmap.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttcmap.c                                                               */
4 /*                                                                         */
5 /*    TrueType character mapping table (cmap) support (body).              */
6 /*                                                                         */
7 /*  Copyright 1996-2000 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 <freetype/internal/ftdebug.h>
20 #include <freetype/internal/tterrors.h>
21
22
23 #ifdef FT_FLAT_COMPILE
24
25 #include "ttload.h"
26 #include "ttcmap.h"
27
28 #else
29
30 #include <freetype/src/sfnt/ttload.h>
31 #include <freetype/src/sfnt/ttcmap.h>
32
33 #endif
34
35
36   /*************************************************************************/
37   /*                                                                       */
38   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
39   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
40   /* messages during execution.                                            */
41   /*                                                                       */
42 #undef  FT_COMPONENT
43 #define FT_COMPONENT  trace_ttcmap
44
45
46   static FT_UInt  code_to_index0( TT_CMapTable*  charmap,
47                                   FT_ULong       char_code );
48   static FT_UInt  code_to_index2( TT_CMapTable*  charmap,
49                                   FT_ULong       char_code );
50   static FT_UInt  code_to_index4( TT_CMapTable*  charmap,
51                                   FT_ULong       char_code );
52   static FT_UInt  code_to_index6( TT_CMapTable*  charmap,
53                                   FT_ULong       char_code );
54
55
56   /*************************************************************************/
57   /*                                                                       */
58   /* <Function>                                                            */
59   /*    TT_CharMap_Load                                                    */
60   /*                                                                       */
61   /* <Description>                                                         */
62   /*    Loads a given TrueType character map into memory.                  */
63   /*                                                                       */
64   /* <Input>                                                               */
65   /*    face   :: A handle to the parent face object.                      */
66   /*    stream :: A handle to the current stream object.                   */
67   /*                                                                       */
68   /* <InOut>                                                               */
69   /*    table  :: A pointer to a cmap object.                              */
70   /*                                                                       */
71   /* <Return>                                                              */
72   /*    FreeType error code.  0 means success.                             */
73   /*                                                                       */
74   /* <Note>                                                                */
75   /*    The function assumes that the stream is already in use (i.e.,      */
76   /*    opened).  In case of error, all partially allocated tables are     */
77   /*    released.                                                          */
78   /*                                                                       */
79   LOCAL_FUNC
80   FT_Error  TT_CharMap_Load( TT_Face        face,
81                              TT_CMapTable*  cmap,
82                              FT_Stream      stream )
83   {
84     FT_Error   error;
85     FT_Memory  memory;
86     FT_UShort  num_SH, num_Seg, i;
87
88     FT_UShort  u, l;
89
90     TT_CMap0*  cmap0;
91     TT_CMap2*  cmap2;
92     TT_CMap4*  cmap4;
93     TT_CMap6*  cmap6;
94
95     TT_CMap2SubHeader*  cmap2sub;
96     TT_CMap4Segment*    segments;
97
98
99     if ( cmap->loaded )
100       return TT_Err_Ok;
101
102     memory = stream->memory;
103
104     if ( FILE_Seek( cmap->offset ) )
105       return error;
106
107     switch ( cmap->format )
108     {
109     case 0:
110       cmap0 = &cmap->c.cmap0;
111
112       if ( ALLOC( cmap0->glyphIdArray, 256L )            ||
113            FILE_Read( cmap0->glyphIdArray, 256L ) )
114          goto Fail;
115
116       cmap->get_index = code_to_index0;
117       break;
118
119     case 2:
120       num_SH = 0;
121       cmap2  = &cmap->c.cmap2;
122
123       /* allocate subheader keys */
124
125       if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
126            ACCESS_Frame( 512L )                                )
127         goto Fail;
128
129       for ( i = 0; i < 256; i++ )
130       {
131         u = GET_UShort() / 8;
132         cmap2->subHeaderKeys[i] = u;
133
134         if ( num_SH < u )
135           num_SH = u;
136       }
137
138       FORGET_Frame();
139
140       /* load subheaders */
141
142       cmap2->numGlyphId = l =
143         ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2;
144
145       if ( ALLOC_ARRAY( cmap2->subHeaders,
146                         num_SH + 1,
147                         TT_CMap2SubHeader )    ||
148            ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
149         goto Fail;
150
151       cmap2sub = cmap2->subHeaders;
152
153       for ( i = 0; i <= num_SH; i++ )
154       {
155         cmap2sub->firstCode     = GET_UShort();
156         cmap2sub->entryCount    = GET_UShort();
157         cmap2sub->idDelta       = GET_Short();
158         /* we apply the location offset immediately */
159         cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
160
161         cmap2sub++;
162       }
163
164       FORGET_Frame();
165
166       /* load glyph IDs */
167
168       if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
169            ACCESS_Frame( l * 2L )                           )
170         goto Fail;
171
172       for ( i = 0; i < l; i++ )
173         cmap2->glyphIdArray[i] = GET_UShort();
174
175       FORGET_Frame();
176
177       cmap->get_index = code_to_index2;
178       break;
179
180     case 4:
181       cmap4 = &cmap->c.cmap4;
182
183       /* load header */
184
185       if ( ACCESS_Frame( 8L ) )
186         goto Fail;
187
188       cmap4->segCountX2    = GET_UShort();
189       cmap4->searchRange   = GET_UShort();
190       cmap4->entrySelector = GET_UShort();
191       cmap4->rangeShift    = GET_UShort();
192
193       num_Seg = cmap4->segCountX2 / 2;
194
195       FORGET_Frame();
196
197       /* load segments */
198
199       if ( ALLOC_ARRAY( cmap4->segments,
200                         num_Seg,
201                         TT_CMap4Segment )           ||
202            ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
203         goto Fail;
204
205       segments = cmap4->segments;
206
207       for ( i = 0; i < num_Seg; i++ )
208         segments[i].endCount      = GET_UShort();
209
210       (void)GET_UShort();
211
212       for ( i = 0; i < num_Seg; i++ )
213         segments[i].startCount    = GET_UShort();
214
215       for ( i = 0; i < num_Seg; i++ )
216         segments[i].idDelta       = GET_Short();
217
218       for ( i = 0; i < num_Seg; i++ )
219         segments[i].idRangeOffset = GET_UShort();
220
221       FORGET_Frame();
222
223       cmap4->numGlyphId = l =
224         ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2;
225
226       /* load IDs */
227
228       if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
229            ACCESS_Frame( l * 2L )                           )
230         goto Fail;
231
232       for ( i = 0; i < l; i++ )
233         cmap4->glyphIdArray[i] = GET_UShort();
234
235       FORGET_Frame();
236
237       cmap->get_index = code_to_index4;
238
239       cmap4->last_segment = cmap4->segments;
240       break;
241
242     case 6:
243       cmap6 = &cmap->c.cmap6;
244
245       if ( ACCESS_Frame( 4L ) )
246         goto Fail;
247
248       cmap6->firstCode  = GET_UShort();
249       cmap6->entryCount = GET_UShort();
250
251       FORGET_Frame();
252
253       l = cmap6->entryCount;
254
255       if ( ALLOC_ARRAY( cmap6->glyphIdArray,
256                         cmap6->entryCount,
257                         FT_Short )           ||
258            ACCESS_Frame( l * 2L )            )
259         goto Fail;
260
261       for ( i = 0; i < l; i++ )
262         cmap6->glyphIdArray[i] = GET_UShort();
263
264       FORGET_Frame();
265       cmap->get_index = code_to_index6;
266       break;
267
268     default:   /* corrupt character mapping table */
269       return TT_Err_Invalid_CharMap_Format;
270
271     }
272
273     return TT_Err_Ok;
274
275   Fail:
276     TT_CharMap_Free( face, cmap );
277     return error;
278   }
279
280
281   /*************************************************************************/
282   /*                                                                       */
283   /* <Function>                                                            */
284   /*    TT_CharMap_Free                                                    */
285   /*                                                                       */
286   /* <Description>                                                         */
287   /*    Destroys a character mapping table.                                */
288   /*                                                                       */
289   /* <Input>                                                               */
290   /*    face :: A handle to the parent face object.                        */
291   /*    cmap :: A handle to a cmap object.                                 */
292   /*                                                                       */
293   /* <Return>                                                              */
294   /*    FreeType error code.  0 means success.                             */
295   /*                                                                       */
296   LOCAL_FUNC
297   FT_Error  TT_CharMap_Free( TT_Face        face,
298                              TT_CMapTable*  cmap )
299   {
300     FT_Memory  memory;
301
302
303     if ( !cmap )
304       return TT_Err_Ok;
305
306     memory = face->root.driver->root.memory;
307
308     switch ( cmap->format )
309     {
310     case 0:
311       FREE( cmap->c.cmap0.glyphIdArray );
312       break;
313
314     case 2:
315       FREE( cmap->c.cmap2.subHeaderKeys );
316       FREE( cmap->c.cmap2.subHeaders );
317       FREE( cmap->c.cmap2.glyphIdArray );
318       break;
319
320     case 4:
321       FREE( cmap->c.cmap4.segments );
322       FREE( cmap->c.cmap4.glyphIdArray );
323       cmap->c.cmap4.segCountX2 = 0;
324       break;
325
326     case 6:
327       FREE( cmap->c.cmap6.glyphIdArray );
328       cmap->c.cmap6.entryCount = 0;
329       break;
330
331     default:
332       /* invalid table format, do nothing */
333       ;
334     }
335
336     cmap->loaded = FALSE;
337     return TT_Err_Ok;
338   }
339
340
341   /*************************************************************************/
342   /*                                                                       */
343   /* <Function>                                                            */
344   /*    code_to_index0                                                     */
345   /*                                                                       */
346   /* <Description>                                                         */
347   /*    Converts the character code into a glyph index.  Uses format 0.    */
348   /*    `charCode' must be in the range 0x00-0xFF (otherwise 0 is          */
349   /*    returned).                                                         */
350   /*                                                                       */
351   /* <Input>                                                               */
352   /*    charCode :: The wanted character code.                             */
353   /*    cmap0    :: A pointer to a cmap table in format 0.                 */
354   /*                                                                       */
355   /* <Return>                                                              */
356   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
357   /*                                                                       */
358   static
359   FT_UInt  code_to_index0( TT_CMapTable*  cmap,
360                            FT_ULong       charCode )
361   {
362     TT_CMap0*  cmap0 = &cmap->c.cmap0;
363
364
365     return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
366   }
367
368
369   /*************************************************************************/
370   /*                                                                       */
371   /* <Function>                                                            */
372   /*    code_to_index2                                                     */
373   /*                                                                       */
374   /* <Description>                                                         */
375   /*    Converts the character code into a glyph index.  Uses format 2.    */
376   /*                                                                       */
377   /* <Input>                                                               */
378   /*    charCode :: The wanted character code.                             */
379   /*    cmap2    :: A pointer to a cmap table in format 2.                 */
380   /*                                                                       */
381   /* <Return>                                                              */
382   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
383   /*                                                                       */
384   static
385   FT_UInt  code_to_index2( TT_CMapTable*  cmap,
386                            FT_ULong       charCode )
387   {
388     FT_UInt             result, index1, offset;
389     FT_UInt             char_lo;
390     FT_ULong            char_hi;
391     TT_CMap2SubHeader*  sh2;
392     TT_CMap2*           cmap2;
393
394
395     cmap2   = &cmap->c.cmap2;
396     result  = 0;
397     char_lo = (FT_UInt)( charCode & 0xFF );
398     char_hi = charCode >> 8;
399
400     if ( char_hi == 0 )
401     {
402       /* an 8-bit character code -- we use the subHeader 0 in this case */
403       /* to test whether the character code is in the charmap           */
404       if ( cmap2->subHeaderKeys[char_lo] == 0 )
405         result = cmap2->glyphIdArray[char_lo];
406     }
407     else
408     {
409       /* a 16-bit character code */
410       index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
411       if ( index1 )
412       {
413         sh2      = cmap2->subHeaders + index1;
414         char_lo -= sh2->firstCode;
415
416         if ( char_lo < sh2->entryCount )
417         {
418           offset = sh2->idRangeOffset / 2 + char_lo;
419           if ( offset < cmap2->numGlyphId )
420           {
421             result = cmap2->glyphIdArray[offset];
422             if ( result )
423               result = ( result + sh2->idDelta ) & 0xFFFF;
424           }
425         }
426       }
427     }
428
429     return result;
430   }
431
432
433   /*************************************************************************/
434   /*                                                                       */
435   /* <Function>                                                            */
436   /*    code_to_index4                                                     */
437   /*                                                                       */
438   /* <Description>                                                         */
439   /*    Converts the character code into a glyph index.  Uses format 4.    */
440   /*                                                                       */
441   /* <Input>                                                               */
442   /*    charCode :: The wanted character code.                             */
443   /*    cmap4    :: A pointer to a cmap table in format 4.                 */
444   /*                                                                       */
445   /* <Return>                                                              */
446   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
447   /*                                                                       */
448   static
449   FT_UInt  code_to_index4( TT_CMapTable*  cmap,
450                            FT_ULong       charCode )
451   {
452     FT_UInt          result, index1, segCount;
453     TT_CMap4*        cmap4;
454     TT_CMap4Segment  *seg4, *limit;
455
456
457     cmap4    = &cmap->c.cmap4;
458     result   = 0;
459     segCount = cmap4->segCountX2 / 2;
460     seg4     = cmap4->segments;
461     limit    = seg4 + segCount;
462
463     /* check against the last segment */
464     seg4 = cmap4->last_segment;
465
466     /* the following is equivalent to performing two tests, as in         */
467     /*                                                                    */
468     /*  if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
469     /*                                                                    */
470     /* Yes, that's a bit strange, but it's faster, and the idea behind    */
471     /* the cache is to significantly speed up charcode to glyph index     */
472     /* conversion.                                                        */
473
474     if ( (FT_ULong)(charCode       - seg4->startCount) <
475          (FT_ULong)(seg4->endCount - seg4->startCount) )
476       goto Found;
477
478     for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
479     {
480       /* the ranges are sorted in increasing order.  If we are out of */
481       /* the range here, the char code isn't in the charmap, so exit. */
482
483       if ( charCode > seg4->endCount )
484         continue;
485
486       if ( charCode >= seg4->startCount )
487         goto Found;
488     }
489     return 0;
490
491  Found:
492     cmap4->last_segment = seg4;
493
494     /* if the idRangeOffset is 0, we can compute the glyph index */
495     /* directly                                                  */
496
497     if ( seg4->idRangeOffset == 0 )
498       result = ( charCode + seg4->idDelta ) & 0xFFFF;
499     else
500     {
501       /* otherwise, we must use the glyphIdArray to do it */
502       index1 = seg4->idRangeOffset / 2
503                + ( charCode - seg4->startCount )
504                + ( seg4 - cmap4->segments )
505                - segCount;
506
507       if ( index1 < cmap4->numGlyphId       &&
508            cmap4->glyphIdArray[index1] != 0 )
509         result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF;
510     }
511
512     return result;
513   }
514
515
516   /*************************************************************************/
517   /*                                                                       */
518   /* <Function>                                                            */
519   /*    code_to_index6                                                     */
520   /*                                                                       */
521   /* <Description>                                                         */
522   /*    Converts the character code into a glyph index.  Uses format 6.    */
523   /*                                                                       */
524   /* <Input>                                                               */
525   /*    charCode :: The wanted character code.                             */
526   /*    cmap6    :: A pointer to a cmap table in format 6.                 */
527   /*                                                                       */
528   /* <Return>                                                              */
529   /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
530   /*                                                                       */
531   static
532   FT_UInt  code_to_index6( TT_CMapTable*  cmap,
533                            FT_ULong       charCode )
534   {
535     TT_CMap6*  cmap6;
536     FT_UInt    result = 0;
537
538
539     cmap6     = &cmap->c.cmap6;
540     result    = 0;
541     charCode -= cmap6->firstCode;
542
543     if ( charCode < cmap6->entryCount )
544       result =  cmap6->glyphIdArray[charCode];
545
546     return result;
547   }
548
549
550 /* END */