Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / third_party / harfbuzz / src / harfbuzz-open.c
blobf12f5b7f08eb2138fc0d11e815469ce237c6cde6
1 /*
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
5 * This is part of HarfBuzz, an OpenType Layout engine library.
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.
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.
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.
26 #include "harfbuzz-impl.h"
27 #include "harfbuzz-open-private.h"
30 /***************************
31 * Script related functions
32 ***************************/
35 /* LangSys */
37 static HB_Error Load_LangSys( HB_LangSys* ls,
38 HB_Stream stream )
40 HB_Error error;
41 HB_UShort n, count;
42 HB_UShort* fi;
45 if ( ACCESS_Frame( 6L ) )
46 return error;
48 ls->LookupOrderOffset = GET_UShort(); /* should be 0 */
49 ls->ReqFeatureIndex = GET_UShort();
50 count = ls->FeatureCount = GET_UShort();
52 FORGET_Frame();
54 ls->FeatureIndex = NULL;
56 if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
57 return error;
59 if ( ACCESS_Frame( count * 2L ) )
61 FREE( ls->FeatureIndex );
62 return error;
65 fi = ls->FeatureIndex;
67 for ( n = 0; n < count; n++ )
68 fi[n] = GET_UShort();
70 FORGET_Frame();
72 return HB_Err_Ok;
76 static void Free_LangSys( HB_LangSys* ls )
78 FREE( ls->FeatureIndex );
82 /* Script */
84 static HB_Error Load_Script( HB_ScriptTable* s,
85 HB_Stream stream )
87 HB_Error error;
88 HB_UShort n, m, count;
89 HB_UInt cur_offset, new_offset, base_offset;
91 HB_LangSysRecord* lsr;
94 base_offset = FILE_Pos();
96 if ( ACCESS_Frame( 2L ) )
97 return error;
99 new_offset = GET_UShort() + base_offset;
101 FORGET_Frame();
103 if ( new_offset != base_offset ) /* not a NULL offset */
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 );
112 else
114 /* we create a DefaultLangSys table with no entries */
116 s->DefaultLangSys.LookupOrderOffset = 0;
117 s->DefaultLangSys.ReqFeatureIndex = 0xFFFF;
118 s->DefaultLangSys.FeatureCount = 0;
119 s->DefaultLangSys.FeatureIndex = NULL;
122 if ( ACCESS_Frame( 2L ) )
123 goto Fail2;
125 count = s->LangSysCount = GET_UShort();
127 /* safety check; otherwise the official handling of TrueType Open
128 fonts won't work */
130 if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
132 error = HB_Err_Not_Covered;
133 goto Fail2;
136 FORGET_Frame();
138 s->LangSysRecord = NULL;
140 if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
141 goto Fail2;
143 lsr = s->LangSysRecord;
145 for ( n = 0; n < count; n++ )
147 if ( ACCESS_Frame( 6L ) )
148 goto Fail1;
150 lsr[n].LangSysTag = GET_ULong();
151 new_offset = GET_UShort() + base_offset;
153 FORGET_Frame();
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 );
162 return HB_Err_Ok;
164 Fail1:
165 for ( m = 0; m < n; m++ )
166 Free_LangSys( &lsr[m].LangSys );
168 FREE( s->LangSysRecord );
170 Fail2:
171 Free_LangSys( &s->DefaultLangSys );
172 return error;
176 static void Free_Script( HB_ScriptTable* s )
178 HB_UShort n, count;
180 HB_LangSysRecord* lsr;
183 Free_LangSys( &s->DefaultLangSys );
185 if ( s->LangSysRecord )
187 count = s->LangSysCount;
188 lsr = s->LangSysRecord;
190 for ( n = 0; n < count; n++ )
191 Free_LangSys( &lsr[n].LangSys );
193 FREE( lsr );
198 /* ScriptList */
200 HB_INTERNAL HB_Error
201 _HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
202 HB_Stream stream )
204 HB_Error error;
206 HB_UShort n, script_count;
207 HB_UInt cur_offset, new_offset, base_offset;
209 HB_ScriptRecord* sr;
212 base_offset = FILE_Pos();
214 if ( ACCESS_Frame( 2L ) )
215 return error;
217 script_count = GET_UShort();
219 FORGET_Frame();
221 sl->ScriptRecord = NULL;
223 if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
224 return error;
226 sr = sl->ScriptRecord;
228 sl->ScriptCount= 0;
229 for ( n = 0; n < script_count; n++ )
231 if ( ACCESS_Frame( 6L ) )
232 goto Fail;
234 sr[sl->ScriptCount].ScriptTag = GET_ULong();
235 new_offset = GET_UShort() + base_offset;
237 FORGET_Frame();
239 cur_offset = FILE_Pos();
241 if ( FILE_Seek( new_offset ) )
242 goto Fail;
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;
250 (void)FILE_Seek( cur_offset );
253 /* Empty tables are harmless and generated by fontforge.
254 * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
256 #if 0
257 if ( sl->ScriptCount == 0 )
259 error = ERR(HB_Err_Invalid_SubTable);
260 goto Fail;
262 #endif
264 return HB_Err_Ok;
266 Fail:
267 for ( n = 0; n < sl->ScriptCount; n++ )
268 Free_Script( &sr[n].Script );
270 FREE( sl->ScriptRecord );
271 return error;
275 HB_INTERNAL void
276 _HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
278 HB_UShort n, count;
280 HB_ScriptRecord* sr;
283 if ( sl->ScriptRecord )
285 count = sl->ScriptCount;
286 sr = sl->ScriptRecord;
288 for ( n = 0; n < count; n++ )
289 Free_Script( &sr[n].Script );
291 FREE( sr );
297 /*********************************
298 * Feature List related functions
299 *********************************/
302 /* Feature */
304 static HB_Error Load_Feature( HB_Feature* f,
305 HB_Stream stream )
307 HB_Error error;
309 HB_UShort n, count;
311 HB_UShort* lli;
314 if ( ACCESS_Frame( 4L ) )
315 return error;
317 f->FeatureParams = GET_UShort(); /* should be 0 */
318 count = f->LookupListCount = GET_UShort();
320 FORGET_Frame();
322 f->LookupListIndex = NULL;
324 if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
325 return error;
327 lli = f->LookupListIndex;
329 if ( ACCESS_Frame( count * 2L ) )
331 FREE( f->LookupListIndex );
332 return error;
335 for ( n = 0; n < count; n++ )
336 lli[n] = GET_UShort();
338 FORGET_Frame();
340 return HB_Err_Ok;
344 static void Free_Feature( HB_Feature* f )
346 FREE( f->LookupListIndex );
350 /* FeatureList */
352 HB_INTERNAL HB_Error
353 _HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
354 HB_Stream stream )
356 HB_Error error;
358 HB_UShort n, m, count;
359 HB_UInt cur_offset, new_offset, base_offset;
361 HB_FeatureRecord* fr;
364 base_offset = FILE_Pos();
366 if ( ACCESS_Frame( 2L ) )
367 return error;
369 count = fl->FeatureCount = GET_UShort();
371 FORGET_Frame();
373 fl->FeatureRecord = NULL;
375 if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
376 return error;
377 if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
378 goto Fail2;
380 fl->ApplyCount = 0;
382 fr = fl->FeatureRecord;
384 for ( n = 0; n < count; n++ )
386 if ( ACCESS_Frame( 6L ) )
387 goto Fail1;
389 fr[n].FeatureTag = GET_ULong();
390 new_offset = GET_UShort() + base_offset;
392 FORGET_Frame();
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 );
401 return HB_Err_Ok;
403 Fail1:
404 for ( m = 0; m < n; m++ )
405 Free_Feature( &fr[m].Feature );
407 FREE( fl->ApplyOrder );
409 Fail2:
410 FREE( fl->FeatureRecord );
412 return error;
416 HB_INTERNAL void
417 _HB_OPEN_Free_FeatureList( HB_FeatureList* fl )
419 HB_UShort n, count;
421 HB_FeatureRecord* fr;
424 if ( fl->FeatureRecord )
426 count = fl->FeatureCount;
427 fr = fl->FeatureRecord;
429 for ( n = 0; n < count; n++ )
430 Free_Feature( &fr[n].Feature );
432 FREE( fr );
435 FREE( fl->ApplyOrder );
440 /********************************
441 * Lookup List related functions
442 ********************************/
444 /* the subroutines of the following two functions are defined in
445 ftxgsub.c and ftxgpos.c respectively */
448 /* SubTable */
450 static HB_Error Load_SubTable( HB_SubTable* st,
451 HB_Stream stream,
452 HB_Type table_type,
453 HB_UShort lookup_type )
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 );
462 static void Free_SubTable( HB_SubTable* st,
463 HB_Type table_type,
464 HB_UShort lookup_type )
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 );
473 /* Lookup */
475 static HB_Error Load_Lookup( HB_Lookup* l,
476 HB_Stream stream,
477 HB_Type type )
479 HB_Error error;
481 HB_UShort n, m, count;
482 HB_UInt cur_offset, new_offset, base_offset;
484 HB_SubTable* st;
486 HB_Bool is_extension = FALSE;
489 base_offset = FILE_Pos();
491 if ( ACCESS_Frame( 6L ) )
492 return error;
494 l->LookupType = GET_UShort();
495 l->LookupFlag = GET_UShort();
496 count = l->SubTableCount = GET_UShort();
498 FORGET_Frame();
500 l->SubTable = NULL;
502 if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
503 return error;
505 st = l->SubTable;
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;
511 for ( n = 0; n < count; n++ )
513 if ( ACCESS_Frame( 2L ) )
514 goto Fail;
516 new_offset = GET_UShort() + base_offset;
518 FORGET_Frame();
520 cur_offset = FILE_Pos();
522 if ( is_extension )
524 if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
525 goto Fail;
527 if (GET_UShort() != 1) /* format should be 1 */
528 goto Fail;
530 l->LookupType = GET_UShort();
531 new_offset += GET_ULong();
533 FORGET_Frame();
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 );
543 return HB_Err_Ok;
545 Fail:
546 for ( m = 0; m < n; m++ )
547 Free_SubTable( &st[m], type, l->LookupType );
549 FREE( l->SubTable );
550 return error;
554 static void Free_Lookup( HB_Lookup* l,
555 HB_Type type)
557 HB_UShort n, count;
559 HB_SubTable* st;
562 if ( l->SubTable )
564 count = l->SubTableCount;
565 st = l->SubTable;
567 for ( n = 0; n < count; n++ )
568 Free_SubTable( &st[n], type, l->LookupType );
570 FREE( st );
575 /* LookupList */
577 HB_INTERNAL HB_Error
578 _HB_OPEN_Load_LookupList( HB_LookupList* ll,
579 HB_Stream stream,
580 HB_Type type )
582 HB_Error error;
584 HB_UShort n, m, count;
585 HB_UInt cur_offset, new_offset, base_offset;
587 HB_Lookup* l;
590 base_offset = FILE_Pos();
592 if ( ACCESS_Frame( 2L ) )
593 return error;
595 count = ll->LookupCount = GET_UShort();
597 FORGET_Frame();
599 ll->Lookup = NULL;
601 if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
602 return error;
603 if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
604 goto Fail2;
606 l = ll->Lookup;
608 for ( n = 0; n < count; n++ )
610 if ( ACCESS_Frame( 2L ) )
611 goto Fail1;
613 new_offset = GET_UShort() + base_offset;
615 FORGET_Frame();
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 );
624 return HB_Err_Ok;
626 Fail1:
627 FREE( ll->Properties );
629 for ( m = 0; m < n; m++ )
630 Free_Lookup( &l[m], type );
632 Fail2:
633 FREE( ll->Lookup );
634 return error;
638 HB_INTERNAL void
639 _HB_OPEN_Free_LookupList( HB_LookupList* ll,
640 HB_Type type )
642 HB_UShort n, count;
644 HB_Lookup* l;
647 FREE( ll->Properties );
649 if ( ll->Lookup )
651 count = ll->LookupCount;
652 l = ll->Lookup;
654 for ( n = 0; n < count; n++ )
655 Free_Lookup( &l[n], type );
657 FREE( l );
663 /*****************************
664 * Coverage related functions
665 *****************************/
668 /* CoverageFormat1 */
670 static HB_Error Load_Coverage1( HB_CoverageFormat1* cf1,
671 HB_Stream stream )
673 HB_Error error;
675 HB_UShort n, count;
677 HB_UShort* ga;
680 if ( ACCESS_Frame( 2L ) )
681 return error;
683 count = cf1->GlyphCount = GET_UShort();
685 FORGET_Frame();
687 cf1->GlyphArray = NULL;
689 if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
690 return error;
692 ga = cf1->GlyphArray;
694 if ( ACCESS_Frame( count * 2L ) )
696 FREE( cf1->GlyphArray );
697 return error;
700 for ( n = 0; n < count; n++ )
701 ga[n] = GET_UShort();
703 FORGET_Frame();
705 return HB_Err_Ok;
709 static void Free_Coverage1( HB_CoverageFormat1* cf1)
711 FREE( cf1->GlyphArray );
715 /* CoverageFormat2 */
717 static HB_Error Load_Coverage2( HB_CoverageFormat2* cf2,
718 HB_Stream stream )
720 HB_Error error;
722 HB_UShort n, count;
724 HB_RangeRecord* rr;
727 if ( ACCESS_Frame( 2L ) )
728 return error;
730 count = cf2->RangeCount = GET_UShort();
732 FORGET_Frame();
734 cf2->RangeRecord = NULL;
736 if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
737 return error;
739 rr = cf2->RangeRecord;
741 if ( ACCESS_Frame( count * 6L ) )
742 goto Fail;
744 for ( n = 0; n < count; n++ )
746 rr[n].Start = GET_UShort();
747 rr[n].End = GET_UShort();
748 rr[n].StartCoverageIndex = GET_UShort();
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 )
755 error = ERR(HB_Err_Invalid_SubTable);
756 goto Fail;
760 FORGET_Frame();
762 return HB_Err_Ok;
764 Fail:
765 FREE( cf2->RangeRecord );
766 return error;
770 static void Free_Coverage2( HB_CoverageFormat2* cf2 )
772 FREE( cf2->RangeRecord );
776 HB_INTERNAL HB_Error
777 _HB_OPEN_Load_Coverage( HB_Coverage* c,
778 HB_Stream stream )
780 HB_Error error;
782 if ( ACCESS_Frame( 2L ) )
783 return error;
785 c->CoverageFormat = GET_UShort();
787 FORGET_Frame();
789 switch ( c->CoverageFormat )
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);
796 return HB_Err_Ok; /* never reached */
800 HB_INTERNAL void
801 _HB_OPEN_Free_Coverage( HB_Coverage* c )
803 switch ( c->CoverageFormat )
805 case 1: Free_Coverage1( &c->cf.cf1 ); break;
806 case 2: Free_Coverage2( &c->cf.cf2 ); break;
807 default: break;
812 static HB_Error Coverage_Index1( HB_CoverageFormat1* cf1,
813 HB_UShort glyphID,
814 HB_UShort* index )
816 HB_UShort min, max, new_min, new_max, middle;
818 HB_UShort* array = cf1->GlyphArray;
821 /* binary search */
823 if ( cf1->GlyphCount == 0 )
824 return HB_Err_Not_Covered;
826 new_min = 0;
827 new_max = cf1->GlyphCount - 1;
831 min = new_min;
832 max = new_max;
834 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
835 overflow and rounding errors */
837 middle = max - ( ( max - min ) >> 1 );
839 if ( glyphID == array[middle] )
841 *index = middle;
842 return HB_Err_Ok;
844 else if ( glyphID < array[middle] )
846 if ( middle == min )
847 break;
848 new_max = middle - 1;
850 else
852 if ( middle == max )
853 break;
854 new_min = middle + 1;
856 } while ( min < max );
858 return HB_Err_Not_Covered;
862 static HB_Error Coverage_Index2( HB_CoverageFormat2* cf2,
863 HB_UShort glyphID,
864 HB_UShort* index )
866 HB_UShort min, max, new_min, new_max, middle;
868 HB_RangeRecord* rr = cf2->RangeRecord;
871 /* binary search */
873 if ( cf2->RangeCount == 0 )
874 return HB_Err_Not_Covered;
876 new_min = 0;
877 new_max = cf2->RangeCount - 1;
881 min = new_min;
882 max = new_max;
884 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
885 overflow and rounding errors */
887 middle = max - ( ( max - min ) >> 1 );
889 if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
891 *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
892 return HB_Err_Ok;
894 else if ( glyphID < rr[middle].Start )
896 if ( middle == min )
897 break;
898 new_max = middle - 1;
900 else
902 if ( middle == max )
903 break;
904 new_min = middle + 1;
906 } while ( min < max );
908 return HB_Err_Not_Covered;
912 HB_INTERNAL HB_Error
913 _HB_OPEN_Coverage_Index( HB_Coverage* c,
914 HB_UShort glyphID,
915 HB_UShort* index )
917 switch ( c->CoverageFormat )
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);
924 return HB_Err_Ok; /* never reached */
929 /*************************************
930 * Class Definition related functions
931 *************************************/
934 /* ClassDefFormat1 */
936 static HB_Error Load_ClassDef1( HB_ClassDefinition* cd,
937 HB_UShort limit,
938 HB_Stream stream )
940 HB_Error error;
942 HB_UShort n, count;
944 HB_UShort* cva;
946 HB_ClassDefFormat1* cdf1;
949 cdf1 = &cd->cd.cd1;
951 if ( ACCESS_Frame( 4L ) )
952 return error;
954 cdf1->StartGlyph = GET_UShort();
955 count = cdf1->GlyphCount = GET_UShort();
957 FORGET_Frame();
959 /* sanity check; we are limited to 16bit integers */
961 if ( cdf1->StartGlyph + (long)count >= 0x10000L )
962 return ERR(HB_Err_Invalid_SubTable);
964 cdf1->ClassValueArray = NULL;
966 if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
967 return error;
969 cva = cdf1->ClassValueArray;
971 if ( ACCESS_Frame( count * 2L ) )
972 goto Fail;
974 for ( n = 0; n < count; n++ )
976 cva[n] = GET_UShort();
977 if ( cva[n] >= limit )
979 error = ERR(HB_Err_Invalid_SubTable);
980 goto Fail;
984 FORGET_Frame();
986 return HB_Err_Ok;
988 Fail:
989 FREE( cva );
991 return error;
995 static void Free_ClassDef1( HB_ClassDefFormat1* cdf1 )
997 FREE( cdf1->ClassValueArray );
1001 /* ClassDefFormat2 */
1003 static HB_Error Load_ClassDef2( HB_ClassDefinition* cd,
1004 HB_UShort limit,
1005 HB_Stream stream )
1007 HB_Error error;
1009 HB_UShort n, count;
1011 HB_ClassRangeRecord* crr;
1013 HB_ClassDefFormat2* cdf2;
1016 cdf2 = &cd->cd.cd2;
1018 if ( ACCESS_Frame( 2L ) )
1019 return error;
1021 count = GET_UShort();
1022 cdf2->ClassRangeCount = 0; /* zero for now. we fill with the number of good entries later */
1024 FORGET_Frame();
1026 cdf2->ClassRangeRecord = NULL;
1028 if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
1029 return error;
1031 crr = cdf2->ClassRangeRecord;
1033 if ( ACCESS_Frame( count * 6L ) )
1034 goto Fail;
1036 for ( n = 0; n < count; n++ )
1038 crr[n].Start = GET_UShort();
1039 crr[n].End = GET_UShort();
1040 crr[n].Class = GET_UShort();
1042 /* sanity check */
1044 if ( crr[n].Start > crr[n].End ||
1045 crr[n].Class >= limit )
1047 /* XXX
1048 * Corrupt entry. Skip it.
1049 * This is hit by Nafees Nastaliq font for example
1051 n--;
1052 count--;
1056 FORGET_Frame();
1058 cdf2->ClassRangeCount = count;
1060 return HB_Err_Ok;
1062 Fail:
1063 FREE( crr );
1065 return error;
1069 static void Free_ClassDef2( HB_ClassDefFormat2* cdf2 )
1071 FREE( cdf2->ClassRangeRecord );
1075 /* ClassDefinition */
1077 HB_INTERNAL HB_Error
1078 _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
1079 HB_UShort limit,
1080 HB_Stream stream )
1082 HB_Error error;
1084 if ( ACCESS_Frame( 2L ) )
1085 return error;
1087 cd->ClassFormat = GET_UShort();
1089 FORGET_Frame();
1091 switch ( cd->ClassFormat )
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;
1098 if ( error )
1099 return error;
1101 cd->loaded = TRUE;
1103 return HB_Err_Ok;
1107 static HB_Error
1108 _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd )
1110 HB_Error error;
1112 cd->ClassFormat = 1; /* Meaningless */
1114 if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
1115 return error;
1117 cd->loaded = TRUE;
1119 return HB_Err_Ok;
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 )
1129 HB_Error error;
1130 HB_UInt cur_offset;
1132 cur_offset = FILE_Pos();
1134 if ( class_offset )
1136 if ( !FILE_Seek( class_offset + base_offset ) )
1137 error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
1139 else
1140 error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
1142 if (error == HB_Err_Ok)
1143 (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
1145 return error;
1148 HB_INTERNAL void
1149 _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd )
1151 if ( !cd->loaded )
1152 return;
1154 switch ( cd->ClassFormat )
1156 case 1: Free_ClassDef1( &cd->cd.cd1 ); break;
1157 case 2: Free_ClassDef2( &cd->cd.cd2 ); break;
1158 default: break;
1163 static HB_Error Get_Class1( HB_ClassDefFormat1* cdf1,
1164 HB_UShort glyphID,
1165 HB_UShort* klass,
1166 HB_UShort* index )
1168 HB_UShort* cva = cdf1->ClassValueArray;
1171 if ( index )
1172 *index = 0;
1174 if ( glyphID >= cdf1->StartGlyph &&
1175 glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
1177 *klass = cva[glyphID - cdf1->StartGlyph];
1178 return HB_Err_Ok;
1180 else
1182 *klass = 0;
1183 return HB_Err_Not_Covered;
1188 /* we need the index value of the last searched class range record
1189 in case of failure for constructed GDEF tables */
1191 static HB_Error Get_Class2( HB_ClassDefFormat2* cdf2,
1192 HB_UShort glyphID,
1193 HB_UShort* klass,
1194 HB_UShort* index )
1196 HB_Error error = HB_Err_Ok;
1197 HB_UShort min, max, new_min, new_max, middle;
1199 HB_ClassRangeRecord* crr = cdf2->ClassRangeRecord;
1202 /* binary search */
1204 if ( cdf2->ClassRangeCount == 0 )
1206 *klass = 0;
1207 if ( index )
1208 *index = 0;
1210 return HB_Err_Not_Covered;
1213 new_min = 0;
1214 new_max = cdf2->ClassRangeCount - 1;
1218 min = new_min;
1219 max = new_max;
1221 /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
1222 overflow and rounding errors */
1224 middle = max - ( ( max - min ) >> 1 );
1226 if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
1228 *klass = crr[middle].Class;
1229 error = HB_Err_Ok;
1230 break;
1232 else if ( glyphID < crr[middle].Start )
1234 if ( middle == min )
1236 *klass = 0;
1237 error = HB_Err_Not_Covered;
1238 break;
1240 new_max = middle - 1;
1242 else
1244 if ( middle == max )
1246 *klass = 0;
1247 error = HB_Err_Not_Covered;
1248 break;
1250 new_min = middle + 1;
1252 } while ( min < max );
1254 if ( index )
1255 *index = middle;
1257 return error;
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 )
1267 switch ( cd->ClassFormat )
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);
1274 return HB_Err_Ok; /* never reached */
1279 /***************************
1280 * Device related functions
1281 ***************************/
1284 HB_INTERNAL HB_Error
1285 _HB_OPEN_Load_Device( HB_Device** device,
1286 HB_Stream stream )
1288 HB_Device* d;
1289 HB_Error error;
1291 HB_UShort n, count;
1293 HB_UShort* dv;
1296 if ( ACCESS_Frame( 6L ) )
1297 return error;
1299 if ( ALLOC( *device, sizeof(HB_Device)) )
1301 *device = 0;
1302 return error;
1305 d = *device;
1307 d->StartSize = GET_UShort();
1308 d->EndSize = GET_UShort();
1309 d->DeltaFormat = GET_UShort();
1311 FORGET_Frame();
1313 d->DeltaValue = NULL;
1315 if ( d->StartSize > d->EndSize ||
1316 d->DeltaFormat == 0 || d->DeltaFormat > 3 )
1318 /* XXX
1319 * I've seen fontforge generate DeltaFormat == 0.
1320 * Just return Ok and let the NULL DeltaValue disable
1321 * this table.
1323 return HB_Err_Ok;
1326 count = ( ( d->EndSize - d->StartSize + 1 ) >>
1327 ( 4 - d->DeltaFormat ) ) + 1;
1329 if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
1331 FREE( *device );
1332 *device = 0;
1333 return error;
1336 if ( ACCESS_Frame( count * 2L ) )
1338 FREE( d->DeltaValue );
1339 FREE( *device );
1340 *device = 0;
1341 return error;
1344 dv = d->DeltaValue;
1346 for ( n = 0; n < count; n++ )
1347 dv[n] = GET_UShort();
1349 FORGET_Frame();
1351 return HB_Err_Ok;
1355 HB_INTERNAL void
1356 _HB_OPEN_Free_Device( HB_Device* d )
1358 if ( d )
1360 FREE( d->DeltaValue );
1361 FREE( d );
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.
1371 format = 1: 0011223344556677|8899101112131415|...
1373 byte 1 byte 2
1375 00: (byte >> 14) & mask
1376 11: (byte >> 12) & mask
1379 mask = 0x0003
1381 format = 2: 0000111122223333|4444555566667777|...
1383 byte 1 byte 2
1385 0000: (byte >> 12) & mask
1386 1111: (byte >> 8) & mask
1389 mask = 0x000F
1391 format = 3: 0000000011111111|2222222233333333|...
1393 byte 1 byte 2
1395 00000000: (byte >> 8) & mask
1396 11111111: (byte >> 0) & mask
1397 ....
1399 mask = 0x00FF */
1401 HB_INTERNAL HB_Error
1402 _HB_OPEN_Get_Device( HB_Device* d,
1403 HB_UShort size,
1404 HB_Short* value )
1406 HB_UShort byte, bits, mask, s;
1408 if ( d && d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
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 ) );
1416 *value = (HB_Short)( bits & mask );
1418 /* conversion to a signed value */
1420 if ( *value >= ( ( mask + 1 ) >> 1 ) )
1421 *value -= mask + 1;
1423 return HB_Err_Ok;
1425 else
1427 *value = 0;
1428 return HB_Err_Not_Covered;
1433 /* END */