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
Load_LangSys(HB_LangSys * ls,HB_Stream stream)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
Free_LangSys(HB_LangSys * ls)76 static void Free_LangSys( HB_LangSys* ls )
77 {
78 FREE( ls->FeatureIndex );
79 }
80
81
82 /* Script */
83
Load_Script(HB_ScriptTable * s,HB_Stream stream)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
Free_Script(HB_ScriptTable * s)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
_HB_OPEN_Load_ScriptList(HB_ScriptList * sl,HB_Stream stream)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
_HB_OPEN_Free_ScriptList(HB_ScriptList * sl)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
Load_Feature(HB_Feature * f,HB_Stream stream)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
Free_Feature(HB_Feature * f)344 static void Free_Feature( HB_Feature* f )
345 {
346 FREE( f->LookupListIndex );
347 }
348
349
350 /* FeatureList */
351
352 HB_INTERNAL HB_Error
_HB_OPEN_Load_FeatureList(HB_FeatureList * fl,HB_Stream stream)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
_HB_OPEN_Free_FeatureList(HB_FeatureList * fl)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
Load_SubTable(HB_SubTable * st,HB_Stream stream,HB_Type table_type,HB_UShort lookup_type)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
Free_SubTable(HB_SubTable * st,HB_Type table_type,HB_UShort lookup_type)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
Load_Lookup(HB_Lookup * l,HB_Stream stream,HB_Type type)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
Free_Lookup(HB_Lookup * l,HB_Type type)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
_HB_OPEN_Load_LookupList(HB_LookupList * ll,HB_Stream stream,HB_Type type)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
_HB_OPEN_Free_LookupList(HB_LookupList * ll,HB_Type type)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
Load_Coverage1(HB_CoverageFormat1 * cf1,HB_Stream stream)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
Free_Coverage1(HB_CoverageFormat1 * cf1)709 static void Free_Coverage1( HB_CoverageFormat1* cf1)
710 {
711 FREE( cf1->GlyphArray );
712 }
713
714
715 /* CoverageFormat2 */
716
Load_Coverage2(HB_CoverageFormat2 * cf2,HB_Stream stream)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
Free_Coverage2(HB_CoverageFormat2 * cf2)770 static void Free_Coverage2( HB_CoverageFormat2* cf2 )
771 {
772 FREE( cf2->RangeRecord );
773 }
774
775
776 HB_INTERNAL HB_Error
_HB_OPEN_Load_Coverage(HB_Coverage * c,HB_Stream stream)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
_HB_OPEN_Free_Coverage(HB_Coverage * c)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
Coverage_Index1(HB_CoverageFormat1 * cf1,HB_UShort glyphID,HB_UShort * index)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
Coverage_Index2(HB_CoverageFormat2 * cf2,HB_UShort glyphID,HB_UShort * index)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
_HB_OPEN_Coverage_Index(HB_Coverage * c,HB_UShort glyphID,HB_UShort * index)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
Load_ClassDef1(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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
Free_ClassDef1(HB_ClassDefFormat1 * cdf1)995 static void Free_ClassDef1( HB_ClassDefFormat1* cdf1 )
996 {
997 FREE( cdf1->ClassValueArray );
998 }
999
1000
1001 /* ClassDefFormat2 */
1002
Load_ClassDef2(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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 entries 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
Free_ClassDef2(HB_ClassDefFormat2 * cdf2)1069 static void Free_ClassDef2( HB_ClassDefFormat2* cdf2 )
1070 {
1071 FREE( cdf2->ClassRangeRecord );
1072 }
1073
1074
1075 /* ClassDefinition */
1076
1077 HB_INTERNAL HB_Error
_HB_OPEN_Load_ClassDefinition(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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
_HB_OPEN_Load_EmptyClassDefinition(HB_ClassDefinition * cd)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
_HB_OPEN_Load_EmptyOrClassDefinition(HB_ClassDefinition * cd,HB_UShort limit,HB_UInt class_offset,HB_UInt base_offset,HB_Stream stream)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
_HB_OPEN_Free_ClassDefinition(HB_ClassDefinition * cd)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
Get_Class1(HB_ClassDefFormat1 * cdf1,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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
Get_Class2(HB_ClassDefFormat2 * cdf2,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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
_HB_OPEN_Get_Class(HB_ClassDefinition * cd,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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
_HB_OPEN_Load_Device(HB_Device ** device,HB_Stream stream)1285 _HB_OPEN_Load_Device( HB_Device** device,
1286 HB_Stream stream )
1287 {
1288 HB_Device* d;
1289 HB_Error error;
1290
1291 HB_UShort n, count;
1292
1293 HB_UShort* dv;
1294
1295
1296 if ( ACCESS_Frame( 6L ) )
1297 return error;
1298
1299 if ( ALLOC( *device, sizeof(HB_Device)) )
1300 {
1301 *device = 0;
1302 return error;
1303 }
1304
1305 d = *device;
1306
1307 d->StartSize = GET_UShort();
1308 d->EndSize = GET_UShort();
1309 d->DeltaFormat = GET_UShort();
1310
1311 FORGET_Frame();
1312
1313 d->DeltaValue = NULL;
1314
1315 if ( d->StartSize > d->EndSize ||
1316 d->DeltaFormat == 0 || d->DeltaFormat > 3 )
1317 {
1318 /* XXX
1319 * I've seen fontforge generate DeltaFormat == 0.
1320 * Just return Ok and let the NULL DeltaValue disable
1321 * this table.
1322 */
1323 return HB_Err_Ok;
1324 }
1325
1326 count = ( ( d->EndSize - d->StartSize + 1 ) >>
1327 ( 4 - d->DeltaFormat ) ) + 1;
1328
1329 if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
1330 {
1331 FREE( *device );
1332 *device = 0;
1333 return error;
1334 }
1335
1336 if ( ACCESS_Frame( count * 2L ) )
1337 {
1338 FREE( d->DeltaValue );
1339 FREE( *device );
1340 *device = 0;
1341 return error;
1342 }
1343
1344 dv = d->DeltaValue;
1345
1346 for ( n = 0; n < count; n++ )
1347 dv[n] = GET_UShort();
1348
1349 FORGET_Frame();
1350
1351 return HB_Err_Ok;
1352 }
1353
1354
1355 HB_INTERNAL void
_HB_OPEN_Free_Device(HB_Device * d)1356 _HB_OPEN_Free_Device( HB_Device* d )
1357 {
1358 if ( d )
1359 {
1360 FREE( d->DeltaValue );
1361 FREE( d );
1362 }
1363 }
1364
1365
1366 /* Since we have the delta values stored in compressed form, we must
1367 uncompress it now. To simplify the interface, the function always
1368 returns a meaningful value in `value'; the error is just for
1369 information.
1370 | |
1371 format = 1: 0011223344556677|8899101112131415|...
1372 | |
1373 byte 1 byte 2
1374
1375 00: (byte >> 14) & mask
1376 11: (byte >> 12) & mask
1377 ...
1378
1379 mask = 0x0003
1380 | |
1381 format = 2: 0000111122223333|4444555566667777|...
1382 | |
1383 byte 1 byte 2
1384
1385 0000: (byte >> 12) & mask
1386 1111: (byte >> 8) & mask
1387 ...
1388
1389 mask = 0x000F
1390 | |
1391 format = 3: 0000000011111111|2222222233333333|...
1392 | |
1393 byte 1 byte 2
1394
1395 00000000: (byte >> 8) & mask
1396 11111111: (byte >> 0) & mask
1397 ....
1398
1399 mask = 0x00FF */
1400
1401 HB_INTERNAL HB_Error
_HB_OPEN_Get_Device(HB_Device * d,HB_UShort size,HB_Short * value)1402 _HB_OPEN_Get_Device( HB_Device* d,
1403 HB_UShort size,
1404 HB_Short* value )
1405 {
1406 HB_UShort byte, bits, mask, s;
1407
1408 if ( d && d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
1409 {
1410 HB_UShort f = d->DeltaFormat;
1411 s = size - d->StartSize;
1412 byte = d->DeltaValue[s >> ( 4 - f )];
1413 bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
1414 mask = 0xFFFF >> ( 16 - ( 1 << f ) );
1415
1416 *value = (HB_Short)( bits & mask );
1417
1418 /* conversion to a signed value */
1419
1420 if ( *value >= ( ( mask + 1 ) >> 1 ) )
1421 *value -= mask + 1;
1422
1423 return HB_Err_Ok;
1424 }
1425 else
1426 {
1427 *value = 0;
1428 return HB_Err_Not_Covered;
1429 }
1430 }
1431
1432
1433 /* END */
1434