OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg | |
3 * Copyright (C) 2006 Behdad Esfahbod | |
4 * | |
5 * This is part of HarfBuzz, an OpenType Layout engine library. | |
6 * | |
7 * Permission is hereby granted, without written agreement and without | |
8 * license or royalty fees, to use, copy, modify, and distribute this | |
9 * software and its documentation for any purpose, provided that the | |
10 * above copyright notice and the following two paragraphs appear in | |
11 * all copies of this software. | |
12 * | |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
17 * DAMAGE. | |
18 * | |
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
24 */ | |
25 | |
26 #include "harfbuzz-impl.h" | |
27 #include "harfbuzz-open-private.h" | |
28 | |
29 | |
30 /*************************** | |
31 * Script related functions | |
32 ***************************/ | |
33 | |
34 | |
35 /* LangSys */ | |
36 | |
37 static HB_Error Load_LangSys( HB_LangSys* ls, | |
38 HB_Stream stream ) | |
39 { | |
40 HB_Error error; | |
41 HB_UShort n, count; | |
42 HB_UShort* fi; | |
43 | |
44 | |
45 if ( ACCESS_Frame( 6L ) ) | |
46 return error; | |
47 | |
48 ls->LookupOrderOffset = GET_UShort(); /* should be 0 */ | |
49 ls->ReqFeatureIndex = GET_UShort(); | |
50 count = ls->FeatureCount = GET_UShort(); | |
51 | |
52 FORGET_Frame(); | |
53 | |
54 ls->FeatureIndex = NULL; | |
55 | |
56 if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) ) | |
57 return error; | |
58 | |
59 if ( ACCESS_Frame( count * 2L ) ) | |
60 { | |
61 FREE( ls->FeatureIndex ); | |
62 return error; | |
63 } | |
64 | |
65 fi = ls->FeatureIndex; | |
66 | |
67 for ( n = 0; n < count; n++ ) | |
68 fi[n] = GET_UShort(); | |
69 | |
70 FORGET_Frame(); | |
71 | |
72 return HB_Err_Ok; | |
73 } | |
74 | |
75 | |
76 static void Free_LangSys( HB_LangSys* ls ) | |
77 { | |
78 FREE( ls->FeatureIndex ); | |
79 } | |
80 | |
81 | |
82 /* Script */ | |
83 | |
84 static HB_Error Load_Script( HB_ScriptTable* s, | |
85 HB_Stream stream ) | |
86 { | |
87 HB_Error error; | |
88 HB_UShort n, m, count; | |
89 HB_UInt cur_offset, new_offset, base_offset; | |
90 | |
91 HB_LangSysRecord* lsr; | |
92 | |
93 | |
94 base_offset = FILE_Pos(); | |
95 | |
96 if ( ACCESS_Frame( 2L ) ) | |
97 return error; | |
98 | |
99 new_offset = GET_UShort() + base_offset; | |
100 | |
101 FORGET_Frame(); | |
102 | |
103 if ( new_offset != base_offset ) /* not a NULL offset */ | |
104 { | |
105 cur_offset = FILE_Pos(); | |
106 if ( FILE_Seek( new_offset ) || | |
107 ( error = Load_LangSys( &s->DefaultLangSys, | |
108 stream ) ) != HB_Err_Ok ) | |
109 return error; | |
110 (void)FILE_Seek( cur_offset ); | |
111 } | |
112 else | |
113 { | |
114 /* we create a DefaultLangSys table with no entries */ | |
115 | |
116 s->DefaultLangSys.LookupOrderOffset = 0; | |
117 s->DefaultLangSys.ReqFeatureIndex = 0xFFFF; | |
118 s->DefaultLangSys.FeatureCount = 0; | |
119 s->DefaultLangSys.FeatureIndex = NULL; | |
120 } | |
121 | |
122 if ( ACCESS_Frame( 2L ) ) | |
123 goto Fail2; | |
124 | |
125 count = s->LangSysCount = GET_UShort(); | |
126 | |
127 /* safety check; otherwise the official handling of TrueType Open | |
128 fonts won't work */ | |
129 | |
130 if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) | |
131 { | |
132 error = HB_Err_Not_Covered; | |
133 goto Fail2; | |
134 } | |
135 | |
136 FORGET_Frame(); | |
137 | |
138 s->LangSysRecord = NULL; | |
139 | |
140 if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) ) | |
141 goto Fail2; | |
142 | |
143 lsr = s->LangSysRecord; | |
144 | |
145 for ( n = 0; n < count; n++ ) | |
146 { | |
147 if ( ACCESS_Frame( 6L ) ) | |
148 goto Fail1; | |
149 | |
150 lsr[n].LangSysTag = GET_ULong(); | |
151 new_offset = GET_UShort() + base_offset; | |
152 | |
153 FORGET_Frame(); | |
154 | |
155 cur_offset = FILE_Pos(); | |
156 if ( FILE_Seek( new_offset ) || | |
157 ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok ) | |
158 goto Fail1; | |
159 (void)FILE_Seek( cur_offset ); | |
160 } | |
161 | |
162 return HB_Err_Ok; | |
163 | |
164 Fail1: | |
165 for ( m = 0; m < n; m++ ) | |
166 Free_LangSys( &lsr[m].LangSys ); | |
167 | |
168 FREE( s->LangSysRecord ); | |
169 | |
170 Fail2: | |
171 Free_LangSys( &s->DefaultLangSys ); | |
172 return error; | |
173 } | |
174 | |
175 | |
176 static void Free_Script( HB_ScriptTable* s ) | |
177 { | |
178 HB_UShort n, count; | |
179 | |
180 HB_LangSysRecord* lsr; | |
181 | |
182 | |
183 Free_LangSys( &s->DefaultLangSys ); | |
184 | |
185 if ( s->LangSysRecord ) | |
186 { | |
187 count = s->LangSysCount; | |
188 lsr = s->LangSysRecord; | |
189 | |
190 for ( n = 0; n < count; n++ ) | |
191 Free_LangSys( &lsr[n].LangSys ); | |
192 | |
193 FREE( lsr ); | |
194 } | |
195 } | |
196 | |
197 | |
198 /* ScriptList */ | |
199 | |
200 HB_INTERNAL HB_Error | |
201 _HB_OPEN_Load_ScriptList( HB_ScriptList* sl, | |
202 HB_Stream stream ) | |
203 { | |
204 HB_Error error; | |
205 | |
206 HB_UShort n, script_count; | |
207 HB_UInt cur_offset, new_offset, base_offset; | |
208 | |
209 HB_ScriptRecord* sr; | |
210 | |
211 | |
212 base_offset = FILE_Pos(); | |
213 | |
214 if ( ACCESS_Frame( 2L ) ) | |
215 return error; | |
216 | |
217 script_count = GET_UShort(); | |
218 | |
219 FORGET_Frame(); | |
220 | |
221 sl->ScriptRecord = NULL; | |
222 | |
223 if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) ) | |
224 return error; | |
225 | |
226 sr = sl->ScriptRecord; | |
227 | |
228 sl->ScriptCount= 0; | |
229 for ( n = 0; n < script_count; n++ ) | |
230 { | |
231 if ( ACCESS_Frame( 6L ) ) | |
232 goto Fail; | |
233 | |
234 sr[sl->ScriptCount].ScriptTag = GET_ULong(); | |
235 new_offset = GET_UShort() + base_offset; | |
236 | |
237 FORGET_Frame(); | |
238 | |
239 cur_offset = FILE_Pos(); | |
240 | |
241 if ( FILE_Seek( new_offset ) ) | |
242 goto Fail; | |
243 | |
244 error = Load_Script( &sr[sl->ScriptCount].Script, stream ); | |
245 if ( error == HB_Err_Ok ) | |
246 sl->ScriptCount += 1; | |
247 else if ( error != HB_Err_Not_Covered ) | |
248 goto Fail; | |
249 | |
250 (void)FILE_Seek( cur_offset ); | |
251 } | |
252 | |
253 /* Empty tables are harmless and generated by fontforge. | |
254 * See http://bugzilla.gnome.org/show_bug.cgi?id=347073 | |
255 */ | |
256 #if 0 | |
257 if ( sl->ScriptCount == 0 ) | |
258 { | |
259 error = ERR(HB_Err_Invalid_SubTable); | |
260 goto Fail; | |
261 } | |
262 #endif | |
263 | |
264 return HB_Err_Ok; | |
265 | |
266 Fail: | |
267 for ( n = 0; n < sl->ScriptCount; n++ ) | |
268 Free_Script( &sr[n].Script ); | |
269 | |
270 FREE( sl->ScriptRecord ); | |
271 return error; | |
272 } | |
273 | |
274 | |
275 HB_INTERNAL void | |
276 _HB_OPEN_Free_ScriptList( HB_ScriptList* sl ) | |
277 { | |
278 HB_UShort n, count; | |
279 | |
280 HB_ScriptRecord* sr; | |
281 | |
282 | |
283 if ( sl->ScriptRecord ) | |
284 { | |
285 count = sl->ScriptCount; | |
286 sr = sl->ScriptRecord; | |
287 | |
288 for ( n = 0; n < count; n++ ) | |
289 Free_Script( &sr[n].Script ); | |
290 | |
291 FREE( sr ); | |
292 } | |
293 } | |
294 | |
295 | |
296 | |
297 /********************************* | |
298 * Feature List related functions | |
299 *********************************/ | |
300 | |
301 | |
302 /* Feature */ | |
303 | |
304 static HB_Error Load_Feature( HB_Feature* f, | |
305 HB_Stream stream ) | |
306 { | |
307 HB_Error error; | |
308 | |
309 HB_UShort n, count; | |
310 | |
311 HB_UShort* lli; | |
312 | |
313 | |
314 if ( ACCESS_Frame( 4L ) ) | |
315 return error; | |
316 | |
317 f->FeatureParams = GET_UShort(); /* should be 0 */ | |
318 count = f->LookupListCount = GET_UShort(); | |
319 | |
320 FORGET_Frame(); | |
321 | |
322 f->LookupListIndex = NULL; | |
323 | |
324 if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) ) | |
325 return error; | |
326 | |
327 lli = f->LookupListIndex; | |
328 | |
329 if ( ACCESS_Frame( count * 2L ) ) | |
330 { | |
331 FREE( f->LookupListIndex ); | |
332 return error; | |
333 } | |
334 | |
335 for ( n = 0; n < count; n++ ) | |
336 lli[n] = GET_UShort(); | |
337 | |
338 FORGET_Frame(); | |
339 | |
340 return HB_Err_Ok; | |
341 } | |
342 | |
343 | |
344 static void Free_Feature( HB_Feature* f ) | |
345 { | |
346 FREE( f->LookupListIndex ); | |
347 } | |
348 | |
349 | |
350 /* FeatureList */ | |
351 | |
352 HB_INTERNAL HB_Error | |
353 _HB_OPEN_Load_FeatureList( HB_FeatureList* fl, | |
354 HB_Stream stream ) | |
355 { | |
356 HB_Error error; | |
357 | |
358 HB_UShort n, m, count; | |
359 HB_UInt cur_offset, new_offset, base_offset; | |
360 | |
361 HB_FeatureRecord* fr; | |
362 | |
363 | |
364 base_offset = FILE_Pos(); | |
365 | |
366 if ( ACCESS_Frame( 2L ) ) | |
367 return error; | |
368 | |
369 count = fl->FeatureCount = GET_UShort(); | |
370 | |
371 FORGET_Frame(); | |
372 | |
373 fl->FeatureRecord = NULL; | |
374 | |
375 if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) ) | |
376 return error; | |
377 if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) ) | |
378 goto Fail2; | |
379 | |
380 fl->ApplyCount = 0; | |
381 | |
382 fr = fl->FeatureRecord; | |
383 | |
384 for ( n = 0; n < count; n++ ) | |
385 { | |
386 if ( ACCESS_Frame( 6L ) ) | |
387 goto Fail1; | |
388 | |
389 fr[n].FeatureTag = GET_ULong(); | |
390 new_offset = GET_UShort() + base_offset; | |
391 | |
392 FORGET_Frame(); | |
393 | |
394 cur_offset = FILE_Pos(); | |
395 if ( FILE_Seek( new_offset ) || | |
396 ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok ) | |
397 goto Fail1; | |
398 (void)FILE_Seek( cur_offset ); | |
399 } | |
400 | |
401 return HB_Err_Ok; | |
402 | |
403 Fail1: | |
404 for ( m = 0; m < n; m++ ) | |
405 Free_Feature( &fr[m].Feature ); | |
406 | |
407 FREE( fl->ApplyOrder ); | |
408 | |
409 Fail2: | |
410 FREE( fl->FeatureRecord ); | |
411 | |
412 return error; | |
413 } | |
414 | |
415 | |
416 HB_INTERNAL void | |
417 _HB_OPEN_Free_FeatureList( HB_FeatureList* fl ) | |
418 { | |
419 HB_UShort n, count; | |
420 | |
421 HB_FeatureRecord* fr; | |
422 | |
423 | |
424 if ( fl->FeatureRecord ) | |
425 { | |
426 count = fl->FeatureCount; | |
427 fr = fl->FeatureRecord; | |
428 | |
429 for ( n = 0; n < count; n++ ) | |
430 Free_Feature( &fr[n].Feature ); | |
431 | |
432 FREE( fr ); | |
433 } | |
434 | |
435 FREE( fl->ApplyOrder ); | |
436 } | |
437 | |
438 | |
439 | |
440 /******************************** | |
441 * Lookup List related functions | |
442 ********************************/ | |
443 | |
444 /* the subroutines of the following two functions are defined in | |
445 ftxgsub.c and ftxgpos.c respectively */ | |
446 | |
447 | |
448 /* SubTable */ | |
449 | |
450 static HB_Error Load_SubTable( HB_SubTable* st, | |
451 HB_Stream stream, | |
452 HB_Type table_type, | |
453 HB_UShort lookup_type ) | |
454 { | |
455 if ( table_type == HB_Type_GSUB ) | |
456 return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type ); | |
457 else | |
458 return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type ); | |
459 } | |
460 | |
461 | |
462 static void Free_SubTable( HB_SubTable* st, | |
463 HB_Type table_type, | |
464 HB_UShort lookup_type ) | |
465 { | |
466 if ( table_type == HB_Type_GSUB ) | |
467 _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type ); | |
468 else | |
469 _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type ); | |
470 } | |
471 | |
472 | |
473 /* Lookup */ | |
474 | |
475 static HB_Error Load_Lookup( HB_Lookup* l, | |
476 HB_Stream stream, | |
477 HB_Type type ) | |
478 { | |
479 HB_Error error; | |
480 | |
481 HB_UShort n, m, count; | |
482 HB_UInt cur_offset, new_offset, base_offset; | |
483 | |
484 HB_SubTable* st; | |
485 | |
486 HB_Bool is_extension = FALSE; | |
487 | |
488 | |
489 base_offset = FILE_Pos(); | |
490 | |
491 if ( ACCESS_Frame( 6L ) ) | |
492 return error; | |
493 | |
494 l->LookupType = GET_UShort(); | |
495 l->LookupFlag = GET_UShort(); | |
496 count = l->SubTableCount = GET_UShort(); | |
497 | |
498 FORGET_Frame(); | |
499 | |
500 l->SubTable = NULL; | |
501 | |
502 if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) ) | |
503 return error; | |
504 | |
505 st = l->SubTable; | |
506 | |
507 if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) || | |
508 ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) ) | |
509 is_extension = TRUE; | |
510 | |
511 for ( n = 0; n < count; n++ ) | |
512 { | |
513 if ( ACCESS_Frame( 2L ) ) | |
514 goto Fail; | |
515 | |
516 new_offset = GET_UShort() + base_offset; | |
517 | |
518 FORGET_Frame(); | |
519 | |
520 cur_offset = FILE_Pos(); | |
521 | |
522 if ( is_extension ) | |
523 { | |
524 if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) ) | |
525 goto Fail; | |
526 | |
527 if (GET_UShort() != 1) /* format should be 1 */ | |
528 goto Fail; | |
529 | |
530 l->LookupType = GET_UShort(); | |
531 new_offset += GET_ULong(); | |
532 | |
533 FORGET_Frame(); | |
534 } | |
535 | |
536 if ( FILE_Seek( new_offset ) || | |
537 ( error = Load_SubTable( &st[n], stream, | |
538 type, l->LookupType ) ) != HB_Err_Ok ) | |
539 goto Fail; | |
540 (void)FILE_Seek( cur_offset ); | |
541 } | |
542 | |
543 return HB_Err_Ok; | |
544 | |
545 Fail: | |
546 for ( m = 0; m < n; m++ ) | |
547 Free_SubTable( &st[m], type, l->LookupType ); | |
548 | |
549 FREE( l->SubTable ); | |
550 return error; | |
551 } | |
552 | |
553 | |
554 static void Free_Lookup( HB_Lookup* l, | |
555 HB_Type type) | |
556 { | |
557 HB_UShort n, count; | |
558 | |
559 HB_SubTable* st; | |
560 | |
561 | |
562 if ( l->SubTable ) | |
563 { | |
564 count = l->SubTableCount; | |
565 st = l->SubTable; | |
566 | |
567 for ( n = 0; n < count; n++ ) | |
568 Free_SubTable( &st[n], type, l->LookupType ); | |
569 | |
570 FREE( st ); | |
571 } | |
572 } | |
573 | |
574 | |
575 /* LookupList */ | |
576 | |
577 HB_INTERNAL HB_Error | |
578 _HB_OPEN_Load_LookupList( HB_LookupList* ll, | |
579 HB_Stream stream, | |
580 HB_Type type ) | |
581 { | |
582 HB_Error error; | |
583 | |
584 HB_UShort n, m, count; | |
585 HB_UInt cur_offset, new_offset, base_offset; | |
586 | |
587 HB_Lookup* l; | |
588 | |
589 | |
590 base_offset = FILE_Pos(); | |
591 | |
592 if ( ACCESS_Frame( 2L ) ) | |
593 return error; | |
594 | |
595 count = ll->LookupCount = GET_UShort(); | |
596 | |
597 FORGET_Frame(); | |
598 | |
599 ll->Lookup = NULL; | |
600 | |
601 if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) ) | |
602 return error; | |
603 if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) ) | |
604 goto Fail2; | |
605 | |
606 l = ll->Lookup; | |
607 | |
608 for ( n = 0; n < count; n++ ) | |
609 { | |
610 if ( ACCESS_Frame( 2L ) ) | |
611 goto Fail1; | |
612 | |
613 new_offset = GET_UShort() + base_offset; | |
614 | |
615 FORGET_Frame(); | |
616 | |
617 cur_offset = FILE_Pos(); | |
618 if ( FILE_Seek( new_offset ) || | |
619 ( error = Load_Lookup( &l[n], stream, type ) ) != HB_Err_Ok ) | |
620 goto Fail1; | |
621 (void)FILE_Seek( cur_offset ); | |
622 } | |
623 | |
624 return HB_Err_Ok; | |
625 | |
626 Fail1: | |
627 FREE( ll->Properties ); | |
628 | |
629 for ( m = 0; m < n; m++ ) | |
630 Free_Lookup( &l[m], type ); | |
631 | |
632 Fail2: | |
633 FREE( ll->Lookup ); | |
634 return error; | |
635 } | |
636 | |
637 | |
638 HB_INTERNAL void | |
639 _HB_OPEN_Free_LookupList( HB_LookupList* ll, | |
640 HB_Type type ) | |
641 { | |
642 HB_UShort n, count; | |
643 | |
644 HB_Lookup* l; | |
645 | |
646 | |
647 FREE( ll->Properties ); | |
648 | |
649 if ( ll->Lookup ) | |
650 { | |
651 count = ll->LookupCount; | |
652 l = ll->Lookup; | |
653 | |
654 for ( n = 0; n < count; n++ ) | |
655 Free_Lookup( &l[n], type ); | |
656 | |
657 FREE( l ); | |
658 } | |
659 } | |
660 | |
661 | |
662 | |
663 /***************************** | |
664 * Coverage related functions | |
665 *****************************/ | |
666 | |
667 | |
668 /* CoverageFormat1 */ | |
669 | |
670 static HB_Error Load_Coverage1( HB_CoverageFormat1* cf1, | |
671 HB_Stream stream ) | |
672 { | |
673 HB_Error error; | |
674 | |
675 HB_UShort n, count; | |
676 | |
677 HB_UShort* ga; | |
678 | |
679 | |
680 if ( ACCESS_Frame( 2L ) ) | |
681 return error; | |
682 | |
683 count = cf1->GlyphCount = GET_UShort(); | |
684 | |
685 FORGET_Frame(); | |
686 | |
687 cf1->GlyphArray = NULL; | |
688 | |
689 if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) ) | |
690 return error; | |
691 | |
692 ga = cf1->GlyphArray; | |
693 | |
694 if ( ACCESS_Frame( count * 2L ) ) | |
695 { | |
696 FREE( cf1->GlyphArray ); | |
697 return error; | |
698 } | |
699 | |
700 for ( n = 0; n < count; n++ ) | |
701 ga[n] = GET_UShort(); | |
702 | |
703 FORGET_Frame(); | |
704 | |
705 return HB_Err_Ok; | |
706 } | |
707 | |
708 | |
709 static void Free_Coverage1( HB_CoverageFormat1* cf1) | |
710 { | |
711 FREE( cf1->GlyphArray ); | |
712 } | |
713 | |
714 | |
715 /* CoverageFormat2 */ | |
716 | |
717 static HB_Error Load_Coverage2( HB_CoverageFormat2* cf2, | |
718 HB_Stream stream ) | |
719 { | |
720 HB_Error error; | |
721 | |
722 HB_UShort n, count; | |
723 | |
724 HB_RangeRecord* rr; | |
725 | |
726 | |
727 if ( ACCESS_Frame( 2L ) ) | |
728 return error; | |
729 | |
730 count = cf2->RangeCount = GET_UShort(); | |
731 | |
732 FORGET_Frame(); | |
733 | |
734 cf2->RangeRecord = NULL; | |
735 | |
736 if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) ) | |
737 return error; | |
738 | |
739 rr = cf2->RangeRecord; | |
740 | |
741 if ( ACCESS_Frame( count * 6L ) ) | |
742 goto Fail; | |
743 | |
744 for ( n = 0; n < count; n++ ) | |
745 { | |
746 rr[n].Start = GET_UShort(); | |
747 rr[n].End = GET_UShort(); | |
748 rr[n].StartCoverageIndex = GET_UShort(); | |
749 | |
750 /* sanity check; we are limited to 16bit integers */ | |
751 if ( rr[n].Start > rr[n].End || | |
752 ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >= | |
753 0x10000L ) | |
754 { | |
755 error = ERR(HB_Err_Invalid_SubTable); | |
756 goto Fail; | |
757 } | |
758 } | |
759 | |
760 FORGET_Frame(); | |
761 | |
762 return HB_Err_Ok; | |
763 | |
764 Fail: | |
765 FREE( cf2->RangeRecord ); | |
766 return error; | |
767 } | |
768 | |
769 | |
770 static void Free_Coverage2( HB_CoverageFormat2* cf2 ) | |
771 { | |
772 FREE( cf2->RangeRecord ); | |
773 } | |
774 | |
775 | |
776 HB_INTERNAL HB_Error | |
777 _HB_OPEN_Load_Coverage( HB_Coverage* c, | |
778 HB_Stream stream ) | |
779 { | |
780 HB_Error error; | |
781 | |
782 if ( ACCESS_Frame( 2L ) ) | |
783 return error; | |
784 | |
785 c->CoverageFormat = GET_UShort(); | |
786 | |
787 FORGET_Frame(); | |
788 | |
789 switch ( c->CoverageFormat ) | |
790 { | |
791 case 1: return Load_Coverage1( &c->cf.cf1, stream ); | |
792 case 2: return Load_Coverage2( &c->cf.cf2, stream ); | |
793 default: return ERR(HB_Err_Invalid_SubTable_Format); | |
794 } | |
795 | |
796 return HB_Err_Ok; /* never reached */ | |
797 } | |
798 | |
799 | |
800 HB_INTERNAL void | |
801 _HB_OPEN_Free_Coverage( HB_Coverage* c ) | |
802 { | |
803 switch ( c->CoverageFormat ) | |
804 { | |
805 case 1: Free_Coverage1( &c->cf.cf1 ); break; | |
806 case 2: Free_Coverage2( &c->cf.cf2 ); break; | |
807 default: break; | |
808 } | |
809 } | |
810 | |
811 | |
812 static HB_Error Coverage_Index1( HB_CoverageFormat1* cf1, | |
813 HB_UShort glyphID, | |
814 HB_UShort* index ) | |
815 { | |
816 HB_UShort min, max, new_min, new_max, middle; | |
817 | |
818 HB_UShort* array = cf1->GlyphArray; | |
819 | |
820 | |
821 /* binary search */ | |
822 | |
823 if ( cf1->GlyphCount == 0 ) | |
824 return HB_Err_Not_Covered; | |
825 | |
826 new_min = 0; | |
827 new_max = cf1->GlyphCount - 1; | |
828 | |
829 do | |
830 { | |
831 min = new_min; | |
832 max = new_max; | |
833 | |
834 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid | |
835 overflow and rounding errors */ | |
836 | |
837 middle = max - ( ( max - min ) >> 1 ); | |
838 | |
839 if ( glyphID == array[middle] ) | |
840 { | |
841 *index = middle; | |
842 return HB_Err_Ok; | |
843 } | |
844 else if ( glyphID < array[middle] ) | |
845 { | |
846 if ( middle == min ) | |
847 break; | |
848 new_max = middle - 1; | |
849 } | |
850 else | |
851 { | |
852 if ( middle == max ) | |
853 break; | |
854 new_min = middle + 1; | |
855 } | |
856 } while ( min < max ); | |
857 | |
858 return HB_Err_Not_Covered; | |
859 } | |
860 | |
861 | |
862 static HB_Error Coverage_Index2( HB_CoverageFormat2* cf2, | |
863 HB_UShort glyphID, | |
864 HB_UShort* index ) | |
865 { | |
866 HB_UShort min, max, new_min, new_max, middle; | |
867 | |
868 HB_RangeRecord* rr = cf2->RangeRecord; | |
869 | |
870 | |
871 /* binary search */ | |
872 | |
873 if ( cf2->RangeCount == 0 ) | |
874 return HB_Err_Not_Covered; | |
875 | |
876 new_min = 0; | |
877 new_max = cf2->RangeCount - 1; | |
878 | |
879 do | |
880 { | |
881 min = new_min; | |
882 max = new_max; | |
883 | |
884 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid | |
885 overflow and rounding errors */ | |
886 | |
887 middle = max - ( ( max - min ) >> 1 ); | |
888 | |
889 if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End ) | |
890 { | |
891 *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start; | |
892 return HB_Err_Ok; | |
893 } | |
894 else if ( glyphID < rr[middle].Start ) | |
895 { | |
896 if ( middle == min ) | |
897 break; | |
898 new_max = middle - 1; | |
899 } | |
900 else | |
901 { | |
902 if ( middle == max ) | |
903 break; | |
904 new_min = middle + 1; | |
905 } | |
906 } while ( min < max ); | |
907 | |
908 return HB_Err_Not_Covered; | |
909 } | |
910 | |
911 | |
912 HB_INTERNAL HB_Error | |
913 _HB_OPEN_Coverage_Index( HB_Coverage* c, | |
914 HB_UShort glyphID, | |
915 HB_UShort* index ) | |
916 { | |
917 switch ( c->CoverageFormat ) | |
918 { | |
919 case 1: return Coverage_Index1( &c->cf.cf1, glyphID, index ); | |
920 case 2: return Coverage_Index2( &c->cf.cf2, glyphID, index ); | |
921 default: return ERR(HB_Err_Invalid_SubTable_Format); | |
922 } | |
923 | |
924 return HB_Err_Ok; /* never reached */ | |
925 } | |
926 | |
927 | |
928 | |
929 /************************************* | |
930 * Class Definition related functions | |
931 *************************************/ | |
932 | |
933 | |
934 /* ClassDefFormat1 */ | |
935 | |
936 static HB_Error Load_ClassDef1( HB_ClassDefinition* cd, | |
937 HB_UShort limit, | |
938 HB_Stream stream ) | |
939 { | |
940 HB_Error error; | |
941 | |
942 HB_UShort n, count; | |
943 | |
944 HB_UShort* cva; | |
945 | |
946 HB_ClassDefFormat1* cdf1; | |
947 | |
948 | |
949 cdf1 = &cd->cd.cd1; | |
950 | |
951 if ( ACCESS_Frame( 4L ) ) | |
952 return error; | |
953 | |
954 cdf1->StartGlyph = GET_UShort(); | |
955 count = cdf1->GlyphCount = GET_UShort(); | |
956 | |
957 FORGET_Frame(); | |
958 | |
959 /* sanity check; we are limited to 16bit integers */ | |
960 | |
961 if ( cdf1->StartGlyph + (long)count >= 0x10000L ) | |
962 return ERR(HB_Err_Invalid_SubTable); | |
963 | |
964 cdf1->ClassValueArray = NULL; | |
965 | |
966 if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) ) | |
967 return error; | |
968 | |
969 cva = cdf1->ClassValueArray; | |
970 | |
971 if ( ACCESS_Frame( count * 2L ) ) | |
972 goto Fail; | |
973 | |
974 for ( n = 0; n < count; n++ ) | |
975 { | |
976 cva[n] = GET_UShort(); | |
977 if ( cva[n] >= limit ) | |
978 { | |
979 error = ERR(HB_Err_Invalid_SubTable); | |
980 goto Fail; | |
981 } | |
982 } | |
983 | |
984 FORGET_Frame(); | |
985 | |
986 return HB_Err_Ok; | |
987 | |
988 Fail: | |
989 FREE( cva ); | |
990 | |
991 return error; | |
992 } | |
993 | |
994 | |
995 static void Free_ClassDef1( HB_ClassDefFormat1* cdf1 ) | |
996 { | |
997 FREE( cdf1->ClassValueArray ); | |
998 } | |
999 | |
1000 | |
1001 /* ClassDefFormat2 */ | |
1002 | |
1003 static HB_Error Load_ClassDef2( HB_ClassDefinition* cd, | |
1004 HB_UShort limit, | |
1005 HB_Stream stream ) | |
1006 { | |
1007 HB_Error error; | |
1008 | |
1009 HB_UShort n, count; | |
1010 | |
1011 HB_ClassRangeRecord* crr; | |
1012 | |
1013 HB_ClassDefFormat2* cdf2; | |
1014 | |
1015 | |
1016 cdf2 = &cd->cd.cd2; | |
1017 | |
1018 if ( ACCESS_Frame( 2L ) ) | |
1019 return error; | |
1020 | |
1021 count = GET_UShort(); | |
1022 cdf2->ClassRangeCount = 0; /* zero for now. we fill with the number of good e
ntries later */ | |
1023 | |
1024 FORGET_Frame(); | |
1025 | |
1026 cdf2->ClassRangeRecord = NULL; | |
1027 | |
1028 if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) ) | |
1029 return error; | |
1030 | |
1031 crr = cdf2->ClassRangeRecord; | |
1032 | |
1033 if ( ACCESS_Frame( count * 6L ) ) | |
1034 goto Fail; | |
1035 | |
1036 for ( n = 0; n < count; n++ ) | |
1037 { | |
1038 crr[n].Start = GET_UShort(); | |
1039 crr[n].End = GET_UShort(); | |
1040 crr[n].Class = GET_UShort(); | |
1041 | |
1042 /* sanity check */ | |
1043 | |
1044 if ( crr[n].Start > crr[n].End || | |
1045 crr[n].Class >= limit ) | |
1046 { | |
1047 /* XXX | |
1048 * Corrupt entry. Skip it. | |
1049 * This is hit by Nafees Nastaliq font for example | |
1050 */ | |
1051 n--; | |
1052 count--; | |
1053 } | |
1054 } | |
1055 | |
1056 FORGET_Frame(); | |
1057 | |
1058 cdf2->ClassRangeCount = count; | |
1059 | |
1060 return HB_Err_Ok; | |
1061 | |
1062 Fail: | |
1063 FREE( crr ); | |
1064 | |
1065 return error; | |
1066 } | |
1067 | |
1068 | |
1069 static void Free_ClassDef2( HB_ClassDefFormat2* cdf2 ) | |
1070 { | |
1071 FREE( cdf2->ClassRangeRecord ); | |
1072 } | |
1073 | |
1074 | |
1075 /* ClassDefinition */ | |
1076 | |
1077 HB_INTERNAL HB_Error | |
1078 _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd, | |
1079 HB_UShort limit, | |
1080 HB_Stream stream ) | |
1081 { | |
1082 HB_Error error; | |
1083 | |
1084 if ( ACCESS_Frame( 2L ) ) | |
1085 return error; | |
1086 | |
1087 cd->ClassFormat = GET_UShort(); | |
1088 | |
1089 FORGET_Frame(); | |
1090 | |
1091 switch ( cd->ClassFormat ) | |
1092 { | |
1093 case 1: error = Load_ClassDef1( cd, limit, stream ); break; | |
1094 case 2: error = Load_ClassDef2( cd, limit, stream ); break; | |
1095 default: error = ERR(HB_Err_Invalid_SubTable_Format); break; | |
1096 } | |
1097 | |
1098 if ( error ) | |
1099 return error; | |
1100 | |
1101 cd->loaded = TRUE; | |
1102 | |
1103 return HB_Err_Ok; | |
1104 } | |
1105 | |
1106 | |
1107 static HB_Error | |
1108 _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd ) | |
1109 { | |
1110 HB_Error error; | |
1111 | |
1112 cd->ClassFormat = 1; /* Meaningless */ | |
1113 | |
1114 if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) ) | |
1115 return error; | |
1116 | |
1117 cd->loaded = TRUE; | |
1118 | |
1119 return HB_Err_Ok; | |
1120 } | |
1121 | |
1122 HB_INTERNAL HB_Error | |
1123 _HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd, | |
1124 HB_UShort limit, | |
1125 HB_UInt class_offset
, | |
1126 HB_UInt base_offset, | |
1127 HB_Stream stream ) | |
1128 { | |
1129 HB_Error error; | |
1130 HB_UInt cur_offset; | |
1131 | |
1132 cur_offset = FILE_Pos(); | |
1133 | |
1134 if ( class_offset ) | |
1135 { | |
1136 if ( !FILE_Seek( class_offset + base_offset ) ) | |
1137 error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream ); | |
1138 } | |
1139 else | |
1140 error = _HB_OPEN_Load_EmptyClassDefinition ( cd ); | |
1141 | |
1142 if (error == HB_Err_Ok) | |
1143 (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */ | |
1144 | |
1145 return error; | |
1146 } | |
1147 | |
1148 HB_INTERNAL void | |
1149 _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd ) | |
1150 { | |
1151 if ( !cd->loaded ) | |
1152 return; | |
1153 | |
1154 switch ( cd->ClassFormat ) | |
1155 { | |
1156 case 1: Free_ClassDef1( &cd->cd.cd1 ); break; | |
1157 case 2: Free_ClassDef2( &cd->cd.cd2 ); break; | |
1158 default: break; | |
1159 } | |
1160 } | |
1161 | |
1162 | |
1163 static HB_Error Get_Class1( HB_ClassDefFormat1* cdf1, | |
1164 HB_UShort glyphID, | |
1165 HB_UShort* klass, | |
1166 HB_UShort* index ) | |
1167 { | |
1168 HB_UShort* cva = cdf1->ClassValueArray; | |
1169 | |
1170 | |
1171 if ( index ) | |
1172 *index = 0; | |
1173 | |
1174 if ( glyphID >= cdf1->StartGlyph && | |
1175 glyphID < cdf1->StartGlyph + cdf1->GlyphCount ) | |
1176 { | |
1177 *klass = cva[glyphID - cdf1->StartGlyph]; | |
1178 return HB_Err_Ok; | |
1179 } | |
1180 else | |
1181 { | |
1182 *klass = 0; | |
1183 return HB_Err_Not_Covered; | |
1184 } | |
1185 } | |
1186 | |
1187 | |
1188 /* we need the index value of the last searched class range record | |
1189 in case of failure for constructed GDEF tables */ | |
1190 | |
1191 static HB_Error Get_Class2( HB_ClassDefFormat2* cdf2, | |
1192 HB_UShort glyphID, | |
1193 HB_UShort* klass, | |
1194 HB_UShort* index ) | |
1195 { | |
1196 HB_Error error = HB_Err_Ok; | |
1197 HB_UShort min, max, new_min, new_max, middle; | |
1198 | |
1199 HB_ClassRangeRecord* crr = cdf2->ClassRangeRecord; | |
1200 | |
1201 | |
1202 /* binary search */ | |
1203 | |
1204 if ( cdf2->ClassRangeCount == 0 ) | |
1205 { | |
1206 *klass = 0; | |
1207 if ( index ) | |
1208 *index = 0; | |
1209 | |
1210 return HB_Err_Not_Covered; | |
1211 } | |
1212 | |
1213 new_min = 0; | |
1214 new_max = cdf2->ClassRangeCount - 1; | |
1215 | |
1216 do | |
1217 { | |
1218 min = new_min; | |
1219 max = new_max; | |
1220 | |
1221 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid | |
1222 overflow and rounding errors */ | |
1223 | |
1224 middle = max - ( ( max - min ) >> 1 ); | |
1225 | |
1226 if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End ) | |
1227 { | |
1228 *klass = crr[middle].Class; | |
1229 error = HB_Err_Ok; | |
1230 break; | |
1231 } | |
1232 else if ( glyphID < crr[middle].Start ) | |
1233 { | |
1234 if ( middle == min ) | |
1235 { | |
1236 *klass = 0; | |
1237 error = HB_Err_Not_Covered; | |
1238 break; | |
1239 } | |
1240 new_max = middle - 1; | |
1241 } | |
1242 else | |
1243 { | |
1244 if ( middle == max ) | |
1245 { | |
1246 *klass = 0; | |
1247 error = HB_Err_Not_Covered; | |
1248 break; | |
1249 } | |
1250 new_min = middle + 1; | |
1251 } | |
1252 } while ( min < max ); | |
1253 | |
1254 if ( index ) | |
1255 *index = middle; | |
1256 | |
1257 return error; | |
1258 } | |
1259 | |
1260 | |
1261 HB_INTERNAL HB_Error | |
1262 _HB_OPEN_Get_Class( HB_ClassDefinition* cd, | |
1263 HB_UShort glyphID, | |
1264 HB_UShort* klass, | |
1265 HB_UShort* index ) | |
1266 { | |
1267 switch ( cd->ClassFormat ) | |
1268 { | |
1269 case 1: return Get_Class1( &cd->cd.cd1, glyphID, klass, index ); | |
1270 case 2: return Get_Class2( &cd->cd.cd2, glyphID, klass, index ); | |
1271 default: return ERR(HB_Err_Invalid_SubTable_Format); | |
1272 } | |
1273 | |
1274 return HB_Err_Ok; /* never reached */ | |
1275 } | |
1276 | |
1277 | |
1278 | |
1279 /*************************** | |
1280 * Device related functions | |
1281 ***************************/ | |
1282 | |
1283 | |
1284 HB_INTERNAL HB_Error | |
1285 _HB_OPEN_Load_Device( HB_Device* d, | |
1286 HB_Stream stream ) | |
1287 { | |
1288 HB_Error error; | |
1289 | |
1290 HB_UShort n, count; | |
1291 | |
1292 HB_UShort* dv; | |
1293 | |
1294 | |
1295 if ( ACCESS_Frame( 6L ) ) | |
1296 return error; | |
1297 | |
1298 d->StartSize = GET_UShort(); | |
1299 d->EndSize = GET_UShort(); | |
1300 d->DeltaFormat = GET_UShort(); | |
1301 | |
1302 FORGET_Frame(); | |
1303 | |
1304 d->DeltaValue = NULL; | |
1305 | |
1306 if ( d->StartSize > d->EndSize || | |
1307 d->DeltaFormat == 0 || d->DeltaFormat > 3 ) | |
1308 { | |
1309 /* XXX | |
1310 * I've seen fontforge generate DeltaFormat == 0. | |
1311 * Just return Ok and let the NULL DeltaValue disable | |
1312 * this table. | |
1313 */ | |
1314 return HB_Err_Ok; | |
1315 } | |
1316 | |
1317 count = ( ( d->EndSize - d->StartSize + 1 ) >> | |
1318 ( 4 - d->DeltaFormat ) ) + 1; | |
1319 | |
1320 if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) ) | |
1321 return error; | |
1322 | |
1323 if ( ACCESS_Frame( count * 2L ) ) | |
1324 { | |
1325 FREE( d->DeltaValue ); | |
1326 return error; | |
1327 } | |
1328 | |
1329 dv = d->DeltaValue; | |
1330 | |
1331 for ( n = 0; n < count; n++ ) | |
1332 dv[n] = GET_UShort(); | |
1333 | |
1334 FORGET_Frame(); | |
1335 | |
1336 return HB_Err_Ok; | |
1337 } | |
1338 | |
1339 | |
1340 HB_INTERNAL void | |
1341 _HB_OPEN_Free_Device( HB_Device* d ) | |
1342 { | |
1343 FREE( d->DeltaValue ); | |
1344 } | |
1345 | |
1346 | |
1347 /* Since we have the delta values stored in compressed form, we must | |
1348 uncompress it now. To simplify the interface, the function always | |
1349 returns a meaningful value in `value'; the error is just for | |
1350 information. | |
1351 | | | |
1352 format = 1: 0011223344556677|8899101112131415|... | |
1353 | | | |
1354 byte 1 byte 2 | |
1355 | |
1356 00: (byte >> 14) & mask | |
1357 11: (byte >> 12) & mask | |
1358 ... | |
1359 | |
1360 mask = 0x0003 | |
1361 | | | |
1362 format = 2: 0000111122223333|4444555566667777|... | |
1363 | | | |
1364 byte 1 byte 2 | |
1365 | |
1366 0000: (byte >> 12) & mask | |
1367 1111: (byte >> 8) & mask | |
1368 ... | |
1369 | |
1370 mask = 0x000F | |
1371 | | | |
1372 format = 3: 0000000011111111|2222222233333333|... | |
1373 | | | |
1374 byte 1 byte 2 | |
1375 | |
1376 00000000: (byte >> 8) & mask | |
1377 11111111: (byte >> 0) & mask | |
1378 .... | |
1379 | |
1380 mask = 0x00FF */ | |
1381 | |
1382 HB_INTERNAL HB_Error | |
1383 _HB_OPEN_Get_Device( HB_Device* d, | |
1384 HB_UShort size, | |
1385 HB_Short* value ) | |
1386 { | |
1387 HB_UShort byte, bits, mask, f, s; | |
1388 | |
1389 | |
1390 f = d->DeltaFormat; | |
1391 | |
1392 if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize ) | |
1393 { | |
1394 s = size - d->StartSize; | |
1395 byte = d->DeltaValue[s >> ( 4 - f )]; | |
1396 bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) ); | |
1397 mask = 0xFFFF >> ( 16 - ( 1 << f ) ); | |
1398 | |
1399 *value = (HB_Short)( bits & mask ); | |
1400 | |
1401 /* conversion to a signed value */ | |
1402 | |
1403 if ( *value >= ( ( mask + 1 ) >> 1 ) ) | |
1404 *value -= mask + 1; | |
1405 | |
1406 return HB_Err_Ok; | |
1407 } | |
1408 else | |
1409 { | |
1410 *value = 0; | |
1411 return HB_Err_Not_Covered; | |
1412 } | |
1413 } | |
1414 | |
1415 | |
1416 /* END */ | |
OLD | NEW |