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
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
,
37 HB_UShort context_length
,
42 /**********************
44 **********************/
48 HB_Error
HB_Load_GSUB_Table( HB_Stream stream
,
49 HB_GSUBHeader
** retptr
,
51 HB_Stream gdefStream
)
54 HB_UInt cur_offset
, new_offset
, base_offset
;
59 return ERR(HB_Err_Invalid_Argument
);
61 if ( GOTO_Table( TTAG_GSUB
) )
64 base_offset
= FILE_Pos();
66 if ( ALLOC ( gsub
, sizeof( *gsub
) ) )
72 if ( FILE_Seek( base_offset
+ 4L ) ||
76 new_offset
= GET_UShort() + base_offset
;
80 cur_offset
= FILE_Pos();
81 if ( FILE_Seek( new_offset
) ||
82 ( error
= _HB_OPEN_Load_ScriptList( &gsub
->ScriptList
,
83 stream
) ) != HB_Err_Ok
)
85 (void)FILE_Seek( cur_offset
);
87 if ( ACCESS_Frame( 2L ) )
90 new_offset
= GET_UShort() + base_offset
;
94 cur_offset
= FILE_Pos();
95 if ( FILE_Seek( new_offset
) ||
96 ( error
= _HB_OPEN_Load_FeatureList( &gsub
->FeatureList
,
97 stream
) ) != HB_Err_Ok
)
99 (void)FILE_Seek( cur_offset
);
101 if ( ACCESS_Frame( 2L ) )
104 new_offset
= GET_UShort() + base_offset
;
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
)
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
) ) )
126 _HB_OPEN_Free_LookupList( &gsub
->LookupList
, HB_Type_GSUB
);
129 _HB_OPEN_Free_FeatureList( &gsub
->FeatureList
);
132 _HB_OPEN_Free_ScriptList( &gsub
->ScriptList
);
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
);
153 /*****************************
154 * SubTable related functions
155 *****************************/
160 /* SingleSubstFormat1 */
161 /* SingleSubstFormat2 */
163 static HB_Error
Load_SingleSubst( HB_GSUB_SubTable
* st
,
167 HB_SingleSubst
* ss
= &st
->single
;
170 HB_UInt cur_offset
, new_offset
, base_offset
;
175 base_offset
= FILE_Pos();
177 if ( ACCESS_Frame( 4L ) )
180 ss
->SubstFormat
= GET_UShort();
181 new_offset
= GET_UShort() + base_offset
;
185 cur_offset
= FILE_Pos();
186 if ( FILE_Seek( new_offset
) ||
187 ( error
= _HB_OPEN_Load_Coverage( &ss
->Coverage
, stream
) ) != HB_Err_Ok
)
189 (void)FILE_Seek( cur_offset
);
191 switch ( ss
->SubstFormat
)
194 if ( ACCESS_Frame( 2L ) )
197 ss
->ssf
.ssf1
.DeltaGlyphID
= GET_UShort();
204 if ( ACCESS_Frame( 2L ) )
207 count
= ss
->ssf
.ssf2
.GlyphCount
= GET_UShort();
211 ss
->ssf
.ssf2
.Substitute
= NULL
;
213 if ( ALLOC_ARRAY( ss
->ssf
.ssf2
.Substitute
, count
, HB_UShort
) )
216 s
= ss
->ssf
.ssf2
.Substitute
;
218 if ( ACCESS_Frame( count
* 2L ) )
221 for ( n
= 0; n
< count
; n
++ )
229 return ERR(HB_Err_Invalid_SubTable_Format
);
238 _HB_OPEN_Free_Coverage( &ss
->Coverage
);
243 static void Free_SingleSubst( HB_GSUB_SubTable
* st
)
245 HB_SingleSubst
* ss
= &st
->single
;
247 switch ( ss
->SubstFormat
)
253 FREE( ss
->ssf
.ssf2
.Substitute
);
260 _HB_OPEN_Free_Coverage( &ss
->Coverage
);
264 static HB_Error
Lookup_SingleSubst( HB_GSUBHeader
* gsub
,
265 HB_GSUB_SubTable
* st
,
268 HB_UShort context_length
,
271 HB_UShort index
, value
, property
;
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
) )
284 error
= _HB_OPEN_Coverage_Index( &ss
->Coverage
, IN_CURGLYPH(), &index
);
288 switch ( ss
->SubstFormat
)
291 value
= ( IN_CURGLYPH() + ss
->ssf
.ssf1
.DeltaGlyphID
) & 0xFFFF;
292 if ( REPLACE_Glyph( buffer
, value
, nesting_level
) )
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
) )
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
)
325 static HB_Error
Load_Sequence( HB_Sequence
* s
,
334 if ( ACCESS_Frame( 2L ) )
337 count
= s
->GlyphCount
= GET_UShort();
341 s
->Substitute
= NULL
;
345 if ( ALLOC_ARRAY( s
->Substitute
, count
, HB_UShort
) )
350 if ( ACCESS_Frame( count
* 2L ) )
356 for ( n
= 0; n
< count
; n
++ )
357 sub
[n
] = GET_UShort();
366 static void Free_Sequence( HB_Sequence
* s
)
368 FREE( s
->Substitute
);
372 /* MultipleSubstFormat1 */
374 static HB_Error
Load_MultipleSubst( HB_GSUB_SubTable
* st
,
378 HB_MultipleSubst
* ms
= &st
->multiple
;
380 HB_UShort n
= 0, m
, count
;
381 HB_UInt cur_offset
, new_offset
, base_offset
;
386 base_offset
= FILE_Pos();
388 if ( ACCESS_Frame( 4L ) )
391 ms
->SubstFormat
= GET_UShort(); /* should be 1 */
392 new_offset
= GET_UShort() + base_offset
;
396 cur_offset
= FILE_Pos();
397 if ( FILE_Seek( new_offset
) ||
398 ( error
= _HB_OPEN_Load_Coverage( &ms
->Coverage
, stream
) ) != HB_Err_Ok
)
400 (void)FILE_Seek( cur_offset
);
402 if ( ACCESS_Frame( 2L ) )
405 count
= ms
->SequenceCount
= GET_UShort();
411 if ( ALLOC_ARRAY( ms
->Sequence
, count
, HB_Sequence
) )
416 for ( n
= 0; n
< count
; n
++ )
418 if ( ACCESS_Frame( 2L ) )
421 new_offset
= GET_UShort() + base_offset
;
425 cur_offset
= FILE_Pos();
426 if ( FILE_Seek( new_offset
) ||
427 ( error
= Load_Sequence( &s
[n
], stream
) ) != HB_Err_Ok
)
429 (void)FILE_Seek( cur_offset
);
435 for ( m
= 0; m
< n
; m
++ )
436 Free_Sequence( &s
[m
] );
441 _HB_OPEN_Free_Coverage( &ms
->Coverage
);
446 static void Free_MultipleSubst( HB_GSUB_SubTable
* st
)
449 HB_MultipleSubst
* ms
= &st
->multiple
;
456 count
= ms
->SequenceCount
;
459 for ( n
= 0; n
< count
; n
++ )
460 Free_Sequence( &s
[n
] );
465 _HB_OPEN_Free_Coverage( &ms
->Coverage
);
469 static HB_Error
Lookup_MultipleSubst( HB_GSUBHeader
* gsub
,
470 HB_GSUB_SubTable
* st
,
473 HB_UShort context_length
,
477 HB_UShort index
, property
, n
, count
;
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
) )
490 error
= _HB_OPEN_Coverage_Index( &ms
->Coverage
, IN_CURGLYPH(), &index
);
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 ) )
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
)
526 static HB_Error
Load_AlternateSet( HB_AlternateSet
* as
,
535 if ( ACCESS_Frame( 2L ) )
538 count
= as
->GlyphCount
= GET_UShort();
542 as
->Alternate
= NULL
;
544 if ( ALLOC_ARRAY( as
->Alternate
, count
, HB_UShort
) )
549 if ( ACCESS_Frame( count
* 2L ) )
555 for ( n
= 0; n
< count
; n
++ )
564 static void Free_AlternateSet( HB_AlternateSet
* as
)
566 FREE( as
->Alternate
);
570 /* AlternateSubstFormat1 */
572 static HB_Error
Load_AlternateSubst( HB_GSUB_SubTable
* st
,
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 ) )
589 as
->SubstFormat
= GET_UShort(); /* should be 1 */
590 new_offset
= GET_UShort() + base_offset
;
594 cur_offset
= FILE_Pos();
595 if ( FILE_Seek( new_offset
) ||
596 ( error
= _HB_OPEN_Load_Coverage( &as
->Coverage
, stream
) ) != HB_Err_Ok
)
598 (void)FILE_Seek( cur_offset
);
600 if ( ACCESS_Frame( 2L ) )
603 count
= as
->AlternateSetCount
= GET_UShort();
607 as
->AlternateSet
= NULL
;
609 if ( ALLOC_ARRAY( as
->AlternateSet
, count
, HB_AlternateSet
) )
612 aset
= as
->AlternateSet
;
614 for ( n
= 0; n
< count
; n
++ )
616 if ( ACCESS_Frame( 2L ) )
619 new_offset
= GET_UShort() + base_offset
;
623 cur_offset
= FILE_Pos();
624 if ( FILE_Seek( new_offset
) ||
625 ( error
= Load_AlternateSet( &aset
[n
], stream
) ) != HB_Err_Ok
)
627 (void)FILE_Seek( cur_offset
);
633 for ( m
= 0; m
< n
; m
++ )
634 Free_AlternateSet( &aset
[m
] );
639 _HB_OPEN_Free_Coverage( &as
->Coverage
);
644 static void Free_AlternateSubst( HB_GSUB_SubTable
* st
)
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
] );
663 _HB_OPEN_Free_Coverage( &as
->Coverage
);
667 static HB_Error
Lookup_AlternateSubst( HB_GSUBHeader
* gsub
,
668 HB_GSUB_SubTable
* st
,
671 HB_UShort context_length
,
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
) )
688 error
= _HB_OPEN_Coverage_Index( &as
->Coverage
, IN_CURGLYPH(), &index
);
692 aset
= as
->AlternateSet
[index
];
694 /* we use a user-defined callback function to get the alternate index */
697 alt_index
= (gsub
->altfunc
)( buffer
->out_pos
, IN_CURGLYPH(),
698 aset
.GlyphCount
, aset
.Alternate
,
703 value
= aset
.Alternate
[alt_index
];
704 if ( REPLACE_Glyph( buffer
, value
, nesting_level
) )
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
)
724 static HB_Error
Load_Ligature( HB_Ligature
* l
,
733 if ( ACCESS_Frame( 4L ) )
736 l
->LigGlyph
= GET_UShort();
737 l
->ComponentCount
= GET_UShort();
743 count
= l
->ComponentCount
- 1; /* only ComponentCount - 1 elements */
745 if ( ALLOC_ARRAY( l
->Component
, count
, HB_UShort
) )
750 if ( ACCESS_Frame( count
* 2L ) )
756 for ( n
= 0; n
< count
; n
++ )
765 static void Free_Ligature( HB_Ligature
* l
)
767 FREE( l
->Component
);
773 static HB_Error
Load_LigatureSet( HB_LigatureSet
* ls
,
778 HB_UShort n
= 0, m
, count
;
779 HB_UInt cur_offset
, new_offset
, base_offset
;
784 base_offset
= FILE_Pos();
786 if ( ACCESS_Frame( 2L ) )
789 count
= ls
->LigatureCount
= GET_UShort();
795 if ( ALLOC_ARRAY( ls
->Ligature
, count
, HB_Ligature
) )
800 for ( n
= 0; n
< count
; n
++ )
802 if ( ACCESS_Frame( 2L ) )
805 new_offset
= GET_UShort() + base_offset
;
809 cur_offset
= FILE_Pos();
810 if ( FILE_Seek( new_offset
) ||
811 ( error
= Load_Ligature( &l
[n
], stream
) ) != HB_Err_Ok
)
813 (void)FILE_Seek( cur_offset
);
819 for ( m
= 0; m
< n
; m
++ )
820 Free_Ligature( &l
[m
] );
827 static void Free_LigatureSet( HB_LigatureSet
* ls
)
836 count
= ls
->LigatureCount
;
839 for ( n
= 0; n
< count
; n
++ )
840 Free_Ligature( &l
[n
] );
847 /* LigatureSubstFormat1 */
849 static HB_Error
Load_LigatureSubst( HB_GSUB_SubTable
* st
,
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 ) )
866 ls
->SubstFormat
= GET_UShort(); /* should be 1 */
867 new_offset
= GET_UShort() + base_offset
;
871 cur_offset
= FILE_Pos();
872 if ( FILE_Seek( new_offset
) ||
873 ( error
= _HB_OPEN_Load_Coverage( &ls
->Coverage
, stream
) ) != HB_Err_Ok
)
875 (void)FILE_Seek( cur_offset
);
877 if ( ACCESS_Frame( 2L ) )
880 count
= ls
->LigatureSetCount
= GET_UShort();
884 ls
->LigatureSet
= NULL
;
886 if ( ALLOC_ARRAY( ls
->LigatureSet
, count
, HB_LigatureSet
) )
889 lset
= ls
->LigatureSet
;
891 for ( n
= 0; n
< count
; n
++ )
893 if ( ACCESS_Frame( 2L ) )
896 new_offset
= GET_UShort() + base_offset
;
900 cur_offset
= FILE_Pos();
901 if ( FILE_Seek( new_offset
) ||
902 ( error
= Load_LigatureSet( &lset
[n
], stream
) ) != HB_Err_Ok
)
904 (void)FILE_Seek( cur_offset
);
910 for ( m
= 0; m
< n
; m
++ )
911 Free_LigatureSet( &lset
[m
] );
916 _HB_OPEN_Free_Coverage( &ls
->Coverage
);
921 static void Free_LigatureSubst( HB_GSUB_SubTable
* st
)
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
] );
940 _HB_OPEN_Free_Coverage( &ls
->Coverage
);
944 static HB_Error
Lookup_LigatureSubst( HB_GSUBHeader
* gsub
,
945 HB_GSUB_SubTable
* st
,
948 HB_UShort context_length
,
951 HB_UShort index
, property
;
953 HB_UShort numlig
, i
, j
, is_mark
, first_is_mark
= FALSE
;
955 HB_LigatureSubst
* ls
= &st
->ligature
;
956 HB_GDEFHeader
* gdef
= gsub
->gdef
;
960 HB_UNUSED(nesting_level
);
962 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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
);
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
;
981 if ( buffer
->in_pos
+ lig
->ComponentCount
> buffer
->in_length
)
982 goto next_ligature
; /* Not enough glyphs in input */
986 is_mark
= first_is_mark
;
988 if ( context_length
!= 0xFFFF && context_length
< lig
->ComponentCount
)
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
)
998 if ( j
+ lig
->ComponentCount
- i
== (HB_Int
)buffer
->in_length
)
1003 if ( !( property
== HB_GDEF_MARK
|| property
& HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS
) )
1006 if ( IN_GLYPH( j
) != c
[i
- 1] )
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
)
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
,
1033 HB_UShort ligID
= _hb_buffer_allocate_ligid( buffer
);
1034 if ( ADD_String( buffer
, i
, 1, &lig
->LigGlyph
,
1041 HB_UShort ligID
= _hb_buffer_allocate_ligid( buffer
);
1042 if ( ADD_Glyph( buffer
, lig
->LigGlyph
, 0xFFFF, ligID
) )
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
) )
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
,
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
);
1103 i
+= buffer
->in_pos
- old_pos
;
1105 if ( error
== HB_Err_Not_Covered
)
1107 if ( COPY_Glyph( buffer
) )
1116 /* No substitution for this index */
1118 if ( COPY_Glyph( buffer
) )
1132 static HB_Error
Load_SubRule( HB_SubRule
* sr
,
1140 HB_SubstLookupRecord
* slr
;
1143 if ( ACCESS_Frame( 4L ) )
1146 sr
->GlyphCount
= GET_UShort();
1147 sr
->SubstCount
= GET_UShort();
1153 count
= sr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
1155 if ( ALLOC_ARRAY( sr
->Input
, count
, HB_UShort
) )
1160 if ( ACCESS_Frame( count
* 2L ) )
1163 for ( n
= 0; n
< count
; n
++ )
1164 i
[n
] = GET_UShort();
1168 sr
->SubstLookupRecord
= NULL
;
1170 count
= sr
->SubstCount
;
1172 if ( ALLOC_ARRAY( sr
->SubstLookupRecord
, count
, HB_SubstLookupRecord
) )
1175 slr
= sr
->SubstLookupRecord
;
1177 if ( ACCESS_Frame( count
* 4L ) )
1180 for ( n
= 0; n
< count
; n
++ )
1182 slr
[n
].SequenceIndex
= GET_UShort();
1183 slr
[n
].LookupListIndex
= GET_UShort();
1199 static void Free_SubRule( HB_SubRule
* sr
)
1201 FREE( sr
->SubstLookupRecord
);
1208 static HB_Error
Load_SubRuleSet( HB_SubRuleSet
* srs
,
1213 HB_UShort n
= 0, m
, count
;
1214 HB_UInt cur_offset
, new_offset
, base_offset
;
1219 base_offset
= FILE_Pos();
1221 if ( ACCESS_Frame( 2L ) )
1224 count
= srs
->SubRuleCount
= GET_UShort();
1228 srs
->SubRule
= NULL
;
1230 if ( ALLOC_ARRAY( srs
->SubRule
, count
, HB_SubRule
) )
1235 for ( n
= 0; n
< count
; n
++ )
1237 if ( ACCESS_Frame( 2L ) )
1240 new_offset
= GET_UShort() + base_offset
;
1244 cur_offset
= FILE_Pos();
1245 if ( FILE_Seek( new_offset
) ||
1246 ( error
= Load_SubRule( &sr
[n
], stream
) ) != HB_Err_Ok
)
1248 (void)FILE_Seek( cur_offset
);
1254 for ( m
= 0; m
< n
; m
++ )
1255 Free_SubRule( &sr
[m
] );
1262 static void Free_SubRuleSet( HB_SubRuleSet
* srs
)
1271 count
= srs
->SubRuleCount
;
1274 for ( n
= 0; n
< count
; n
++ )
1275 Free_SubRule( &sr
[n
] );
1282 /* ContextSubstFormat1 */
1284 static HB_Error
Load_ContextSubst1( HB_ContextSubstFormat1
* csf1
,
1289 HB_UShort n
= 0, m
, count
;
1290 HB_UInt cur_offset
, new_offset
, base_offset
;
1295 base_offset
= FILE_Pos() - 2L;
1297 if ( ACCESS_Frame( 2L ) )
1300 new_offset
= GET_UShort() + base_offset
;
1304 cur_offset
= FILE_Pos();
1305 if ( FILE_Seek( new_offset
) ||
1306 ( error
= _HB_OPEN_Load_Coverage( &csf1
->Coverage
, stream
) ) != HB_Err_Ok
)
1308 (void)FILE_Seek( cur_offset
);
1310 if ( ACCESS_Frame( 2L ) )
1313 count
= csf1
->SubRuleSetCount
= GET_UShort();
1317 csf1
->SubRuleSet
= NULL
;
1319 if ( ALLOC_ARRAY( csf1
->SubRuleSet
, count
, HB_SubRuleSet
) )
1322 srs
= csf1
->SubRuleSet
;
1324 for ( n
= 0; n
< count
; n
++ )
1326 if ( ACCESS_Frame( 2L ) )
1329 new_offset
= GET_UShort() + base_offset
;
1333 cur_offset
= FILE_Pos();
1334 if ( FILE_Seek( new_offset
) ||
1335 ( error
= Load_SubRuleSet( &srs
[n
], stream
) ) != HB_Err_Ok
)
1337 (void)FILE_Seek( cur_offset
);
1343 for ( m
= 0; m
< n
; m
++ )
1344 Free_SubRuleSet( &srs
[m
] );
1349 _HB_OPEN_Free_Coverage( &csf1
->Coverage
);
1354 static void Free_ContextSubst1( HB_ContextSubstFormat1
* csf1
)
1361 if ( csf1
->SubRuleSet
)
1363 count
= csf1
->SubRuleSetCount
;
1364 srs
= csf1
->SubRuleSet
;
1366 for ( n
= 0; n
< count
; n
++ )
1367 Free_SubRuleSet( &srs
[n
] );
1372 _HB_OPEN_Free_Coverage( &csf1
->Coverage
);
1378 static HB_Error
Load_SubClassRule( HB_ContextSubstFormat2
* csf2
,
1379 HB_SubClassRule
* scr
,
1387 HB_SubstLookupRecord
* slr
;
1390 if ( ACCESS_Frame( 4L ) )
1393 scr
->GlyphCount
= GET_UShort();
1394 scr
->SubstCount
= GET_UShort();
1396 if ( scr
->GlyphCount
> csf2
->MaxContextLength
)
1397 csf2
->MaxContextLength
= scr
->GlyphCount
;
1403 count
= scr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
1405 if ( ALLOC_ARRAY( scr
->Class
, count
, HB_UShort
) )
1410 if ( ACCESS_Frame( count
* 2L ) )
1413 for ( n
= 0; n
< count
; n
++ )
1414 c
[n
] = GET_UShort();
1418 scr
->SubstLookupRecord
= NULL
;
1420 count
= scr
->SubstCount
;
1422 if ( ALLOC_ARRAY( scr
->SubstLookupRecord
, count
, HB_SubstLookupRecord
) )
1425 slr
= scr
->SubstLookupRecord
;
1427 if ( ACCESS_Frame( count
* 4L ) )
1430 for ( n
= 0; n
< count
; n
++ )
1432 slr
[n
].SequenceIndex
= GET_UShort();
1433 slr
[n
].LookupListIndex
= GET_UShort();
1449 static void Free_SubClassRule( HB_SubClassRule
* scr
)
1451 FREE( scr
->SubstLookupRecord
);
1458 static HB_Error
Load_SubClassSet( HB_ContextSubstFormat2
* csf2
,
1459 HB_SubClassSet
* scs
,
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 ) )
1475 count
= scs
->SubClassRuleCount
= GET_UShort();
1479 scs
->SubClassRule
= NULL
;
1481 if ( ALLOC_ARRAY( scs
->SubClassRule
, count
, HB_SubClassRule
) )
1484 scr
= scs
->SubClassRule
;
1486 for ( n
= 0; n
< count
; n
++ )
1488 if ( ACCESS_Frame( 2L ) )
1491 new_offset
= GET_UShort() + base_offset
;
1495 cur_offset
= FILE_Pos();
1496 if ( FILE_Seek( new_offset
) ||
1497 ( error
= Load_SubClassRule( csf2
, &scr
[n
],
1498 stream
) ) != HB_Err_Ok
)
1500 (void)FILE_Seek( cur_offset
);
1506 for ( m
= 0; m
< n
; m
++ )
1507 Free_SubClassRule( &scr
[m
] );
1514 static void Free_SubClassSet( HB_SubClassSet
* scs
)
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
] );
1534 /* ContextSubstFormat2 */
1536 static HB_Error
Load_ContextSubst2( HB_ContextSubstFormat2
* csf2
,
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 ) )
1552 new_offset
= GET_UShort() + base_offset
;
1556 cur_offset
= FILE_Pos();
1557 if ( FILE_Seek( new_offset
) ||
1558 ( error
= _HB_OPEN_Load_Coverage( &csf2
->Coverage
, stream
) ) != HB_Err_Ok
)
1560 (void)FILE_Seek( cur_offset
);
1562 if ( ACCESS_Frame( 4L ) )
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();
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
)
1579 (void)FILE_Seek( cur_offset
);
1581 csf2
->SubClassSet
= NULL
;
1582 csf2
->MaxContextLength
= 0;
1584 if ( ALLOC_ARRAY( csf2
->SubClassSet
, count
, HB_SubClassSet
) )
1587 scs
= csf2
->SubClassSet
;
1589 for ( n
= 0; n
< count
; n
++ )
1591 if ( ACCESS_Frame( 2L ) )
1594 new_offset
= GET_UShort() + base_offset
;
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
)
1605 (void)FILE_Seek( cur_offset
);
1609 /* we create a SubClassSet table with no entries */
1611 csf2
->SubClassSet
[n
].SubClassRuleCount
= 0;
1612 csf2
->SubClassSet
[n
].SubClassRule
= NULL
;
1619 for ( m
= 0; m
< n
; m
++ )
1620 Free_SubClassSet( &scs
[m
] );
1625 _HB_OPEN_Free_ClassDefinition( &csf2
->ClassDef
);
1628 _HB_OPEN_Free_Coverage( &csf2
->Coverage
);
1633 static void Free_ContextSubst2( HB_ContextSubstFormat2
* csf2
)
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
] );
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
,
1663 HB_UShort n
= 0, m
, count
;
1664 HB_UInt cur_offset
, new_offset
, base_offset
;
1667 HB_SubstLookupRecord
* slr
;
1670 base_offset
= FILE_Pos() - 2L;
1672 if ( ACCESS_Frame( 4L ) )
1675 csf3
->GlyphCount
= GET_UShort();
1676 csf3
->SubstCount
= GET_UShort();
1680 csf3
->Coverage
= NULL
;
1682 count
= csf3
->GlyphCount
;
1684 if ( ALLOC_ARRAY( csf3
->Coverage
, count
, HB_Coverage
) )
1689 for ( n
= 0; n
< count
; n
++ )
1691 if ( ACCESS_Frame( 2L ) )
1694 new_offset
= GET_UShort() + base_offset
;
1698 cur_offset
= FILE_Pos();
1699 if ( FILE_Seek( new_offset
) ||
1700 ( error
= _HB_OPEN_Load_Coverage( &c
[n
], stream
) ) != HB_Err_Ok
)
1702 (void)FILE_Seek( cur_offset
);
1705 csf3
->SubstLookupRecord
= NULL
;
1707 count
= csf3
->SubstCount
;
1709 if ( ALLOC_ARRAY( csf3
->SubstLookupRecord
, count
,
1710 HB_SubstLookupRecord
) )
1713 slr
= csf3
->SubstLookupRecord
;
1715 if ( ACCESS_Frame( count
* 4L ) )
1718 for ( n
= 0; n
< count
; n
++ )
1720 slr
[n
].SequenceIndex
= GET_UShort();
1721 slr
[n
].LookupListIndex
= GET_UShort();
1732 for ( m
= 0; m
< n
; m
++ )
1733 _HB_OPEN_Free_Coverage( &c
[m
] );
1740 static void Free_ContextSubst3( HB_ContextSubstFormat3
* csf3
)
1747 FREE( csf3
->SubstLookupRecord
);
1749 if ( csf3
->Coverage
)
1751 count
= csf3
->GlyphCount
;
1754 for ( n
= 0; n
< count
; n
++ )
1755 _HB_OPEN_Free_Coverage( &c
[n
] );
1764 static HB_Error
Load_ContextSubst( HB_GSUB_SubTable
* st
,
1768 HB_ContextSubst
* cs
= &st
->context
;
1771 if ( ACCESS_Frame( 2L ) )
1774 cs
->SubstFormat
= GET_UShort();
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;
1804 static HB_Error
Lookup_ContextSubst1( HB_GSUBHeader
* gsub
,
1805 HB_ContextSubstFormat1
* csf1
,
1808 HB_UShort context_length
,
1811 HB_UShort index
, property
;
1812 HB_UShort i
, j
, k
, numsr
;
1816 HB_GDEFHeader
* gdef
;
1821 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
1824 error
= _HB_OPEN_Coverage_Index( &csf1
->Coverage
, IN_CURGLYPH(), &index
);
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
)
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
)
1846 if ( j
+ sr
[k
].GlyphCount
- i
== (HB_Int
)buffer
->in_length
)
1851 if ( IN_GLYPH( j
) != sr
[k
].Input
[i
- 1] )
1855 return Do_ContextSubst( gsub
, sr
[k
].GlyphCount
,
1856 sr
[k
].SubstCount
, sr
[k
].SubstLookupRecord
,
1863 return HB_Err_Not_Covered
;
1867 static HB_Error
Lookup_ContextSubst2( HB_GSUBHeader
* gsub
,
1868 HB_ContextSubstFormat2
* csf2
,
1871 HB_UShort context_length
,
1874 HB_UShort index
, property
;
1876 HB_UShort i
, j
, k
, known_classes
;
1881 HB_SubClassSet
* scs
;
1882 HB_SubClassRule
* sr
;
1883 HB_GDEFHeader
* gdef
;
1888 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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
);
1899 if (csf2
->MaxContextLength
< 1)
1900 return HB_Err_Not_Covered
;
1902 if ( ALLOC_ARRAY( classes
, csf2
->MaxContextLength
, HB_UShort
) )
1905 error
= _HB_OPEN_Get_Class( &csf2
->ClassDef
, IN_CURGLYPH(),
1906 &classes
[0], NULL
);
1907 if ( error
&& error
!= HB_Err_Not_Covered
)
1911 scs
= &csf2
->SubClassSet
[classes
[0]];
1914 error
= ERR(HB_Err_Invalid_SubTable
);
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 */
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
)
1939 if ( j
+ sr
->GlyphCount
- i
< (HB_Int
)buffer
->in_length
)
1940 goto next_subclassrule
;
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
)
1954 if ( cl
[i
- 1] != classes
[i
] )
1955 goto next_subclassrule
;
1958 error
= Do_ContextSubst( gsub
, sr
->GlyphCount
,
1959 sr
->SubstCount
, sr
->SubstLookupRecord
,
1968 error
= HB_Err_Not_Covered
;
1976 static HB_Error
Lookup_ContextSubst3( HB_GSUBHeader
* gsub
,
1977 HB_ContextSubstFormat3
* csf3
,
1980 HB_UShort context_length
,
1984 HB_UShort index
, i
, j
, property
;
1987 HB_GDEFHeader
* gdef
;
1992 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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 */
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
)
2010 if ( j
+ csf3
->GlyphCount
- i
== (HB_Int
)buffer
->in_length
)
2011 return HB_Err_Not_Covered
;
2015 error
= _HB_OPEN_Coverage_Index( &c
[i
], IN_GLYPH( j
), &index
);
2020 return Do_ContextSubst( gsub
, csf3
->GlyphCount
,
2021 csf3
->SubstCount
, csf3
->SubstLookupRecord
,
2027 static HB_Error
Lookup_ContextSubst( HB_GSUBHeader
* gsub
,
2028 HB_GSUB_SubTable
* st
,
2031 HB_UShort context_length
,
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 */
2052 static HB_Error
Load_ChainSubRule( HB_ChainSubRule
* csr
,
2062 HB_SubstLookupRecord
* slr
;
2065 if ( ACCESS_Frame( 2L ) )
2068 csr
->BacktrackGlyphCount
= GET_UShort();
2072 csr
->Backtrack
= NULL
;
2074 count
= csr
->BacktrackGlyphCount
;
2076 if ( ALLOC_ARRAY( csr
->Backtrack
, count
, HB_UShort
) )
2081 if ( ACCESS_Frame( count
* 2L ) )
2084 for ( n
= 0; n
< count
; n
++ )
2085 b
[n
] = GET_UShort();
2089 if ( ACCESS_Frame( 2L ) )
2092 csr
->InputGlyphCount
= GET_UShort();
2098 count
= csr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
2100 if ( ALLOC_ARRAY( csr
->Input
, count
, HB_UShort
) )
2105 if ( ACCESS_Frame( count
* 2L ) )
2108 for ( n
= 0; n
< count
; n
++ )
2109 i
[n
] = GET_UShort();
2113 if ( ACCESS_Frame( 2L ) )
2116 csr
->LookaheadGlyphCount
= GET_UShort();
2120 csr
->Lookahead
= NULL
;
2122 count
= csr
->LookaheadGlyphCount
;
2124 if ( ALLOC_ARRAY( csr
->Lookahead
, count
, HB_UShort
) )
2129 if ( ACCESS_Frame( count
* 2L ) )
2132 for ( n
= 0; n
< count
; n
++ )
2133 l
[n
] = GET_UShort();
2137 if ( ACCESS_Frame( 2L ) )
2140 csr
->SubstCount
= GET_UShort();
2144 csr
->SubstLookupRecord
= NULL
;
2146 count
= csr
->SubstCount
;
2148 if ( ALLOC_ARRAY( csr
->SubstLookupRecord
, count
, HB_SubstLookupRecord
) )
2151 slr
= csr
->SubstLookupRecord
;
2153 if ( ACCESS_Frame( count
* 4L ) )
2156 for ( n
= 0; n
< count
; n
++ )
2158 slr
[n
].SequenceIndex
= GET_UShort();
2159 slr
[n
].LookupListIndex
= GET_UShort();
2181 static void Free_ChainSubRule( HB_ChainSubRule
* csr
)
2183 FREE( csr
->SubstLookupRecord
);
2184 FREE( csr
->Lookahead
);
2186 FREE( csr
->Backtrack
);
2190 /* ChainSubRuleSet */
2192 static HB_Error
Load_ChainSubRuleSet( HB_ChainSubRuleSet
* csrs
,
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 ) )
2208 count
= csrs
->ChainSubRuleCount
= GET_UShort();
2212 csrs
->ChainSubRule
= NULL
;
2214 if ( ALLOC_ARRAY( csrs
->ChainSubRule
, count
, HB_ChainSubRule
) )
2217 csr
= csrs
->ChainSubRule
;
2219 for ( n
= 0; n
< count
; n
++ )
2221 if ( ACCESS_Frame( 2L ) )
2224 new_offset
= GET_UShort() + base_offset
;
2228 cur_offset
= FILE_Pos();
2229 if ( FILE_Seek( new_offset
) ||
2230 ( error
= Load_ChainSubRule( &csr
[n
], stream
) ) != HB_Err_Ok
)
2232 (void)FILE_Seek( cur_offset
);
2238 for ( m
= 0; m
< n
; m
++ )
2239 Free_ChainSubRule( &csr
[m
] );
2246 static void Free_ChainSubRuleSet( HB_ChainSubRuleSet
* csrs
)
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
] );
2266 /* ChainContextSubstFormat1 */
2268 static HB_Error
Load_ChainContextSubst1(
2269 HB_ChainContextSubstFormat1
* ccsf1
,
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 ) )
2285 new_offset
= GET_UShort() + base_offset
;
2289 cur_offset
= FILE_Pos();
2290 if ( FILE_Seek( new_offset
) ||
2291 ( error
= _HB_OPEN_Load_Coverage( &ccsf1
->Coverage
, stream
) ) != HB_Err_Ok
)
2293 (void)FILE_Seek( cur_offset
);
2295 if ( ACCESS_Frame( 2L ) )
2298 count
= ccsf1
->ChainSubRuleSetCount
= GET_UShort();
2302 ccsf1
->ChainSubRuleSet
= NULL
;
2304 if ( ALLOC_ARRAY( ccsf1
->ChainSubRuleSet
, count
, HB_ChainSubRuleSet
) )
2307 csrs
= ccsf1
->ChainSubRuleSet
;
2309 for ( n
= 0; n
< count
; n
++ )
2311 if ( ACCESS_Frame( 2L ) )
2314 new_offset
= GET_UShort() + base_offset
;
2318 cur_offset
= FILE_Pos();
2319 if ( FILE_Seek( new_offset
) ||
2320 ( error
= Load_ChainSubRuleSet( &csrs
[n
], stream
) ) != HB_Err_Ok
)
2322 (void)FILE_Seek( cur_offset
);
2328 for ( m
= 0; m
< n
; m
++ )
2329 Free_ChainSubRuleSet( &csrs
[m
] );
2334 _HB_OPEN_Free_Coverage( &ccsf1
->Coverage
);
2339 static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1
* ccsf1
)
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
] );
2357 _HB_OPEN_Free_Coverage( &ccsf1
->Coverage
);
2361 /* ChainSubClassRule */
2363 static HB_Error
Load_ChainSubClassRule(
2364 HB_ChainContextSubstFormat2
* ccsf2
,
2365 HB_ChainSubClassRule
* cscr
,
2375 HB_SubstLookupRecord
* slr
;
2378 if ( ACCESS_Frame( 2L ) )
2381 cscr
->BacktrackGlyphCount
= GET_UShort();
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
) )
2395 b
= cscr
->Backtrack
;
2397 if ( ACCESS_Frame( count
* 2L ) )
2400 for ( n
= 0; n
< count
; n
++ )
2401 b
[n
] = GET_UShort();
2405 if ( ACCESS_Frame( 2L ) )
2408 cscr
->InputGlyphCount
= GET_UShort();
2412 if ( cscr
->InputGlyphCount
> ccsf2
->MaxInputLength
)
2413 ccsf2
->MaxInputLength
= cscr
->InputGlyphCount
;
2417 count
= cscr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
2419 if ( ALLOC_ARRAY( cscr
->Input
, count
, HB_UShort
) )
2424 if ( ACCESS_Frame( count
* 2L ) )
2427 for ( n
= 0; n
< count
; n
++ )
2428 i
[n
] = GET_UShort();
2432 if ( ACCESS_Frame( 2L ) )
2435 cscr
->LookaheadGlyphCount
= GET_UShort();
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
) )
2449 l
= cscr
->Lookahead
;
2451 if ( ACCESS_Frame( count
* 2L ) )
2454 for ( n
= 0; n
< count
; n
++ )
2455 l
[n
] = GET_UShort();
2459 if ( ACCESS_Frame( 2L ) )
2462 cscr
->SubstCount
= GET_UShort();
2466 cscr
->SubstLookupRecord
= NULL
;
2468 count
= cscr
->SubstCount
;
2470 if ( ALLOC_ARRAY( cscr
->SubstLookupRecord
, count
,
2471 HB_SubstLookupRecord
) )
2474 slr
= cscr
->SubstLookupRecord
;
2476 if ( ACCESS_Frame( count
* 4L ) )
2479 for ( n
= 0; n
< count
; n
++ )
2481 slr
[n
].SequenceIndex
= GET_UShort();
2482 slr
[n
].LookupListIndex
= GET_UShort();
2504 static void Free_ChainSubClassRule( HB_ChainSubClassRule
* cscr
)
2506 FREE( cscr
->SubstLookupRecord
);
2507 FREE( cscr
->Lookahead
);
2508 FREE( cscr
->Input
);
2509 FREE( cscr
->Backtrack
);
2515 static HB_Error
Load_ChainSubClassSet(
2516 HB_ChainContextSubstFormat2
* ccsf2
,
2517 HB_ChainSubClassSet
* cscs
,
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 ) )
2533 count
= cscs
->ChainSubClassRuleCount
= GET_UShort();
2537 cscs
->ChainSubClassRule
= NULL
;
2539 if ( ALLOC_ARRAY( cscs
->ChainSubClassRule
, count
,
2540 HB_ChainSubClassRule
) )
2543 cscr
= cscs
->ChainSubClassRule
;
2545 for ( n
= 0; n
< count
; n
++ )
2547 if ( ACCESS_Frame( 2L ) )
2550 new_offset
= GET_UShort() + base_offset
;
2554 cur_offset
= FILE_Pos();
2555 if ( FILE_Seek( new_offset
) ||
2556 ( error
= Load_ChainSubClassRule( ccsf2
, &cscr
[n
],
2557 stream
) ) != HB_Err_Ok
)
2559 (void)FILE_Seek( cur_offset
);
2565 for ( m
= 0; m
< n
; m
++ )
2566 Free_ChainSubClassRule( &cscr
[m
] );
2573 static void Free_ChainSubClassSet( HB_ChainSubClassSet
* cscs
)
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
] );
2593 /* ChainContextSubstFormat2 */
2595 static HB_Error
Load_ChainContextSubst2(
2596 HB_ChainContextSubstFormat2
* ccsf2
,
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 ) )
2613 new_offset
= GET_UShort() + base_offset
;
2617 cur_offset
= FILE_Pos();
2618 if ( FILE_Seek( new_offset
) ||
2619 ( error
= _HB_OPEN_Load_Coverage( &ccsf2
->Coverage
, stream
) ) != HB_Err_Ok
)
2621 (void)FILE_Seek( cur_offset
);
2623 if ( ACCESS_Frame( 8L ) )
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();
2638 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2
->BacktrackClassDef
, 65535,
2639 backtrack_offset
, base_offset
,
2640 stream
) ) != HB_Err_Ok
)
2643 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2
->InputClassDef
, count
,
2644 input_offset
, base_offset
,
2645 stream
) ) != HB_Err_Ok
)
2647 if ( ( error
= _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2
->LookaheadClassDef
, 65535,
2648 lookahead_offset
, base_offset
,
2649 stream
) ) != HB_Err_Ok
)
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
) )
2660 cscs
= ccsf2
->ChainSubClassSet
;
2662 for ( n
= 0; n
< count
; n
++ )
2664 if ( ACCESS_Frame( 2L ) )
2667 new_offset
= GET_UShort() + base_offset
;
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
)
2678 (void)FILE_Seek( cur_offset
);
2682 /* we create a ChainSubClassSet table with no entries */
2684 ccsf2
->ChainSubClassSet
[n
].ChainSubClassRuleCount
= 0;
2685 ccsf2
->ChainSubClassSet
[n
].ChainSubClassRule
= NULL
;
2692 for ( m
= 0; m
< n
; m
++ )
2693 Free_ChainSubClassSet( &cscs
[m
] );
2698 _HB_OPEN_Free_ClassDefinition( &ccsf2
->LookaheadClassDef
);
2701 _HB_OPEN_Free_ClassDefinition( &ccsf2
->InputClassDef
);
2704 _HB_OPEN_Free_ClassDefinition( &ccsf2
->BacktrackClassDef
);
2707 _HB_OPEN_Free_Coverage( &ccsf2
->Coverage
);
2712 static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2
* ccsf2
)
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
] );
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
,
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
;
2753 HB_SubstLookupRecord
* slr
;
2756 base_offset
= FILE_Pos() - 2L;
2758 if ( ACCESS_Frame( 2L ) )
2761 ccsf3
->BacktrackGlyphCount
= GET_UShort();
2765 ccsf3
->BacktrackCoverage
= NULL
;
2767 backtrack_count
= ccsf3
->BacktrackGlyphCount
;
2769 if ( ALLOC_ARRAY( ccsf3
->BacktrackCoverage
, backtrack_count
,
2773 b
= ccsf3
->BacktrackCoverage
;
2775 for ( nb
= 0; nb
< backtrack_count
; nb
++ )
2777 if ( ACCESS_Frame( 2L ) )
2780 new_offset
= GET_UShort() + base_offset
;
2784 cur_offset
= FILE_Pos();
2785 if ( FILE_Seek( new_offset
) ||
2786 ( error
= _HB_OPEN_Load_Coverage( &b
[nb
], stream
) ) != HB_Err_Ok
)
2788 (void)FILE_Seek( cur_offset
);
2791 if ( ACCESS_Frame( 2L ) )
2794 ccsf3
->InputGlyphCount
= GET_UShort();
2798 ccsf3
->InputCoverage
= NULL
;
2800 input_count
= ccsf3
->InputGlyphCount
;
2802 if ( ALLOC_ARRAY( ccsf3
->InputCoverage
, input_count
, HB_Coverage
) )
2805 i
= ccsf3
->InputCoverage
;
2807 for ( ni
= 0; ni
< input_count
; ni
++ )
2809 if ( ACCESS_Frame( 2L ) )
2812 new_offset
= GET_UShort() + base_offset
;
2816 cur_offset
= FILE_Pos();
2817 if ( FILE_Seek( new_offset
) ||
2818 ( error
= _HB_OPEN_Load_Coverage( &i
[ni
], stream
) ) != HB_Err_Ok
)
2820 (void)FILE_Seek( cur_offset
);
2823 if ( ACCESS_Frame( 2L ) )
2826 ccsf3
->LookaheadGlyphCount
= GET_UShort();
2830 ccsf3
->LookaheadCoverage
= NULL
;
2832 lookahead_count
= ccsf3
->LookaheadGlyphCount
;
2834 if ( ALLOC_ARRAY( ccsf3
->LookaheadCoverage
, lookahead_count
,
2838 l
= ccsf3
->LookaheadCoverage
;
2840 for ( nl
= 0; nl
< lookahead_count
; nl
++ )
2842 if ( ACCESS_Frame( 2L ) )
2845 new_offset
= GET_UShort() + base_offset
;
2849 cur_offset
= FILE_Pos();
2850 if ( FILE_Seek( new_offset
) ||
2851 ( error
= _HB_OPEN_Load_Coverage( &l
[nl
], stream
) ) != HB_Err_Ok
)
2853 (void)FILE_Seek( cur_offset
);
2856 if ( ACCESS_Frame( 2L ) )
2859 ccsf3
->SubstCount
= GET_UShort();
2863 ccsf3
->SubstLookupRecord
= NULL
;
2865 count
= ccsf3
->SubstCount
;
2867 if ( ALLOC_ARRAY( ccsf3
->SubstLookupRecord
, count
,
2868 HB_SubstLookupRecord
) )
2871 slr
= ccsf3
->SubstLookupRecord
;
2873 if ( ACCESS_Frame( count
* 4L ) )
2876 for ( n
= 0; n
< count
; n
++ )
2878 slr
[n
].SequenceIndex
= GET_UShort();
2879 slr
[n
].LookupListIndex
= GET_UShort();
2890 for ( m
= 0; m
< nl
; m
++ )
2891 _HB_OPEN_Free_Coverage( &l
[m
] );
2896 for ( m
= 0; m
< ni
; m
++ )
2897 _HB_OPEN_Free_Coverage( &i
[m
] );
2902 for ( m
= 0; m
< nb
; m
++ )
2903 _HB_OPEN_Free_Coverage( &b
[m
] );
2910 static void Free_ChainContextSubst3( HB_ChainContextSubstFormat3
* ccsf3
)
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
] );
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
] );
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
] );
2954 /* ChainContextSubst */
2956 static HB_Error
Load_ChainContextSubst( HB_GSUB_SubTable
* st
,
2960 HB_ChainContextSubst
* ccs
= &st
->chain
;
2962 if ( ACCESS_Frame( 2L ) )
2965 ccs
->SubstFormat
= GET_UShort();
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;
2993 static HB_Error
Lookup_ChainContextSubst1( HB_GSUBHeader
* gsub
,
2994 HB_ChainContextSubstFormat1
* ccsf1
,
2997 HB_UShort context_length
,
3000 HB_UShort index
, property
;
3001 HB_UShort i
, j
, k
, num_csr
;
3002 HB_UShort bgc
, igc
, lgc
;
3005 HB_ChainSubRule
* csr
;
3006 HB_ChainSubRule curr_csr
;
3007 HB_GDEFHeader
* gdef
;
3012 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
3015 error
= _HB_OPEN_Coverage_Index( &ccsf1
->Coverage
, IN_CURGLYPH(), &index
);
3019 csr
= ccsf1
->ChainSubRuleSet
[index
].ChainSubRule
;
3020 num_csr
= ccsf1
->ChainSubRuleSet
[index
].ChainSubRuleCount
;
3022 for ( k
= 0; k
< num_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
;
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
)
3049 if ( j
+ 1 == bgc
- i
)
3050 goto next_chainsubrule
;
3054 /* In OpenType 1.3, it is undefined whether the offsets of
3055 backtrack glyphs is in logical order or not. Version 1.4
3058 Logical order - a b c d e f g h i j
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
)
3078 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
3079 goto next_chainsubrule
;
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
)
3097 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
3098 goto next_chainsubrule
;
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
,
3116 return HB_Err_Not_Covered
;
3120 static HB_Error
Lookup_ChainContextSubst2( HB_GSUBHeader
* gsub
,
3121 HB_ChainContextSubstFormat2
* ccsf2
,
3124 HB_UShort context_length
,
3127 HB_UShort index
, property
;
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
;
3143 HB_ChainSubClassSet
* cscs
;
3144 HB_ChainSubClassRule ccsr
;
3145 HB_GDEFHeader
* gdef
;
3150 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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
);
3161 if (ccsf2
->MaxInputLength
< 1)
3162 return HB_Err_Not_Covered
;
3164 if ( ALLOC_ARRAY( backtrack_classes
, ccsf2
->MaxBacktrackLength
, HB_UShort
) )
3166 known_backtrack_classes
= 0;
3168 if ( ALLOC_ARRAY( input_classes
, ccsf2
->MaxInputLength
, HB_UShort
) )
3170 known_input_classes
= 1;
3172 if ( ALLOC_ARRAY( lookahead_classes
, ccsf2
->MaxLookaheadLength
, HB_UShort
) )
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
)
3181 cscs
= &ccsf2
->ChainSubClassSet
[input_classes
[0]];
3184 error
= ERR(HB_Err_Invalid_SubTable
);
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
;
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
)
3218 if ( j
+ 1 == bgc
- i
)
3219 goto next_chainsubclassrule
;
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
)
3231 known_backtrack_classes
= i
;
3234 if ( bc
[i
] != backtrack_classes
[i
] )
3235 goto next_chainsubclassrule
;
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
)
3250 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
3251 goto next_chainsubclassrule
;
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
)
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
)
3280 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
3281 goto next_chainsubclassrule
;
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
)
3291 known_lookahead_classes
= i
;
3294 if ( lc
[i
] != lookahead_classes
[i
] )
3295 goto next_chainsubclassrule
;
3298 error
= Do_ContextSubst( gsub
, igc
,
3300 ccsr
.SubstLookupRecord
,
3305 next_chainsubclassrule
:
3309 error
= HB_Err_Not_Covered
;
3312 FREE( lookahead_classes
);
3315 FREE( input_classes
);
3318 FREE( backtrack_classes
);
3323 static HB_Error
Lookup_ChainContextSubst3( HB_GSUBHeader
* gsub
,
3324 HB_ChainContextSubstFormat3
* ccsf3
,
3327 HB_UShort context_length
,
3330 HB_UShort index
, i
, j
, property
;
3331 HB_UShort bgc
, igc
, lgc
;
3337 HB_GDEFHeader
* gdef
;
3342 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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
;
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
)
3371 if ( j
+ 1 == bgc
- i
)
3372 return HB_Err_Not_Covered
;
3376 error
= _HB_OPEN_Coverage_Index( &bc
[i
], OUT_GLYPH( j
), &index
);
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
)
3392 if ( j
+ igc
- i
+ lgc
== (HB_Int
)buffer
->in_length
)
3393 return HB_Err_Not_Covered
;
3397 error
= _HB_OPEN_Coverage_Index( &ic
[i
], IN_GLYPH( j
), &index
);
3402 /* we are starting for lookahead glyphs right after the last context
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
)
3414 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
3415 return HB_Err_Not_Covered
;
3419 error
= _HB_OPEN_Coverage_Index( &lc
[i
], IN_GLYPH( j
), &index
);
3424 return Do_ContextSubst( gsub
, igc
,
3426 ccsf3
->SubstLookupRecord
,
3432 static HB_Error
Lookup_ChainContextSubst( HB_GSUBHeader
* gsub
,
3433 HB_GSUB_SubTable
* st
,
3436 HB_UShort context_length
,
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
,
3454 HB_ReverseChainContextSubst
* rccs
= &st
->reverse
;
3458 HB_UShort nb
= 0, nl
= 0, n
;
3459 HB_UShort backtrack_count
, lookahead_count
;
3460 HB_UInt cur_offset
, new_offset
, base_offset
;
3466 base_offset
= FILE_Pos();
3468 if ( ACCESS_Frame( 2L ) )
3471 rccs
->SubstFormat
= GET_UShort();
3473 if ( rccs
->SubstFormat
!= 1 )
3474 return ERR(HB_Err_Invalid_SubTable_Format
);
3478 if ( ACCESS_Frame( 2L ) )
3481 new_offset
= GET_UShort() + base_offset
;
3485 cur_offset
= FILE_Pos();
3486 if ( FILE_Seek( new_offset
) ||
3487 ( error
= _HB_OPEN_Load_Coverage( &rccs
->Coverage
, stream
) ) != HB_Err_Ok
)
3489 (void)FILE_Seek( cur_offset
);
3492 if ( ACCESS_Frame( 2L ) )
3495 rccs
->BacktrackGlyphCount
= GET_UShort();
3499 rccs
->BacktrackCoverage
= NULL
;
3501 backtrack_count
= rccs
->BacktrackGlyphCount
;
3503 if ( ALLOC_ARRAY( rccs
->BacktrackCoverage
, backtrack_count
,
3507 b
= rccs
->BacktrackCoverage
;
3509 for ( nb
= 0; nb
< backtrack_count
; nb
++ )
3511 if ( ACCESS_Frame( 2L ) )
3514 new_offset
= GET_UShort() + base_offset
;
3518 cur_offset
= FILE_Pos();
3519 if ( FILE_Seek( new_offset
) ||
3520 ( error
= _HB_OPEN_Load_Coverage( &b
[nb
], stream
) ) != HB_Err_Ok
)
3522 (void)FILE_Seek( cur_offset
);
3526 if ( ACCESS_Frame( 2L ) )
3529 rccs
->LookaheadGlyphCount
= GET_UShort();
3533 rccs
->LookaheadCoverage
= NULL
;
3535 lookahead_count
= rccs
->LookaheadGlyphCount
;
3537 if ( ALLOC_ARRAY( rccs
->LookaheadCoverage
, lookahead_count
,
3541 l
= rccs
->LookaheadCoverage
;
3543 for ( nl
= 0; nl
< lookahead_count
; nl
++ )
3545 if ( ACCESS_Frame( 2L ) )
3548 new_offset
= GET_UShort() + base_offset
;
3552 cur_offset
= FILE_Pos();
3553 if ( FILE_Seek( new_offset
) ||
3554 ( error
= _HB_OPEN_Load_Coverage( &l
[nl
], stream
) ) != HB_Err_Ok
)
3556 (void)FILE_Seek( cur_offset
);
3559 if ( ACCESS_Frame( 2L ) )
3562 rccs
->GlyphCount
= GET_UShort();
3566 rccs
->Substitute
= NULL
;
3568 count
= rccs
->GlyphCount
;
3570 if ( ALLOC_ARRAY( rccs
->Substitute
, count
,
3574 sub
= rccs
->Substitute
;
3576 if ( ACCESS_Frame( count
* 2L ) )
3579 for ( n
= 0; n
< count
; n
++ )
3580 sub
[n
] = GET_UShort();
3590 for ( m
= 0; m
< nl
; m
++ )
3591 _HB_OPEN_Free_Coverage( &l
[m
] );
3596 for ( m
= 0; m
< nb
; m
++ )
3597 _HB_OPEN_Free_Coverage( &b
[m
] );
3602 _HB_OPEN_Free_Coverage( &rccs
->Coverage
);
3607 static void Free_ReverseChainContextSubst( HB_GSUB_SubTable
* st
)
3610 HB_ReverseChainContextSubst
* rccs
= &st
->reverse
;
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
] );
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
] );
3638 FREE ( rccs
->Substitute
);
3642 static HB_Error
Lookup_ReverseChainContextSubst( HB_GSUBHeader
* gsub
,
3643 HB_GSUB_SubTable
* st
,
3646 HB_UShort context_length
,
3649 HB_UShort index
, input_index
, i
, j
, property
;
3653 HB_ReverseChainContextSubst
* rccs
= &st
->reverse
;
3656 HB_GDEFHeader
* gdef
;
3658 if ( nesting_level
!= 1 || context_length
!= 0xFFFF )
3659 return HB_Err_Not_Covered
;
3663 if ( CHECK_Property( gdef
, IN_CURITEM(), flags
, &property
) )
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
;
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
)
3688 if ( j
+ 1 == bgc
- i
)
3689 return HB_Err_Not_Covered
;
3693 error
= _HB_OPEN_Coverage_Index( &bc
[i
], IN_GLYPH( j
), &index
);
3701 error
= _HB_OPEN_Coverage_Index( &rccs
->Coverage
, IN_GLYPH( j
), &input_index
);
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
)
3714 if ( j
+ lgc
- i
== (HB_Int
)buffer
->in_length
)
3715 return HB_Err_Not_Covered
;
3719 error
= _HB_OPEN_Coverage_Index( &lc
[i
], IN_GLYPH( j
), &index
);
3724 IN_CURGLYPH() = rccs
->Substitute
[input_index
];
3725 buffer
->in_pos
--; /* Reverse! */
3738 HB_Error
HB_GSUB_Select_Script( HB_GSUBHeader
* gsub
,
3740 HB_UShort
* script_index
)
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
)
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
)
3776 HB_ScriptRecord
* sr
;
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
;
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
)
3819 HB_ScriptRecord
* sr
;
3821 HB_LangSysRecord
* lsr
;
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
;
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
];
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
)
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
) )
3896 for ( n
= 0; n
< sl
->ScriptCount
; n
++ )
3897 stl
[n
] = sr
[n
].ScriptTag
;
3900 *script_tag_list
= stl
;
3907 HB_Error
HB_GSUB_Query_Languages( HB_GSUBHeader
* gsub
,
3908 HB_UShort script_index
,
3909 HB_UInt
** language_tag_list
)
3916 HB_ScriptRecord
* sr
;
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
) )
3936 for ( n
= 0; n
< s
->LangSysCount
; n
++ )
3937 ltl
[n
] = lsr
[n
].LangSysTag
;
3940 *language_tag_list
= ltl
;
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
)
3960 HB_ScriptRecord
* sr
;
3962 HB_LangSysRecord
* lsr
;
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
;
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
) )
4000 for ( n
= 0; n
< ls
->FeatureCount
; n
++ )
4002 if ( fi
[n
] >= fl
->FeatureCount
)
4005 return ERR(HB_Err_Invalid_SubTable_Format
);
4007 ftl
[n
] = fr
[fi
[n
]].FeatureTag
;
4011 *feature_tag_list
= ftl
;
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
,
4022 HB_UShort context_length
,
4025 HB_Error error
= HB_Err_Not_Covered
;
4026 HB_UShort i
, flags
, lookup_count
;
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
)
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;
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
)
4074 return HB_Err_Not_Covered
;
4078 HB_INTERNAL HB_Error
4079 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable
* st
,
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
);
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;
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
,
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
);
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
);
4150 if ( error
!= HB_Err_Not_Covered
)
4157 error
= HB_Err_Not_Covered
;
4159 if ( error
== HB_Err_Not_Covered
)
4160 if ( COPY_Glyph ( buffer
) )
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
);
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
);
4184 if ( error
!= HB_Err_Not_Covered
)
4191 error
= HB_Err_Not_Covered
;
4193 if ( error
== HB_Err_Not_Covered
)
4196 while ((HB_Int
) buffer
->in_pos
>= 0);
4200 /*case HB_GSUB_LOOKUP_EXTENSION:*/
4207 HB_Error
HB_GSUB_Add_Feature( HB_GSUBHeader
* gsub
,
4208 HB_UShort feature_index
,
4214 HB_UInt
* properties
;
4216 HB_UShort lookup_count
;
4218 /* Each feature can only be added once */
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
;
4245 HB_Error
HB_GSUB_Clear_Features( HB_GSUBHeader
* gsub
)
4249 HB_UInt
* properties
;
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
++ )
4267 HB_Error
HB_GSUB_Register_Alternate_Function( HB_GSUBHeader
* gsub
,
4268 HB_AltFunction altfunc
,
4272 return ERR(HB_Err_Invalid_Argument
);
4274 gsub
->altfunc
= altfunc
;
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
,
4286 HB_Error error
, retError
= HB_Err_Not_Covered
;
4287 int i
, j
, lookup_count
, num_features
;
4291 return ERR(HB_Err_Invalid_Argument
);
4293 if ( buffer
->in_length
== 0 )
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
)
4312 error
= GSUB_Do_String_Lookup( gsub
, lookup_index
, buffer
);
4315 if ( error
!= HB_Err_Not_Covered
)