]> git.saurik.com Git - wxWidgets.git/blob - src/freetype/sfnt/ttcmap.c
case-insensitive sort of HTML help index
[wxWidgets.git] / src / freetype / 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 <sfnt/ttload.h>
31 #include <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 */