Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / third_party / harfbuzz / src / harfbuzz-gsub.c
blobceb703430dbc2880e0e5f1ed5616f9b0829cd85c
1 /*
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
4 * Copyright (C) 2007 Red Hat, Inc.
6 * This is part of HarfBuzz, an OpenType Layout engine library.
8 * Permission is hereby granted, without written agreement and without
9 * license or royalty fees, to use, copy, modify, and distribute this
10 * software and its documentation for any purpose, provided that the
11 * above copyright notice and the following two paragraphs appear in
12 * all copies of this software.
14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * DAMAGE.
20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 * Red Hat Author(s): Behdad Esfahbod
29 #include "harfbuzz-impl.h"
30 #include "harfbuzz-gsub-private.h"
31 #include "harfbuzz-open-private.h"
32 #include "harfbuzz-gdef-private.h"
34 static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
35 HB_UShort lookup_index,
36 HB_Buffer buffer,
37 HB_UShort context_length,
38 int nesting_level );
42 /**********************
43 * Auxiliary functions
44 **********************/
48 HB_Error HB_Load_GSUB_Table( HB_Stream stream,
49 HB_GSUBHeader** retptr,
50 HB_GDEFHeader* gdef,
51 HB_Stream gdefStream )
53 HB_Error error;
54 HB_UInt cur_offset, new_offset, base_offset;
56 HB_GSUBHeader* gsub;
58 if ( !retptr )
59 return ERR(HB_Err_Invalid_Argument);
61 if ( GOTO_Table( TTAG_GSUB ) )
62 return error;
64 base_offset = FILE_Pos();
66 if ( ALLOC ( gsub, sizeof( *gsub ) ) )
67 return error;
70 /* skip version */
72 if ( FILE_Seek( base_offset + 4L ) ||
73 ACCESS_Frame( 2L ) )
74 goto Fail4;
76 new_offset = GET_UShort() + base_offset;
78 FORGET_Frame();
80 cur_offset = FILE_Pos();
81 if ( FILE_Seek( new_offset ) ||
82 ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList,
83 stream ) ) != HB_Err_Ok )
84 goto Fail4;
85 (void)FILE_Seek( cur_offset );
87 if ( ACCESS_Frame( 2L ) )
88 goto Fail3;
90 new_offset = GET_UShort() + base_offset;
92 FORGET_Frame();
94 cur_offset = FILE_Pos();
95 if ( FILE_Seek( new_offset ) ||
96 ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList,
97 stream ) ) != HB_Err_Ok )
98 goto Fail3;
99 (void)FILE_Seek( cur_offset );
101 if ( ACCESS_Frame( 2L ) )
102 goto Fail2;
104 new_offset = GET_UShort() + base_offset;
106 FORGET_Frame();
108 cur_offset = FILE_Pos();
109 if ( FILE_Seek( new_offset ) ||
110 ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList,
111 stream, HB_Type_GSUB ) ) != HB_Err_Ok )
112 goto Fail2;
114 gsub->gdef = gdef; /* can be NULL */
116 if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
117 gsub->LookupList.Lookup,
118 gsub->LookupList.LookupCount ) ) )
119 goto Fail1;
121 *retptr = gsub;
123 return HB_Err_Ok;
125 Fail1:
126 _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
128 Fail2:
129 _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
131 Fail3:
132 _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
134 Fail4:
135 FREE ( gsub );
138 return error;
142 HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
144 _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
145 _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
146 _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
148 FREE( gsub );
150 return HB_Err_Ok;
153 /*****************************
154 * SubTable related functions
155 *****************************/
158 /* LookupType 1 */
160 /* SingleSubstFormat1 */
161 /* SingleSubstFormat2 */
163 static HB_Error Load_SingleSubst( HB_GSUB_SubTable* st,
164 HB_Stream stream )
166 HB_Error error;
167 HB_SingleSubst* ss = &st->single;
169 HB_UShort n, count;
170 HB_UInt cur_offset, new_offset, base_offset;
172 HB_UShort* s;
175 base_offset = FILE_Pos();
177 if ( ACCESS_Frame( 4L ) )
178 return error;
180 ss->SubstFormat = GET_UShort();
181 new_offset = GET_UShort() + base_offset;
183 FORGET_Frame();
185 cur_offset = FILE_Pos();
186 if ( FILE_Seek( new_offset ) ||
187 ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
188 return error;
189 (void)FILE_Seek( cur_offset );
191 switch ( ss->SubstFormat )
193 case 1:
194 if ( ACCESS_Frame( 2L ) )
195 goto Fail2;
197 ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
199 FORGET_Frame();
201 break;
203 case 2:
204 if ( ACCESS_Frame( 2L ) )
205 goto Fail2;
207 count = ss->ssf.ssf2.GlyphCount = GET_UShort();
209 FORGET_Frame();
211 ss->ssf.ssf2.Substitute = NULL;
213 if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
214 goto Fail2;
216 s = ss->ssf.ssf2.Substitute;
218 if ( ACCESS_Frame( count * 2L ) )
219 goto Fail1;
221 for ( n = 0; n < count; n++ )
222 s[n] = GET_UShort();
224 FORGET_Frame();
226 break;
228 default:
229 return ERR(HB_Err_Invalid_SubTable_Format);
232 return HB_Err_Ok;
234 Fail1:
235 FREE( s );
237 Fail2:
238 _HB_OPEN_Free_Coverage( &ss->Coverage );
239 return error;
243 static void Free_SingleSubst( HB_GSUB_SubTable* st )
245 HB_SingleSubst* ss = &st->single;
247 switch ( ss->SubstFormat )
249 case 1:
250 break;
252 case 2:
253 FREE( ss->ssf.ssf2.Substitute );
254 break;
256 default:
257 break;
260 _HB_OPEN_Free_Coverage( &ss->Coverage );
264 static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub,
265 HB_GSUB_SubTable* st,
266 HB_Buffer buffer,
267 HB_UShort flags,
268 HB_UShort context_length,
269 int nesting_level )
271 HB_UShort index, value, property;
272 HB_Error error;
273 HB_SingleSubst* ss = &st->single;
274 HB_GDEFHeader* gdef = gsub->gdef;
276 HB_UNUSED(nesting_level);
278 if ( context_length != 0xFFFF && context_length < 1 )
279 return HB_Err_Not_Covered;
281 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
282 return error;
284 error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
285 if ( error )
286 return error;
288 switch ( ss->SubstFormat )
290 case 1:
291 value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
292 if ( REPLACE_Glyph( buffer, value, nesting_level ) )
293 return error;
294 break;
296 case 2:
297 if ( index >= ss->ssf.ssf2.GlyphCount )
298 return ERR(HB_Err_Invalid_SubTable);
299 value = ss->ssf.ssf2.Substitute[index];
300 if ( REPLACE_Glyph( buffer, value, nesting_level ) )
301 return error;
302 break;
304 default:
305 return ERR(HB_Err_Invalid_SubTable);
308 if ( gdef && gdef->NewGlyphClasses )
310 /* we inherit the old glyph class to the substituted glyph */
312 error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
313 if ( error && error != HB_Err_Not_Covered )
314 return error;
317 return HB_Err_Ok;
321 /* LookupType 2 */
323 /* Sequence */
325 static HB_Error Load_Sequence( HB_Sequence* s,
326 HB_Stream stream )
328 HB_Error error;
330 HB_UShort n, count;
331 HB_UShort* sub;
334 if ( ACCESS_Frame( 2L ) )
335 return error;
337 count = s->GlyphCount = GET_UShort();
339 FORGET_Frame();
341 s->Substitute = NULL;
343 if ( count )
345 if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
346 return error;
348 sub = s->Substitute;
350 if ( ACCESS_Frame( count * 2L ) )
352 FREE( sub );
353 return error;
356 for ( n = 0; n < count; n++ )
357 sub[n] = GET_UShort();
359 FORGET_Frame();
362 return HB_Err_Ok;
366 static void Free_Sequence( HB_Sequence* s )
368 FREE( s->Substitute );
372 /* MultipleSubstFormat1 */
374 static HB_Error Load_MultipleSubst( HB_GSUB_SubTable* st,
375 HB_Stream stream )
377 HB_Error error;
378 HB_MultipleSubst* ms = &st->multiple;
380 HB_UShort n = 0, m, count;
381 HB_UInt cur_offset, new_offset, base_offset;
383 HB_Sequence* s;
386 base_offset = FILE_Pos();
388 if ( ACCESS_Frame( 4L ) )
389 return error;
391 ms->SubstFormat = GET_UShort(); /* should be 1 */
392 new_offset = GET_UShort() + base_offset;
394 FORGET_Frame();
396 cur_offset = FILE_Pos();
397 if ( FILE_Seek( new_offset ) ||
398 ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
399 return error;
400 (void)FILE_Seek( cur_offset );
402 if ( ACCESS_Frame( 2L ) )
403 goto Fail2;
405 count = ms->SequenceCount = GET_UShort();
407 FORGET_Frame();
409 ms->Sequence = NULL;
411 if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
412 goto Fail2;
414 s = ms->Sequence;
416 for ( n = 0; n < count; n++ )
418 if ( ACCESS_Frame( 2L ) )
419 goto Fail1;
421 new_offset = GET_UShort() + base_offset;
423 FORGET_Frame();
425 cur_offset = FILE_Pos();
426 if ( FILE_Seek( new_offset ) ||
427 ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok )
428 goto Fail1;
429 (void)FILE_Seek( cur_offset );
432 return HB_Err_Ok;
434 Fail1:
435 for ( m = 0; m < n; m++ )
436 Free_Sequence( &s[m] );
438 FREE( s );
440 Fail2:
441 _HB_OPEN_Free_Coverage( &ms->Coverage );
442 return error;
446 static void Free_MultipleSubst( HB_GSUB_SubTable* st )
448 HB_UShort n, count;
449 HB_MultipleSubst* ms = &st->multiple;
451 HB_Sequence* s;
454 if ( ms->Sequence )
456 count = ms->SequenceCount;
457 s = ms->Sequence;
459 for ( n = 0; n < count; n++ )
460 Free_Sequence( &s[n] );
462 FREE( s );
465 _HB_OPEN_Free_Coverage( &ms->Coverage );
469 static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub,
470 HB_GSUB_SubTable* st,
471 HB_Buffer buffer,
472 HB_UShort flags,
473 HB_UShort context_length,
474 int nesting_level )
476 HB_Error error;
477 HB_UShort index, property, n, count;
478 HB_UShort*s;
479 HB_MultipleSubst* ms = &st->multiple;
480 HB_GDEFHeader* gdef = gsub->gdef;
482 HB_UNUSED(nesting_level);
484 if ( context_length != 0xFFFF && context_length < 1 )
485 return HB_Err_Not_Covered;
487 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
488 return error;
490 error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
491 if ( error )
492 return error;
494 if ( index >= ms->SequenceCount )
495 return ERR(HB_Err_Invalid_SubTable);
497 count = ms->Sequence[index].GlyphCount;
498 s = ms->Sequence[index].Substitute;
500 if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
501 return error;
503 if ( gdef && gdef->NewGlyphClasses )
505 /* this is a guess only ... */
507 if ( property == HB_GDEF_LIGATURE )
508 property = HB_GDEF_BASE_GLYPH;
510 for ( n = 0; n < count; n++ )
512 error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
513 if ( error && error != HB_Err_Not_Covered )
514 return error;
518 return HB_Err_Ok;
522 /* LookupType 3 */
524 /* AlternateSet */
526 static HB_Error Load_AlternateSet( HB_AlternateSet* as,
527 HB_Stream stream )
529 HB_Error error;
531 HB_UShort n, count;
532 HB_UShort* a;
535 if ( ACCESS_Frame( 2L ) )
536 return error;
538 count = as->GlyphCount = GET_UShort();
540 FORGET_Frame();
542 as->Alternate = NULL;
544 if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
545 return error;
547 a = as->Alternate;
549 if ( ACCESS_Frame( count * 2L ) )
551 FREE( a );
552 return error;
555 for ( n = 0; n < count; n++ )
556 a[n] = GET_UShort();
558 FORGET_Frame();
560 return HB_Err_Ok;
564 static void Free_AlternateSet( HB_AlternateSet* as )
566 FREE( as->Alternate );
570 /* AlternateSubstFormat1 */
572 static HB_Error Load_AlternateSubst( HB_GSUB_SubTable* st,
573 HB_Stream stream )
575 HB_Error error;
576 HB_AlternateSubst* as = &st->alternate;
578 HB_UShort n = 0, m, count;
579 HB_UInt cur_offset, new_offset, base_offset;
581 HB_AlternateSet* aset;
584 base_offset = FILE_Pos();
586 if ( ACCESS_Frame( 4L ) )
587 return error;
589 as->SubstFormat = GET_UShort(); /* should be 1 */
590 new_offset = GET_UShort() + base_offset;
592 FORGET_Frame();
594 cur_offset = FILE_Pos();
595 if ( FILE_Seek( new_offset ) ||
596 ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
597 return error;
598 (void)FILE_Seek( cur_offset );
600 if ( ACCESS_Frame( 2L ) )
601 goto Fail2;
603 count = as->AlternateSetCount = GET_UShort();
605 FORGET_Frame();
607 as->AlternateSet = NULL;
609 if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
610 goto Fail2;
612 aset = as->AlternateSet;
614 for ( n = 0; n < count; n++ )
616 if ( ACCESS_Frame( 2L ) )
617 goto Fail1;
619 new_offset = GET_UShort() + base_offset;
621 FORGET_Frame();
623 cur_offset = FILE_Pos();
624 if ( FILE_Seek( new_offset ) ||
625 ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
626 goto Fail1;
627 (void)FILE_Seek( cur_offset );
630 return HB_Err_Ok;
632 Fail1:
633 for ( m = 0; m < n; m++ )
634 Free_AlternateSet( &aset[m] );
636 FREE( aset );
638 Fail2:
639 _HB_OPEN_Free_Coverage( &as->Coverage );
640 return error;
644 static void Free_AlternateSubst( HB_GSUB_SubTable* st )
646 HB_UShort n, count;
647 HB_AlternateSubst* as = &st->alternate;
649 HB_AlternateSet* aset;
652 if ( as->AlternateSet )
654 count = as->AlternateSetCount;
655 aset = as->AlternateSet;
657 for ( n = 0; n < count; n++ )
658 Free_AlternateSet( &aset[n] );
660 FREE( aset );
663 _HB_OPEN_Free_Coverage( &as->Coverage );
667 static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub,
668 HB_GSUB_SubTable* st,
669 HB_Buffer buffer,
670 HB_UShort flags,
671 HB_UShort context_length,
672 int nesting_level )
674 HB_Error error;
675 HB_UShort index, value, alt_index, property;
676 HB_AlternateSubst* as = &st->alternate;
677 HB_GDEFHeader* gdef = gsub->gdef;
678 HB_AlternateSet aset;
680 HB_UNUSED(nesting_level);
682 if ( context_length != 0xFFFF && context_length < 1 )
683 return HB_Err_Not_Covered;
685 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
686 return error;
688 error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
689 if ( error )
690 return error;
692 aset = as->AlternateSet[index];
694 /* we use a user-defined callback function to get the alternate index */
696 if ( gsub->altfunc )
697 alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
698 aset.GlyphCount, aset.Alternate,
699 gsub->data );
700 else
701 alt_index = 0;
703 value = aset.Alternate[alt_index];
704 if ( REPLACE_Glyph( buffer, value, nesting_level ) )
705 return error;
707 if ( gdef && gdef->NewGlyphClasses )
709 /* we inherit the old glyph class to the substituted glyph */
711 error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
712 if ( error && error != HB_Err_Not_Covered )
713 return error;
716 return HB_Err_Ok;
720 /* LookupType 4 */
722 /* Ligature */
724 static HB_Error Load_Ligature( HB_Ligature* l,
725 HB_Stream stream )
727 HB_Error error;
729 HB_UShort n, count;
730 HB_UShort* c;
733 if ( ACCESS_Frame( 4L ) )
734 return error;
736 l->LigGlyph = GET_UShort();
737 l->ComponentCount = GET_UShort();
739 FORGET_Frame();
741 l->Component = NULL;
743 count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */
745 if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
746 return error;
748 c = l->Component;
750 if ( ACCESS_Frame( count * 2L ) )
752 FREE( c );
753 return error;
756 for ( n = 0; n < count; n++ )
757 c[n] = GET_UShort();
759 FORGET_Frame();
761 return HB_Err_Ok;
765 static void Free_Ligature( HB_Ligature* l )
767 FREE( l->Component );
771 /* LigatureSet */
773 static HB_Error Load_LigatureSet( HB_LigatureSet* ls,
774 HB_Stream stream )
776 HB_Error error;
778 HB_UShort n = 0, m, count;
779 HB_UInt cur_offset, new_offset, base_offset;
781 HB_Ligature* l;
784 base_offset = FILE_Pos();
786 if ( ACCESS_Frame( 2L ) )
787 return error;
789 count = ls->LigatureCount = GET_UShort();
791 FORGET_Frame();
793 ls->Ligature = NULL;
795 if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
796 return error;
798 l = ls->Ligature;
800 for ( n = 0; n < count; n++ )
802 if ( ACCESS_Frame( 2L ) )
803 goto Fail;
805 new_offset = GET_UShort() + base_offset;
807 FORGET_Frame();
809 cur_offset = FILE_Pos();
810 if ( FILE_Seek( new_offset ) ||
811 ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok )
812 goto Fail;
813 (void)FILE_Seek( cur_offset );
816 return HB_Err_Ok;
818 Fail:
819 for ( m = 0; m < n; m++ )
820 Free_Ligature( &l[m] );
822 FREE( l );
823 return error;
827 static void Free_LigatureSet( HB_LigatureSet* ls )
829 HB_UShort n, count;
831 HB_Ligature* l;
834 if ( ls->Ligature )
836 count = ls->LigatureCount;
837 l = ls->Ligature;
839 for ( n = 0; n < count; n++ )
840 Free_Ligature( &l[n] );
842 FREE( l );
847 /* LigatureSubstFormat1 */
849 static HB_Error Load_LigatureSubst( HB_GSUB_SubTable* st,
850 HB_Stream stream )
852 HB_Error error;
853 HB_LigatureSubst* ls = &st->ligature;
855 HB_UShort n = 0, m, count;
856 HB_UInt cur_offset, new_offset, base_offset;
858 HB_LigatureSet* lset;
861 base_offset = FILE_Pos();
863 if ( ACCESS_Frame( 4L ) )
864 return error;
866 ls->SubstFormat = GET_UShort(); /* should be 1 */
867 new_offset = GET_UShort() + base_offset;
869 FORGET_Frame();
871 cur_offset = FILE_Pos();
872 if ( FILE_Seek( new_offset ) ||
873 ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
874 return error;
875 (void)FILE_Seek( cur_offset );
877 if ( ACCESS_Frame( 2L ) )
878 goto Fail2;
880 count = ls->LigatureSetCount = GET_UShort();
882 FORGET_Frame();
884 ls->LigatureSet = NULL;
886 if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
887 goto Fail2;
889 lset = ls->LigatureSet;
891 for ( n = 0; n < count; n++ )
893 if ( ACCESS_Frame( 2L ) )
894 goto Fail1;
896 new_offset = GET_UShort() + base_offset;
898 FORGET_Frame();
900 cur_offset = FILE_Pos();
901 if ( FILE_Seek( new_offset ) ||
902 ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
903 goto Fail1;
904 (void)FILE_Seek( cur_offset );
907 return HB_Err_Ok;
909 Fail1:
910 for ( m = 0; m < n; m++ )
911 Free_LigatureSet( &lset[m] );
913 FREE( lset );
915 Fail2:
916 _HB_OPEN_Free_Coverage( &ls->Coverage );
917 return error;
921 static void Free_LigatureSubst( HB_GSUB_SubTable* st )
923 HB_UShort n, count;
924 HB_LigatureSubst* ls = &st->ligature;
926 HB_LigatureSet* lset;
929 if ( ls->LigatureSet )
931 count = ls->LigatureSetCount;
932 lset = ls->LigatureSet;
934 for ( n = 0; n < count; n++ )
935 Free_LigatureSet( &lset[n] );
937 FREE( lset );
940 _HB_OPEN_Free_Coverage( &ls->Coverage );
944 static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub,
945 HB_GSUB_SubTable* st,
946 HB_Buffer buffer,
947 HB_UShort flags,
948 HB_UShort context_length,
949 int nesting_level )
951 HB_UShort index, property;
952 HB_Error error;
953 HB_UShort numlig, i, j, is_mark, first_is_mark = FALSE;
954 HB_UShort* c;
955 HB_LigatureSubst* ls = &st->ligature;
956 HB_GDEFHeader* gdef = gsub->gdef;
958 HB_Ligature* lig;
960 HB_UNUSED(nesting_level);
962 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
963 return error;
965 if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
966 first_is_mark = TRUE;
968 error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
969 if ( error )
970 return error;
972 if ( index >= ls->LigatureSetCount )
973 return ERR(HB_Err_Invalid_SubTable);
975 lig = ls->LigatureSet[index].Ligature;
977 for ( numlig = ls->LigatureSet[index].LigatureCount;
978 numlig;
979 numlig--, lig++ )
981 if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
982 goto next_ligature; /* Not enough glyphs in input */
984 c = lig->Component;
986 is_mark = first_is_mark;
988 if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
989 break;
991 for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
993 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
995 if ( error && error != HB_Err_Not_Covered )
996 return error;
998 if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
999 goto next_ligature;
1000 j++;
1003 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
1004 is_mark = FALSE;
1006 if ( IN_GLYPH( j ) != c[i - 1] )
1007 goto next_ligature;
1010 if ( gdef && gdef->NewGlyphClasses )
1012 /* this is just a guess ... */
1014 error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
1015 is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
1016 if ( error && error != HB_Err_Not_Covered )
1017 return error;
1020 if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
1022 /* We don't use a new ligature ID if there are no skipped
1023 glyphs and the ligature already has an ID. */
1025 if ( IN_LIGID( buffer->in_pos ) )
1027 if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
1028 0xFFFF, 0xFFFF ) )
1029 return error;
1031 else
1033 HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
1034 if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
1035 0xFFFF, ligID ) )
1036 return error;
1039 else
1041 HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
1042 if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
1043 return error;
1045 /* Now we must do a second loop to copy the skipped glyphs to
1046 `out' and assign component values to it. We start with the
1047 glyph after the first component. Glyphs between component
1048 i and i+1 belong to component i. Together with the ligID
1049 value it is later possible to check whether a specific
1050 component value really belongs to a given ligature. */
1052 for ( i = 0; i < lig->ComponentCount - 1; i++ )
1054 while ( CHECK_Property( gdef, IN_CURITEM(),
1055 flags, &property ) )
1056 if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
1057 return error;
1059 (buffer->in_pos)++;
1063 return HB_Err_Ok;
1065 next_ligature:
1069 return HB_Err_Not_Covered;
1073 /* Do the actual substitution for a context substitution (either format
1074 5 or 6). This is only called after we've determined that the input
1075 matches the subrule. */
1077 static HB_Error Do_ContextSubst( HB_GSUBHeader* gsub,
1078 HB_UShort GlyphCount,
1079 HB_UShort SubstCount,
1080 HB_SubstLookupRecord* subst,
1081 HB_Buffer buffer,
1082 int nesting_level )
1084 HB_Error error;
1085 HB_UInt i, old_pos;
1088 i = 0;
1090 while ( i < GlyphCount )
1092 if ( SubstCount && i == subst->SequenceIndex )
1094 old_pos = buffer->in_pos;
1096 /* Do a substitution */
1098 error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
1099 GlyphCount, nesting_level );
1101 subst++;
1102 SubstCount--;
1103 i += buffer->in_pos - old_pos;
1105 if ( error == HB_Err_Not_Covered )
1107 if ( COPY_Glyph( buffer ) )
1108 return error;
1109 i++;
1111 else if ( error )
1112 return error;
1114 else
1116 /* No substitution for this index */
1118 if ( COPY_Glyph( buffer ) )
1119 return error;
1120 i++;
1124 return HB_Err_Ok;
1128 /* LookupType 5 */
1130 /* SubRule */
1132 static HB_Error Load_SubRule( HB_SubRule* sr,
1133 HB_Stream stream )
1135 HB_Error error;
1137 HB_UShort n, count;
1138 HB_UShort* i;
1140 HB_SubstLookupRecord* slr;
1143 if ( ACCESS_Frame( 4L ) )
1144 return error;
1146 sr->GlyphCount = GET_UShort();
1147 sr->SubstCount = GET_UShort();
1149 FORGET_Frame();
1151 sr->Input = NULL;
1153 count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */
1155 if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
1156 return error;
1158 i = sr->Input;
1160 if ( ACCESS_Frame( count * 2L ) )
1161 goto Fail2;
1163 for ( n = 0; n < count; n++ )
1164 i[n] = GET_UShort();
1166 FORGET_Frame();
1168 sr->SubstLookupRecord = NULL;
1170 count = sr->SubstCount;
1172 if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
1173 goto Fail2;
1175 slr = sr->SubstLookupRecord;
1177 if ( ACCESS_Frame( count * 4L ) )
1178 goto Fail1;
1180 for ( n = 0; n < count; n++ )
1182 slr[n].SequenceIndex = GET_UShort();
1183 slr[n].LookupListIndex = GET_UShort();
1186 FORGET_Frame();
1188 return HB_Err_Ok;
1190 Fail1:
1191 FREE( slr );
1193 Fail2:
1194 FREE( i );
1195 return error;
1199 static void Free_SubRule( HB_SubRule* sr )
1201 FREE( sr->SubstLookupRecord );
1202 FREE( sr->Input );
1206 /* SubRuleSet */
1208 static HB_Error Load_SubRuleSet( HB_SubRuleSet* srs,
1209 HB_Stream stream )
1211 HB_Error error;
1213 HB_UShort n = 0, m, count;
1214 HB_UInt cur_offset, new_offset, base_offset;
1216 HB_SubRule* sr;
1219 base_offset = FILE_Pos();
1221 if ( ACCESS_Frame( 2L ) )
1222 return error;
1224 count = srs->SubRuleCount = GET_UShort();
1226 FORGET_Frame();
1228 srs->SubRule = NULL;
1230 if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
1231 return error;
1233 sr = srs->SubRule;
1235 for ( n = 0; n < count; n++ )
1237 if ( ACCESS_Frame( 2L ) )
1238 goto Fail;
1240 new_offset = GET_UShort() + base_offset;
1242 FORGET_Frame();
1244 cur_offset = FILE_Pos();
1245 if ( FILE_Seek( new_offset ) ||
1246 ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
1247 goto Fail;
1248 (void)FILE_Seek( cur_offset );
1251 return HB_Err_Ok;
1253 Fail:
1254 for ( m = 0; m < n; m++ )
1255 Free_SubRule( &sr[m] );
1257 FREE( sr );
1258 return error;
1262 static void Free_SubRuleSet( HB_SubRuleSet* srs )
1264 HB_UShort n, count;
1266 HB_SubRule* sr;
1269 if ( srs->SubRule )
1271 count = srs->SubRuleCount;
1272 sr = srs->SubRule;
1274 for ( n = 0; n < count; n++ )
1275 Free_SubRule( &sr[n] );
1277 FREE( sr );
1282 /* ContextSubstFormat1 */
1284 static HB_Error Load_ContextSubst1( HB_ContextSubstFormat1* csf1,
1285 HB_Stream stream )
1287 HB_Error error;
1289 HB_UShort n = 0, m, count;
1290 HB_UInt cur_offset, new_offset, base_offset;
1292 HB_SubRuleSet* srs;
1295 base_offset = FILE_Pos() - 2L;
1297 if ( ACCESS_Frame( 2L ) )
1298 return error;
1300 new_offset = GET_UShort() + base_offset;
1302 FORGET_Frame();
1304 cur_offset = FILE_Pos();
1305 if ( FILE_Seek( new_offset ) ||
1306 ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok )
1307 return error;
1308 (void)FILE_Seek( cur_offset );
1310 if ( ACCESS_Frame( 2L ) )
1311 goto Fail2;
1313 count = csf1->SubRuleSetCount = GET_UShort();
1315 FORGET_Frame();
1317 csf1->SubRuleSet = NULL;
1319 if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
1320 goto Fail2;
1322 srs = csf1->SubRuleSet;
1324 for ( n = 0; n < count; n++ )
1326 if ( ACCESS_Frame( 2L ) )
1327 goto Fail1;
1329 new_offset = GET_UShort() + base_offset;
1331 FORGET_Frame();
1333 cur_offset = FILE_Pos();
1334 if ( FILE_Seek( new_offset ) ||
1335 ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
1336 goto Fail1;
1337 (void)FILE_Seek( cur_offset );
1340 return HB_Err_Ok;
1342 Fail1:
1343 for ( m = 0; m < n; m++ )
1344 Free_SubRuleSet( &srs[m] );
1346 FREE( srs );
1348 Fail2:
1349 _HB_OPEN_Free_Coverage( &csf1->Coverage );
1350 return error;
1354 static void Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
1356 HB_UShort n, count;
1358 HB_SubRuleSet* srs;
1361 if ( csf1->SubRuleSet )
1363 count = csf1->SubRuleSetCount;
1364 srs = csf1->SubRuleSet;
1366 for ( n = 0; n < count; n++ )
1367 Free_SubRuleSet( &srs[n] );
1369 FREE( srs );
1372 _HB_OPEN_Free_Coverage( &csf1->Coverage );
1376 /* SubClassRule */
1378 static HB_Error Load_SubClassRule( HB_ContextSubstFormat2* csf2,
1379 HB_SubClassRule* scr,
1380 HB_Stream stream )
1382 HB_Error error;
1384 HB_UShort n, count;
1386 HB_UShort* c;
1387 HB_SubstLookupRecord* slr;
1390 if ( ACCESS_Frame( 4L ) )
1391 return error;
1393 scr->GlyphCount = GET_UShort();
1394 scr->SubstCount = GET_UShort();
1396 if ( scr->GlyphCount > csf2->MaxContextLength )
1397 csf2->MaxContextLength = scr->GlyphCount;
1399 FORGET_Frame();
1401 scr->Class = NULL;
1403 count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */
1405 if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
1406 return error;
1408 c = scr->Class;
1410 if ( ACCESS_Frame( count * 2L ) )
1411 goto Fail2;
1413 for ( n = 0; n < count; n++ )
1414 c[n] = GET_UShort();
1416 FORGET_Frame();
1418 scr->SubstLookupRecord = NULL;
1420 count = scr->SubstCount;
1422 if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
1423 goto Fail2;
1425 slr = scr->SubstLookupRecord;
1427 if ( ACCESS_Frame( count * 4L ) )
1428 goto Fail1;
1430 for ( n = 0; n < count; n++ )
1432 slr[n].SequenceIndex = GET_UShort();
1433 slr[n].LookupListIndex = GET_UShort();
1436 FORGET_Frame();
1438 return HB_Err_Ok;
1440 Fail1:
1441 FREE( slr );
1443 Fail2:
1444 FREE( c );
1445 return error;
1449 static void Free_SubClassRule( HB_SubClassRule* scr )
1451 FREE( scr->SubstLookupRecord );
1452 FREE( scr->Class );
1456 /* SubClassSet */
1458 static HB_Error Load_SubClassSet( HB_ContextSubstFormat2* csf2,
1459 HB_SubClassSet* scs,
1460 HB_Stream stream )
1462 HB_Error error;
1464 HB_UShort n = 0, m, count;
1465 HB_UInt cur_offset, new_offset, base_offset;
1467 HB_SubClassRule* scr;
1470 base_offset = FILE_Pos();
1472 if ( ACCESS_Frame( 2L ) )
1473 return error;
1475 count = scs->SubClassRuleCount = GET_UShort();
1477 FORGET_Frame();
1479 scs->SubClassRule = NULL;
1481 if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
1482 return error;
1484 scr = scs->SubClassRule;
1486 for ( n = 0; n < count; n++ )
1488 if ( ACCESS_Frame( 2L ) )
1489 goto Fail;
1491 new_offset = GET_UShort() + base_offset;
1493 FORGET_Frame();
1495 cur_offset = FILE_Pos();
1496 if ( FILE_Seek( new_offset ) ||
1497 ( error = Load_SubClassRule( csf2, &scr[n],
1498 stream ) ) != HB_Err_Ok )
1499 goto Fail;
1500 (void)FILE_Seek( cur_offset );
1503 return HB_Err_Ok;
1505 Fail:
1506 for ( m = 0; m < n; m++ )
1507 Free_SubClassRule( &scr[m] );
1509 FREE( scr );
1510 return error;
1514 static void Free_SubClassSet( HB_SubClassSet* scs )
1516 HB_UShort n, count;
1518 HB_SubClassRule* scr;
1521 if ( scs->SubClassRule )
1523 count = scs->SubClassRuleCount;
1524 scr = scs->SubClassRule;
1526 for ( n = 0; n < count; n++ )
1527 Free_SubClassRule( &scr[n] );
1529 FREE( scr );
1534 /* ContextSubstFormat2 */
1536 static HB_Error Load_ContextSubst2( HB_ContextSubstFormat2* csf2,
1537 HB_Stream stream )
1539 HB_Error error;
1541 HB_UShort n = 0, m, count;
1542 HB_UInt cur_offset, new_offset, base_offset;
1544 HB_SubClassSet* scs;
1547 base_offset = FILE_Pos() - 2;
1549 if ( ACCESS_Frame( 2L ) )
1550 return error;
1552 new_offset = GET_UShort() + base_offset;
1554 FORGET_Frame();
1556 cur_offset = FILE_Pos();
1557 if ( FILE_Seek( new_offset ) ||
1558 ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
1559 return error;
1560 (void)FILE_Seek( cur_offset );
1562 if ( ACCESS_Frame( 4L ) )
1563 goto Fail3;
1565 new_offset = GET_UShort() + base_offset;
1567 /* `SubClassSetCount' is the upper limit for class values, thus we
1568 read it now to make an additional safety check. */
1570 count = csf2->SubClassSetCount = GET_UShort();
1572 FORGET_Frame();
1574 cur_offset = FILE_Pos();
1575 if ( FILE_Seek( new_offset ) ||
1576 ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
1577 stream ) ) != HB_Err_Ok )
1578 goto Fail3;
1579 (void)FILE_Seek( cur_offset );
1581 csf2->SubClassSet = NULL;
1582 csf2->MaxContextLength = 0;
1584 if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
1585 goto Fail2;
1587 scs = csf2->SubClassSet;
1589 for ( n = 0; n < count; n++ )
1591 if ( ACCESS_Frame( 2L ) )
1592 goto Fail1;
1594 new_offset = GET_UShort() + base_offset;
1596 FORGET_Frame();
1598 if ( new_offset != base_offset ) /* not a NULL offset */
1600 cur_offset = FILE_Pos();
1601 if ( FILE_Seek( new_offset ) ||
1602 ( error = Load_SubClassSet( csf2, &scs[n],
1603 stream ) ) != HB_Err_Ok )
1604 goto Fail1;
1605 (void)FILE_Seek( cur_offset );
1607 else
1609 /* we create a SubClassSet table with no entries */
1611 csf2->SubClassSet[n].SubClassRuleCount = 0;
1612 csf2->SubClassSet[n].SubClassRule = NULL;
1616 return HB_Err_Ok;
1618 Fail1:
1619 for ( m = 0; m < n; m++ )
1620 Free_SubClassSet( &scs[m] );
1622 FREE( scs );
1624 Fail2:
1625 _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1627 Fail3:
1628 _HB_OPEN_Free_Coverage( &csf2->Coverage );
1629 return error;
1633 static void Free_ContextSubst2( HB_ContextSubstFormat2* csf2 )
1635 HB_UShort n, count;
1637 HB_SubClassSet* scs;
1640 if ( csf2->SubClassSet )
1642 count = csf2->SubClassSetCount;
1643 scs = csf2->SubClassSet;
1645 for ( n = 0; n < count; n++ )
1646 Free_SubClassSet( &scs[n] );
1648 FREE( scs );
1651 _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1652 _HB_OPEN_Free_Coverage( &csf2->Coverage );
1656 /* ContextSubstFormat3 */
1658 static HB_Error Load_ContextSubst3( HB_ContextSubstFormat3* csf3,
1659 HB_Stream stream )
1661 HB_Error error;
1663 HB_UShort n = 0, m, count;
1664 HB_UInt cur_offset, new_offset, base_offset;
1666 HB_Coverage* c;
1667 HB_SubstLookupRecord* slr;
1670 base_offset = FILE_Pos() - 2L;
1672 if ( ACCESS_Frame( 4L ) )
1673 return error;
1675 csf3->GlyphCount = GET_UShort();
1676 csf3->SubstCount = GET_UShort();
1678 FORGET_Frame();
1680 csf3->Coverage = NULL;
1682 count = csf3->GlyphCount;
1684 if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
1685 return error;
1687 c = csf3->Coverage;
1689 for ( n = 0; n < count; n++ )
1691 if ( ACCESS_Frame( 2L ) )
1692 goto Fail2;
1694 new_offset = GET_UShort() + base_offset;
1696 FORGET_Frame();
1698 cur_offset = FILE_Pos();
1699 if ( FILE_Seek( new_offset ) ||
1700 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
1701 goto Fail2;
1702 (void)FILE_Seek( cur_offset );
1705 csf3->SubstLookupRecord = NULL;
1707 count = csf3->SubstCount;
1709 if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
1710 HB_SubstLookupRecord ) )
1711 goto Fail2;
1713 slr = csf3->SubstLookupRecord;
1715 if ( ACCESS_Frame( count * 4L ) )
1716 goto Fail1;
1718 for ( n = 0; n < count; n++ )
1720 slr[n].SequenceIndex = GET_UShort();
1721 slr[n].LookupListIndex = GET_UShort();
1724 FORGET_Frame();
1726 return HB_Err_Ok;
1728 Fail1:
1729 FREE( slr );
1731 Fail2:
1732 for ( m = 0; m < n; m++ )
1733 _HB_OPEN_Free_Coverage( &c[m] );
1735 FREE( c );
1736 return error;
1740 static void Free_ContextSubst3( HB_ContextSubstFormat3* csf3 )
1742 HB_UShort n, count;
1744 HB_Coverage* c;
1747 FREE( csf3->SubstLookupRecord );
1749 if ( csf3->Coverage )
1751 count = csf3->GlyphCount;
1752 c = csf3->Coverage;
1754 for ( n = 0; n < count; n++ )
1755 _HB_OPEN_Free_Coverage( &c[n] );
1757 FREE( c );
1762 /* ContextSubst */
1764 static HB_Error Load_ContextSubst( HB_GSUB_SubTable* st,
1765 HB_Stream stream )
1767 HB_Error error;
1768 HB_ContextSubst* cs = &st->context;
1771 if ( ACCESS_Frame( 2L ) )
1772 return error;
1774 cs->SubstFormat = GET_UShort();
1776 FORGET_Frame();
1778 switch ( cs->SubstFormat )
1780 case 1: return Load_ContextSubst1( &cs->csf.csf1, stream );
1781 case 2: return Load_ContextSubst2( &cs->csf.csf2, stream );
1782 case 3: return Load_ContextSubst3( &cs->csf.csf3, stream );
1783 default: return ERR(HB_Err_Invalid_SubTable_Format);
1786 return HB_Err_Ok; /* never reached */
1790 static void Free_ContextSubst( HB_GSUB_SubTable* st )
1792 HB_ContextSubst* cs = &st->context;
1794 switch ( cs->SubstFormat )
1796 case 1: Free_ContextSubst1( &cs->csf.csf1 ); break;
1797 case 2: Free_ContextSubst2( &cs->csf.csf2 ); break;
1798 case 3: Free_ContextSubst3( &cs->csf.csf3 ); break;
1799 default: break;
1804 static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub,
1805 HB_ContextSubstFormat1* csf1,
1806 HB_Buffer buffer,
1807 HB_UShort flags,
1808 HB_UShort context_length,
1809 int nesting_level )
1811 HB_UShort index, property;
1812 HB_UShort i, j, k, numsr;
1813 HB_Error error;
1815 HB_SubRule* sr;
1816 HB_GDEFHeader* gdef;
1819 gdef = gsub->gdef;
1821 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1822 return error;
1824 error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
1825 if ( error )
1826 return error;
1828 sr = csf1->SubRuleSet[index].SubRule;
1829 numsr = csf1->SubRuleSet[index].SubRuleCount;
1831 for ( k = 0; k < numsr; k++ )
1833 if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
1834 goto next_subrule;
1836 if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
1837 goto next_subrule; /* context is too long */
1839 for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
1841 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1843 if ( error && error != HB_Err_Not_Covered )
1844 return error;
1846 if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
1847 goto next_subrule;
1848 j++;
1851 if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
1852 goto next_subrule;
1855 return Do_ContextSubst( gsub, sr[k].GlyphCount,
1856 sr[k].SubstCount, sr[k].SubstLookupRecord,
1857 buffer,
1858 nesting_level );
1859 next_subrule:
1863 return HB_Err_Not_Covered;
1867 static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub,
1868 HB_ContextSubstFormat2* csf2,
1869 HB_Buffer buffer,
1870 HB_UShort flags,
1871 HB_UShort context_length,
1872 int nesting_level )
1874 HB_UShort index, property;
1875 HB_Error error;
1876 HB_UShort i, j, k, known_classes;
1878 HB_UShort* classes;
1879 HB_UShort* cl;
1881 HB_SubClassSet* scs;
1882 HB_SubClassRule* sr;
1883 HB_GDEFHeader* gdef;
1886 gdef = gsub->gdef;
1888 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1889 return error;
1891 /* Note: The coverage table in format 2 doesn't give an index into
1892 anything. It just lets us know whether or not we need to
1893 do any lookup at all. */
1895 error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
1896 if ( error )
1897 return error;
1899 if (csf2->MaxContextLength < 1)
1900 return HB_Err_Not_Covered;
1902 if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
1903 return error;
1905 error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
1906 &classes[0], NULL );
1907 if ( error && error != HB_Err_Not_Covered )
1908 goto End;
1909 known_classes = 0;
1911 scs = &csf2->SubClassSet[classes[0]];
1912 if ( !scs )
1914 error = ERR(HB_Err_Invalid_SubTable);
1915 goto End;
1918 for ( k = 0; k < scs->SubClassRuleCount; k++ )
1920 sr = &scs->SubClassRule[k];
1922 if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
1923 goto next_subclassrule;
1925 if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
1926 goto next_subclassrule; /* context is too long */
1928 cl = sr->Class;
1930 /* Start at 1 because [0] is implied */
1932 for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
1934 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1936 if ( error && error != HB_Err_Not_Covered )
1937 goto End;
1939 if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
1940 goto next_subclassrule;
1941 j++;
1944 if ( i > known_classes )
1946 /* Keeps us from having to do this for each rule */
1948 error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
1949 if ( error && error != HB_Err_Not_Covered )
1950 goto End;
1951 known_classes = i;
1954 if ( cl[i - 1] != classes[i] )
1955 goto next_subclassrule;
1958 error = Do_ContextSubst( gsub, sr->GlyphCount,
1959 sr->SubstCount, sr->SubstLookupRecord,
1960 buffer,
1961 nesting_level );
1962 goto End;
1964 next_subclassrule:
1968 error = HB_Err_Not_Covered;
1970 End:
1971 FREE( classes );
1972 return error;
1976 static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub,
1977 HB_ContextSubstFormat3* csf3,
1978 HB_Buffer buffer,
1979 HB_UShort flags,
1980 HB_UShort context_length,
1981 int nesting_level )
1983 HB_Error error;
1984 HB_UShort index, i, j, property;
1986 HB_Coverage* c;
1987 HB_GDEFHeader* gdef;
1990 gdef = gsub->gdef;
1992 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1993 return error;
1995 if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
1996 return HB_Err_Not_Covered;
1998 if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
1999 return HB_Err_Not_Covered; /* context is too long */
2001 c = csf3->Coverage;
2003 for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
2005 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
2007 if ( error && error != HB_Err_Not_Covered )
2008 return error;
2010 if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
2011 return HB_Err_Not_Covered;
2012 j++;
2015 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
2016 if ( error )
2017 return error;
2020 return Do_ContextSubst( gsub, csf3->GlyphCount,
2021 csf3->SubstCount, csf3->SubstLookupRecord,
2022 buffer,
2023 nesting_level );
2027 static HB_Error Lookup_ContextSubst( HB_GSUBHeader* gsub,
2028 HB_GSUB_SubTable* st,
2029 HB_Buffer buffer,
2030 HB_UShort flags,
2031 HB_UShort context_length,
2032 int nesting_level )
2034 HB_ContextSubst* cs = &st->context;
2036 switch ( cs->SubstFormat )
2038 case 1: return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
2039 case 2: return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
2040 case 3: return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
2041 default: return ERR(HB_Err_Invalid_SubTable_Format);
2044 return HB_Err_Ok; /* never reached */
2048 /* LookupType 6 */
2050 /* ChainSubRule */
2052 static HB_Error Load_ChainSubRule( HB_ChainSubRule* csr,
2053 HB_Stream stream )
2055 HB_Error error;
2057 HB_UShort n, count;
2058 HB_UShort* b;
2059 HB_UShort* i;
2060 HB_UShort* l;
2062 HB_SubstLookupRecord* slr;
2065 if ( ACCESS_Frame( 2L ) )
2066 return error;
2068 csr->BacktrackGlyphCount = GET_UShort();
2070 FORGET_Frame();
2072 csr->Backtrack = NULL;
2074 count = csr->BacktrackGlyphCount;
2076 if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
2077 return error;
2079 b = csr->Backtrack;
2081 if ( ACCESS_Frame( count * 2L ) )
2082 goto Fail4;
2084 for ( n = 0; n < count; n++ )
2085 b[n] = GET_UShort();
2087 FORGET_Frame();
2089 if ( ACCESS_Frame( 2L ) )
2090 goto Fail4;
2092 csr->InputGlyphCount = GET_UShort();
2094 FORGET_Frame();
2096 csr->Input = NULL;
2098 count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2100 if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
2101 goto Fail4;
2103 i = csr->Input;
2105 if ( ACCESS_Frame( count * 2L ) )
2106 goto Fail3;
2108 for ( n = 0; n < count; n++ )
2109 i[n] = GET_UShort();
2111 FORGET_Frame();
2113 if ( ACCESS_Frame( 2L ) )
2114 goto Fail3;
2116 csr->LookaheadGlyphCount = GET_UShort();
2118 FORGET_Frame();
2120 csr->Lookahead = NULL;
2122 count = csr->LookaheadGlyphCount;
2124 if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
2125 goto Fail3;
2127 l = csr->Lookahead;
2129 if ( ACCESS_Frame( count * 2L ) )
2130 goto Fail2;
2132 for ( n = 0; n < count; n++ )
2133 l[n] = GET_UShort();
2135 FORGET_Frame();
2137 if ( ACCESS_Frame( 2L ) )
2138 goto Fail2;
2140 csr->SubstCount = GET_UShort();
2142 FORGET_Frame();
2144 csr->SubstLookupRecord = NULL;
2146 count = csr->SubstCount;
2148 if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
2149 goto Fail2;
2151 slr = csr->SubstLookupRecord;
2153 if ( ACCESS_Frame( count * 4L ) )
2154 goto Fail1;
2156 for ( n = 0; n < count; n++ )
2158 slr[n].SequenceIndex = GET_UShort();
2159 slr[n].LookupListIndex = GET_UShort();
2162 FORGET_Frame();
2164 return HB_Err_Ok;
2166 Fail1:
2167 FREE( slr );
2169 Fail2:
2170 FREE( l );
2172 Fail3:
2173 FREE( i );
2175 Fail4:
2176 FREE( b );
2177 return error;
2181 static void Free_ChainSubRule( HB_ChainSubRule* csr )
2183 FREE( csr->SubstLookupRecord );
2184 FREE( csr->Lookahead );
2185 FREE( csr->Input );
2186 FREE( csr->Backtrack );
2190 /* ChainSubRuleSet */
2192 static HB_Error Load_ChainSubRuleSet( HB_ChainSubRuleSet* csrs,
2193 HB_Stream stream )
2195 HB_Error error;
2197 HB_UShort n = 0, m, count;
2198 HB_UInt cur_offset, new_offset, base_offset;
2200 HB_ChainSubRule* csr;
2203 base_offset = FILE_Pos();
2205 if ( ACCESS_Frame( 2L ) )
2206 return error;
2208 count = csrs->ChainSubRuleCount = GET_UShort();
2210 FORGET_Frame();
2212 csrs->ChainSubRule = NULL;
2214 if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
2215 return error;
2217 csr = csrs->ChainSubRule;
2219 for ( n = 0; n < count; n++ )
2221 if ( ACCESS_Frame( 2L ) )
2222 goto Fail;
2224 new_offset = GET_UShort() + base_offset;
2226 FORGET_Frame();
2228 cur_offset = FILE_Pos();
2229 if ( FILE_Seek( new_offset ) ||
2230 ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
2231 goto Fail;
2232 (void)FILE_Seek( cur_offset );
2235 return HB_Err_Ok;
2237 Fail:
2238 for ( m = 0; m < n; m++ )
2239 Free_ChainSubRule( &csr[m] );
2241 FREE( csr );
2242 return error;
2246 static void Free_ChainSubRuleSet( HB_ChainSubRuleSet* csrs )
2248 HB_UShort n, count;
2250 HB_ChainSubRule* csr;
2253 if ( csrs->ChainSubRule )
2255 count = csrs->ChainSubRuleCount;
2256 csr = csrs->ChainSubRule;
2258 for ( n = 0; n < count; n++ )
2259 Free_ChainSubRule( &csr[n] );
2261 FREE( csr );
2266 /* ChainContextSubstFormat1 */
2268 static HB_Error Load_ChainContextSubst1(
2269 HB_ChainContextSubstFormat1* ccsf1,
2270 HB_Stream stream )
2272 HB_Error error;
2274 HB_UShort n = 0, m, count;
2275 HB_UInt cur_offset, new_offset, base_offset;
2277 HB_ChainSubRuleSet* csrs;
2280 base_offset = FILE_Pos() - 2L;
2282 if ( ACCESS_Frame( 2L ) )
2283 return error;
2285 new_offset = GET_UShort() + base_offset;
2287 FORGET_Frame();
2289 cur_offset = FILE_Pos();
2290 if ( FILE_Seek( new_offset ) ||
2291 ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
2292 return error;
2293 (void)FILE_Seek( cur_offset );
2295 if ( ACCESS_Frame( 2L ) )
2296 goto Fail2;
2298 count = ccsf1->ChainSubRuleSetCount = GET_UShort();
2300 FORGET_Frame();
2302 ccsf1->ChainSubRuleSet = NULL;
2304 if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
2305 goto Fail2;
2307 csrs = ccsf1->ChainSubRuleSet;
2309 for ( n = 0; n < count; n++ )
2311 if ( ACCESS_Frame( 2L ) )
2312 goto Fail1;
2314 new_offset = GET_UShort() + base_offset;
2316 FORGET_Frame();
2318 cur_offset = FILE_Pos();
2319 if ( FILE_Seek( new_offset ) ||
2320 ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
2321 goto Fail1;
2322 (void)FILE_Seek( cur_offset );
2325 return HB_Err_Ok;
2327 Fail1:
2328 for ( m = 0; m < n; m++ )
2329 Free_ChainSubRuleSet( &csrs[m] );
2331 FREE( csrs );
2333 Fail2:
2334 _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2335 return error;
2339 static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1* ccsf1 )
2341 HB_UShort n, count;
2343 HB_ChainSubRuleSet* csrs;
2346 if ( ccsf1->ChainSubRuleSet )
2348 count = ccsf1->ChainSubRuleSetCount;
2349 csrs = ccsf1->ChainSubRuleSet;
2351 for ( n = 0; n < count; n++ )
2352 Free_ChainSubRuleSet( &csrs[n] );
2354 FREE( csrs );
2357 _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2361 /* ChainSubClassRule */
2363 static HB_Error Load_ChainSubClassRule(
2364 HB_ChainContextSubstFormat2* ccsf2,
2365 HB_ChainSubClassRule* cscr,
2366 HB_Stream stream )
2368 HB_Error error;
2370 HB_UShort n, count;
2372 HB_UShort* b;
2373 HB_UShort* i;
2374 HB_UShort* l;
2375 HB_SubstLookupRecord* slr;
2378 if ( ACCESS_Frame( 2L ) )
2379 return error;
2381 cscr->BacktrackGlyphCount = GET_UShort();
2383 FORGET_Frame();
2385 if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
2386 ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
2388 cscr->Backtrack = NULL;
2390 count = cscr->BacktrackGlyphCount;
2392 if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
2393 return error;
2395 b = cscr->Backtrack;
2397 if ( ACCESS_Frame( count * 2L ) )
2398 goto Fail4;
2400 for ( n = 0; n < count; n++ )
2401 b[n] = GET_UShort();
2403 FORGET_Frame();
2405 if ( ACCESS_Frame( 2L ) )
2406 goto Fail4;
2408 cscr->InputGlyphCount = GET_UShort();
2410 FORGET_Frame();
2412 if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
2413 ccsf2->MaxInputLength = cscr->InputGlyphCount;
2415 cscr->Input = NULL;
2417 count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2419 if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
2420 goto Fail4;
2422 i = cscr->Input;
2424 if ( ACCESS_Frame( count * 2L ) )
2425 goto Fail3;
2427 for ( n = 0; n < count; n++ )
2428 i[n] = GET_UShort();
2430 FORGET_Frame();
2432 if ( ACCESS_Frame( 2L ) )
2433 goto Fail3;
2435 cscr->LookaheadGlyphCount = GET_UShort();
2437 FORGET_Frame();
2439 if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
2440 ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
2442 cscr->Lookahead = NULL;
2444 count = cscr->LookaheadGlyphCount;
2446 if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
2447 goto Fail3;
2449 l = cscr->Lookahead;
2451 if ( ACCESS_Frame( count * 2L ) )
2452 goto Fail2;
2454 for ( n = 0; n < count; n++ )
2455 l[n] = GET_UShort();
2457 FORGET_Frame();
2459 if ( ACCESS_Frame( 2L ) )
2460 goto Fail2;
2462 cscr->SubstCount = GET_UShort();
2464 FORGET_Frame();
2466 cscr->SubstLookupRecord = NULL;
2468 count = cscr->SubstCount;
2470 if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
2471 HB_SubstLookupRecord ) )
2472 goto Fail2;
2474 slr = cscr->SubstLookupRecord;
2476 if ( ACCESS_Frame( count * 4L ) )
2477 goto Fail1;
2479 for ( n = 0; n < count; n++ )
2481 slr[n].SequenceIndex = GET_UShort();
2482 slr[n].LookupListIndex = GET_UShort();
2485 FORGET_Frame();
2487 return HB_Err_Ok;
2489 Fail1:
2490 FREE( slr );
2492 Fail2:
2493 FREE( l );
2495 Fail3:
2496 FREE( i );
2498 Fail4:
2499 FREE( b );
2500 return error;
2504 static void Free_ChainSubClassRule( HB_ChainSubClassRule* cscr )
2506 FREE( cscr->SubstLookupRecord );
2507 FREE( cscr->Lookahead );
2508 FREE( cscr->Input );
2509 FREE( cscr->Backtrack );
2513 /* SubClassSet */
2515 static HB_Error Load_ChainSubClassSet(
2516 HB_ChainContextSubstFormat2* ccsf2,
2517 HB_ChainSubClassSet* cscs,
2518 HB_Stream stream )
2520 HB_Error error;
2522 HB_UShort n = 0, m, count;
2523 HB_UInt cur_offset, new_offset, base_offset;
2525 HB_ChainSubClassRule* cscr;
2528 base_offset = FILE_Pos();
2530 if ( ACCESS_Frame( 2L ) )
2531 return error;
2533 count = cscs->ChainSubClassRuleCount = GET_UShort();
2535 FORGET_Frame();
2537 cscs->ChainSubClassRule = NULL;
2539 if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
2540 HB_ChainSubClassRule ) )
2541 return error;
2543 cscr = cscs->ChainSubClassRule;
2545 for ( n = 0; n < count; n++ )
2547 if ( ACCESS_Frame( 2L ) )
2548 goto Fail;
2550 new_offset = GET_UShort() + base_offset;
2552 FORGET_Frame();
2554 cur_offset = FILE_Pos();
2555 if ( FILE_Seek( new_offset ) ||
2556 ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
2557 stream ) ) != HB_Err_Ok )
2558 goto Fail;
2559 (void)FILE_Seek( cur_offset );
2562 return HB_Err_Ok;
2564 Fail:
2565 for ( m = 0; m < n; m++ )
2566 Free_ChainSubClassRule( &cscr[m] );
2568 FREE( cscr );
2569 return error;
2573 static void Free_ChainSubClassSet( HB_ChainSubClassSet* cscs )
2575 HB_UShort n, count;
2577 HB_ChainSubClassRule* cscr;
2580 if ( cscs->ChainSubClassRule )
2582 count = cscs->ChainSubClassRuleCount;
2583 cscr = cscs->ChainSubClassRule;
2585 for ( n = 0; n < count; n++ )
2586 Free_ChainSubClassRule( &cscr[n] );
2588 FREE( cscr );
2593 /* ChainContextSubstFormat2 */
2595 static HB_Error Load_ChainContextSubst2(
2596 HB_ChainContextSubstFormat2* ccsf2,
2597 HB_Stream stream )
2599 HB_Error error;
2601 HB_UShort n = 0, m, count;
2602 HB_UInt cur_offset, new_offset, base_offset;
2603 HB_UInt backtrack_offset, input_offset, lookahead_offset;
2605 HB_ChainSubClassSet* cscs;
2608 base_offset = FILE_Pos() - 2;
2610 if ( ACCESS_Frame( 2L ) )
2611 return error;
2613 new_offset = GET_UShort() + base_offset;
2615 FORGET_Frame();
2617 cur_offset = FILE_Pos();
2618 if ( FILE_Seek( new_offset ) ||
2619 ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
2620 return error;
2621 (void)FILE_Seek( cur_offset );
2623 if ( ACCESS_Frame( 8L ) )
2624 goto Fail5;
2626 backtrack_offset = GET_UShort();
2627 input_offset = GET_UShort();
2628 lookahead_offset = GET_UShort();
2630 /* `ChainSubClassSetCount' is the upper limit for input class values,
2631 thus we read it now to make an additional safety check. No limit
2632 is known or needed for the other two class definitions */
2634 count = ccsf2->ChainSubClassSetCount = GET_UShort();
2636 FORGET_Frame();
2638 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
2639 backtrack_offset, base_offset,
2640 stream ) ) != HB_Err_Ok )
2641 goto Fail5;
2643 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
2644 input_offset, base_offset,
2645 stream ) ) != HB_Err_Ok )
2646 goto Fail4;
2647 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
2648 lookahead_offset, base_offset,
2649 stream ) ) != HB_Err_Ok )
2650 goto Fail3;
2652 ccsf2->ChainSubClassSet = NULL;
2653 ccsf2->MaxBacktrackLength = 0;
2654 ccsf2->MaxInputLength = 0;
2655 ccsf2->MaxLookaheadLength = 0;
2657 if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
2658 goto Fail2;
2660 cscs = ccsf2->ChainSubClassSet;
2662 for ( n = 0; n < count; n++ )
2664 if ( ACCESS_Frame( 2L ) )
2665 goto Fail1;
2667 new_offset = GET_UShort() + base_offset;
2669 FORGET_Frame();
2671 if ( new_offset != base_offset ) /* not a NULL offset */
2673 cur_offset = FILE_Pos();
2674 if ( FILE_Seek( new_offset ) ||
2675 ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
2676 stream ) ) != HB_Err_Ok )
2677 goto Fail1;
2678 (void)FILE_Seek( cur_offset );
2680 else
2682 /* we create a ChainSubClassSet table with no entries */
2684 ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
2685 ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL;
2689 return HB_Err_Ok;
2691 Fail1:
2692 for ( m = 0; m < n; m++ )
2693 Free_ChainSubClassSet( &cscs[m] );
2695 FREE( cscs );
2697 Fail2:
2698 _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2700 Fail3:
2701 _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2703 Fail4:
2704 _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2706 Fail5:
2707 _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2708 return error;
2712 static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2* ccsf2 )
2714 HB_UShort n, count;
2716 HB_ChainSubClassSet* cscs;
2719 if ( ccsf2->ChainSubClassSet )
2721 count = ccsf2->ChainSubClassSetCount;
2722 cscs = ccsf2->ChainSubClassSet;
2724 for ( n = 0; n < count; n++ )
2725 Free_ChainSubClassSet( &cscs[n] );
2727 FREE( cscs );
2730 _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2731 _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2732 _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2734 _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2738 /* ChainContextSubstFormat3 */
2740 static HB_Error Load_ChainContextSubst3(
2741 HB_ChainContextSubstFormat3* ccsf3,
2742 HB_Stream stream )
2744 HB_Error error;
2746 HB_UShort n, nb = 0, ni =0, nl = 0, m, count;
2747 HB_UShort backtrack_count, input_count, lookahead_count;
2748 HB_UInt cur_offset, new_offset, base_offset;
2750 HB_Coverage* b;
2751 HB_Coverage* i;
2752 HB_Coverage* l;
2753 HB_SubstLookupRecord* slr;
2756 base_offset = FILE_Pos() - 2L;
2758 if ( ACCESS_Frame( 2L ) )
2759 return error;
2761 ccsf3->BacktrackGlyphCount = GET_UShort();
2763 FORGET_Frame();
2765 ccsf3->BacktrackCoverage = NULL;
2767 backtrack_count = ccsf3->BacktrackGlyphCount;
2769 if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
2770 HB_Coverage ) )
2771 return error;
2773 b = ccsf3->BacktrackCoverage;
2775 for ( nb = 0; nb < backtrack_count; nb++ )
2777 if ( ACCESS_Frame( 2L ) )
2778 goto Fail4;
2780 new_offset = GET_UShort() + base_offset;
2782 FORGET_Frame();
2784 cur_offset = FILE_Pos();
2785 if ( FILE_Seek( new_offset ) ||
2786 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
2787 goto Fail4;
2788 (void)FILE_Seek( cur_offset );
2791 if ( ACCESS_Frame( 2L ) )
2792 goto Fail4;
2794 ccsf3->InputGlyphCount = GET_UShort();
2796 FORGET_Frame();
2798 ccsf3->InputCoverage = NULL;
2800 input_count = ccsf3->InputGlyphCount;
2802 if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
2803 goto Fail4;
2805 i = ccsf3->InputCoverage;
2807 for ( ni = 0; ni < input_count; ni++ )
2809 if ( ACCESS_Frame( 2L ) )
2810 goto Fail3;
2812 new_offset = GET_UShort() + base_offset;
2814 FORGET_Frame();
2816 cur_offset = FILE_Pos();
2817 if ( FILE_Seek( new_offset ) ||
2818 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
2819 goto Fail3;
2820 (void)FILE_Seek( cur_offset );
2823 if ( ACCESS_Frame( 2L ) )
2824 goto Fail3;
2826 ccsf3->LookaheadGlyphCount = GET_UShort();
2828 FORGET_Frame();
2830 ccsf3->LookaheadCoverage = NULL;
2832 lookahead_count = ccsf3->LookaheadGlyphCount;
2834 if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
2835 HB_Coverage ) )
2836 goto Fail3;
2838 l = ccsf3->LookaheadCoverage;
2840 for ( nl = 0; nl < lookahead_count; nl++ )
2842 if ( ACCESS_Frame( 2L ) )
2843 goto Fail2;
2845 new_offset = GET_UShort() + base_offset;
2847 FORGET_Frame();
2849 cur_offset = FILE_Pos();
2850 if ( FILE_Seek( new_offset ) ||
2851 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
2852 goto Fail2;
2853 (void)FILE_Seek( cur_offset );
2856 if ( ACCESS_Frame( 2L ) )
2857 goto Fail2;
2859 ccsf3->SubstCount = GET_UShort();
2861 FORGET_Frame();
2863 ccsf3->SubstLookupRecord = NULL;
2865 count = ccsf3->SubstCount;
2867 if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
2868 HB_SubstLookupRecord ) )
2869 goto Fail2;
2871 slr = ccsf3->SubstLookupRecord;
2873 if ( ACCESS_Frame( count * 4L ) )
2874 goto Fail1;
2876 for ( n = 0; n < count; n++ )
2878 slr[n].SequenceIndex = GET_UShort();
2879 slr[n].LookupListIndex = GET_UShort();
2882 FORGET_Frame();
2884 return HB_Err_Ok;
2886 Fail1:
2887 FREE( slr );
2889 Fail2:
2890 for ( m = 0; m < nl; m++ )
2891 _HB_OPEN_Free_Coverage( &l[m] );
2893 FREE( l );
2895 Fail3:
2896 for ( m = 0; m < ni; m++ )
2897 _HB_OPEN_Free_Coverage( &i[m] );
2899 FREE( i );
2901 Fail4:
2902 for ( m = 0; m < nb; m++ )
2903 _HB_OPEN_Free_Coverage( &b[m] );
2905 FREE( b );
2906 return error;
2910 static void Free_ChainContextSubst3( HB_ChainContextSubstFormat3* ccsf3 )
2912 HB_UShort n, count;
2914 HB_Coverage* c;
2917 FREE( ccsf3->SubstLookupRecord );
2919 if ( ccsf3->LookaheadCoverage )
2921 count = ccsf3->LookaheadGlyphCount;
2922 c = ccsf3->LookaheadCoverage;
2924 for ( n = 0; n < count; n++ )
2925 _HB_OPEN_Free_Coverage( &c[n] );
2927 FREE( c );
2930 if ( ccsf3->InputCoverage )
2932 count = ccsf3->InputGlyphCount;
2933 c = ccsf3->InputCoverage;
2935 for ( n = 0; n < count; n++ )
2936 _HB_OPEN_Free_Coverage( &c[n] );
2938 FREE( c );
2941 if ( ccsf3->BacktrackCoverage )
2943 count = ccsf3->BacktrackGlyphCount;
2944 c = ccsf3->BacktrackCoverage;
2946 for ( n = 0; n < count; n++ )
2947 _HB_OPEN_Free_Coverage( &c[n] );
2949 FREE( c );
2954 /* ChainContextSubst */
2956 static HB_Error Load_ChainContextSubst( HB_GSUB_SubTable* st,
2957 HB_Stream stream )
2959 HB_Error error;
2960 HB_ChainContextSubst* ccs = &st->chain;
2962 if ( ACCESS_Frame( 2L ) )
2963 return error;
2965 ccs->SubstFormat = GET_UShort();
2967 FORGET_Frame();
2969 switch ( ccs->SubstFormat ) {
2970 case 1: return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
2971 case 2: return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
2972 case 3: return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
2973 default: return ERR(HB_Err_Invalid_SubTable_Format);
2976 return HB_Err_Ok; /* never reached */
2980 static void Free_ChainContextSubst( HB_GSUB_SubTable* st )
2982 HB_ChainContextSubst* ccs = &st->chain;
2984 switch ( ccs->SubstFormat ) {
2985 case 1: Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
2986 case 2: Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
2987 case 3: Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
2988 default: break;
2993 static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub,
2994 HB_ChainContextSubstFormat1* ccsf1,
2995 HB_Buffer buffer,
2996 HB_UShort flags,
2997 HB_UShort context_length,
2998 int nesting_level )
3000 HB_UShort index, property;
3001 HB_UShort i, j, k, num_csr;
3002 HB_UShort bgc, igc, lgc;
3003 HB_Error error;
3005 HB_ChainSubRule* csr;
3006 HB_ChainSubRule curr_csr;
3007 HB_GDEFHeader* gdef;
3010 gdef = gsub->gdef;
3012 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3013 return error;
3015 error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
3016 if ( error )
3017 return error;
3019 csr = ccsf1->ChainSubRuleSet[index].ChainSubRule;
3020 num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
3022 for ( k = 0; k < num_csr; k++ )
3024 curr_csr = csr[k];
3025 bgc = curr_csr.BacktrackGlyphCount;
3026 igc = curr_csr.InputGlyphCount;
3027 lgc = curr_csr.LookaheadGlyphCount;
3029 if ( context_length != 0xFFFF && context_length < igc )
3030 goto next_chainsubrule;
3032 /* check whether context is too long; it is a first guess only */
3034 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3035 goto next_chainsubrule;
3037 if ( bgc )
3039 /* since we don't know in advance the number of glyphs to inspect,
3040 we search backwards for matches in the backtrack glyph array */
3042 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3044 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3046 if ( error && error != HB_Err_Not_Covered )
3047 return error;
3049 if ( j + 1 == bgc - i )
3050 goto next_chainsubrule;
3051 j--;
3054 /* In OpenType 1.3, it is undefined whether the offsets of
3055 backtrack glyphs is in logical order or not. Version 1.4
3056 will clarify this:
3058 Logical order - a b c d e f g h i j
3060 Input offsets - 0 1
3061 Backtrack offsets - 3 2 1 0
3062 Lookahead offsets - 0 1 2 3 */
3064 if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
3065 goto next_chainsubrule;
3069 /* Start at 1 because [0] is implied */
3071 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3073 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3075 if ( error && error != HB_Err_Not_Covered )
3076 return error;
3078 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3079 goto next_chainsubrule;
3080 j++;
3083 if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
3084 goto next_chainsubrule;
3087 /* we are starting to check for lookahead glyphs right after the
3088 last context glyph */
3090 for ( i = 0; i < lgc; i++, j++ )
3092 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3094 if ( error && error != HB_Err_Not_Covered )
3095 return error;
3097 if ( j + lgc - i == (HB_Int)buffer->in_length )
3098 goto next_chainsubrule;
3099 j++;
3102 if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
3103 goto next_chainsubrule;
3106 return Do_ContextSubst( gsub, igc,
3107 curr_csr.SubstCount,
3108 curr_csr.SubstLookupRecord,
3109 buffer,
3110 nesting_level );
3112 next_chainsubrule:
3116 return HB_Err_Not_Covered;
3120 static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub,
3121 HB_ChainContextSubstFormat2* ccsf2,
3122 HB_Buffer buffer,
3123 HB_UShort flags,
3124 HB_UShort context_length,
3125 int nesting_level )
3127 HB_UShort index, property;
3128 HB_Error error;
3129 HB_UShort i, j, k;
3130 HB_UShort bgc, igc, lgc;
3131 HB_UShort known_backtrack_classes,
3132 known_input_classes,
3133 known_lookahead_classes;
3135 HB_UShort* backtrack_classes;
3136 HB_UShort* input_classes;
3137 HB_UShort* lookahead_classes;
3139 HB_UShort* bc;
3140 HB_UShort* ic;
3141 HB_UShort* lc;
3143 HB_ChainSubClassSet* cscs;
3144 HB_ChainSubClassRule ccsr;
3145 HB_GDEFHeader* gdef;
3148 gdef = gsub->gdef;
3150 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3151 return error;
3153 /* Note: The coverage table in format 2 doesn't give an index into
3154 anything. It just lets us know whether or not we need to
3155 do any lookup at all. */
3157 error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
3158 if ( error )
3159 return error;
3161 if (ccsf2->MaxInputLength < 1)
3162 return HB_Err_Not_Covered;
3164 if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
3165 return error;
3166 known_backtrack_classes = 0;
3168 if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
3169 goto End3;
3170 known_input_classes = 1;
3172 if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
3173 goto End2;
3174 known_lookahead_classes = 0;
3176 error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
3177 &input_classes[0], NULL );
3178 if ( error && error != HB_Err_Not_Covered )
3179 goto End1;
3181 cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
3182 if ( !cscs )
3184 error = ERR(HB_Err_Invalid_SubTable);
3185 goto End1;
3188 for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
3190 ccsr = cscs->ChainSubClassRule[k];
3191 bgc = ccsr.BacktrackGlyphCount;
3192 igc = ccsr.InputGlyphCount;
3193 lgc = ccsr.LookaheadGlyphCount;
3195 if ( context_length != 0xFFFF && context_length < igc )
3196 goto next_chainsubclassrule;
3198 /* check whether context is too long; it is a first guess only */
3200 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3201 goto next_chainsubclassrule;
3203 if ( bgc )
3205 /* Since we don't know in advance the number of glyphs to inspect,
3206 we search backwards for matches in the backtrack glyph array.
3207 Note that `known_backtrack_classes' starts at index 0. */
3209 bc = ccsr.Backtrack;
3211 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3213 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3215 if ( error && error != HB_Err_Not_Covered )
3216 goto End1;
3218 if ( j + 1 == bgc - i )
3219 goto next_chainsubclassrule;
3220 j--;
3223 if ( i >= known_backtrack_classes )
3225 /* Keeps us from having to do this for each rule */
3227 error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
3228 &backtrack_classes[i], NULL );
3229 if ( error && error != HB_Err_Not_Covered )
3230 goto End1;
3231 known_backtrack_classes = i;
3234 if ( bc[i] != backtrack_classes[i] )
3235 goto next_chainsubclassrule;
3239 ic = ccsr.Input;
3241 /* Start at 1 because [0] is implied */
3243 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3245 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3247 if ( error && error != HB_Err_Not_Covered )
3248 goto End1;
3250 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3251 goto next_chainsubclassrule;
3252 j++;
3255 if ( i >= known_input_classes )
3257 error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
3258 &input_classes[i], NULL );
3259 if ( error && error != HB_Err_Not_Covered )
3260 goto End1;
3261 known_input_classes = i;
3264 if ( ic[i - 1] != input_classes[i] )
3265 goto next_chainsubclassrule;
3268 /* we are starting to check for lookahead glyphs right after the
3269 last context glyph */
3271 lc = ccsr.Lookahead;
3273 for ( i = 0; i < lgc; i++, j++ )
3275 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3277 if ( error && error != HB_Err_Not_Covered )
3278 goto End1;
3280 if ( j + lgc - i == (HB_Int)buffer->in_length )
3281 goto next_chainsubclassrule;
3282 j++;
3285 if ( i >= known_lookahead_classes )
3287 error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
3288 &lookahead_classes[i], NULL );
3289 if ( error && error != HB_Err_Not_Covered )
3290 goto End1;
3291 known_lookahead_classes = i;
3294 if ( lc[i] != lookahead_classes[i] )
3295 goto next_chainsubclassrule;
3298 error = Do_ContextSubst( gsub, igc,
3299 ccsr.SubstCount,
3300 ccsr.SubstLookupRecord,
3301 buffer,
3302 nesting_level );
3303 goto End1;
3305 next_chainsubclassrule:
3309 error = HB_Err_Not_Covered;
3311 End1:
3312 FREE( lookahead_classes );
3314 End2:
3315 FREE( input_classes );
3317 End3:
3318 FREE( backtrack_classes );
3319 return error;
3323 static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub,
3324 HB_ChainContextSubstFormat3* ccsf3,
3325 HB_Buffer buffer,
3326 HB_UShort flags,
3327 HB_UShort context_length,
3328 int nesting_level )
3330 HB_UShort index, i, j, property;
3331 HB_UShort bgc, igc, lgc;
3332 HB_Error error;
3334 HB_Coverage* bc;
3335 HB_Coverage* ic;
3336 HB_Coverage* lc;
3337 HB_GDEFHeader* gdef;
3340 gdef = gsub->gdef;
3342 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3343 return error;
3345 bgc = ccsf3->BacktrackGlyphCount;
3346 igc = ccsf3->InputGlyphCount;
3347 lgc = ccsf3->LookaheadGlyphCount;
3349 if ( context_length != 0xFFFF && context_length < igc )
3350 return HB_Err_Not_Covered;
3352 /* check whether context is too long; it is a first guess only */
3354 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3355 return HB_Err_Not_Covered;
3357 if ( bgc )
3359 /* Since we don't know in advance the number of glyphs to inspect,
3360 we search backwards for matches in the backtrack glyph array */
3362 bc = ccsf3->BacktrackCoverage;
3364 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3366 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3368 if ( error && error != HB_Err_Not_Covered )
3369 return error;
3371 if ( j + 1 == bgc - i )
3372 return HB_Err_Not_Covered;
3373 j--;
3376 error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
3377 if ( error )
3378 return error;
3382 ic = ccsf3->InputCoverage;
3384 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
3386 /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
3387 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3389 if ( error && error != HB_Err_Not_Covered )
3390 return error;
3392 if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3393 return HB_Err_Not_Covered;
3394 j++;
3397 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
3398 if ( error )
3399 return error;
3402 /* we are starting for lookahead glyphs right after the last context
3403 glyph */
3405 lc = ccsf3->LookaheadCoverage;
3407 for ( i = 0; i < lgc; i++, j++ )
3409 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3411 if ( error && error != HB_Err_Not_Covered )
3412 return error;
3414 if ( j + lgc - i == (HB_Int)buffer->in_length )
3415 return HB_Err_Not_Covered;
3416 j++;
3419 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3420 if ( error )
3421 return error;
3424 return Do_ContextSubst( gsub, igc,
3425 ccsf3->SubstCount,
3426 ccsf3->SubstLookupRecord,
3427 buffer,
3428 nesting_level );
3432 static HB_Error Lookup_ChainContextSubst( HB_GSUBHeader* gsub,
3433 HB_GSUB_SubTable* st,
3434 HB_Buffer buffer,
3435 HB_UShort flags,
3436 HB_UShort context_length,
3437 int nesting_level )
3439 HB_ChainContextSubst* ccs = &st->chain;
3441 switch ( ccs->SubstFormat ) {
3442 case 1: return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
3443 case 2: return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
3444 case 3: return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
3445 default: return ERR(HB_Err_Invalid_SubTable_Format);
3450 static HB_Error Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
3451 HB_Stream stream )
3453 HB_Error error;
3454 HB_ReverseChainContextSubst* rccs = &st->reverse;
3456 HB_UShort m, count;
3458 HB_UShort nb = 0, nl = 0, n;
3459 HB_UShort backtrack_count, lookahead_count;
3460 HB_UInt cur_offset, new_offset, base_offset;
3462 HB_Coverage* b;
3463 HB_Coverage* l;
3464 HB_UShort* sub;
3466 base_offset = FILE_Pos();
3468 if ( ACCESS_Frame( 2L ) )
3469 return error;
3471 rccs->SubstFormat = GET_UShort();
3473 if ( rccs->SubstFormat != 1 )
3474 return ERR(HB_Err_Invalid_SubTable_Format);
3476 FORGET_Frame();
3478 if ( ACCESS_Frame( 2L ) )
3479 return error;
3481 new_offset = GET_UShort() + base_offset;
3483 FORGET_Frame();
3485 cur_offset = FILE_Pos();
3486 if ( FILE_Seek( new_offset ) ||
3487 ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
3488 return error;
3489 (void)FILE_Seek( cur_offset );
3492 if ( ACCESS_Frame( 2L ) )
3493 goto Fail4;
3495 rccs->BacktrackGlyphCount = GET_UShort();
3497 FORGET_Frame();
3499 rccs->BacktrackCoverage = NULL;
3501 backtrack_count = rccs->BacktrackGlyphCount;
3503 if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
3504 HB_Coverage ) )
3505 goto Fail4;
3507 b = rccs->BacktrackCoverage;
3509 for ( nb = 0; nb < backtrack_count; nb++ )
3511 if ( ACCESS_Frame( 2L ) )
3512 goto Fail3;
3514 new_offset = GET_UShort() + base_offset;
3516 FORGET_Frame();
3518 cur_offset = FILE_Pos();
3519 if ( FILE_Seek( new_offset ) ||
3520 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
3521 goto Fail3;
3522 (void)FILE_Seek( cur_offset );
3526 if ( ACCESS_Frame( 2L ) )
3527 goto Fail3;
3529 rccs->LookaheadGlyphCount = GET_UShort();
3531 FORGET_Frame();
3533 rccs->LookaheadCoverage = NULL;
3535 lookahead_count = rccs->LookaheadGlyphCount;
3537 if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
3538 HB_Coverage ) )
3539 goto Fail3;
3541 l = rccs->LookaheadCoverage;
3543 for ( nl = 0; nl < lookahead_count; nl++ )
3545 if ( ACCESS_Frame( 2L ) )
3546 goto Fail2;
3548 new_offset = GET_UShort() + base_offset;
3550 FORGET_Frame();
3552 cur_offset = FILE_Pos();
3553 if ( FILE_Seek( new_offset ) ||
3554 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
3555 goto Fail2;
3556 (void)FILE_Seek( cur_offset );
3559 if ( ACCESS_Frame( 2L ) )
3560 goto Fail2;
3562 rccs->GlyphCount = GET_UShort();
3564 FORGET_Frame();
3566 rccs->Substitute = NULL;
3568 count = rccs->GlyphCount;
3570 if ( ALLOC_ARRAY( rccs->Substitute, count,
3571 HB_UShort ) )
3572 goto Fail2;
3574 sub = rccs->Substitute;
3576 if ( ACCESS_Frame( count * 2L ) )
3577 goto Fail1;
3579 for ( n = 0; n < count; n++ )
3580 sub[n] = GET_UShort();
3582 FORGET_Frame();
3584 return HB_Err_Ok;
3586 Fail1:
3587 FREE( sub );
3589 Fail2:
3590 for ( m = 0; m < nl; m++ )
3591 _HB_OPEN_Free_Coverage( &l[m] );
3593 FREE( l );
3595 Fail3:
3596 for ( m = 0; m < nb; m++ )
3597 _HB_OPEN_Free_Coverage( &b[m] );
3599 FREE( b );
3601 Fail4:
3602 _HB_OPEN_Free_Coverage( &rccs->Coverage );
3603 return error;
3607 static void Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
3609 HB_UShort n, count;
3610 HB_ReverseChainContextSubst* rccs = &st->reverse;
3612 HB_Coverage* c;
3614 _HB_OPEN_Free_Coverage( &rccs->Coverage );
3616 if ( rccs->LookaheadCoverage )
3618 count = rccs->LookaheadGlyphCount;
3619 c = rccs->LookaheadCoverage;
3621 for ( n = 0; n < count; n++ )
3622 _HB_OPEN_Free_Coverage( &c[n] );
3624 FREE( c );
3627 if ( rccs->BacktrackCoverage )
3629 count = rccs->BacktrackGlyphCount;
3630 c = rccs->BacktrackCoverage;
3632 for ( n = 0; n < count; n++ )
3633 _HB_OPEN_Free_Coverage( &c[n] );
3635 FREE( c );
3638 FREE ( rccs->Substitute );
3642 static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub,
3643 HB_GSUB_SubTable* st,
3644 HB_Buffer buffer,
3645 HB_UShort flags,
3646 HB_UShort context_length,
3647 int nesting_level )
3649 HB_UShort index, input_index, i, j, property;
3650 HB_UShort bgc, lgc;
3651 HB_Error error;
3653 HB_ReverseChainContextSubst* rccs = &st->reverse;
3654 HB_Coverage* bc;
3655 HB_Coverage* lc;
3656 HB_GDEFHeader* gdef;
3658 if ( nesting_level != 1 || context_length != 0xFFFF )
3659 return HB_Err_Not_Covered;
3661 gdef = gsub->gdef;
3663 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3664 return error;
3666 bgc = rccs->BacktrackGlyphCount;
3667 lgc = rccs->LookaheadGlyphCount;
3669 /* check whether context is too long; it is a first guess only */
3671 if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
3672 return HB_Err_Not_Covered;
3674 if ( bgc )
3676 /* Since we don't know in advance the number of glyphs to inspect,
3677 we search backwards for matches in the backtrack glyph array */
3679 bc = rccs->BacktrackCoverage;
3681 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
3683 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3685 if ( error && error != HB_Err_Not_Covered )
3686 return error;
3688 if ( j + 1 == bgc - i )
3689 return HB_Err_Not_Covered;
3690 j--;
3693 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
3694 if ( error )
3695 return error;
3699 j = buffer->in_pos;
3701 error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
3702 if ( error )
3703 return error;
3705 lc = rccs->LookaheadCoverage;
3707 for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
3709 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3711 if ( error && error != HB_Err_Not_Covered )
3712 return error;
3714 if ( j + lgc - i == (HB_Int)buffer->in_length )
3715 return HB_Err_Not_Covered;
3716 j++;
3719 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3720 if ( error )
3721 return error;
3724 IN_CURGLYPH() = rccs->Substitute[input_index];
3725 buffer->in_pos--; /* Reverse! */
3727 return error;
3732 /***********
3733 * GSUB API
3734 ***********/
3738 HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub,
3739 HB_UInt script_tag,
3740 HB_UShort* script_index )
3742 HB_UShort n;
3744 HB_ScriptList* sl;
3745 HB_ScriptRecord* sr;
3748 if ( !gsub || !script_index )
3749 return ERR(HB_Err_Invalid_Argument);
3751 sl = &gsub->ScriptList;
3752 sr = sl->ScriptRecord;
3754 for ( n = 0; n < sl->ScriptCount; n++ )
3755 if ( script_tag == sr[n].ScriptTag )
3757 *script_index = n;
3759 return HB_Err_Ok;
3762 return HB_Err_Not_Covered;
3767 HB_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub,
3768 HB_UInt language_tag,
3769 HB_UShort script_index,
3770 HB_UShort* language_index,
3771 HB_UShort* req_feature_index )
3773 HB_UShort n;
3775 HB_ScriptList* sl;
3776 HB_ScriptRecord* sr;
3777 HB_ScriptTable* s;
3778 HB_LangSysRecord* lsr;
3781 if ( !gsub || !language_index || !req_feature_index )
3782 return ERR(HB_Err_Invalid_Argument);
3784 sl = &gsub->ScriptList;
3785 sr = sl->ScriptRecord;
3787 if ( script_index >= sl->ScriptCount )
3788 return ERR(HB_Err_Invalid_Argument);
3790 s = &sr[script_index].Script;
3791 lsr = s->LangSysRecord;
3793 for ( n = 0; n < s->LangSysCount; n++ )
3794 if ( language_tag == lsr[n].LangSysTag )
3796 *language_index = n;
3797 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
3799 return HB_Err_Ok;
3802 return HB_Err_Not_Covered;
3806 /* selecting 0xFFFF for language_index asks for the values of the
3807 default language (DefaultLangSys) */
3810 HB_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub,
3811 HB_UInt feature_tag,
3812 HB_UShort script_index,
3813 HB_UShort language_index,
3814 HB_UShort* feature_index )
3816 HB_UShort n;
3818 HB_ScriptList* sl;
3819 HB_ScriptRecord* sr;
3820 HB_ScriptTable* s;
3821 HB_LangSysRecord* lsr;
3822 HB_LangSys* ls;
3823 HB_UShort* fi;
3825 HB_FeatureList* fl;
3826 HB_FeatureRecord* fr;
3829 if ( !gsub || !feature_index )
3830 return ERR(HB_Err_Invalid_Argument);
3832 sl = &gsub->ScriptList;
3833 sr = sl->ScriptRecord;
3835 fl = &gsub->FeatureList;
3836 fr = fl->FeatureRecord;
3838 if ( script_index >= sl->ScriptCount )
3839 return ERR(HB_Err_Invalid_Argument);
3841 s = &sr[script_index].Script;
3842 lsr = s->LangSysRecord;
3844 if ( language_index == 0xFFFF )
3845 ls = &s->DefaultLangSys;
3846 else
3848 if ( language_index >= s->LangSysCount )
3849 return ERR(HB_Err_Invalid_Argument);
3851 ls = &lsr[language_index].LangSys;
3854 fi = ls->FeatureIndex;
3856 for ( n = 0; n < ls->FeatureCount; n++ )
3858 if ( fi[n] >= fl->FeatureCount )
3859 return ERR(HB_Err_Invalid_SubTable_Format);
3861 if ( feature_tag == fr[fi[n]].FeatureTag )
3863 *feature_index = fi[n];
3865 return HB_Err_Ok;
3869 return HB_Err_Not_Covered;
3873 /* The next three functions return a null-terminated list */
3876 HB_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub,
3877 HB_UInt** script_tag_list )
3879 HB_UShort n;
3880 HB_Error error;
3881 HB_UInt* stl;
3883 HB_ScriptList* sl;
3884 HB_ScriptRecord* sr;
3887 if ( !gsub || !script_tag_list )
3888 return ERR(HB_Err_Invalid_Argument);
3890 sl = &gsub->ScriptList;
3891 sr = sl->ScriptRecord;
3893 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
3894 return error;
3896 for ( n = 0; n < sl->ScriptCount; n++ )
3897 stl[n] = sr[n].ScriptTag;
3898 stl[n] = 0;
3900 *script_tag_list = stl;
3902 return HB_Err_Ok;
3907 HB_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub,
3908 HB_UShort script_index,
3909 HB_UInt** language_tag_list )
3911 HB_UShort n;
3912 HB_Error error;
3913 HB_UInt* ltl;
3915 HB_ScriptList* sl;
3916 HB_ScriptRecord* sr;
3917 HB_ScriptTable* s;
3918 HB_LangSysRecord* lsr;
3921 if ( !gsub || !language_tag_list )
3922 return ERR(HB_Err_Invalid_Argument);
3924 sl = &gsub->ScriptList;
3925 sr = sl->ScriptRecord;
3927 if ( script_index >= sl->ScriptCount )
3928 return ERR(HB_Err_Invalid_Argument);
3930 s = &sr[script_index].Script;
3931 lsr = s->LangSysRecord;
3933 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
3934 return error;
3936 for ( n = 0; n < s->LangSysCount; n++ )
3937 ltl[n] = lsr[n].LangSysTag;
3938 ltl[n] = 0;
3940 *language_tag_list = ltl;
3942 return HB_Err_Ok;
3946 /* selecting 0xFFFF for language_index asks for the values of the
3947 default language (DefaultLangSys) */
3950 HB_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub,
3951 HB_UShort script_index,
3952 HB_UShort language_index,
3953 HB_UInt** feature_tag_list )
3955 HB_UShort n;
3956 HB_Error error;
3957 HB_UInt* ftl;
3959 HB_ScriptList* sl;
3960 HB_ScriptRecord* sr;
3961 HB_ScriptTable* s;
3962 HB_LangSysRecord* lsr;
3963 HB_LangSys* ls;
3964 HB_UShort* fi;
3966 HB_FeatureList* fl;
3967 HB_FeatureRecord* fr;
3970 if ( !gsub || !feature_tag_list )
3971 return ERR(HB_Err_Invalid_Argument);
3973 sl = &gsub->ScriptList;
3974 sr = sl->ScriptRecord;
3976 fl = &gsub->FeatureList;
3977 fr = fl->FeatureRecord;
3979 if ( script_index >= sl->ScriptCount )
3980 return ERR(HB_Err_Invalid_Argument);
3982 s = &sr[script_index].Script;
3983 lsr = s->LangSysRecord;
3985 if ( language_index == 0xFFFF )
3986 ls = &s->DefaultLangSys;
3987 else
3989 if ( language_index >= s->LangSysCount )
3990 return ERR(HB_Err_Invalid_Argument);
3992 ls = &lsr[language_index].LangSys;
3995 fi = ls->FeatureIndex;
3997 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
3998 return error;
4000 for ( n = 0; n < ls->FeatureCount; n++ )
4002 if ( fi[n] >= fl->FeatureCount )
4004 FREE( ftl );
4005 return ERR(HB_Err_Invalid_SubTable_Format);
4007 ftl[n] = fr[fi[n]].FeatureTag;
4009 ftl[n] = 0;
4011 *feature_tag_list = ftl;
4013 return HB_Err_Ok;
4017 /* Do an individual subtable lookup. Returns HB_Err_Ok if substitution
4018 has been done, or HB_Err_Not_Covered if not. */
4019 static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
4020 HB_UShort lookup_index,
4021 HB_Buffer buffer,
4022 HB_UShort context_length,
4023 int nesting_level )
4025 HB_Error error = HB_Err_Not_Covered;
4026 HB_UShort i, flags, lookup_count;
4027 HB_Lookup* lo;
4028 int lookup_type;
4030 nesting_level++;
4032 if ( nesting_level > HB_MAX_NESTING_LEVEL )
4033 return ERR(HB_Err_Not_Covered); /* ERR() call intended */
4035 lookup_count = gsub->LookupList.LookupCount;
4036 if (lookup_index >= lookup_count)
4037 return error;
4039 lo = &gsub->LookupList.Lookup[lookup_index];
4040 flags = lo->LookupFlag;
4041 lookup_type = lo->LookupType;
4043 for ( i = 0; i < lo->SubTableCount; i++ )
4045 HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
4047 switch (lookup_type) {
4048 case HB_GSUB_LOOKUP_SINGLE:
4049 error = Lookup_SingleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4050 case HB_GSUB_LOOKUP_MULTIPLE:
4051 error = Lookup_MultipleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4052 case HB_GSUB_LOOKUP_ALTERNATE:
4053 error = Lookup_AlternateSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4054 case HB_GSUB_LOOKUP_LIGATURE:
4055 error = Lookup_LigatureSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4056 case HB_GSUB_LOOKUP_CONTEXT:
4057 error = Lookup_ContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4058 case HB_GSUB_LOOKUP_CHAIN:
4059 error = Lookup_ChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4060 /*case HB_GSUB_LOOKUP_EXTENSION:
4061 error = Lookup_ExtensionSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
4062 case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4063 error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4064 default:
4065 error = HB_Err_Not_Covered;
4068 /* Check whether we have a successful substitution or an error other
4069 than HB_Err_Not_Covered */
4070 if ( error != HB_Err_Not_Covered )
4071 return error;
4074 return HB_Err_Not_Covered;
4078 HB_INTERNAL HB_Error
4079 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
4080 HB_Stream stream,
4081 HB_UShort lookup_type )
4083 switch (lookup_type) {
4084 case HB_GSUB_LOOKUP_SINGLE: return Load_SingleSubst ( st, stream );
4085 case HB_GSUB_LOOKUP_MULTIPLE: return Load_MultipleSubst ( st, stream );
4086 case HB_GSUB_LOOKUP_ALTERNATE: return Load_AlternateSubst ( st, stream );
4087 case HB_GSUB_LOOKUP_LIGATURE: return Load_LigatureSubst ( st, stream );
4088 case HB_GSUB_LOOKUP_CONTEXT: return Load_ContextSubst ( st, stream );
4089 case HB_GSUB_LOOKUP_CHAIN: return Load_ChainContextSubst ( st, stream );
4090 /*case HB_GSUB_LOOKUP_EXTENSION: return Load_ExtensionSubst ( st, stream );*/
4091 case HB_GSUB_LOOKUP_REVERSE_CHAIN: return Load_ReverseChainContextSubst ( st, stream );
4092 default: return ERR(HB_Err_Invalid_SubTable_Format);
4097 HB_INTERNAL void
4098 _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
4099 HB_UShort lookup_type )
4101 switch ( lookup_type ) {
4102 case HB_GSUB_LOOKUP_SINGLE: Free_SingleSubst ( st ); return;
4103 case HB_GSUB_LOOKUP_MULTIPLE: Free_MultipleSubst ( st ); return;
4104 case HB_GSUB_LOOKUP_ALTERNATE: Free_AlternateSubst ( st ); return;
4105 case HB_GSUB_LOOKUP_LIGATURE: Free_LigatureSubst ( st ); return;
4106 case HB_GSUB_LOOKUP_CONTEXT: Free_ContextSubst ( st ); return;
4107 case HB_GSUB_LOOKUP_CHAIN: Free_ChainContextSubst ( st ); return;
4108 /*case HB_GSUB_LOOKUP_EXTENSION: Free_ExtensionSubst ( st ); return;*/
4109 case HB_GSUB_LOOKUP_REVERSE_CHAIN: Free_ReverseChainContextSubst ( st ); return;
4110 default: return;
4116 /* apply one lookup to the input string object */
4118 static HB_Error GSUB_Do_String_Lookup( HB_GSUBHeader* gsub,
4119 HB_UShort lookup_index,
4120 HB_Buffer buffer )
4122 HB_Error error, retError = HB_Err_Not_Covered;
4124 HB_UInt* properties = gsub->LookupList.Properties;
4125 int lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
4127 const int nesting_level = 0;
4128 /* 0xFFFF indicates that we don't have a context length yet */
4129 const HB_UShort context_length = 0xFFFF;
4131 switch (lookup_type) {
4133 case HB_GSUB_LOOKUP_SINGLE:
4134 case HB_GSUB_LOOKUP_MULTIPLE:
4135 case HB_GSUB_LOOKUP_ALTERNATE:
4136 case HB_GSUB_LOOKUP_LIGATURE:
4137 case HB_GSUB_LOOKUP_CONTEXT:
4138 case HB_GSUB_LOOKUP_CHAIN:
4139 /* in/out forward substitution (implemented lazy) */
4141 _hb_buffer_clear_output ( buffer );
4142 buffer->in_pos = 0;
4143 while ( buffer->in_pos < buffer->in_length )
4145 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4147 error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4148 if ( error )
4150 if ( error != HB_Err_Not_Covered )
4151 return error;
4153 else
4154 retError = error;
4156 else
4157 error = HB_Err_Not_Covered;
4159 if ( error == HB_Err_Not_Covered )
4160 if ( COPY_Glyph ( buffer ) )
4161 return error;
4163 /* we shouldn't swap if error occurred.
4165 * also don't swap if nothing changed (ie HB_Err_Not_Covered).
4166 * shouldn't matter in that case though.
4168 if ( retError == HB_Err_Ok )
4169 _hb_buffer_swap( buffer );
4171 return retError;
4173 case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4174 /* in-place backward substitution */
4176 buffer->in_pos = buffer->in_length - 1;
4179 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4181 error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4182 if ( error )
4184 if ( error != HB_Err_Not_Covered )
4185 return error;
4187 else
4188 retError = error;
4190 else
4191 error = HB_Err_Not_Covered;
4193 if ( error == HB_Err_Not_Covered )
4194 buffer->in_pos--;
4196 while ((HB_Int) buffer->in_pos >= 0);
4198 return retError;
4200 /*case HB_GSUB_LOOKUP_EXTENSION:*/
4201 default:
4202 return retError;
4207 HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub,
4208 HB_UShort feature_index,
4209 HB_UInt property )
4211 HB_UShort i;
4213 HB_Feature feature;
4214 HB_UInt* properties;
4215 HB_UShort* index;
4216 HB_UShort lookup_count;
4218 /* Each feature can only be added once */
4220 if ( !gsub ||
4221 feature_index >= gsub->FeatureList.FeatureCount ||
4222 gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
4223 return ERR(HB_Err_Invalid_Argument);
4225 gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
4227 properties = gsub->LookupList.Properties;
4229 feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4230 index = feature.LookupListIndex;
4231 lookup_count = gsub->LookupList.LookupCount;
4233 for ( i = 0; i < feature.LookupListCount; i++ )
4235 HB_UShort lookup_index = index[i];
4236 if (lookup_index < lookup_count)
4237 properties[lookup_index] |= property;
4240 return HB_Err_Ok;
4245 HB_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub )
4247 HB_UShort i;
4249 HB_UInt* properties;
4252 if ( !gsub )
4253 return ERR(HB_Err_Invalid_Argument);
4255 gsub->FeatureList.ApplyCount = 0;
4257 properties = gsub->LookupList.Properties;
4259 for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
4260 properties[i] = 0;
4262 return HB_Err_Ok;
4267 HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub,
4268 HB_AltFunction altfunc,
4269 void* data )
4271 if ( !gsub )
4272 return ERR(HB_Err_Invalid_Argument);
4274 gsub->altfunc = altfunc;
4275 gsub->data = data;
4277 return HB_Err_Ok;
4280 /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
4281 * feature were applied, or HB_Err_Ok otherwise.
4283 HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub,
4284 HB_Buffer buffer )
4286 HB_Error error, retError = HB_Err_Not_Covered;
4287 int i, j, lookup_count, num_features;
4289 if ( !gsub ||
4290 !buffer)
4291 return ERR(HB_Err_Invalid_Argument);
4293 if ( buffer->in_length == 0 )
4294 return retError;
4296 lookup_count = gsub->LookupList.LookupCount;
4297 num_features = gsub->FeatureList.ApplyCount;
4299 for ( i = 0; i < num_features; i++)
4301 HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i];
4302 HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4304 for ( j = 0; j < feature.LookupListCount; j++ )
4306 HB_UShort lookup_index = feature.LookupListIndex[j];
4308 /* Skip nonexistant lookups */
4309 if (lookup_index >= lookup_count)
4310 continue;
4312 error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
4313 if ( error )
4315 if ( error != HB_Err_Not_Covered )
4316 return error;
4318 else
4319 retError = error;
4323 error = retError;
4325 return error;
4329 /* END */