1 /*******************************************************************
5 * TrueType Open GSUB table support.
7 * Copyright 1996-1999 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
10 * This file is part of the FreeType project, and may only be used
11 * modified and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
16 ******************************************************************/
18 /* XXX There is *a lot* of duplicated code (cf. formats 5 and 6), but
19 I don't care currently. I believe that it would be possible to
20 save about 50% of TTO code by carefully designing the structures,
21 sharing as much as possible with extensive use of macros. This
22 is something for a volunteer :-) */
35 #define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' )
38 #define ADD_String( in, num_in, out, num_out, data ) \
39 ( ( error = TT_GSUB_Add_String( (in), (num_in), \
41 (data) ) ) != TT_Err_Ok )
43 #define CHECK_Property( gdef, index, flags, property ) \
44 ( ( error = Check_Property( (gdef), (index), (flags), \
45 (property) ) ) != TT_Err_Ok )
48 static TT_Error
Do_Glyph_Lookup( TTO_GSUBHeader
* gsub
,
52 UShort context_length
,
57 /**********************
59 **********************/
62 /* The following function copies `num_out' elements from `data' to
63 `out', advancing the array pointer in the `in' structure by `num_in'
64 elements and in `out' by `num_out' elements. If the string (resp.
65 the properties) array in `out' is empty or too small, it allocates
66 resp. reallocates the string (and properties) array. Finally, it
67 sets the `length' field of `out' equal to `pos' of the `out'
70 The properties (if defined) for all replaced glyphs are taken from
71 the glyph at position `in->pos'. */
74 TT_Error
TT_GSUB_Add_String( TTO_GSUB_String
* in
,
89 in
->length
== 0 || in
->pos
>= in
->length
||
90 in
->length
< in
->pos
+ num_in
)
91 return TT_Err_Invalid_Argument
;
93 if ( out
->pos
+ num_out
>= out
->allocated
)
95 ULong size
= out
->pos
+ num_out
+ 256L;
98 /* The following works because all fields in `out' must be
99 initialized to zero (including the `string' field) for the
102 if ( REALLOC( out
->string
, size
* sizeof ( UShort
) ) )
104 if ( in
->properties
)
105 if ( REALLOC( out
->properties
, size
* sizeof ( UShort
) ) )
107 out
->allocated
= size
;
112 MEM_Copy( &out
->string
[out
->pos
], data
, num_out
* sizeof ( UShort
) );
113 if ( in
->properties
)
115 p_in
= in
->properties
[in
->pos
];
116 p_out
= out
->properties
;
118 for ( i
= out
->pos
; i
< out
->pos
+ num_out
; i
++ )
126 out
->length
= out
->pos
;
132 static TT_Error
Check_Property( TTO_GDEFHeader
* gdef
,
142 error
= TT_GDEF_Get_Glyph_Property( gdef
, index
, property
);
146 /* This is OpenType 1.2 */
148 if ( flags
& IGNORE_SPECIAL_MARKS
)
149 if ( (flags
& 0xFF00) != *property
)
150 return TTO_Err_Not_Covered
;
152 if ( flags
& *property
)
153 return TTO_Err_Not_Covered
;
161 /**********************
162 * Extension Functions
163 **********************/
166 static TT_Error
GSUB_Create( void* ext
,
169 DEFINE_LOAD_LOCALS( face
->stream
);
171 TTO_GSUBHeader
* gsub
= (TTO_GSUBHeader
*)ext
;
180 /* a null offset indicates that there is no GSUB table */
184 /* we store the start offset and the size of the subtable */
186 table
= TT_LookUp_Table( face
, TTAG_GSUB
);
188 return TT_Err_Ok
; /* The table is optional */
190 if ( FILE_Seek( face
->dirTables
[table
].Offset
) ||
194 gsub
->offset
= FILE_Pos() - 4L; /* undo ACCESS_Frame() */
195 gsub
->Version
= GET_ULong();
199 gsub
->loaded
= FALSE
;
205 static TT_Error
GSUB_Destroy( void* ext
,
208 TTO_GSUBHeader
* gsub
= (TTO_GSUBHeader
*)ext
;
218 Free_LookupList( &gsub
->LookupList
, GSUB
);
219 Free_FeatureList( &gsub
->FeatureList
);
220 Free_ScriptList( &gsub
->ScriptList
);
228 TT_Error
TT_Init_GSUB_Extension( TT_Engine engine
)
230 PEngine_Instance _engine
= HANDLE_Engine( engine
);
234 return TT_Err_Invalid_Engine
;
236 return TT_Register_Extension( _engine
,
238 sizeof ( TTO_GSUBHeader
),
245 TT_Error
TT_Load_GSUB_Table( TT_Face face
,
246 TTO_GSUBHeader
* retptr
,
247 TTO_GDEFHeader
* gdef
)
249 ULong cur_offset
, new_offset
, base_offset
;
251 TT_UShort i
, num_lookups
;
254 TTO_GSUBHeader
* gsub
;
257 PFace faze
= HANDLE_Face( face
);
261 return TT_Err_Invalid_Argument
;
264 return TT_Err_Invalid_Face_Handle
;
266 error
= TT_Extension_Get( faze
, GSUB_ID
, (void**)&gsub
);
270 if ( gsub
->offset
== 0 )
271 return TT_Err_Table_Missing
; /* no GSUB table; nothing to do */
273 /* now access stream */
275 if ( USE_Stream( faze
->stream
, stream
) )
278 base_offset
= gsub
->offset
;
282 if ( FILE_Seek( base_offset
+ 4L ) ||
286 new_offset
= GET_UShort() + base_offset
;
290 cur_offset
= FILE_Pos();
291 if ( FILE_Seek( new_offset
) ||
292 ( error
= Load_ScriptList( &gsub
->ScriptList
,
293 faze
) ) != TT_Err_Ok
)
295 (void)FILE_Seek( cur_offset
);
297 if ( ACCESS_Frame( 2L ) )
300 new_offset
= GET_UShort() + base_offset
;
304 cur_offset
= FILE_Pos();
305 if ( FILE_Seek( new_offset
) ||
306 ( error
= Load_FeatureList( &gsub
->FeatureList
,
307 faze
) ) != TT_Err_Ok
)
309 (void)FILE_Seek( cur_offset
);
311 if ( ACCESS_Frame( 2L ) )
314 new_offset
= GET_UShort() + base_offset
;
318 cur_offset
= FILE_Pos();
319 if ( FILE_Seek( new_offset
) ||
320 ( error
= Load_LookupList( &gsub
->LookupList
,
321 faze
, GSUB
) ) != TT_Err_Ok
)
324 gsub
->gdef
= gdef
; /* can be NULL */
326 /* We now check the LookupFlags for values larger than 0xFF to find
327 out whether we need to load the `MarkAttachClassDef' field of the
328 GDEF table -- this hack is necessary for OpenType 1.2 tables since
329 the version field of the GDEF table hasn't been incremented.
331 For constructed GDEF tables, we only load it if
332 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
333 a constructed mark attach table is not supported currently). */
336 gdef
->MarkAttachClassDef_offset
&& !gdef
->MarkAttachClassDef
.loaded
)
338 lo
= gsub
->LookupList
.Lookup
;
339 num_lookups
= gsub
->LookupList
.LookupCount
;
341 for ( i
= 0; i
< num_lookups
; i
++ )
343 if ( lo
[i
].LookupFlag
& IGNORE_SPECIAL_MARKS
)
345 if ( FILE_Seek( gdef
->MarkAttachClassDef_offset
) ||
349 new_offset
= GET_UShort();
354 return TTO_Err_Invalid_GDEF_SubTable
;
356 new_offset
+= base_offset
;
358 if ( FILE_Seek( new_offset
) ||
359 ( error
= Load_ClassDefinition( &gdef
->MarkAttachClassDef
,
360 256, faze
) ) != TT_Err_Ok
)
370 DONE_Stream( stream
);
375 Free_LookupList( &gsub
->LookupList
, GSUB
);
378 Free_FeatureList( &gsub
->FeatureList
);
381 Free_ScriptList( &gsub
->ScriptList
);
385 DONE_Stream( stream
);
392 /*****************************
393 * SubTable related functions
394 *****************************/
399 /* SingleSubstFormat1 */
400 /* SingleSubstFormat2 */
402 TT_Error
Load_SingleSubst( TTO_SingleSubst
* ss
,
405 DEFINE_LOAD_LOCALS( input
->stream
);
408 ULong cur_offset
, new_offset
, base_offset
;
413 base_offset
= FILE_Pos();
415 if ( ACCESS_Frame( 4L ) )
418 ss
->SubstFormat
= GET_UShort();
419 new_offset
= GET_UShort() + base_offset
;
423 cur_offset
= FILE_Pos();
424 if ( FILE_Seek( new_offset
) ||
425 ( error
= Load_Coverage( &ss
->Coverage
, input
) ) != TT_Err_Ok
)
427 (void)FILE_Seek( cur_offset
);
429 switch ( ss
->SubstFormat
)
432 if ( ACCESS_Frame( 2L ) )
435 ss
->ssf
.ssf1
.DeltaGlyphID
= GET_UShort();
442 if ( ACCESS_Frame( 2L ) )
445 count
= ss
->ssf
.ssf2
.GlyphCount
= GET_UShort();
449 ss
->ssf
.ssf2
.Substitute
= NULL
;
451 if ( ALLOC_ARRAY( ss
->ssf
.ssf2
.Substitute
, count
, UShort
) )
454 s
= ss
->ssf
.ssf2
.Substitute
;
456 if ( ACCESS_Frame( count
* 2L ) )
459 for ( n
= 0; n
< count
; n
++ )
467 return TTO_Err_Invalid_GSUB_SubTable_Format
;
476 Free_Coverage( &ss
->Coverage
);
481 void Free_SingleSubst( TTO_SingleSubst
* ss
)
483 switch ( ss
->SubstFormat
)
489 FREE( ss
->ssf
.ssf2
.Substitute
);
493 Free_Coverage( &ss
->Coverage
);
497 static TT_Error
Lookup_SingleSubst( TTO_SingleSubst
* ss
,
499 TTO_GSUB_String
* out
,
501 UShort context_length
,
502 TTO_GDEFHeader
* gdef
)
504 UShort index
, value
[1], property
;
508 if ( context_length
!= 0xFFFF && context_length
< 1 )
509 return TTO_Err_Not_Covered
;
511 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
514 error
= Coverage_Index( &ss
->Coverage
, in
->string
[in
->pos
], &index
);
518 switch ( ss
->SubstFormat
)
521 value
[0] = ( in
->string
[in
->pos
] + ss
->ssf
.ssf1
.DeltaGlyphID
) & 0xFFFF;
522 if ( ADD_String( in
, 1, out
, 1, value
) )
527 if ( index
>= ss
->ssf
.ssf2
.GlyphCount
)
528 return TTO_Err_Invalid_GSUB_SubTable
;
529 value
[0] = ss
->ssf
.ssf2
.Substitute
[index
];
530 if ( ADD_String( in
, 1, out
, 1, value
) )
535 return TTO_Err_Invalid_GSUB_SubTable
;
538 if ( gdef
&& gdef
->NewGlyphClasses
)
540 /* we inherit the old glyph class to the substituted glyph */
542 error
= Add_Glyph_Property( gdef
, value
[0], property
);
543 if ( error
&& error
!= TTO_Err_Not_Covered
)
555 static TT_Error
Load_Sequence( TTO_Sequence
* s
,
558 DEFINE_LOAD_LOCALS( input
->stream
);
564 if ( ACCESS_Frame( 2L ) )
567 count
= s
->GlyphCount
= GET_UShort();
571 s
->Substitute
= NULL
;
575 if ( ALLOC_ARRAY( s
->Substitute
, count
, UShort
) )
580 if ( ACCESS_Frame( count
* 2L ) )
586 for ( n
= 0; n
< count
; n
++ )
587 sub
[n
] = GET_UShort();
596 static void Free_Sequence( TTO_Sequence
* s
)
598 FREE( s
->Substitute
);
602 /* MultipleSubstFormat1 */
604 TT_Error
Load_MultipleSubst( TTO_MultipleSubst
* ms
,
607 DEFINE_LOAD_LOCALS( input
->stream
);
610 ULong cur_offset
, new_offset
, base_offset
;
615 base_offset
= FILE_Pos();
617 if ( ACCESS_Frame( 4L ) )
620 ms
->SubstFormat
= GET_UShort(); /* should be 1 */
621 new_offset
= GET_UShort() + base_offset
;
625 cur_offset
= FILE_Pos();
626 if ( FILE_Seek( new_offset
) ||
627 ( error
= Load_Coverage( &ms
->Coverage
, input
) ) != TT_Err_Ok
)
629 (void)FILE_Seek( cur_offset
);
631 if ( ACCESS_Frame( 2L ) )
634 count
= ms
->SequenceCount
= GET_UShort();
640 if ( ALLOC_ARRAY( ms
->Sequence
, count
, TTO_Sequence
) )
645 for ( n
= 0; n
< count
; n
++ )
647 if ( ACCESS_Frame( 2L ) )
650 new_offset
= GET_UShort() + base_offset
;
654 cur_offset
= FILE_Pos();
655 if ( FILE_Seek( new_offset
) ||
656 ( error
= Load_Sequence( &s
[n
], input
) ) != TT_Err_Ok
)
658 (void)FILE_Seek( cur_offset
);
664 for ( n
= 0; n
< count
; n
++ )
665 Free_Sequence( &s
[n
] );
670 Free_Coverage( &ms
->Coverage
);
675 void Free_MultipleSubst( TTO_MultipleSubst
* ms
)
684 count
= ms
->SequenceCount
;
687 for ( n
= 0; n
< count
; n
++ )
688 Free_Sequence( &s
[n
] );
693 Free_Coverage( &ms
->Coverage
);
697 static TT_Error
Lookup_MultipleSubst( TTO_MultipleSubst
* ms
,
699 TTO_GSUB_String
* out
,
701 UShort context_length
,
702 TTO_GDEFHeader
* gdef
)
705 UShort index
, property
, n
, count
;
709 if ( context_length
!= 0xFFFF && context_length
< 1 )
710 return TTO_Err_Not_Covered
;
712 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
715 error
= Coverage_Index( &ms
->Coverage
, in
->string
[in
->pos
], &index
);
719 if ( index
>= ms
->SequenceCount
)
720 return TTO_Err_Invalid_GSUB_SubTable
;
722 count
= ms
->Sequence
[index
].GlyphCount
;
723 s
= ms
->Sequence
[index
].Substitute
;
725 if ( ADD_String( in
, 1, out
, count
, s
) )
728 if ( gdef
&& gdef
->NewGlyphClasses
)
730 /* this is a guess only ... */
732 if ( property
== TTO_LIGATURE
)
733 property
= TTO_BASE_GLYPH
;
735 for ( n
= 0; n
< count
; n
++ )
737 error
= Add_Glyph_Property( gdef
, s
[n
], property
);
738 if ( error
&& error
!= TTO_Err_Not_Covered
)
751 static TT_Error
Load_AlternateSet( TTO_AlternateSet
* as
,
754 DEFINE_LOAD_LOCALS( input
->stream
);
760 if ( ACCESS_Frame( 2L ) )
763 count
= as
->GlyphCount
= GET_UShort();
767 as
->Alternate
= NULL
;
769 if ( ALLOC_ARRAY( as
->Alternate
, count
, UShort
) )
774 if ( ACCESS_Frame( count
* 2L ) )
780 for ( n
= 0; n
< count
; n
++ )
789 static void Free_AlternateSet( TTO_AlternateSet
* as
)
791 FREE( as
->Alternate
);
795 /* AlternateSubstFormat1 */
797 TT_Error
Load_AlternateSubst( TTO_AlternateSubst
* as
,
800 DEFINE_LOAD_LOCALS( input
->stream
);
803 ULong cur_offset
, new_offset
, base_offset
;
805 TTO_AlternateSet
* aset
;
808 base_offset
= FILE_Pos();
810 if ( ACCESS_Frame( 4L ) )
813 as
->SubstFormat
= GET_UShort(); /* should be 1 */
814 new_offset
= GET_UShort() + base_offset
;
818 cur_offset
= FILE_Pos();
819 if ( FILE_Seek( new_offset
) ||
820 ( error
= Load_Coverage( &as
->Coverage
, input
) ) != TT_Err_Ok
)
822 (void)FILE_Seek( cur_offset
);
824 if ( ACCESS_Frame( 2L ) )
827 count
= as
->AlternateSetCount
= GET_UShort();
831 as
->AlternateSet
= NULL
;
833 if ( ALLOC_ARRAY( as
->AlternateSet
, count
, TTO_AlternateSet
) )
836 aset
= as
->AlternateSet
;
838 for ( n
= 0; n
< count
; n
++ )
840 if ( ACCESS_Frame( 2L ) )
843 new_offset
= GET_UShort() + base_offset
;
847 cur_offset
= FILE_Pos();
848 if ( FILE_Seek( new_offset
) ||
849 ( error
= Load_AlternateSet( &aset
[n
], input
) ) != TT_Err_Ok
)
851 (void)FILE_Seek( cur_offset
);
857 for ( n
= 0; n
< count
; n
++ )
858 Free_AlternateSet( &aset
[n
] );
863 Free_Coverage( &as
->Coverage
);
868 void Free_AlternateSubst( TTO_AlternateSubst
* as
)
872 TTO_AlternateSet
* aset
;
875 if ( as
->AlternateSet
)
877 count
= as
->AlternateSetCount
;
878 aset
= as
->AlternateSet
;
880 for ( n
= 0; n
< count
; n
++ )
881 Free_AlternateSet( &aset
[n
] );
886 Free_Coverage( &as
->Coverage
);
890 static TT_Error
Lookup_AlternateSubst( TTO_GSUBHeader
* gsub
,
891 TTO_AlternateSubst
* as
,
893 TTO_GSUB_String
* out
,
895 UShort context_length
,
896 TTO_GDEFHeader
* gdef
)
899 UShort index
, alt_index
, property
;
901 TTO_AlternateSet aset
;
904 if ( context_length
!= 0xFFFF && context_length
< 1 )
905 return TTO_Err_Not_Covered
;
907 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
910 error
= Coverage_Index( &as
->Coverage
, in
->string
[in
->pos
], &index
);
914 aset
= as
->AlternateSet
[index
];
916 /* we use a user-defined callback function to get the alternate index */
919 alt_index
= (gsub
->alt
)( out
->pos
, in
->string
[in
->pos
],
920 aset
.GlyphCount
, aset
.Alternate
,
925 if ( ADD_String( in
, 1, out
, 1, &aset
.Alternate
[alt_index
] ) )
928 if ( gdef
&& gdef
->NewGlyphClasses
)
930 /* we inherit the old glyph class to the substituted glyph */
932 error
= Add_Glyph_Property( gdef
, aset
.Alternate
[alt_index
],
934 if ( error
&& error
!= TTO_Err_Not_Covered
)
946 static TT_Error
Load_Ligature( TTO_Ligature
* l
,
949 DEFINE_LOAD_LOCALS( input
->stream
);
955 if ( ACCESS_Frame( 4L ) )
958 l
->LigGlyph
= GET_UShort();
959 l
->ComponentCount
= GET_UShort();
965 count
= l
->ComponentCount
- 1; /* only ComponentCount - 1 elements */
967 if ( ALLOC_ARRAY( l
->Component
, count
, UShort
) )
972 if ( ACCESS_Frame( count
* 2L ) )
978 for ( n
= 0; n
< count
; n
++ )
987 static void Free_Ligature( TTO_Ligature
* l
)
989 FREE( l
->Component
);
995 static TT_Error
Load_LigatureSet( TTO_LigatureSet
* ls
,
998 DEFINE_LOAD_LOCALS( input
->stream
);
1001 ULong cur_offset
, new_offset
, base_offset
;
1006 base_offset
= FILE_Pos();
1008 if ( ACCESS_Frame( 2L ) )
1011 count
= ls
->LigatureCount
= GET_UShort();
1015 ls
->Ligature
= NULL
;
1017 if ( ALLOC_ARRAY( ls
->Ligature
, count
, TTO_Ligature
) )
1022 for ( n
= 0; n
< count
; n
++ )
1024 if ( ACCESS_Frame( 2L ) )
1027 new_offset
= GET_UShort() + base_offset
;
1031 cur_offset
= FILE_Pos();
1032 if ( FILE_Seek( new_offset
) ||
1033 ( error
= Load_Ligature( &l
[n
], input
) ) != TT_Err_Ok
)
1035 (void)FILE_Seek( cur_offset
);
1041 for ( n
= 0; n
< count
; n
++ )
1042 Free_Ligature( &l
[n
] );
1049 static void Free_LigatureSet( TTO_LigatureSet
* ls
)
1058 count
= ls
->LigatureCount
;
1061 for ( n
= 0; n
< count
; n
++ )
1062 Free_Ligature( &l
[n
] );
1069 /* LigatureSubstFormat1 */
1071 TT_Error
Load_LigatureSubst( TTO_LigatureSubst
* ls
,
1074 DEFINE_LOAD_LOCALS( input
->stream
);
1077 ULong cur_offset
, new_offset
, base_offset
;
1079 TTO_LigatureSet
* lset
;
1082 base_offset
= FILE_Pos();
1084 if ( ACCESS_Frame( 4L ) )
1087 ls
->SubstFormat
= GET_UShort(); /* should be 1 */
1088 new_offset
= GET_UShort() + base_offset
;
1092 cur_offset
= FILE_Pos();
1093 if ( FILE_Seek( new_offset
) ||
1094 ( error
= Load_Coverage( &ls
->Coverage
, input
) ) != TT_Err_Ok
)
1096 (void)FILE_Seek( cur_offset
);
1098 if ( ACCESS_Frame( 2L ) )
1101 count
= ls
->LigatureSetCount
= GET_UShort();
1105 ls
->LigatureSet
= NULL
;
1107 if ( ALLOC_ARRAY( ls
->LigatureSet
, count
, TTO_LigatureSet
) )
1110 lset
= ls
->LigatureSet
;
1112 for ( n
= 0; n
< count
; n
++ )
1114 if ( ACCESS_Frame( 2L ) )
1117 new_offset
= GET_UShort() + base_offset
;
1121 cur_offset
= FILE_Pos();
1122 if ( FILE_Seek( new_offset
) ||
1123 ( error
= Load_LigatureSet( &lset
[n
], input
) ) != TT_Err_Ok
)
1125 (void)FILE_Seek( cur_offset
);
1131 for ( n
= 0; n
< count
; n
++ )
1132 Free_LigatureSet( &lset
[n
] );
1137 Free_Coverage( &ls
->Coverage
);
1142 void Free_LigatureSubst( TTO_LigatureSubst
* ls
)
1146 TTO_LigatureSet
* lset
;
1149 if ( ls
->LigatureSet
)
1151 count
= ls
->LigatureSetCount
;
1152 lset
= ls
->LigatureSet
;
1154 for ( n
= 0; n
< count
; n
++ )
1155 Free_LigatureSet( &lset
[n
] );
1160 Free_Coverage( &ls
->Coverage
);
1164 static TT_Error
Lookup_LigatureSubst( TTO_LigatureSubst
* ls
,
1165 TTO_GSUB_String
* in
,
1166 TTO_GSUB_String
* out
,
1168 UShort context_length
,
1169 TTO_GDEFHeader
* gdef
)
1171 UShort index
, property
;
1173 UShort numlig
, i
, j
;
1180 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
1183 error
= Coverage_Index( &ls
->Coverage
, in
->string
[in
->pos
], &index
);
1187 if ( index
>= ls
->LigatureSetCount
)
1188 return TTO_Err_Invalid_GSUB_SubTable
;
1190 lig
= ls
->LigatureSet
[index
].Ligature
;
1192 for ( numlig
= ls
->LigatureSet
[index
].LigatureCount
;
1196 if ( in
->pos
+ lig
->ComponentCount
> in
->length
)
1197 continue; /* Not enough glyphs in input */
1199 s_in
= &in
->string
[in
->pos
];
1202 if ( context_length
!= 0xFFFF && context_length
< lig
->ComponentCount
)
1205 for ( i
= 1, j
= 1; i
< lig
->ComponentCount
; i
++, j
++ )
1207 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
1209 if ( error
&& error
!= TTO_Err_Not_Covered
)
1212 if ( in
->pos
+ j
< in
->length
)
1218 if ( s_in
[j
] != c
[i
- 1] )
1222 if ( i
== lig
->ComponentCount
)
1224 if ( ADD_String( in
, lig
->ComponentCount
, out
, 1, &lig
->LigGlyph
) )
1227 if ( gdef
&& gdef
->NewGlyphClasses
)
1229 /* this is just a guess ... */
1231 error
= Add_Glyph_Property( gdef
, lig
->LigGlyph
, TTO_LIGATURE
);
1232 if ( error
&& error
!= TTO_Err_Not_Covered
)
1240 return TTO_Err_Not_Covered
;
1244 /* Do the actual substitution for a context substitution (either format
1245 5 or 6). This is only called after we've determined that the input
1246 matches the subrule. */
1248 static TT_Error
Do_ContextSubst( TTO_GSUBHeader
* gsub
,
1251 TTO_SubstLookupRecord
* subst
,
1252 TTO_GSUB_String
* in
,
1253 TTO_GSUB_String
* out
,
1262 while ( i
< GlyphCount
)
1264 if ( SubstCount
&& i
== subst
->SequenceIndex
)
1268 /* Do a substitution */
1270 error
= Do_Glyph_Lookup( gsub
, subst
->LookupListIndex
, in
, out
,
1271 GlyphCount
, nesting_level
);
1275 i
+= in
->pos
- old_pos
;
1277 if ( error
== TTO_Err_Not_Covered
)
1279 /* XXX "can't happen" -- but don't count on it */
1281 if ( ADD_String( in
, 1, out
, 1, &in
->string
[in
->pos
] ) )
1290 /* No substitution for this index */
1292 if ( ADD_String( in
, 1, out
, 1, &in
->string
[in
->pos
] ) )
1306 static TT_Error
Load_SubRule( TTO_SubRule
* sr
,
1309 DEFINE_LOAD_LOCALS( input
->stream
);
1314 TTO_SubstLookupRecord
* slr
;
1317 if ( ACCESS_Frame( 4L ) )
1320 sr
->GlyphCount
= GET_UShort();
1321 sr
->SubstCount
= GET_UShort();
1327 count
= sr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
1329 if ( ALLOC_ARRAY( sr
->Input
, count
, UShort
) )
1334 if ( ACCESS_Frame( count
* 2L ) )
1337 for ( n
= 0; n
< count
; n
++ )
1338 i
[n
] = GET_UShort();
1342 sr
->SubstLookupRecord
= NULL
;
1344 count
= sr
->SubstCount
;
1346 if ( ALLOC_ARRAY( sr
->SubstLookupRecord
, count
, TTO_SubstLookupRecord
) )
1349 slr
= sr
->SubstLookupRecord
;
1351 if ( ACCESS_Frame( count
* 4L ) )
1354 for ( n
= 0; n
< count
; n
++ )
1356 slr
[n
].SequenceIndex
= GET_UShort();
1357 slr
[n
].LookupListIndex
= GET_UShort();
1373 static void Free_SubRule( TTO_SubRule
* sr
)
1375 FREE( sr
->SubstLookupRecord
);
1382 static TT_Error
Load_SubRuleSet( TTO_SubRuleSet
* srs
,
1385 DEFINE_LOAD_LOCALS( input
->stream
);
1388 ULong cur_offset
, new_offset
, base_offset
;
1393 base_offset
= FILE_Pos();
1395 if ( ACCESS_Frame( 2L ) )
1398 count
= srs
->SubRuleCount
= GET_UShort();
1402 srs
->SubRule
= NULL
;
1404 if ( ALLOC_ARRAY( srs
->SubRule
, count
, TTO_SubRule
) )
1409 for ( n
= 0; n
< count
; n
++ )
1411 if ( ACCESS_Frame( 2L ) )
1414 new_offset
= GET_UShort() + base_offset
;
1418 cur_offset
= FILE_Pos();
1419 if ( FILE_Seek( new_offset
) ||
1420 ( error
= Load_SubRule( &sr
[n
], input
) ) != TT_Err_Ok
)
1422 (void)FILE_Seek( cur_offset
);
1428 for ( n
= 0; n
< count
; n
++ )
1429 Free_SubRule( &sr
[n
] );
1436 static void Free_SubRuleSet( TTO_SubRuleSet
* srs
)
1445 count
= srs
->SubRuleCount
;
1448 for ( n
= 0; n
< count
; n
++ )
1449 Free_SubRule( &sr
[n
] );
1456 /* ContextSubstFormat1 */
1458 static TT_Error
Load_ContextSubst1( TTO_ContextSubstFormat1
* csf1
,
1461 DEFINE_LOAD_LOCALS( input
->stream
);
1464 ULong cur_offset
, new_offset
, base_offset
;
1466 TTO_SubRuleSet
* srs
;
1469 base_offset
= FILE_Pos() - 2L;
1471 if ( ACCESS_Frame( 2L ) )
1474 new_offset
= GET_UShort() + base_offset
;
1478 cur_offset
= FILE_Pos();
1479 if ( FILE_Seek( new_offset
) ||
1480 ( error
= Load_Coverage( &csf1
->Coverage
, input
) ) != TT_Err_Ok
)
1482 (void)FILE_Seek( cur_offset
);
1484 if ( ACCESS_Frame( 2L ) )
1487 count
= csf1
->SubRuleSetCount
= GET_UShort();
1491 csf1
->SubRuleSet
= NULL
;
1493 if ( ALLOC_ARRAY( csf1
->SubRuleSet
, count
, TTO_SubRuleSet
) )
1496 srs
= csf1
->SubRuleSet
;
1498 for ( n
= 0; n
< count
; n
++ )
1500 if ( ACCESS_Frame( 2L ) )
1503 new_offset
= GET_UShort() + base_offset
;
1507 cur_offset
= FILE_Pos();
1508 if ( FILE_Seek( new_offset
) ||
1509 ( error
= Load_SubRuleSet( &srs
[n
], input
) ) != TT_Err_Ok
)
1511 (void)FILE_Seek( cur_offset
);
1517 for ( n
= 0; n
< count
; n
++ )
1518 Free_SubRuleSet( &srs
[n
] );
1523 Free_Coverage( &csf1
->Coverage
);
1528 static void Free_Context1( TTO_ContextSubstFormat1
* csf1
)
1532 TTO_SubRuleSet
* srs
;
1535 if ( csf1
->SubRuleSet
)
1537 count
= csf1
->SubRuleSetCount
;
1538 srs
= csf1
->SubRuleSet
;
1540 for ( n
= 0; n
< count
; n
++ )
1541 Free_SubRuleSet( &srs
[n
] );
1546 Free_Coverage( &csf1
->Coverage
);
1552 static TT_Error
Load_SubClassRule( TTO_ContextSubstFormat2
* csf2
,
1553 TTO_SubClassRule
* scr
,
1556 DEFINE_LOAD_LOCALS( input
->stream
);
1561 TTO_SubstLookupRecord
* slr
;
1565 if ( ACCESS_Frame( 4L ) )
1568 scr
->GlyphCount
= GET_UShort();
1569 scr
->SubstCount
= GET_UShort();
1571 if ( scr
->GlyphCount
> csf2
->MaxContextLength
)
1572 csf2
->MaxContextLength
= scr
->GlyphCount
;
1578 count
= scr
->GlyphCount
- 1; /* only GlyphCount - 1 elements */
1580 if ( ALLOC_ARRAY( scr
->Class
, count
, UShort
) )
1584 d
= csf2
->ClassDef
.Defined
;
1586 if ( ACCESS_Frame( count
* 2L ) )
1589 for ( n
= 0; n
< count
; n
++ )
1591 c
[n
] = GET_UShort();
1593 /* We check whether the specific class is used at all. If not,
1594 class 0 is used instead. */
1602 scr
->SubstLookupRecord
= NULL
;
1604 count
= scr
->SubstCount
;
1606 if ( ALLOC_ARRAY( scr
->SubstLookupRecord
, count
, TTO_SubstLookupRecord
) )
1609 slr
= scr
->SubstLookupRecord
;
1611 if ( ACCESS_Frame( count
* 4L ) )
1614 for ( n
= 0; n
< count
; n
++ )
1616 slr
[n
].SequenceIndex
= GET_UShort();
1617 slr
[n
].LookupListIndex
= GET_UShort();
1633 static void Free_SubClassRule( TTO_SubClassRule
* scr
)
1635 FREE( scr
->SubstLookupRecord
);
1642 static TT_Error
Load_SubClassSet( TTO_ContextSubstFormat2
* csf2
,
1643 TTO_SubClassSet
* scs
,
1646 DEFINE_LOAD_LOCALS( input
->stream
);
1649 ULong cur_offset
, new_offset
, base_offset
;
1651 TTO_SubClassRule
* scr
;
1654 base_offset
= FILE_Pos();
1656 if ( ACCESS_Frame( 2L ) )
1659 count
= scs
->SubClassRuleCount
= GET_UShort();
1663 scs
->SubClassRule
= NULL
;
1665 if ( ALLOC_ARRAY( scs
->SubClassRule
, count
, TTO_SubClassRule
) )
1668 scr
= scs
->SubClassRule
;
1670 for ( n
= 0; n
< count
; n
++ )
1672 if ( ACCESS_Frame( 2L ) )
1675 new_offset
= GET_UShort() + base_offset
;
1679 cur_offset
= FILE_Pos();
1680 if ( FILE_Seek( new_offset
) ||
1681 ( error
= Load_SubClassRule( csf2
, &scr
[n
],
1682 input
) ) != TT_Err_Ok
)
1684 (void)FILE_Seek( cur_offset
);
1690 for ( n
= 0; n
< count
; n
++ )
1691 Free_SubClassRule( &scr
[n
] );
1698 static void Free_SubClassSet( TTO_SubClassSet
* scs
)
1702 TTO_SubClassRule
* scr
;
1705 if ( scs
->SubClassRule
)
1707 count
= scs
->SubClassRuleCount
;
1708 scr
= scs
->SubClassRule
;
1710 for ( n
= 0; n
< count
; n
++ )
1711 Free_SubClassRule( &scr
[n
] );
1718 /* ContextSubstFormat2 */
1720 static TT_Error
Load_ContextSubst2( TTO_ContextSubstFormat2
* csf2
,
1723 DEFINE_LOAD_LOCALS( input
->stream
);
1726 ULong cur_offset
, new_offset
, base_offset
;
1728 TTO_SubClassSet
* scs
;
1731 base_offset
= FILE_Pos() - 2;
1733 if ( ACCESS_Frame( 2L ) )
1736 new_offset
= GET_UShort() + base_offset
;
1740 cur_offset
= FILE_Pos();
1741 if ( FILE_Seek( new_offset
) ||
1742 ( error
= Load_Coverage( &csf2
->Coverage
, input
) ) != TT_Err_Ok
)
1744 (void)FILE_Seek( cur_offset
);
1746 if ( ACCESS_Frame( 4L ) )
1749 new_offset
= GET_UShort() + base_offset
;
1751 /* `SubClassSetCount' is the upper limit for class values, thus we
1752 read it now to make an additional safety check. */
1754 count
= csf2
->SubClassSetCount
= GET_UShort();
1758 cur_offset
= FILE_Pos();
1759 if ( FILE_Seek( new_offset
) ||
1760 ( error
= Load_ClassDefinition( &csf2
->ClassDef
, count
,
1761 input
) ) != TT_Err_Ok
)
1763 (void)FILE_Seek( cur_offset
);
1765 csf2
->SubClassSet
= NULL
;
1766 csf2
->MaxContextLength
= 0;
1768 if ( ALLOC_ARRAY( csf2
->SubClassSet
, count
, TTO_SubClassSet
) )
1771 scs
= csf2
->SubClassSet
;
1773 for ( n
= 0; n
< count
; n
++ )
1775 if ( ACCESS_Frame( 2L ) )
1778 new_offset
= GET_UShort() + base_offset
;
1782 if ( new_offset
!= base_offset
) /* not a NULL offset */
1784 cur_offset
= FILE_Pos();
1785 if ( FILE_Seek( new_offset
) ||
1786 ( error
= Load_SubClassSet( csf2
, &scs
[n
],
1787 input
) ) != TT_Err_Ok
)
1789 (void)FILE_Seek( cur_offset
);
1793 /* we create a SubClassSet table with no entries */
1795 csf2
->SubClassSet
[n
].SubClassRuleCount
= 0;
1796 csf2
->SubClassSet
[n
].SubClassRule
= NULL
;
1803 for ( n
= 0; n
< count
; n
++ )
1804 Free_SubClassSet( &scs
[n
] );
1809 Free_ClassDefinition( &csf2
->ClassDef
);
1812 Free_Coverage( &csf2
->Coverage
);
1817 static void Free_Context2( TTO_ContextSubstFormat2
* csf2
)
1821 TTO_SubClassSet
* scs
;
1824 if ( csf2
->SubClassSet
)
1826 count
= csf2
->SubClassSetCount
;
1827 scs
= csf2
->SubClassSet
;
1829 for ( n
= 0; n
< count
; n
++ )
1830 Free_SubClassSet( &scs
[n
] );
1835 Free_ClassDefinition( &csf2
->ClassDef
);
1836 Free_Coverage( &csf2
->Coverage
);
1840 /* ContextSubstFormat3 */
1842 static TT_Error
Load_ContextSubst3( TTO_ContextSubstFormat3
* csf3
,
1845 DEFINE_LOAD_LOCALS( input
->stream
);
1848 ULong cur_offset
, new_offset
, base_offset
;
1851 TTO_SubstLookupRecord
* slr
;
1854 base_offset
= FILE_Pos() - 2L;
1856 if ( ACCESS_Frame( 4L ) )
1859 csf3
->GlyphCount
= GET_UShort();
1860 csf3
->SubstCount
= GET_UShort();
1864 csf3
->Coverage
= NULL
;
1866 count
= csf3
->GlyphCount
;
1868 if ( ALLOC_ARRAY( csf3
->Coverage
, count
, TTO_Coverage
) )
1873 for ( n
= 0; n
< count
; n
++ )
1875 if ( ACCESS_Frame( 2L ) )
1878 new_offset
= GET_UShort() + base_offset
;
1882 cur_offset
= FILE_Pos();
1883 if ( FILE_Seek( new_offset
) ||
1884 ( error
= Load_Coverage( &c
[n
], input
) ) != TT_Err_Ok
)
1886 (void)FILE_Seek( cur_offset
);
1889 csf3
->SubstLookupRecord
= NULL
;
1891 count
= csf3
->SubstCount
;
1893 if ( ALLOC_ARRAY( csf3
->SubstLookupRecord
, count
,
1894 TTO_SubstLookupRecord
) )
1897 slr
= csf3
->SubstLookupRecord
;
1899 if ( ACCESS_Frame( count
* 4L ) )
1902 for ( n
= 0; n
< count
; n
++ )
1904 slr
[n
].SequenceIndex
= GET_UShort();
1905 slr
[n
].LookupListIndex
= GET_UShort();
1916 for ( n
= 0; n
< count
; n
++ )
1917 Free_Coverage( &c
[n
] );
1924 static void Free_Context3( TTO_ContextSubstFormat3
* csf3
)
1931 FREE( csf3
->SubstLookupRecord
);
1933 if ( csf3
->Coverage
)
1935 count
= csf3
->GlyphCount
;
1938 for ( n
= 0; n
< count
; n
++ )
1939 Free_Coverage( &c
[n
] );
1948 TT_Error
Load_ContextSubst( TTO_ContextSubst
* cs
,
1951 DEFINE_LOAD_LOCALS( input
->stream
);
1954 if ( ACCESS_Frame( 2L ) )
1957 cs
->SubstFormat
= GET_UShort();
1961 switch ( cs
->SubstFormat
)
1964 return Load_ContextSubst1( &cs
->csf
.csf1
, input
);
1967 return Load_ContextSubst2( &cs
->csf
.csf2
, input
);
1970 return Load_ContextSubst3( &cs
->csf
.csf3
, input
);
1973 return TTO_Err_Invalid_GSUB_SubTable_Format
;
1976 return TT_Err_Ok
; /* never reached */
1980 void Free_ContextSubst( TTO_ContextSubst
* cs
)
1982 switch ( cs
->SubstFormat
)
1985 Free_Context1( &cs
->csf
.csf1
);
1989 Free_Context2( &cs
->csf
.csf2
);
1993 Free_Context3( &cs
->csf
.csf3
);
1999 static TT_Error
Lookup_ContextSubst1(
2000 TTO_GSUBHeader
* gsub
,
2001 TTO_ContextSubstFormat1
* csf1
,
2002 TTO_GSUB_String
* in
,
2003 TTO_GSUB_String
* out
,
2005 UShort context_length
,
2008 UShort index
, property
;
2009 UShort i
, j
, k
, numsr
;
2014 TTO_GDEFHeader
* gdef
;
2019 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
2022 error
= Coverage_Index( &csf1
->Coverage
, in
->string
[in
->pos
], &index
);
2026 sr
= csf1
->SubRuleSet
[index
].SubRule
;
2027 numsr
= csf1
->SubRuleSet
[index
].SubRuleCount
;
2029 for ( k
= 0; k
< numsr
; k
++ )
2031 if ( context_length
!= 0xFFFF && context_length
< sr
[k
].GlyphCount
)
2034 if ( in
->pos
+ sr
[k
].GlyphCount
> in
->length
)
2035 continue; /* context is too long */
2037 s_in
= &in
->string
[in
->pos
];
2039 for ( i
= 1, j
= 1; i
< sr
[k
].GlyphCount
; i
++, j
++ )
2041 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
2043 if ( error
&& error
!= TTO_Err_Not_Covered
)
2046 if ( in
->pos
+ j
< in
->length
)
2052 if ( s_in
[j
] != sr
[k
].Input
[i
- 1] )
2056 if ( i
== sr
[k
].GlyphCount
)
2057 return Do_ContextSubst( gsub
, sr
[k
].GlyphCount
,
2058 sr
[k
].SubstCount
, sr
[k
].SubstLookupRecord
,
2063 return TTO_Err_Not_Covered
;
2067 static TT_Error
Lookup_ContextSubst2(
2068 TTO_GSUBHeader
* gsub
,
2069 TTO_ContextSubstFormat2
* csf2
,
2070 TTO_GSUB_String
* in
,
2071 TTO_GSUB_String
* out
,
2073 UShort context_length
,
2076 UShort index
, property
;
2078 UShort i
, j
, k
, known_classes
;
2084 TTO_SubClassSet
* scs
;
2085 TTO_SubClassRule
* sr
;
2086 TTO_GDEFHeader
* gdef
;
2091 if ( ALLOC_ARRAY( classes
, csf2
->MaxContextLength
, UShort
) )
2094 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
2097 /* Note: The coverage table in format 2 doesn't give an index into
2098 anything. It just lets us know whether or not we need to
2099 do any lookup at all. */
2101 error
= Coverage_Index( &csf2
->Coverage
, in
->string
[in
->pos
], &index
);
2105 error
= Get_Class( &csf2
->ClassDef
, in
->string
[in
->pos
],
2106 &classes
[0], NULL
);
2111 scs
= &csf2
->SubClassSet
[classes
[0]];
2114 error
= TTO_Err_Invalid_GSUB_SubTable
;
2118 for ( k
= 0; k
< scs
->SubClassRuleCount
; k
++ )
2120 sr
= &scs
->SubClassRule
[k
];
2122 if ( context_length
!= 0xFFFF && context_length
< sr
->GlyphCount
)
2125 if ( in
->pos
+ sr
->GlyphCount
> in
->length
)
2126 continue; /* context is too long */
2128 s_in
= &in
->string
[in
->pos
];
2131 /* Start at 1 because [0] is implied */
2133 for ( i
= 1, j
= 1; i
< sr
->GlyphCount
; i
++, j
++ )
2135 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
2137 if ( error
&& error
!= TTO_Err_Not_Covered
)
2140 if ( in
->pos
+ j
< in
->length
)
2146 if ( i
> known_classes
)
2148 /* Keeps us from having to do this for each rule */
2150 error
= Get_Class( &csf2
->ClassDef
, s_in
[j
], &classes
[i
], NULL
);
2151 if ( error
&& error
!= TTO_Err_Not_Covered
)
2156 if ( cl
[i
- 1] != classes
[i
] )
2160 if ( i
== sr
->GlyphCount
)
2162 error
= Do_ContextSubst( gsub
, sr
->GlyphCount
,
2163 sr
->SubstCount
, sr
->SubstLookupRecord
,
2170 error
= TTO_Err_Not_Covered
;
2178 static TT_Error
Lookup_ContextSubst3(
2179 TTO_GSUBHeader
* gsub
,
2180 TTO_ContextSubstFormat3
* csf3
,
2181 TTO_GSUB_String
* in
,
2182 TTO_GSUB_String
* out
,
2184 UShort context_length
,
2188 UShort index
, i
, j
, property
;
2192 TTO_GDEFHeader
* gdef
;
2197 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
2200 if ( context_length
!= 0xFFFF && context_length
< csf3
->GlyphCount
)
2201 return TTO_Err_Not_Covered
;
2203 if ( in
->pos
+ csf3
->GlyphCount
> in
->length
)
2204 return TTO_Err_Not_Covered
; /* context is too long */
2206 s_in
= &in
->string
[in
->pos
];
2209 for ( i
= 1, j
= 1; i
< csf3
->GlyphCount
; i
++, j
++ )
2211 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
2213 if ( error
&& error
!= TTO_Err_Not_Covered
)
2216 if ( in
->pos
+ j
< in
->length
)
2219 return TTO_Err_Not_Covered
;
2222 error
= Coverage_Index( &c
[i
], s_in
[j
], &index
);
2227 return Do_ContextSubst( gsub
, csf3
->GlyphCount
,
2228 csf3
->SubstCount
, csf3
->SubstLookupRecord
,
2234 static TT_Error
Lookup_ContextSubst( TTO_GSUBHeader
* gsub
,
2235 TTO_ContextSubst
* cs
,
2236 TTO_GSUB_String
* in
,
2237 TTO_GSUB_String
* out
,
2239 UShort context_length
,
2242 switch ( cs
->SubstFormat
)
2245 return Lookup_ContextSubst1( gsub
, &cs
->csf
.csf1
, in
, out
,
2246 flags
, context_length
, nesting_level
);
2249 return Lookup_ContextSubst2( gsub
, &cs
->csf
.csf2
, in
, out
,
2250 flags
, context_length
, nesting_level
);
2253 return Lookup_ContextSubst3( gsub
, &cs
->csf
.csf3
, in
, out
,
2254 flags
, context_length
, nesting_level
);
2257 return TTO_Err_Invalid_GSUB_SubTable_Format
;
2260 return TT_Err_Ok
; /* never reached */
2268 static TT_Error
Load_ChainSubRule( TTO_ChainSubRule
* csr
,
2271 DEFINE_LOAD_LOCALS( input
->stream
);
2278 TTO_SubstLookupRecord
* slr
;
2281 if ( ACCESS_Frame( 2L ) )
2284 csr
->BacktrackGlyphCount
= GET_UShort();
2288 csr
->Backtrack
= NULL
;
2290 count
= csr
->BacktrackGlyphCount
;
2292 if ( ALLOC_ARRAY( csr
->Backtrack
, count
, UShort
) )
2297 if ( ACCESS_Frame( count
* 2L ) )
2300 for ( n
= 0; n
< count
; n
++ )
2301 b
[n
] = GET_UShort();
2305 if ( ACCESS_Frame( 2L ) )
2308 csr
->InputGlyphCount
= GET_UShort();
2314 count
= csr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
2316 if ( ALLOC_ARRAY( csr
->Input
, count
, UShort
) )
2321 if ( ACCESS_Frame( count
* 2L ) )
2324 for ( n
= 0; n
< count
; n
++ )
2325 i
[n
] = GET_UShort();
2329 if ( ACCESS_Frame( 2L ) )
2332 csr
->LookaheadGlyphCount
= GET_UShort();
2336 csr
->Lookahead
= NULL
;
2338 count
= csr
->LookaheadGlyphCount
;
2340 if ( ALLOC_ARRAY( csr
->Lookahead
, count
, UShort
) )
2345 if ( ACCESS_Frame( count
* 2L ) )
2348 for ( n
= 0; n
< count
; n
++ )
2349 l
[n
] = GET_UShort();
2353 if ( ACCESS_Frame( 2L ) )
2356 csr
->SubstCount
= GET_UShort();
2360 csr
->SubstLookupRecord
= NULL
;
2362 count
= csr
->SubstCount
;
2364 if ( ALLOC_ARRAY( csr
->SubstLookupRecord
, count
, TTO_SubstLookupRecord
) )
2367 slr
= csr
->SubstLookupRecord
;
2369 if ( ACCESS_Frame( count
* 4L ) )
2372 for ( n
= 0; n
< count
; n
++ )
2374 slr
[n
].SequenceIndex
= GET_UShort();
2375 slr
[n
].LookupListIndex
= GET_UShort();
2397 static void Free_ChainSubRule( TTO_ChainSubRule
* csr
)
2399 FREE( csr
->SubstLookupRecord
);
2400 FREE( csr
->Lookahead
);
2402 FREE( csr
->Backtrack
);
2406 /* ChainSubRuleSet */
2408 static TT_Error
Load_ChainSubRuleSet( TTO_ChainSubRuleSet
* csrs
,
2411 DEFINE_LOAD_LOCALS( input
->stream
);
2414 ULong cur_offset
, new_offset
, base_offset
;
2416 TTO_ChainSubRule
* csr
;
2419 base_offset
= FILE_Pos();
2421 if ( ACCESS_Frame( 2L ) )
2424 count
= csrs
->ChainSubRuleCount
= GET_UShort();
2428 csrs
->ChainSubRule
= NULL
;
2430 if ( ALLOC_ARRAY( csrs
->ChainSubRule
, count
, TTO_ChainSubRule
) )
2433 csr
= csrs
->ChainSubRule
;
2435 for ( n
= 0; n
< count
; n
++ )
2437 if ( ACCESS_Frame( 2L ) )
2440 new_offset
= GET_UShort() + base_offset
;
2444 cur_offset
= FILE_Pos();
2445 if ( FILE_Seek( new_offset
) ||
2446 ( error
= Load_ChainSubRule( &csr
[n
], input
) ) != TT_Err_Ok
)
2448 (void)FILE_Seek( cur_offset
);
2454 for ( n
= 0; n
< count
; n
++ )
2455 Free_ChainSubRule( &csr
[n
] );
2462 static void Free_ChainSubRuleSet( TTO_ChainSubRuleSet
* csrs
)
2466 TTO_ChainSubRule
* csr
;
2469 if ( csrs
->ChainSubRule
)
2471 count
= csrs
->ChainSubRuleCount
;
2472 csr
= csrs
->ChainSubRule
;
2474 for ( n
= 0; n
< count
; n
++ )
2475 Free_ChainSubRule( &csr
[n
] );
2482 /* ChainContextSubstFormat1 */
2484 static TT_Error
Load_ChainContextSubst1(
2485 TTO_ChainContextSubstFormat1
* ccsf1
,
2488 DEFINE_LOAD_LOCALS( input
->stream
);
2491 ULong cur_offset
, new_offset
, base_offset
;
2493 TTO_ChainSubRuleSet
* csrs
;
2496 base_offset
= FILE_Pos() - 2L;
2498 if ( ACCESS_Frame( 2L ) )
2501 new_offset
= GET_UShort() + base_offset
;
2505 cur_offset
= FILE_Pos();
2506 if ( FILE_Seek( new_offset
) ||
2507 ( error
= Load_Coverage( &ccsf1
->Coverage
, input
) ) != TT_Err_Ok
)
2509 (void)FILE_Seek( cur_offset
);
2511 if ( ACCESS_Frame( 2L ) )
2514 count
= ccsf1
->ChainSubRuleSetCount
= GET_UShort();
2518 ccsf1
->ChainSubRuleSet
= NULL
;
2520 if ( ALLOC_ARRAY( ccsf1
->ChainSubRuleSet
, count
, TTO_ChainSubRuleSet
) )
2523 csrs
= ccsf1
->ChainSubRuleSet
;
2525 for ( n
= 0; n
< count
; n
++ )
2527 if ( ACCESS_Frame( 2L ) )
2530 new_offset
= GET_UShort() + base_offset
;
2534 cur_offset
= FILE_Pos();
2535 if ( FILE_Seek( new_offset
) ||
2536 ( error
= Load_ChainSubRuleSet( &csrs
[n
], input
) ) != TT_Err_Ok
)
2538 (void)FILE_Seek( cur_offset
);
2544 for ( n
= 0; n
< count
; n
++ )
2545 Free_ChainSubRuleSet( &csrs
[n
] );
2550 Free_Coverage( &ccsf1
->Coverage
);
2555 static void Free_ChainContext1( TTO_ChainContextSubstFormat1
* ccsf1
)
2559 TTO_ChainSubRuleSet
* csrs
;
2562 if ( ccsf1
->ChainSubRuleSet
)
2564 count
= ccsf1
->ChainSubRuleSetCount
;
2565 csrs
= ccsf1
->ChainSubRuleSet
;
2567 for ( n
= 0; n
< count
; n
++ )
2568 Free_ChainSubRuleSet( &csrs
[n
] );
2573 Free_Coverage( &ccsf1
->Coverage
);
2577 /* ChainSubClassRule */
2579 static TT_Error
Load_ChainSubClassRule(
2580 TTO_ChainContextSubstFormat2
* ccsf2
,
2581 TTO_ChainSubClassRule
* cscr
,
2584 DEFINE_LOAD_LOCALS( input
->stream
);
2591 TTO_SubstLookupRecord
* slr
;
2595 if ( ACCESS_Frame( 2L ) )
2598 cscr
->BacktrackGlyphCount
= GET_UShort();
2602 if ( cscr
->BacktrackGlyphCount
> ccsf2
->MaxBacktrackLength
)
2603 ccsf2
->MaxBacktrackLength
= cscr
->BacktrackGlyphCount
;
2605 cscr
->Backtrack
= NULL
;
2607 count
= cscr
->BacktrackGlyphCount
;
2609 if ( ALLOC_ARRAY( cscr
->Backtrack
, count
, UShort
) )
2612 b
= cscr
->Backtrack
;
2613 d
= ccsf2
->BacktrackClassDef
.Defined
;
2615 if ( ACCESS_Frame( count
* 2L ) )
2618 for ( n
= 0; n
< count
; n
++ )
2620 b
[n
] = GET_UShort();
2622 /* We check whether the specific class is used at all. If not,
2623 class 0 is used instead. */
2631 if ( ACCESS_Frame( 2L ) )
2634 cscr
->InputGlyphCount
= GET_UShort();
2638 if ( cscr
->InputGlyphCount
> ccsf2
->MaxInputLength
)
2639 ccsf2
->MaxInputLength
= cscr
->InputGlyphCount
;
2643 count
= cscr
->InputGlyphCount
- 1; /* only InputGlyphCount - 1 elements */
2645 if ( ALLOC_ARRAY( cscr
->Input
, count
, UShort
) )
2649 d
= ccsf2
->InputClassDef
.Defined
;
2651 if ( ACCESS_Frame( count
* 2L ) )
2654 for ( n
= 0; n
< count
; n
++ )
2656 i
[n
] = GET_UShort();
2664 if ( ACCESS_Frame( 2L ) )
2667 cscr
->LookaheadGlyphCount
= GET_UShort();
2671 if ( cscr
->LookaheadGlyphCount
> ccsf2
->MaxLookaheadLength
)
2672 ccsf2
->MaxLookaheadLength
= cscr
->LookaheadGlyphCount
;
2674 cscr
->Lookahead
= NULL
;
2676 count
= cscr
->LookaheadGlyphCount
;
2678 if ( ALLOC_ARRAY( cscr
->Lookahead
, count
, UShort
) )
2681 l
= cscr
->Lookahead
;
2682 d
= ccsf2
->LookaheadClassDef
.Defined
;
2684 if ( ACCESS_Frame( count
* 2L ) )
2687 for ( n
= 0; n
< count
; n
++ )
2689 l
[n
] = GET_UShort();
2697 if ( ACCESS_Frame( 2L ) )
2700 cscr
->SubstCount
= GET_UShort();
2704 cscr
->SubstLookupRecord
= NULL
;
2706 count
= cscr
->SubstCount
;
2708 if ( ALLOC_ARRAY( cscr
->SubstLookupRecord
, count
,
2709 TTO_SubstLookupRecord
) )
2712 slr
= cscr
->SubstLookupRecord
;
2714 if ( ACCESS_Frame( count
* 4L ) )
2717 for ( n
= 0; n
< count
; n
++ )
2719 slr
[n
].SequenceIndex
= GET_UShort();
2720 slr
[n
].LookupListIndex
= GET_UShort();
2742 static void Free_ChainSubClassRule( TTO_ChainSubClassRule
* cscr
)
2744 FREE( cscr
->SubstLookupRecord
);
2745 FREE( cscr
->Lookahead
);
2746 FREE( cscr
->Input
);
2747 FREE( cscr
->Backtrack
);
2753 static TT_Error
Load_ChainSubClassSet(
2754 TTO_ChainContextSubstFormat2
* ccsf2
,
2755 TTO_ChainSubClassSet
* cscs
,
2758 DEFINE_LOAD_LOCALS( input
->stream
);
2761 ULong cur_offset
, new_offset
, base_offset
;
2763 TTO_ChainSubClassRule
* cscr
;
2766 base_offset
= FILE_Pos();
2768 if ( ACCESS_Frame( 2L ) )
2771 count
= cscs
->ChainSubClassRuleCount
= GET_UShort();
2775 cscs
->ChainSubClassRule
= NULL
;
2777 if ( ALLOC_ARRAY( cscs
->ChainSubClassRule
, count
,
2778 TTO_ChainSubClassRule
) )
2781 cscr
= cscs
->ChainSubClassRule
;
2783 for ( n
= 0; n
< count
; n
++ )
2785 if ( ACCESS_Frame( 2L ) )
2788 new_offset
= GET_UShort() + base_offset
;
2792 cur_offset
= FILE_Pos();
2793 if ( FILE_Seek( new_offset
) ||
2794 ( error
= Load_ChainSubClassRule( ccsf2
, &cscr
[n
],
2795 input
) ) != TT_Err_Ok
)
2797 (void)FILE_Seek( cur_offset
);
2803 for ( n
= 0; n
< count
; n
++ )
2804 Free_ChainSubClassRule( &cscr
[n
] );
2811 static void Free_ChainSubClassSet( TTO_ChainSubClassSet
* cscs
)
2815 TTO_ChainSubClassRule
* cscr
;
2818 if ( cscs
->ChainSubClassRule
)
2820 count
= cscs
->ChainSubClassRuleCount
;
2821 cscr
= cscs
->ChainSubClassRule
;
2823 for ( n
= 0; n
< count
; n
++ )
2824 Free_ChainSubClassRule( &cscr
[n
] );
2831 /* ChainContextSubstFormat2 */
2833 static TT_Error
Load_ChainContextSubst2(
2834 TTO_ChainContextSubstFormat2
* ccsf2
,
2837 DEFINE_LOAD_LOCALS( input
->stream
);
2840 ULong cur_offset
, new_offset
, base_offset
;
2841 ULong backtrack_offset
, input_offset
, lookahead_offset
;
2843 TTO_ChainSubClassSet
* cscs
;
2846 base_offset
= FILE_Pos() - 2;
2848 if ( ACCESS_Frame( 2L ) )
2851 new_offset
= GET_UShort() + base_offset
;
2855 cur_offset
= FILE_Pos();
2856 if ( FILE_Seek( new_offset
) ||
2857 ( error
= Load_Coverage( &ccsf2
->Coverage
, input
) ) != TT_Err_Ok
)
2859 (void)FILE_Seek( cur_offset
);
2861 if ( ACCESS_Frame( 8L ) )
2864 backtrack_offset
= GET_UShort() + base_offset
;
2865 input_offset
= GET_UShort() + base_offset
;
2866 lookahead_offset
= GET_UShort() + base_offset
;
2868 /* `ChainSubClassSetCount' is the upper limit for input class values,
2869 thus we read it now to make an additional safety check. */
2871 count
= ccsf2
->ChainSubClassSetCount
= GET_UShort();
2875 cur_offset
= FILE_Pos();
2876 if ( FILE_Seek( backtrack_offset
) ||
2877 ( error
= Load_ClassDefinition( &ccsf2
->BacktrackClassDef
, count
,
2878 input
) ) != TT_Err_Ok
)
2880 if ( FILE_Seek( input_offset
) ||
2881 ( error
= Load_ClassDefinition( &ccsf2
->InputClassDef
, count
,
2882 input
) ) != TT_Err_Ok
)
2884 if ( FILE_Seek( lookahead_offset
) ||
2885 ( error
= Load_ClassDefinition( &ccsf2
->LookaheadClassDef
, count
,
2886 input
) ) != TT_Err_Ok
)
2888 (void)FILE_Seek( cur_offset
);
2890 ccsf2
->ChainSubClassSet
= NULL
;
2891 ccsf2
->MaxBacktrackLength
= 0;
2892 ccsf2
->MaxInputLength
= 0;
2893 ccsf2
->MaxLookaheadLength
= 0;
2895 if ( ALLOC_ARRAY( ccsf2
->ChainSubClassSet
, count
, TTO_ChainSubClassSet
) )
2898 cscs
= ccsf2
->ChainSubClassSet
;
2900 for ( n
= 0; n
< count
; n
++ )
2902 if ( ACCESS_Frame( 2L ) )
2905 new_offset
= GET_UShort() + base_offset
;
2909 if ( new_offset
!= base_offset
) /* not a NULL offset */
2911 cur_offset
= FILE_Pos();
2912 if ( FILE_Seek( new_offset
) ||
2913 ( error
= Load_ChainSubClassSet( ccsf2
, &cscs
[n
],
2914 input
) ) != TT_Err_Ok
)
2916 (void)FILE_Seek( cur_offset
);
2920 /* we create a ChainSubClassSet table with no entries */
2922 ccsf2
->ChainSubClassSet
[n
].ChainSubClassRuleCount
= 0;
2923 ccsf2
->ChainSubClassSet
[n
].ChainSubClassRule
= NULL
;
2930 for ( n
= 0; n
< count
; n
++ )
2931 Free_ChainSubClassSet( &cscs
[n
] );
2936 Free_ClassDefinition( &ccsf2
->LookaheadClassDef
);
2939 Free_ClassDefinition( &ccsf2
->InputClassDef
);
2942 Free_ClassDefinition( &ccsf2
->BacktrackClassDef
);
2945 Free_Coverage( &ccsf2
->Coverage
);
2950 static void Free_ChainContext2( TTO_ChainContextSubstFormat2
* ccsf2
)
2954 TTO_ChainSubClassSet
* cscs
;
2957 if ( ccsf2
->ChainSubClassSet
)
2959 count
= ccsf2
->ChainSubClassSetCount
;
2960 cscs
= ccsf2
->ChainSubClassSet
;
2962 for ( n
= 0; n
< count
; n
++ )
2963 Free_ChainSubClassSet( &cscs
[n
] );
2968 Free_ClassDefinition( &ccsf2
->LookaheadClassDef
);
2969 Free_ClassDefinition( &ccsf2
->InputClassDef
);
2970 Free_ClassDefinition( &ccsf2
->BacktrackClassDef
);
2972 Free_Coverage( &ccsf2
->Coverage
);
2976 /* ChainContextSubstFormat3 */
2978 static TT_Error
Load_ChainContextSubst3(
2979 TTO_ChainContextSubstFormat3
* ccsf3
,
2982 DEFINE_LOAD_LOCALS( input
->stream
);
2985 UShort backtrack_count
, input_count
, lookahead_count
;
2986 ULong cur_offset
, new_offset
, base_offset
;
2991 TTO_SubstLookupRecord
* slr
;
2994 base_offset
= FILE_Pos() - 2L;
2996 if ( ACCESS_Frame( 2L ) )
2999 ccsf3
->BacktrackGlyphCount
= GET_UShort();
3003 ccsf3
->BacktrackCoverage
= NULL
;
3005 backtrack_count
= ccsf3
->BacktrackGlyphCount
;
3007 if ( ALLOC_ARRAY( ccsf3
->BacktrackCoverage
, backtrack_count
,
3011 b
= ccsf3
->BacktrackCoverage
;
3013 for ( n
= 0; n
< backtrack_count
; n
++ )
3015 if ( ACCESS_Frame( 2L ) )
3018 new_offset
= GET_UShort() + base_offset
;
3022 cur_offset
= FILE_Pos();
3023 if ( FILE_Seek( new_offset
) ||
3024 ( error
= Load_Coverage( &b
[n
], input
) ) != TT_Err_Ok
)
3026 (void)FILE_Seek( cur_offset
);
3029 if ( ACCESS_Frame( 2L ) )
3032 ccsf3
->InputGlyphCount
= GET_UShort();
3036 ccsf3
->InputCoverage
= NULL
;
3038 input_count
= ccsf3
->InputGlyphCount
;
3040 if ( ALLOC_ARRAY( ccsf3
->InputCoverage
, input_count
, TTO_Coverage
) )
3043 i
= ccsf3
->InputCoverage
;
3045 for ( n
= 0; n
< input_count
; n
++ )
3047 if ( ACCESS_Frame( 2L ) )
3050 new_offset
= GET_UShort() + base_offset
;
3054 cur_offset
= FILE_Pos();
3055 if ( FILE_Seek( new_offset
) ||
3056 ( error
= Load_Coverage( &i
[n
], input
) ) != TT_Err_Ok
)
3058 (void)FILE_Seek( cur_offset
);
3061 if ( ACCESS_Frame( 2L ) )
3064 ccsf3
->LookaheadGlyphCount
= GET_UShort();
3068 ccsf3
->LookaheadCoverage
= NULL
;
3070 lookahead_count
= ccsf3
->LookaheadGlyphCount
;
3072 if ( ALLOC_ARRAY( ccsf3
->LookaheadCoverage
, lookahead_count
,
3076 l
= ccsf3
->LookaheadCoverage
;
3078 for ( n
= 0; n
< lookahead_count
; n
++ )
3080 if ( ACCESS_Frame( 2L ) )
3083 new_offset
= GET_UShort() + base_offset
;
3087 cur_offset
= FILE_Pos();
3088 if ( FILE_Seek( new_offset
) ||
3089 ( error
= Load_Coverage( &l
[n
], input
) ) != TT_Err_Ok
)
3091 (void)FILE_Seek( cur_offset
);
3094 if ( ACCESS_Frame( 2L ) )
3097 ccsf3
->SubstCount
= GET_UShort();
3101 ccsf3
->SubstLookupRecord
= NULL
;
3103 count
= ccsf3
->SubstCount
;
3105 if ( ALLOC_ARRAY( ccsf3
->SubstLookupRecord
, count
,
3106 TTO_SubstLookupRecord
) )
3109 slr
= ccsf3
->SubstLookupRecord
;
3111 if ( ACCESS_Frame( count
* 4L ) )
3114 for ( n
= 0; n
< count
; n
++ )
3116 slr
[n
].SequenceIndex
= GET_UShort();
3117 slr
[n
].LookupListIndex
= GET_UShort();
3128 for ( n
= 0; n
< lookahead_count
; n
++ )
3129 Free_Coverage( &l
[n
] );
3134 for ( n
= 0; n
< input_count
; n
++ )
3135 Free_Coverage( &i
[n
] );
3140 for ( n
= 0; n
< backtrack_count
; n
++ )
3141 Free_Coverage( &b
[n
] );
3148 static void Free_ChainContext3( TTO_ChainContextSubstFormat3
* ccsf3
)
3155 FREE( ccsf3
->SubstLookupRecord
);
3157 if ( ccsf3
->LookaheadCoverage
)
3159 count
= ccsf3
->LookaheadGlyphCount
;
3160 c
= ccsf3
->LookaheadCoverage
;
3162 for ( n
= 0; n
< count
; n
++ )
3163 Free_Coverage( &c
[n
] );
3168 if ( ccsf3
->InputCoverage
)
3170 count
= ccsf3
->InputGlyphCount
;
3171 c
= ccsf3
->InputCoverage
;
3173 for ( n
= 0; n
< count
; n
++ )
3174 Free_Coverage( &c
[n
] );
3179 if ( ccsf3
->BacktrackCoverage
)
3181 count
= ccsf3
->BacktrackGlyphCount
;
3182 c
= ccsf3
->BacktrackCoverage
;
3184 for ( n
= 0; n
< count
; n
++ )
3185 Free_Coverage( &c
[n
] );
3192 /* ChainContextSubst */
3194 TT_Error
Load_ChainContextSubst( TTO_ChainContextSubst
* ccs
,
3197 DEFINE_LOAD_LOCALS( input
->stream
);
3200 if ( ACCESS_Frame( 2L ) )
3203 ccs
->SubstFormat
= GET_UShort();
3207 switch ( ccs
->SubstFormat
)
3210 return Load_ChainContextSubst1( &ccs
->ccsf
.ccsf1
, input
);
3213 return Load_ChainContextSubst2( &ccs
->ccsf
.ccsf2
, input
);
3216 return Load_ChainContextSubst3( &ccs
->ccsf
.ccsf3
, input
);
3219 return TTO_Err_Invalid_GSUB_SubTable_Format
;
3222 return TT_Err_Ok
; /* never reached */
3226 void Free_ChainContextSubst( TTO_ChainContextSubst
* ccs
)
3228 switch ( ccs
->SubstFormat
)
3231 Free_ChainContext1( &ccs
->ccsf
.ccsf1
);
3235 Free_ChainContext2( &ccs
->ccsf
.ccsf2
);
3239 Free_ChainContext3( &ccs
->ccsf
.ccsf3
);
3245 static TT_Error
Lookup_ChainContextSubst1(
3246 TTO_GSUBHeader
* gsub
,
3247 TTO_ChainContextSubstFormat1
* ccsf1
,
3248 TTO_GSUB_String
* in
,
3249 TTO_GSUB_String
* out
,
3251 UShort context_length
,
3254 UShort index
, property
;
3255 UShort i
, j
, k
, num_csr
, curr_pos
;
3256 UShort bgc
, igc
, lgc
;
3260 TTO_ChainSubRule
* csr
;
3261 TTO_ChainSubRule curr_csr
;
3262 TTO_GDEFHeader
* gdef
;
3267 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
3270 error
= Coverage_Index( &ccsf1
->Coverage
, in
->string
[in
->pos
], &index
);
3274 csr
= ccsf1
->ChainSubRuleSet
[index
].ChainSubRule
;
3275 num_csr
= ccsf1
->ChainSubRuleSet
[index
].ChainSubRuleCount
;
3277 for ( k
= 0; k
< num_csr
; k
++ )
3280 bgc
= curr_csr
.BacktrackGlyphCount
;
3281 igc
= curr_csr
.InputGlyphCount
;
3282 lgc
= curr_csr
.LookaheadGlyphCount
;
3284 if ( context_length
!= 0xFFFF && context_length
< igc
)
3287 /* check whether context is too long; it is a first guess only */
3289 if ( bgc
> in
->pos
|| in
->pos
+ igc
+ lgc
> in
->length
)
3294 /* Since we don't know in advance the number of glyphs to inspect,
3295 we search backwards for matches in the backtrack glyph array */
3298 s_in
= &in
->string
[curr_pos
];
3300 for ( i
= bgc
, j
= in
->pos
- 1; i
> 0; i
--, j
-- )
3302 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3304 if ( error
&& error
!= TTO_Err_Not_Covered
)
3313 if ( s_in
[j
] != curr_csr
.Backtrack
[i
- 1] )
3322 s_in
= &in
->string
[curr_pos
];
3324 /* Start at 1 because [0] is implied */
3326 for ( i
= 1, j
= 1; i
< igc
; i
++, j
++ )
3328 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3330 if ( error
&& error
!= TTO_Err_Not_Covered
)
3333 if ( curr_pos
+ j
< in
->length
)
3339 if ( s_in
[j
] != curr_csr
.Input
[i
- 1] )
3346 /* we are starting to check for lookahead glyphs right after the
3347 last context glyph */
3350 s_in
= &in
->string
[curr_pos
];
3352 for ( i
= 0, j
= 0; i
< lgc
; i
++, j
++ )
3354 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3356 if ( error
&& error
!= TTO_Err_Not_Covered
)
3359 if ( curr_pos
+ j
< in
->length
)
3365 if ( s_in
[j
] != curr_csr
.Lookahead
[i
] )
3370 return Do_ContextSubst( gsub
, igc
,
3371 curr_csr
.SubstCount
,
3372 curr_csr
.SubstLookupRecord
,
3377 return TTO_Err_Not_Covered
;
3381 static TT_Error
Lookup_ChainContextSubst2(
3382 TTO_GSUBHeader
* gsub
,
3383 TTO_ChainContextSubstFormat2
* ccsf2
,
3384 TTO_GSUB_String
* in
,
3385 TTO_GSUB_String
* out
,
3387 UShort context_length
,
3390 UShort index
, property
;
3392 UShort i
, j
, k
, curr_pos
;
3393 UShort bgc
, igc
, lgc
;
3394 UShort known_backtrack_classes
,
3395 known_input_classes
,
3396 known_lookahead_classes
;
3398 UShort
* backtrack_classes
;
3399 UShort
* input_classes
;
3400 UShort
* lookahead_classes
;
3408 TTO_ChainSubClassSet
* cscs
;
3409 TTO_ChainSubClassRule ccsr
;
3410 TTO_GDEFHeader
* gdef
;
3415 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
3418 /* Note: The coverage table in format 2 doesn't give an index into
3419 anything. It just lets us know whether or not we need to
3420 do any lookup at all. */
3422 error
= Coverage_Index( &ccsf2
->Coverage
, in
->string
[in
->pos
], &index
);
3426 if ( ALLOC_ARRAY( backtrack_classes
, ccsf2
->MaxBacktrackLength
, UShort
) )
3428 known_backtrack_classes
= 0;
3430 if ( ALLOC_ARRAY( input_classes
, ccsf2
->MaxInputLength
, UShort
) )
3432 known_input_classes
= 1;
3434 if ( ALLOC_ARRAY( lookahead_classes
, ccsf2
->MaxLookaheadLength
, UShort
) )
3436 known_lookahead_classes
= 0;
3438 error
= Get_Class( &ccsf2
->InputClassDef
, in
->string
[in
->pos
],
3439 &input_classes
[0], NULL
);
3443 cscs
= &ccsf2
->ChainSubClassSet
[input_classes
[0]];
3446 error
= TTO_Err_Invalid_GSUB_SubTable
;
3450 for ( k
= 0; k
< cscs
->ChainSubClassRuleCount
; k
++ )
3452 ccsr
= cscs
->ChainSubClassRule
[k
];
3453 bgc
= ccsr
.BacktrackGlyphCount
;
3454 igc
= ccsr
.InputGlyphCount
;
3455 lgc
= ccsr
.LookaheadGlyphCount
;
3457 if ( context_length
!= 0xFFFF && context_length
< igc
)
3460 /* check whether context is too long; it is a first guess only */
3462 if ( bgc
> in
->pos
|| in
->pos
+ igc
+ lgc
> in
->length
)
3467 /* Since we don't know in advance the number of glyphs to inspect,
3468 we search backwards for matches in the backtrack glyph array.
3469 Note that `known_backtrack_classes' starts at index 0. */
3472 s_in
= &in
->string
[curr_pos
];
3473 bc
= ccsr
.Backtrack
;
3475 for ( i
= 0, j
= in
->pos
- 1; i
< bgc
; i
++, j
-- )
3477 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3479 if ( error
&& error
!= TTO_Err_Not_Covered
)
3488 if ( i
>= known_backtrack_classes
)
3490 /* Keeps us from having to do this for each rule */
3492 error
= Get_Class( &ccsf2
->BacktrackClassDef
, s_in
[j
],
3493 &backtrack_classes
[i
], NULL
);
3494 if ( error
&& error
!= TTO_Err_Not_Covered
)
3496 known_backtrack_classes
= i
;
3499 if ( bc
[bgc
- 1 - i
] != backtrack_classes
[i
] )
3508 s_in
= &in
->string
[curr_pos
];
3511 /* Start at 1 because [0] is implied */
3513 for ( i
= 1, j
= 1; i
< igc
; i
++, j
++ )
3515 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3517 if ( error
&& error
!= TTO_Err_Not_Covered
)
3520 if ( curr_pos
+ j
< in
->length
)
3526 if ( i
>= known_input_classes
)
3528 error
= Get_Class( &ccsf2
->InputClassDef
, s_in
[j
],
3529 &input_classes
[i
], NULL
);
3530 if ( error
&& error
!= TTO_Err_Not_Covered
)
3532 known_input_classes
= i
;
3535 if ( ic
[i
- 1] != input_classes
[i
] )
3542 /* we are starting to check for lookahead glyphs right after the
3543 last context glyph */
3546 s_in
= &in
->string
[curr_pos
];
3547 lc
= ccsr
.Lookahead
;
3549 for ( i
= 0, j
= 0; i
< lgc
; i
++, j
++ )
3551 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3553 if ( error
&& error
!= TTO_Err_Not_Covered
)
3556 if ( curr_pos
+ j
< in
->length
)
3562 if ( i
>= known_lookahead_classes
)
3564 error
= Get_Class( &ccsf2
->LookaheadClassDef
, s_in
[j
],
3565 &lookahead_classes
[i
], NULL
);
3566 if ( error
&& error
!= TTO_Err_Not_Covered
)
3568 known_lookahead_classes
= i
;
3571 if ( lc
[i
] != lookahead_classes
[i
] )
3577 error
= Do_ContextSubst( gsub
, igc
,
3579 ccsr
.SubstLookupRecord
,
3586 error
= TTO_Err_Not_Covered
;
3589 FREE( lookahead_classes
);
3592 FREE( input_classes
);
3595 FREE( backtrack_classes
);
3600 static TT_Error
Lookup_ChainContextSubst3(
3601 TTO_GSUBHeader
* gsub
,
3602 TTO_ChainContextSubstFormat3
* ccsf3
,
3603 TTO_GSUB_String
* in
,
3604 TTO_GSUB_String
* out
,
3606 UShort context_length
,
3609 UShort index
, i
, j
, curr_pos
, property
;
3610 UShort bgc
, igc
, lgc
;
3617 TTO_GDEFHeader
* gdef
;
3622 if ( CHECK_Property( gdef
, in
->string
[in
->pos
], flags
, &property
) )
3625 bgc
= ccsf3
->BacktrackGlyphCount
;
3626 igc
= ccsf3
->InputGlyphCount
;
3627 lgc
= ccsf3
->LookaheadGlyphCount
;
3629 if ( context_length
!= 0xFFFF && context_length
< igc
)
3630 return TTO_Err_Not_Covered
;
3632 /* check whether context is too long; it is a first guess only */
3634 if ( bgc
> in
->pos
|| in
->pos
+ igc
+ lgc
> in
->length
)
3635 return TTO_Err_Not_Covered
;
3639 /* Since we don't know in advance the number of glyphs to inspect,
3640 we search backwards for matches in the backtrack glyph array */
3643 s_in
= &in
->string
[curr_pos
];
3644 bc
= ccsf3
->BacktrackCoverage
;
3646 for ( i
= bgc
, j
= in
->pos
- 1; i
> 0; i
--, j
-- )
3648 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3650 if ( error
&& error
!= TTO_Err_Not_Covered
)
3656 return TTO_Err_Not_Covered
;
3659 error
= Coverage_Index( &bc
[i
- 1], s_in
[j
], &index
);
3666 s_in
= &in
->string
[curr_pos
];
3667 ic
= ccsf3
->InputCoverage
;
3669 /* Start at 1 because [0] is implied */
3671 for ( i
= 1, j
= 1; i
< igc
; i
++, j
++ )
3673 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3675 if ( error
&& error
!= TTO_Err_Not_Covered
)
3678 if ( curr_pos
+ j
< in
->length
)
3681 return TTO_Err_Not_Covered
;
3684 error
= Coverage_Index( &ic
[i
], s_in
[j
], &index
);
3689 /* we are starting for lookahead glyphs right after the last context
3693 s_in
= &in
->string
[curr_pos
];
3694 lc
= ccsf3
->LookaheadCoverage
;
3696 for ( i
= 0, j
= 0; i
< lgc
; i
++, j
++ )
3698 while ( CHECK_Property( gdef
, s_in
[j
], flags
, &property
) )
3700 if ( error
&& error
!= TTO_Err_Not_Covered
)
3703 if ( curr_pos
+ j
< in
->length
)
3706 return TTO_Err_Not_Covered
;
3709 error
= Coverage_Index( &lc
[i
], s_in
[j
], &index
);
3714 return Do_ContextSubst( gsub
, igc
,
3716 ccsf3
->SubstLookupRecord
,
3722 static TT_Error
Lookup_ChainContextSubst(
3723 TTO_GSUBHeader
* gsub
,
3724 TTO_ChainContextSubst
* ccs
,
3725 TTO_GSUB_String
* in
,
3726 TTO_GSUB_String
* out
,
3728 UShort context_length
,
3731 switch ( ccs
->SubstFormat
)
3734 return Lookup_ChainContextSubst1( gsub
, &ccs
->ccsf
.ccsf1
, in
, out
,
3735 flags
, context_length
,
3739 return Lookup_ChainContextSubst2( gsub
, &ccs
->ccsf
.ccsf2
, in
, out
,
3740 flags
, context_length
,
3744 return Lookup_ChainContextSubst3( gsub
, &ccs
->ccsf
.ccsf3
, in
, out
,
3745 flags
, context_length
,
3749 return TTO_Err_Invalid_GSUB_SubTable_Format
;
3752 return TT_Err_Ok
; /* never reached */
3763 TT_Error
TT_GSUB_Select_Script( TTO_GSUBHeader
* gsub
,
3764 TT_ULong script_tag
,
3765 TT_UShort
* script_index
)
3770 TTO_ScriptRecord
* sr
;
3773 if ( !gsub
|| !script_index
)
3774 return TT_Err_Invalid_Argument
;
3776 sl
= &gsub
->ScriptList
;
3777 sr
= sl
->ScriptRecord
;
3779 for ( n
= 0; n
< sl
->ScriptCount
; n
++ )
3780 if ( script_tag
== sr
[n
].ScriptTag
)
3787 return TTO_Err_Not_Covered
;
3792 TT_Error
TT_GSUB_Select_Language( TTO_GSUBHeader
* gsub
,
3793 TT_ULong language_tag
,
3794 TT_UShort script_index
,
3795 TT_UShort
* language_index
,
3796 TT_UShort
* req_feature_index
)
3801 TTO_ScriptRecord
* sr
;
3803 TTO_LangSysRecord
* lsr
;
3806 if ( !gsub
|| !language_index
|| !req_feature_index
)
3807 return TT_Err_Invalid_Argument
;
3809 sl
= &gsub
->ScriptList
;
3810 sr
= sl
->ScriptRecord
;
3812 if ( script_index
>= sl
->ScriptCount
)
3813 return TT_Err_Invalid_Argument
;
3815 s
= &sr
[script_index
].Script
;
3816 lsr
= s
->LangSysRecord
;
3818 for ( n
= 0; n
< s
->LangSysCount
; n
++ )
3819 if ( language_tag
== lsr
[n
].LangSysTag
)
3821 *language_index
= n
;
3822 *req_feature_index
= lsr
[n
].LangSys
.ReqFeatureIndex
;
3827 return TTO_Err_Not_Covered
;
3831 /* selecting 0xFFFF for language_index asks for the values of the
3832 default language (DefaultLangSys) */
3835 TT_Error
TT_GSUB_Select_Feature( TTO_GSUBHeader
* gsub
,
3836 TT_ULong feature_tag
,
3837 TT_UShort script_index
,
3838 TT_UShort language_index
,
3839 TT_UShort
* feature_index
)
3844 TTO_ScriptRecord
* sr
;
3846 TTO_LangSysRecord
* lsr
;
3850 TTO_FeatureList
* fl
;
3851 TTO_FeatureRecord
* fr
;
3854 if ( !gsub
|| !feature_index
)
3855 return TT_Err_Invalid_Argument
;
3857 sl
= &gsub
->ScriptList
;
3858 sr
= sl
->ScriptRecord
;
3860 fl
= &gsub
->FeatureList
;
3861 fr
= fl
->FeatureRecord
;
3863 if ( script_index
>= sl
->ScriptCount
)
3864 return TT_Err_Invalid_Argument
;
3866 s
= &sr
[script_index
].Script
;
3867 lsr
= s
->LangSysRecord
;
3869 if ( language_index
== 0xFFFF )
3870 ls
= &s
->DefaultLangSys
;
3873 if ( language_index
>= s
->LangSysCount
)
3874 return TT_Err_Invalid_Argument
;
3876 ls
= &lsr
[language_index
].LangSys
;
3879 fi
= ls
->FeatureIndex
;
3881 for ( n
= 0; n
< ls
->FeatureCount
; n
++ )
3883 if ( fi
[n
] >= fl
->FeatureCount
)
3884 return TTO_Err_Invalid_GSUB_SubTable_Format
;
3886 if ( feature_tag
== fr
[fi
[n
]].FeatureTag
)
3888 *feature_index
= fi
[n
];
3894 return TTO_Err_Not_Covered
;
3898 /* The next three functions return a null-terminated list */
3901 TT_Error
TT_GSUB_Query_Scripts( TTO_GSUBHeader
* gsub
,
3902 TT_ULong
** script_tag_list
)
3909 TTO_ScriptRecord
* sr
;
3912 if ( !gsub
|| !script_tag_list
)
3913 return TT_Err_Invalid_Argument
;
3915 sl
= &gsub
->ScriptList
;
3916 sr
= sl
->ScriptRecord
;
3918 if ( ALLOC_ARRAY( stl
, sl
->ScriptCount
+ 1, ULong
) )
3921 for ( n
= 0; n
< sl
->ScriptCount
; n
++ )
3922 stl
[n
] = sr
[n
].ScriptTag
;
3925 *script_tag_list
= stl
;
3932 TT_Error
TT_GSUB_Query_Languages( TTO_GSUBHeader
* gsub
,
3933 TT_UShort script_index
,
3934 TT_ULong
** language_tag_list
)
3941 TTO_ScriptRecord
* sr
;
3943 TTO_LangSysRecord
* lsr
;
3946 if ( !gsub
|| !language_tag_list
)
3947 return TT_Err_Invalid_Argument
;
3949 sl
= &gsub
->ScriptList
;
3950 sr
= sl
->ScriptRecord
;
3952 if ( script_index
>= sl
->ScriptCount
)
3953 return TT_Err_Invalid_Argument
;
3955 s
= &sr
[script_index
].Script
;
3956 lsr
= s
->LangSysRecord
;
3958 if ( ALLOC_ARRAY( ltl
, s
->LangSysCount
+ 1, ULong
) )
3961 for ( n
= 0; n
< s
->LangSysCount
; n
++ )
3962 ltl
[n
] = lsr
[n
].LangSysTag
;
3965 *language_tag_list
= ltl
;
3971 /* selecting 0xFFFF for language_index asks for the values of the
3972 default language (DefaultLangSys) */
3975 TT_Error
TT_GSUB_Query_Features( TTO_GSUBHeader
* gsub
,
3976 TT_UShort script_index
,
3977 TT_UShort language_index
,
3978 TT_ULong
** feature_tag_list
)
3985 TTO_ScriptRecord
* sr
;
3987 TTO_LangSysRecord
* lsr
;
3991 TTO_FeatureList
* fl
;
3992 TTO_FeatureRecord
* fr
;
3995 if ( !gsub
|| !feature_tag_list
)
3996 return TT_Err_Invalid_Argument
;
3998 sl
= &gsub
->ScriptList
;
3999 sr
= sl
->ScriptRecord
;
4001 fl
= &gsub
->FeatureList
;
4002 fr
= fl
->FeatureRecord
;
4004 if ( script_index
>= sl
->ScriptCount
)
4005 return TT_Err_Invalid_Argument
;
4007 s
= &sr
[script_index
].Script
;
4008 lsr
= s
->LangSysRecord
;
4010 if ( language_index
== 0xFFFF )
4011 ls
= &s
->DefaultLangSys
;
4014 if ( language_index
>= s
->LangSysCount
)
4015 return TT_Err_Invalid_Argument
;
4017 ls
= &lsr
[language_index
].LangSys
;
4020 fi
= ls
->FeatureIndex
;
4022 if ( ALLOC_ARRAY( ftl
, ls
->FeatureCount
+ 1, ULong
) )
4025 for ( n
= 0; n
< ls
->FeatureCount
; n
++ )
4027 if ( fi
[n
] >= fl
->FeatureCount
)
4030 return TTO_Err_Invalid_GSUB_SubTable_Format
;
4032 ftl
[n
] = fr
[fi
[n
]].FeatureTag
;
4036 *feature_tag_list
= ftl
;
4042 /* Do an individual subtable lookup. Returns TT_Err_Ok if substitution
4043 has been done, or TTO_Err_Not_Covered if not. */
4045 static TT_Error
Do_Glyph_Lookup( TTO_GSUBHeader
* gsub
,
4046 UShort lookup_index
,
4047 TTO_GSUB_String
* in
,
4048 TTO_GSUB_String
* out
,
4049 UShort context_length
,
4052 TT_Error error
= TT_Err_Ok
;
4059 if ( nesting_level
> TTO_MAX_NESTING_LEVEL
)
4060 return TTO_Err_Too_Many_Nested_Contexts
;
4062 lo
= &gsub
->LookupList
.Lookup
[lookup_index
];
4063 flags
= lo
->LookupFlag
;
4065 for ( i
= 0; i
< lo
->SubTableCount
; i
++ )
4067 switch ( lo
->LookupType
)
4069 case GSUB_LOOKUP_SINGLE
:
4070 error
= Lookup_SingleSubst( &lo
->SubTable
[i
].st
.gsub
.single
,
4072 flags
, context_length
, gsub
->gdef
);
4075 case GSUB_LOOKUP_MULTIPLE
:
4076 error
= Lookup_MultipleSubst( &lo
->SubTable
[i
].st
.gsub
.multiple
,
4078 flags
, context_length
, gsub
->gdef
);
4081 case GSUB_LOOKUP_ALTERNATE
:
4082 error
= Lookup_AlternateSubst( gsub
,
4083 &lo
->SubTable
[i
].st
.gsub
.alternate
,
4085 flags
, context_length
, gsub
->gdef
);
4088 case GSUB_LOOKUP_LIGATURE
:
4089 error
= Lookup_LigatureSubst( &lo
->SubTable
[i
].st
.gsub
.ligature
,
4091 flags
, context_length
, gsub
->gdef
);
4094 case GSUB_LOOKUP_CONTEXT
:
4095 error
= Lookup_ContextSubst( gsub
, &lo
->SubTable
[i
].st
.gsub
.context
,
4097 flags
, context_length
, nesting_level
);
4100 case GSUB_LOOKUP_CHAIN
:
4101 error
= Lookup_ChainContextSubst( gsub
,
4102 &lo
->SubTable
[i
].st
.gsub
.chain
,
4104 flags
, context_length
,
4109 /* Check whether we have a successful substitution or an error other
4110 than TTO_Err_Not_Covered */
4112 if ( error
!= TTO_Err_Not_Covered
)
4116 return TTO_Err_Not_Covered
;
4120 /* apply one lookup to the input string object */
4122 static TT_Error
Do_String_Lookup( TTO_GSUBHeader
* gsub
,
4123 UShort lookup_index
,
4124 TTO_GSUB_String
* in
,
4125 TTO_GSUB_String
* out
)
4127 TT_Error error
= TTO_Err_Not_Covered
;
4129 UShort
* properties
= gsub
->LookupList
.Properties
;
4130 UShort
* p_in
= in
->properties
;
4131 UShort
* s_in
= in
->string
;
4133 int nesting_level
= 0;
4136 while ( in
->pos
< in
->length
)
4138 if ( ~p_in
[in
->pos
] & properties
[lookup_index
] )
4140 /* 0xFFFF indicates that we don't have a context length yet */
4141 error
= Do_Glyph_Lookup( gsub
, lookup_index
, in
, out
,
4142 0xFFFF, nesting_level
);
4143 if ( error
&& error
!= TTO_Err_Not_Covered
)
4147 error
= TTO_Err_Not_Covered
;
4149 if ( error
== TTO_Err_Not_Covered
)
4150 if ( ADD_String( in
, 1, out
, 1, &s_in
[in
->pos
] ) )
4159 TT_Error
TT_GSUB_Add_Feature( TTO_GSUBHeader
* gsub
,
4160 TT_UShort feature_index
,
4161 TT_UShort property
)
4165 TTO_Feature feature
;
4171 feature_index
>= gsub
->FeatureList
.FeatureCount
)
4172 return TT_Err_Invalid_Argument
;
4174 properties
= gsub
->LookupList
.Properties
;
4176 feature
= gsub
->FeatureList
.FeatureRecord
[feature_index
].Feature
;
4177 index
= feature
.LookupListIndex
;
4179 for ( i
= 0; i
< feature
.LookupListCount
; i
++ )
4180 properties
[index
[i
]] |= property
;
4187 TT_Error
TT_GSUB_Clear_Features( TTO_GSUBHeader
* gsub
)
4195 return TT_Err_Invalid_Argument
;
4197 properties
= gsub
->LookupList
.Properties
;
4199 for ( i
= 0; i
< gsub
->LookupList
.LookupCount
; i
++ )
4207 TT_Error
TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader
* gsub
,
4208 TTO_AltFunction alt
,
4212 return TT_Err_Invalid_Argument
;
4222 TT_Error
TT_GSUB_Apply_String( TTO_GSUBHeader
* gsub
,
4223 TTO_GSUB_String
* in
,
4224 TTO_GSUB_String
* out
)
4226 TT_Error error
= TTO_Err_Not_Covered
;
4229 TTO_GSUB_String tmp1
;
4230 TTO_GSUB_String
* ptmp1
;
4231 TTO_GSUB_String tmp2
;
4232 TTO_GSUB_String
* ptmp2
;
4239 !in
|| !out
|| in
->length
== 0 || in
->pos
>= in
->length
)
4240 return TT_Err_Invalid_Argument
;
4242 properties
= gsub
->LookupList
.Properties
;
4244 tmp1
.length
= in
->length
;
4245 tmp1
.allocated
= in
->length
;
4248 if ( ALLOC_ARRAY( tmp1
.string
, tmp1
.length
, UShort
) )
4250 MEM_Copy( tmp1
.string
, in
->string
, in
->length
* sizeof ( UShort
) );
4252 /* make sure that we always have a `properties' array in the string
4255 if ( ALLOC_ARRAY( tmp1
.properties
, tmp1
.length
, UShort
) )
4257 if ( in
->properties
)
4258 MEM_Copy( tmp1
.properties
, in
->properties
,
4259 in
->length
* sizeof( UShort
) );
4264 tmp2
.properties
= NULL
;
4269 for ( j
= 0; j
< gsub
->LookupList
.LookupCount
; j
++ )
4270 if ( properties
[j
] )
4272 error
= Do_String_Lookup( gsub
, j
, ptmp1
, ptmp2
);
4273 if ( error
&& error
!= TTO_Err_Not_Covered
)
4276 /* flipping `in' and `out', preparing for the next loop */
4278 ptmp1
->pos
= in
->pos
;
4279 ptmp2
->length
= ptmp2
->pos
;
4280 ptmp2
->pos
= in
->pos
;
4287 out
->length
= ptmp1
->length
;
4289 out
->allocated
= ptmp1
->allocated
;
4290 out
->string
= ptmp1
->string
;
4292 if ( in
->properties
)
4293 out
->properties
= ptmp1
->properties
;
4296 free( ptmp1
->properties
);
4297 out
->properties
= NULL
;
4300 free( ptmp2
->string
);
4301 free( ptmp2
->properties
);