contrib/OWB: add correct SDL dependency, fix compilers used
[AROS-Contrib.git] / freetype1 / lib / extend / ftxgsub.c
blob81930c80244805e272e409436cae5f51909c3921
1 /*******************************************************************
3 * ftxgsub.c
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 :-) */
24 #include "tttypes.h"
25 #include "tttags.h"
26 #include "ttload.h"
27 #include "ttextend.h"
28 #include "ttmemory.h"
29 #include "ttfile.h"
31 #include "ftxopen.h"
32 #include "ftxopenf.h"
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), \
40 (out), (num_out), \
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,
49 UShort lookup_index,
50 TTO_GSUB_String* in,
51 TTO_GSUB_String* out,
52 UShort context_length,
53 int nesting_level );
57 /**********************
58 * Auxiliary functions
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'
68 structure.
70 The properties (if defined) for all replaced glyphs are taken from
71 the glyph at position `in->pos'. */
73 EXPORT_FUNC
74 TT_Error TT_GSUB_Add_String( TTO_GSUB_String* in,
75 UShort num_in,
76 TTO_GSUB_String* out,
77 UShort num_out,
78 UShort* data )
80 TT_Error error;
81 UShort i;
82 UShort p_in;
83 UShort* p_out;
86 /* sanity check */
88 if ( !in || !out ||
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
100 first use. */
102 if ( REALLOC( out->string, size * sizeof ( UShort ) ) )
103 return error;
104 if ( in->properties )
105 if ( REALLOC( out->properties, size * sizeof ( UShort ) ) )
106 return error;
107 out->allocated = size;
110 if ( num_out )
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++ )
119 p_out[i] = p_in;
123 in->pos += num_in;
124 out->pos += num_out;
126 out->length = out->pos;
128 return TT_Err_Ok;
132 static TT_Error Check_Property( TTO_GDEFHeader* gdef,
133 UShort index,
134 UShort flags,
135 UShort* property )
137 TT_Error error;
140 if ( gdef )
142 error = TT_GDEF_Get_Glyph_Property( gdef, index, property );
143 if ( error )
144 return error;
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;
156 return TT_Err_Ok;
161 /**********************
162 * Extension Functions
163 **********************/
166 static TT_Error GSUB_Create( void* ext,
167 PFace face )
169 DEFINE_LOAD_LOCALS( face->stream );
171 TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
172 Long table;
175 /* by convention */
177 if ( !gsub )
178 return TT_Err_Ok;
180 /* a null offset indicates that there is no GSUB table */
182 gsub->offset = 0;
184 /* we store the start offset and the size of the subtable */
186 table = TT_LookUp_Table( face, TTAG_GSUB );
187 if ( table < 0 )
188 return TT_Err_Ok; /* The table is optional */
190 if ( FILE_Seek( face->dirTables[table].Offset ) ||
191 ACCESS_Frame( 4L ) )
192 return error;
194 gsub->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
195 gsub->Version = GET_ULong();
197 FORGET_Frame();
199 gsub->loaded = FALSE;
201 return TT_Err_Ok;
205 static TT_Error GSUB_Destroy( void* ext,
206 PFace face )
208 TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
211 /* by convention */
213 if ( !gsub )
214 return TT_Err_Ok;
216 if ( gsub->loaded )
218 Free_LookupList( &gsub->LookupList, GSUB );
219 Free_FeatureList( &gsub->FeatureList );
220 Free_ScriptList( &gsub->ScriptList );
223 return TT_Err_Ok;
227 EXPORT_FUNC
228 TT_Error TT_Init_GSUB_Extension( TT_Engine engine )
230 PEngine_Instance _engine = HANDLE_Engine( engine );
233 if ( !_engine )
234 return TT_Err_Invalid_Engine;
236 return TT_Register_Extension( _engine,
237 GSUB_ID,
238 sizeof ( TTO_GSUBHeader ),
239 GSUB_Create,
240 GSUB_Destroy );
244 EXPORT_FUNC
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;
252 TT_Error error;
253 TT_Stream stream;
254 TTO_GSUBHeader* gsub;
255 TTO_Lookup* lo;
257 PFace faze = HANDLE_Face( face );
260 if ( !retptr )
261 return TT_Err_Invalid_Argument;
263 if ( !faze )
264 return TT_Err_Invalid_Face_Handle;
266 error = TT_Extension_Get( faze, GSUB_ID, (void**)&gsub );
267 if ( error )
268 return error;
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 ) )
276 return error;
278 base_offset = gsub->offset;
280 /* skip version */
282 if ( FILE_Seek( base_offset + 4L ) ||
283 ACCESS_Frame( 2L ) )
284 return error;
286 new_offset = GET_UShort() + base_offset;
288 FORGET_Frame();
290 cur_offset = FILE_Pos();
291 if ( FILE_Seek( new_offset ) ||
292 ( error = Load_ScriptList( &gsub->ScriptList,
293 faze ) ) != TT_Err_Ok )
294 return error;
295 (void)FILE_Seek( cur_offset );
297 if ( ACCESS_Frame( 2L ) )
298 goto Fail3;
300 new_offset = GET_UShort() + base_offset;
302 FORGET_Frame();
304 cur_offset = FILE_Pos();
305 if ( FILE_Seek( new_offset ) ||
306 ( error = Load_FeatureList( &gsub->FeatureList,
307 faze ) ) != TT_Err_Ok )
308 goto Fail3;
309 (void)FILE_Seek( cur_offset );
311 if ( ACCESS_Frame( 2L ) )
312 goto Fail2;
314 new_offset = GET_UShort() + base_offset;
316 FORGET_Frame();
318 cur_offset = FILE_Pos();
319 if ( FILE_Seek( new_offset ) ||
320 ( error = Load_LookupList( &gsub->LookupList,
321 faze, GSUB ) ) != TT_Err_Ok )
322 goto Fail2;
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). */
335 if ( gdef &&
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 ) ||
346 ACCESS_Frame( 2L ) )
347 goto Fail1;
349 new_offset = GET_UShort();
351 FORGET_Frame();
353 if ( !new_offset )
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 )
361 goto Fail1;
363 break;
368 gsub->loaded = TRUE;
369 *retptr = *gsub;
370 DONE_Stream( stream );
372 return TT_Err_Ok;
374 Fail1:
375 Free_LookupList( &gsub->LookupList, GSUB );
377 Fail2:
378 Free_FeatureList( &gsub->FeatureList );
380 Fail3:
381 Free_ScriptList( &gsub->ScriptList );
383 /* release stream */
385 DONE_Stream( stream );
387 return error;
392 /*****************************
393 * SubTable related functions
394 *****************************/
397 /* LookupType 1 */
399 /* SingleSubstFormat1 */
400 /* SingleSubstFormat2 */
402 TT_Error Load_SingleSubst( TTO_SingleSubst* ss,
403 PFace input )
405 DEFINE_LOAD_LOCALS( input->stream );
407 UShort n, count;
408 ULong cur_offset, new_offset, base_offset;
410 UShort* s;
413 base_offset = FILE_Pos();
415 if ( ACCESS_Frame( 4L ) )
416 return error;
418 ss->SubstFormat = GET_UShort();
419 new_offset = GET_UShort() + base_offset;
421 FORGET_Frame();
423 cur_offset = FILE_Pos();
424 if ( FILE_Seek( new_offset ) ||
425 ( error = Load_Coverage( &ss->Coverage, input ) ) != TT_Err_Ok )
426 return error;
427 (void)FILE_Seek( cur_offset );
429 switch ( ss->SubstFormat )
431 case 1:
432 if ( ACCESS_Frame( 2L ) )
433 goto Fail2;
435 ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
437 FORGET_Frame();
439 break;
441 case 2:
442 if ( ACCESS_Frame( 2L ) )
443 goto Fail2;
445 count = ss->ssf.ssf2.GlyphCount = GET_UShort();
447 FORGET_Frame();
449 ss->ssf.ssf2.Substitute = NULL;
451 if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, UShort ) )
452 goto Fail2;
454 s = ss->ssf.ssf2.Substitute;
456 if ( ACCESS_Frame( count * 2L ) )
457 goto Fail1;
459 for ( n = 0; n < count; n++ )
460 s[n] = GET_UShort();
462 FORGET_Frame();
464 break;
466 default:
467 return TTO_Err_Invalid_GSUB_SubTable_Format;
470 return TT_Err_Ok;
472 Fail1:
473 FREE( s );
475 Fail2:
476 Free_Coverage( &ss->Coverage );
477 return error;
481 void Free_SingleSubst( TTO_SingleSubst* ss )
483 switch ( ss->SubstFormat )
485 case 1:
486 break;
488 case 2:
489 FREE( ss->ssf.ssf2.Substitute );
490 break;
493 Free_Coverage( &ss->Coverage );
497 static TT_Error Lookup_SingleSubst( TTO_SingleSubst* ss,
498 TTO_GSUB_String* in,
499 TTO_GSUB_String* out,
500 UShort flags,
501 UShort context_length,
502 TTO_GDEFHeader* gdef )
504 UShort index, value[1], property;
505 TT_Error error;
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 ) )
512 return error;
514 error = Coverage_Index( &ss->Coverage, in->string[in->pos], &index );
515 if ( error )
516 return error;
518 switch ( ss->SubstFormat )
520 case 1:
521 value[0] = ( in->string[in->pos] + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
522 if ( ADD_String( in, 1, out, 1, value ) )
523 return error;
524 break;
526 case 2:
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 ) )
531 return error;
532 break;
534 default:
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 )
544 return error;
547 return TT_Err_Ok;
551 /* LookupType 2 */
553 /* Sequence */
555 static TT_Error Load_Sequence( TTO_Sequence* s,
556 PFace input )
558 DEFINE_LOAD_LOCALS( input->stream );
560 UShort n, count;
561 UShort* sub;
564 if ( ACCESS_Frame( 2L ) )
565 return error;
567 count = s->GlyphCount = GET_UShort();
569 FORGET_Frame();
571 s->Substitute = NULL;
573 if ( count )
575 if ( ALLOC_ARRAY( s->Substitute, count, UShort ) )
576 return error;
578 sub = s->Substitute;
580 if ( ACCESS_Frame( count * 2L ) )
582 FREE( sub );
583 return error;
586 for ( n = 0; n < count; n++ )
587 sub[n] = GET_UShort();
589 FORGET_Frame();
592 return TT_Err_Ok;
596 static void Free_Sequence( TTO_Sequence* s )
598 FREE( s->Substitute );
602 /* MultipleSubstFormat1 */
604 TT_Error Load_MultipleSubst( TTO_MultipleSubst* ms,
605 PFace input )
607 DEFINE_LOAD_LOCALS( input->stream );
609 UShort n, count;
610 ULong cur_offset, new_offset, base_offset;
612 TTO_Sequence* s;
615 base_offset = FILE_Pos();
617 if ( ACCESS_Frame( 4L ) )
618 return error;
620 ms->SubstFormat = GET_UShort(); /* should be 1 */
621 new_offset = GET_UShort() + base_offset;
623 FORGET_Frame();
625 cur_offset = FILE_Pos();
626 if ( FILE_Seek( new_offset ) ||
627 ( error = Load_Coverage( &ms->Coverage, input ) ) != TT_Err_Ok )
628 return error;
629 (void)FILE_Seek( cur_offset );
631 if ( ACCESS_Frame( 2L ) )
632 goto Fail2;
634 count = ms->SequenceCount = GET_UShort();
636 FORGET_Frame();
638 ms->Sequence = NULL;
640 if ( ALLOC_ARRAY( ms->Sequence, count, TTO_Sequence ) )
641 goto Fail2;
643 s = ms->Sequence;
645 for ( n = 0; n < count; n++ )
647 if ( ACCESS_Frame( 2L ) )
648 goto Fail1;
650 new_offset = GET_UShort() + base_offset;
652 FORGET_Frame();
654 cur_offset = FILE_Pos();
655 if ( FILE_Seek( new_offset ) ||
656 ( error = Load_Sequence( &s[n], input ) ) != TT_Err_Ok )
657 goto Fail1;
658 (void)FILE_Seek( cur_offset );
661 return TT_Err_Ok;
663 Fail1:
664 for ( n = 0; n < count; n++ )
665 Free_Sequence( &s[n] );
667 FREE( s );
669 Fail2:
670 Free_Coverage( &ms->Coverage );
671 return error;
675 void Free_MultipleSubst( TTO_MultipleSubst* ms )
677 UShort n, count;
679 TTO_Sequence* s;
682 if ( ms->Sequence )
684 count = ms->SequenceCount;
685 s = ms->Sequence;
687 for ( n = 0; n < count; n++ )
688 Free_Sequence( &s[n] );
690 FREE( s );
693 Free_Coverage( &ms->Coverage );
697 static TT_Error Lookup_MultipleSubst( TTO_MultipleSubst* ms,
698 TTO_GSUB_String* in,
699 TTO_GSUB_String* out,
700 UShort flags,
701 UShort context_length,
702 TTO_GDEFHeader* gdef )
704 TT_Error error;
705 UShort index, property, n, count;
706 UShort* s;
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 ) )
713 return error;
715 error = Coverage_Index( &ms->Coverage, in->string[in->pos], &index );
716 if ( error )
717 return error;
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 ) )
726 return error;
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 )
739 return error;
743 return TT_Err_Ok;
747 /* LookupType 3 */
749 /* AlternateSet */
751 static TT_Error Load_AlternateSet( TTO_AlternateSet* as,
752 PFace input )
754 DEFINE_LOAD_LOCALS( input->stream );
756 UShort n, count;
757 UShort* a;
760 if ( ACCESS_Frame( 2L ) )
761 return error;
763 count = as->GlyphCount = GET_UShort();
765 FORGET_Frame();
767 as->Alternate = NULL;
769 if ( ALLOC_ARRAY( as->Alternate, count, UShort ) )
770 return error;
772 a = as->Alternate;
774 if ( ACCESS_Frame( count * 2L ) )
776 FREE( a );
777 return error;
780 for ( n = 0; n < count; n++ )
781 a[n] = GET_UShort();
783 FORGET_Frame();
785 return TT_Err_Ok;
789 static void Free_AlternateSet( TTO_AlternateSet* as )
791 FREE( as->Alternate );
795 /* AlternateSubstFormat1 */
797 TT_Error Load_AlternateSubst( TTO_AlternateSubst* as,
798 PFace input )
800 DEFINE_LOAD_LOCALS( input->stream );
802 UShort n, count;
803 ULong cur_offset, new_offset, base_offset;
805 TTO_AlternateSet* aset;
808 base_offset = FILE_Pos();
810 if ( ACCESS_Frame( 4L ) )
811 return error;
813 as->SubstFormat = GET_UShort(); /* should be 1 */
814 new_offset = GET_UShort() + base_offset;
816 FORGET_Frame();
818 cur_offset = FILE_Pos();
819 if ( FILE_Seek( new_offset ) ||
820 ( error = Load_Coverage( &as->Coverage, input ) ) != TT_Err_Ok )
821 return error;
822 (void)FILE_Seek( cur_offset );
824 if ( ACCESS_Frame( 2L ) )
825 goto Fail2;
827 count = as->AlternateSetCount = GET_UShort();
829 FORGET_Frame();
831 as->AlternateSet = NULL;
833 if ( ALLOC_ARRAY( as->AlternateSet, count, TTO_AlternateSet ) )
834 goto Fail2;
836 aset = as->AlternateSet;
838 for ( n = 0; n < count; n++ )
840 if ( ACCESS_Frame( 2L ) )
841 goto Fail1;
843 new_offset = GET_UShort() + base_offset;
845 FORGET_Frame();
847 cur_offset = FILE_Pos();
848 if ( FILE_Seek( new_offset ) ||
849 ( error = Load_AlternateSet( &aset[n], input ) ) != TT_Err_Ok )
850 goto Fail1;
851 (void)FILE_Seek( cur_offset );
854 return TT_Err_Ok;
856 Fail1:
857 for ( n = 0; n < count; n++ )
858 Free_AlternateSet( &aset[n] );
860 FREE( aset );
862 Fail2:
863 Free_Coverage( &as->Coverage );
864 return error;
868 void Free_AlternateSubst( TTO_AlternateSubst* as )
870 UShort n, count;
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] );
883 FREE( aset );
886 Free_Coverage( &as->Coverage );
890 static TT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub,
891 TTO_AlternateSubst* as,
892 TTO_GSUB_String* in,
893 TTO_GSUB_String* out,
894 UShort flags,
895 UShort context_length,
896 TTO_GDEFHeader* gdef )
898 TT_Error error;
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 ) )
908 return error;
910 error = Coverage_Index( &as->Coverage, in->string[in->pos], &index );
911 if ( error )
912 return error;
914 aset = as->AlternateSet[index];
916 /* we use a user-defined callback function to get the alternate index */
918 if ( gsub->alt )
919 alt_index = (gsub->alt)( out->pos, in->string[in->pos],
920 aset.GlyphCount, aset.Alternate,
921 gsub->data );
922 else
923 alt_index = 0;
925 if ( ADD_String( in, 1, out, 1, &aset.Alternate[alt_index] ) )
926 return error;
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],
933 property );
934 if ( error && error != TTO_Err_Not_Covered )
935 return error;
938 return TT_Err_Ok;
942 /* LookupType 4 */
944 /* Ligature */
946 static TT_Error Load_Ligature( TTO_Ligature* l,
947 PFace input )
949 DEFINE_LOAD_LOCALS( input->stream );
951 UShort n, count;
952 UShort* c;
955 if ( ACCESS_Frame( 4L ) )
956 return error;
958 l->LigGlyph = GET_UShort();
959 l->ComponentCount = GET_UShort();
961 FORGET_Frame();
963 l->Component = NULL;
965 count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */
967 if ( ALLOC_ARRAY( l->Component, count, UShort ) )
968 return error;
970 c = l->Component;
972 if ( ACCESS_Frame( count * 2L ) )
974 FREE( c );
975 return error;
978 for ( n = 0; n < count; n++ )
979 c[n] = GET_UShort();
981 FORGET_Frame();
983 return TT_Err_Ok;
987 static void Free_Ligature( TTO_Ligature* l )
989 FREE( l->Component );
993 /* LigatureSet */
995 static TT_Error Load_LigatureSet( TTO_LigatureSet* ls,
996 PFace input )
998 DEFINE_LOAD_LOCALS( input->stream );
1000 UShort n, count;
1001 ULong cur_offset, new_offset, base_offset;
1003 TTO_Ligature* l;
1006 base_offset = FILE_Pos();
1008 if ( ACCESS_Frame( 2L ) )
1009 return error;
1011 count = ls->LigatureCount = GET_UShort();
1013 FORGET_Frame();
1015 ls->Ligature = NULL;
1017 if ( ALLOC_ARRAY( ls->Ligature, count, TTO_Ligature ) )
1018 return error;
1020 l = ls->Ligature;
1022 for ( n = 0; n < count; n++ )
1024 if ( ACCESS_Frame( 2L ) )
1025 goto Fail;
1027 new_offset = GET_UShort() + base_offset;
1029 FORGET_Frame();
1031 cur_offset = FILE_Pos();
1032 if ( FILE_Seek( new_offset ) ||
1033 ( error = Load_Ligature( &l[n], input ) ) != TT_Err_Ok )
1034 goto Fail;
1035 (void)FILE_Seek( cur_offset );
1038 return TT_Err_Ok;
1040 Fail:
1041 for ( n = 0; n < count; n++ )
1042 Free_Ligature( &l[n] );
1044 FREE( l );
1045 return error;
1049 static void Free_LigatureSet( TTO_LigatureSet* ls )
1051 UShort n, count;
1053 TTO_Ligature* l;
1056 if ( ls->Ligature )
1058 count = ls->LigatureCount;
1059 l = ls->Ligature;
1061 for ( n = 0; n < count; n++ )
1062 Free_Ligature( &l[n] );
1064 FREE( l );
1069 /* LigatureSubstFormat1 */
1071 TT_Error Load_LigatureSubst( TTO_LigatureSubst* ls,
1072 PFace input )
1074 DEFINE_LOAD_LOCALS( input->stream );
1076 UShort n, count;
1077 ULong cur_offset, new_offset, base_offset;
1079 TTO_LigatureSet* lset;
1082 base_offset = FILE_Pos();
1084 if ( ACCESS_Frame( 4L ) )
1085 return error;
1087 ls->SubstFormat = GET_UShort(); /* should be 1 */
1088 new_offset = GET_UShort() + base_offset;
1090 FORGET_Frame();
1092 cur_offset = FILE_Pos();
1093 if ( FILE_Seek( new_offset ) ||
1094 ( error = Load_Coverage( &ls->Coverage, input ) ) != TT_Err_Ok )
1095 return error;
1096 (void)FILE_Seek( cur_offset );
1098 if ( ACCESS_Frame( 2L ) )
1099 goto Fail2;
1101 count = ls->LigatureSetCount = GET_UShort();
1103 FORGET_Frame();
1105 ls->LigatureSet = NULL;
1107 if ( ALLOC_ARRAY( ls->LigatureSet, count, TTO_LigatureSet ) )
1108 goto Fail2;
1110 lset = ls->LigatureSet;
1112 for ( n = 0; n < count; n++ )
1114 if ( ACCESS_Frame( 2L ) )
1115 goto Fail1;
1117 new_offset = GET_UShort() + base_offset;
1119 FORGET_Frame();
1121 cur_offset = FILE_Pos();
1122 if ( FILE_Seek( new_offset ) ||
1123 ( error = Load_LigatureSet( &lset[n], input ) ) != TT_Err_Ok )
1124 goto Fail1;
1125 (void)FILE_Seek( cur_offset );
1128 return TT_Err_Ok;
1130 Fail1:
1131 for ( n = 0; n < count; n++ )
1132 Free_LigatureSet( &lset[n] );
1134 FREE( lset );
1136 Fail2:
1137 Free_Coverage( &ls->Coverage );
1138 return error;
1142 void Free_LigatureSubst( TTO_LigatureSubst* ls )
1144 UShort n, count;
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] );
1157 FREE( lset );
1160 Free_Coverage( &ls->Coverage );
1164 static TT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls,
1165 TTO_GSUB_String* in,
1166 TTO_GSUB_String* out,
1167 UShort flags,
1168 UShort context_length,
1169 TTO_GDEFHeader* gdef )
1171 UShort index, property;
1172 TT_Error error;
1173 UShort numlig, i, j;
1174 UShort* s_in;
1175 UShort* c;
1177 TTO_Ligature* lig;
1180 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
1181 return error;
1183 error = Coverage_Index( &ls->Coverage, in->string[in->pos], &index );
1184 if ( error )
1185 return error;
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;
1193 numlig;
1194 numlig--, lig++ )
1196 if ( in->pos + lig->ComponentCount > in->length )
1197 continue; /* Not enough glyphs in input */
1199 s_in = &in->string[in->pos];
1200 c = lig->Component;
1202 if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
1203 break;
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 )
1210 return error;
1212 if ( in->pos + j < in->length )
1213 j++;
1214 else
1215 break;
1218 if ( s_in[j] != c[i - 1] )
1219 break;
1222 if ( i == lig->ComponentCount )
1224 if ( ADD_String( in, lig->ComponentCount, out, 1, &lig->LigGlyph ) )
1225 return error;
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 )
1233 return error;
1236 return TT_Err_Ok;
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,
1249 UShort GlyphCount,
1250 UShort SubstCount,
1251 TTO_SubstLookupRecord* subst,
1252 TTO_GSUB_String* in,
1253 TTO_GSUB_String* out,
1254 int nesting_level )
1256 TT_Error error;
1257 UShort i, old_pos;
1260 i = 0;
1262 while ( i < GlyphCount )
1264 if ( SubstCount && i == subst->SequenceIndex )
1266 old_pos = in->pos;
1268 /* Do a substitution */
1270 error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, in, out,
1271 GlyphCount, nesting_level );
1273 subst++;
1274 SubstCount--;
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] ) )
1282 return error;
1283 i++;
1285 else if ( error )
1286 return error;
1288 else
1290 /* No substitution for this index */
1292 if ( ADD_String( in, 1, out, 1, &in->string[in->pos] ) )
1293 return error;
1294 i++;
1298 return TT_Err_Ok;
1302 /* LookupType 5 */
1304 /* SubRule */
1306 static TT_Error Load_SubRule( TTO_SubRule* sr,
1307 PFace input )
1309 DEFINE_LOAD_LOCALS( input->stream );
1311 UShort n, count;
1312 UShort* i;
1314 TTO_SubstLookupRecord* slr;
1317 if ( ACCESS_Frame( 4L ) )
1318 return error;
1320 sr->GlyphCount = GET_UShort();
1321 sr->SubstCount = GET_UShort();
1323 FORGET_Frame();
1325 sr->Input = NULL;
1327 count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */
1329 if ( ALLOC_ARRAY( sr->Input, count, UShort ) )
1330 return error;
1332 i = sr->Input;
1334 if ( ACCESS_Frame( count * 2L ) )
1335 goto Fail2;
1337 for ( n = 0; n < count; n++ )
1338 i[n] = GET_UShort();
1340 FORGET_Frame();
1342 sr->SubstLookupRecord = NULL;
1344 count = sr->SubstCount;
1346 if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
1347 goto Fail2;
1349 slr = sr->SubstLookupRecord;
1351 if ( ACCESS_Frame( count * 4L ) )
1352 goto Fail1;
1354 for ( n = 0; n < count; n++ )
1356 slr[n].SequenceIndex = GET_UShort();
1357 slr[n].LookupListIndex = GET_UShort();
1360 FORGET_Frame();
1362 return TT_Err_Ok;
1364 Fail1:
1365 FREE( slr );
1367 Fail2:
1368 FREE( i );
1369 return error;
1373 static void Free_SubRule( TTO_SubRule* sr )
1375 FREE( sr->SubstLookupRecord );
1376 FREE( sr->Input );
1380 /* SubRuleSet */
1382 static TT_Error Load_SubRuleSet( TTO_SubRuleSet* srs,
1383 PFace input )
1385 DEFINE_LOAD_LOCALS( input->stream );
1387 UShort n, count;
1388 ULong cur_offset, new_offset, base_offset;
1390 TTO_SubRule* sr;
1393 base_offset = FILE_Pos();
1395 if ( ACCESS_Frame( 2L ) )
1396 return error;
1398 count = srs->SubRuleCount = GET_UShort();
1400 FORGET_Frame();
1402 srs->SubRule = NULL;
1404 if ( ALLOC_ARRAY( srs->SubRule, count, TTO_SubRule ) )
1405 return error;
1407 sr = srs->SubRule;
1409 for ( n = 0; n < count; n++ )
1411 if ( ACCESS_Frame( 2L ) )
1412 goto Fail;
1414 new_offset = GET_UShort() + base_offset;
1416 FORGET_Frame();
1418 cur_offset = FILE_Pos();
1419 if ( FILE_Seek( new_offset ) ||
1420 ( error = Load_SubRule( &sr[n], input ) ) != TT_Err_Ok )
1421 goto Fail;
1422 (void)FILE_Seek( cur_offset );
1425 return TT_Err_Ok;
1427 Fail:
1428 for ( n = 0; n < count; n++ )
1429 Free_SubRule( &sr[n] );
1431 FREE( sr );
1432 return error;
1436 static void Free_SubRuleSet( TTO_SubRuleSet* srs )
1438 UShort n, count;
1440 TTO_SubRule* sr;
1443 if ( srs->SubRule )
1445 count = srs->SubRuleCount;
1446 sr = srs->SubRule;
1448 for ( n = 0; n < count; n++ )
1449 Free_SubRule( &sr[n] );
1451 FREE( sr );
1456 /* ContextSubstFormat1 */
1458 static TT_Error Load_ContextSubst1( TTO_ContextSubstFormat1* csf1,
1459 PFace input )
1461 DEFINE_LOAD_LOCALS( input->stream );
1463 UShort n, count;
1464 ULong cur_offset, new_offset, base_offset;
1466 TTO_SubRuleSet* srs;
1469 base_offset = FILE_Pos() - 2L;
1471 if ( ACCESS_Frame( 2L ) )
1472 return error;
1474 new_offset = GET_UShort() + base_offset;
1476 FORGET_Frame();
1478 cur_offset = FILE_Pos();
1479 if ( FILE_Seek( new_offset ) ||
1480 ( error = Load_Coverage( &csf1->Coverage, input ) ) != TT_Err_Ok )
1481 return error;
1482 (void)FILE_Seek( cur_offset );
1484 if ( ACCESS_Frame( 2L ) )
1485 goto Fail2;
1487 count = csf1->SubRuleSetCount = GET_UShort();
1489 FORGET_Frame();
1491 csf1->SubRuleSet = NULL;
1493 if ( ALLOC_ARRAY( csf1->SubRuleSet, count, TTO_SubRuleSet ) )
1494 goto Fail2;
1496 srs = csf1->SubRuleSet;
1498 for ( n = 0; n < count; n++ )
1500 if ( ACCESS_Frame( 2L ) )
1501 goto Fail1;
1503 new_offset = GET_UShort() + base_offset;
1505 FORGET_Frame();
1507 cur_offset = FILE_Pos();
1508 if ( FILE_Seek( new_offset ) ||
1509 ( error = Load_SubRuleSet( &srs[n], input ) ) != TT_Err_Ok )
1510 goto Fail1;
1511 (void)FILE_Seek( cur_offset );
1514 return TT_Err_Ok;
1516 Fail1:
1517 for ( n = 0; n < count; n++ )
1518 Free_SubRuleSet( &srs[n] );
1520 FREE( srs );
1522 Fail2:
1523 Free_Coverage( &csf1->Coverage );
1524 return error;
1528 static void Free_Context1( TTO_ContextSubstFormat1* csf1 )
1530 UShort n, count;
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] );
1543 FREE( srs );
1546 Free_Coverage( &csf1->Coverage );
1550 /* SubClassRule */
1552 static TT_Error Load_SubClassRule( TTO_ContextSubstFormat2* csf2,
1553 TTO_SubClassRule* scr,
1554 PFace input )
1556 DEFINE_LOAD_LOCALS( input->stream );
1558 UShort n, count;
1560 UShort* c;
1561 TTO_SubstLookupRecord* slr;
1562 Bool* d;
1565 if ( ACCESS_Frame( 4L ) )
1566 return error;
1568 scr->GlyphCount = GET_UShort();
1569 scr->SubstCount = GET_UShort();
1571 if ( scr->GlyphCount > csf2->MaxContextLength )
1572 csf2->MaxContextLength = scr->GlyphCount;
1574 FORGET_Frame();
1576 scr->Class = NULL;
1578 count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */
1580 if ( ALLOC_ARRAY( scr->Class, count, UShort ) )
1581 return error;
1583 c = scr->Class;
1584 d = csf2->ClassDef.Defined;
1586 if ( ACCESS_Frame( count * 2L ) )
1587 goto Fail2;
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. */
1596 if ( !d[c[n]] )
1597 c[n] = 0;
1600 FORGET_Frame();
1602 scr->SubstLookupRecord = NULL;
1604 count = scr->SubstCount;
1606 if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
1607 goto Fail2;
1609 slr = scr->SubstLookupRecord;
1611 if ( ACCESS_Frame( count * 4L ) )
1612 goto Fail1;
1614 for ( n = 0; n < count; n++ )
1616 slr[n].SequenceIndex = GET_UShort();
1617 slr[n].LookupListIndex = GET_UShort();
1620 FORGET_Frame();
1622 return TT_Err_Ok;
1624 Fail1:
1625 FREE( slr );
1627 Fail2:
1628 FREE( c );
1629 return error;
1633 static void Free_SubClassRule( TTO_SubClassRule* scr )
1635 FREE( scr->SubstLookupRecord );
1636 FREE( scr->Class );
1640 /* SubClassSet */
1642 static TT_Error Load_SubClassSet( TTO_ContextSubstFormat2* csf2,
1643 TTO_SubClassSet* scs,
1644 PFace input )
1646 DEFINE_LOAD_LOCALS( input->stream );
1648 UShort n, count;
1649 ULong cur_offset, new_offset, base_offset;
1651 TTO_SubClassRule* scr;
1654 base_offset = FILE_Pos();
1656 if ( ACCESS_Frame( 2L ) )
1657 return error;
1659 count = scs->SubClassRuleCount = GET_UShort();
1661 FORGET_Frame();
1663 scs->SubClassRule = NULL;
1665 if ( ALLOC_ARRAY( scs->SubClassRule, count, TTO_SubClassRule ) )
1666 return error;
1668 scr = scs->SubClassRule;
1670 for ( n = 0; n < count; n++ )
1672 if ( ACCESS_Frame( 2L ) )
1673 goto Fail;
1675 new_offset = GET_UShort() + base_offset;
1677 FORGET_Frame();
1679 cur_offset = FILE_Pos();
1680 if ( FILE_Seek( new_offset ) ||
1681 ( error = Load_SubClassRule( csf2, &scr[n],
1682 input ) ) != TT_Err_Ok )
1683 goto Fail;
1684 (void)FILE_Seek( cur_offset );
1687 return TT_Err_Ok;
1689 Fail:
1690 for ( n = 0; n < count; n++ )
1691 Free_SubClassRule( &scr[n] );
1693 FREE( scr );
1694 return error;
1698 static void Free_SubClassSet( TTO_SubClassSet* scs )
1700 UShort n, count;
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] );
1713 FREE( scr );
1718 /* ContextSubstFormat2 */
1720 static TT_Error Load_ContextSubst2( TTO_ContextSubstFormat2* csf2,
1721 PFace input )
1723 DEFINE_LOAD_LOCALS( input->stream );
1725 UShort n, count;
1726 ULong cur_offset, new_offset, base_offset;
1728 TTO_SubClassSet* scs;
1731 base_offset = FILE_Pos() - 2;
1733 if ( ACCESS_Frame( 2L ) )
1734 return error;
1736 new_offset = GET_UShort() + base_offset;
1738 FORGET_Frame();
1740 cur_offset = FILE_Pos();
1741 if ( FILE_Seek( new_offset ) ||
1742 ( error = Load_Coverage( &csf2->Coverage, input ) ) != TT_Err_Ok )
1743 return error;
1744 (void)FILE_Seek( cur_offset );
1746 if ( ACCESS_Frame( 4L ) )
1747 goto Fail3;
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();
1756 FORGET_Frame();
1758 cur_offset = FILE_Pos();
1759 if ( FILE_Seek( new_offset ) ||
1760 ( error = Load_ClassDefinition( &csf2->ClassDef, count,
1761 input ) ) != TT_Err_Ok )
1762 goto Fail3;
1763 (void)FILE_Seek( cur_offset );
1765 csf2->SubClassSet = NULL;
1766 csf2->MaxContextLength = 0;
1768 if ( ALLOC_ARRAY( csf2->SubClassSet, count, TTO_SubClassSet ) )
1769 goto Fail2;
1771 scs = csf2->SubClassSet;
1773 for ( n = 0; n < count; n++ )
1775 if ( ACCESS_Frame( 2L ) )
1776 goto Fail1;
1778 new_offset = GET_UShort() + base_offset;
1780 FORGET_Frame();
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 )
1788 goto Fail1;
1789 (void)FILE_Seek( cur_offset );
1791 else
1793 /* we create a SubClassSet table with no entries */
1795 csf2->SubClassSet[n].SubClassRuleCount = 0;
1796 csf2->SubClassSet[n].SubClassRule = NULL;
1800 return TT_Err_Ok;
1802 Fail1:
1803 for ( n = 0; n < count; n++ )
1804 Free_SubClassSet( &scs[n] );
1806 FREE( scs );
1808 Fail2:
1809 Free_ClassDefinition( &csf2->ClassDef );
1811 Fail3:
1812 Free_Coverage( &csf2->Coverage );
1813 return error;
1817 static void Free_Context2( TTO_ContextSubstFormat2* csf2 )
1819 UShort n, count;
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] );
1832 FREE( scs );
1835 Free_ClassDefinition( &csf2->ClassDef );
1836 Free_Coverage( &csf2->Coverage );
1840 /* ContextSubstFormat3 */
1842 static TT_Error Load_ContextSubst3( TTO_ContextSubstFormat3* csf3,
1843 PFace input )
1845 DEFINE_LOAD_LOCALS( input->stream );
1847 UShort n, count;
1848 ULong cur_offset, new_offset, base_offset;
1850 TTO_Coverage* c;
1851 TTO_SubstLookupRecord* slr;
1854 base_offset = FILE_Pos() - 2L;
1856 if ( ACCESS_Frame( 4L ) )
1857 return error;
1859 csf3->GlyphCount = GET_UShort();
1860 csf3->SubstCount = GET_UShort();
1862 FORGET_Frame();
1864 csf3->Coverage = NULL;
1866 count = csf3->GlyphCount;
1868 if ( ALLOC_ARRAY( csf3->Coverage, count, TTO_Coverage ) )
1869 return error;
1871 c = csf3->Coverage;
1873 for ( n = 0; n < count; n++ )
1875 if ( ACCESS_Frame( 2L ) )
1876 goto Fail2;
1878 new_offset = GET_UShort() + base_offset;
1880 FORGET_Frame();
1882 cur_offset = FILE_Pos();
1883 if ( FILE_Seek( new_offset ) ||
1884 ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok )
1885 goto Fail2;
1886 (void)FILE_Seek( cur_offset );
1889 csf3->SubstLookupRecord = NULL;
1891 count = csf3->SubstCount;
1893 if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
1894 TTO_SubstLookupRecord ) )
1895 goto Fail2;
1897 slr = csf3->SubstLookupRecord;
1899 if ( ACCESS_Frame( count * 4L ) )
1900 goto Fail1;
1902 for ( n = 0; n < count; n++ )
1904 slr[n].SequenceIndex = GET_UShort();
1905 slr[n].LookupListIndex = GET_UShort();
1908 FORGET_Frame();
1910 return TT_Err_Ok;
1912 Fail1:
1913 FREE( slr );
1915 Fail2:
1916 for ( n = 0; n < count; n++ )
1917 Free_Coverage( &c[n] );
1919 FREE( c );
1920 return error;
1924 static void Free_Context3( TTO_ContextSubstFormat3* csf3 )
1926 UShort n, count;
1928 TTO_Coverage* c;
1931 FREE( csf3->SubstLookupRecord );
1933 if ( csf3->Coverage )
1935 count = csf3->GlyphCount;
1936 c = csf3->Coverage;
1938 for ( n = 0; n < count; n++ )
1939 Free_Coverage( &c[n] );
1941 FREE( c );
1946 /* ContextSubst */
1948 TT_Error Load_ContextSubst( TTO_ContextSubst* cs,
1949 PFace input )
1951 DEFINE_LOAD_LOCALS( input->stream );
1954 if ( ACCESS_Frame( 2L ) )
1955 return error;
1957 cs->SubstFormat = GET_UShort();
1959 FORGET_Frame();
1961 switch ( cs->SubstFormat )
1963 case 1:
1964 return Load_ContextSubst1( &cs->csf.csf1, input );
1966 case 2:
1967 return Load_ContextSubst2( &cs->csf.csf2, input );
1969 case 3:
1970 return Load_ContextSubst3( &cs->csf.csf3, input );
1972 default:
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 )
1984 case 1:
1985 Free_Context1( &cs->csf.csf1 );
1986 break;
1988 case 2:
1989 Free_Context2( &cs->csf.csf2 );
1990 break;
1992 case 3:
1993 Free_Context3( &cs->csf.csf3 );
1994 break;
1999 static TT_Error Lookup_ContextSubst1(
2000 TTO_GSUBHeader* gsub,
2001 TTO_ContextSubstFormat1* csf1,
2002 TTO_GSUB_String* in,
2003 TTO_GSUB_String* out,
2004 UShort flags,
2005 UShort context_length,
2006 int nesting_level )
2008 UShort index, property;
2009 UShort i, j, k, numsr;
2010 TT_Error error;
2011 UShort* s_in;
2013 TTO_SubRule* sr;
2014 TTO_GDEFHeader* gdef;
2017 gdef = gsub->gdef;
2019 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
2020 return error;
2022 error = Coverage_Index( &csf1->Coverage, in->string[in->pos], &index );
2023 if ( error )
2024 return error;
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 )
2032 continue;
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 )
2044 return error;
2046 if ( in->pos + j < in->length )
2047 j++;
2048 else
2049 break;
2052 if ( s_in[j] != sr[k].Input[i - 1] )
2053 break;
2056 if ( i == sr[k].GlyphCount )
2057 return Do_ContextSubst( gsub, sr[k].GlyphCount,
2058 sr[k].SubstCount, sr[k].SubstLookupRecord,
2059 in, out,
2060 nesting_level );
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,
2072 UShort flags,
2073 UShort context_length,
2074 int nesting_level )
2076 UShort index, property;
2077 TT_Error error;
2078 UShort i, j, k, known_classes;
2080 UShort* classes;
2081 UShort* s_in;
2082 UShort* cl;
2084 TTO_SubClassSet* scs;
2085 TTO_SubClassRule* sr;
2086 TTO_GDEFHeader* gdef;
2089 gdef = gsub->gdef;
2091 if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, UShort ) )
2092 return error;
2094 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
2095 return error;
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 );
2102 if ( error )
2103 goto End;
2105 error = Get_Class( &csf2->ClassDef, in->string[in->pos],
2106 &classes[0], NULL );
2107 if ( error )
2108 goto End;
2109 known_classes = 0;
2111 scs = &csf2->SubClassSet[classes[0]];
2112 if ( !scs )
2114 error = TTO_Err_Invalid_GSUB_SubTable;
2115 goto End;
2118 for ( k = 0; k < scs->SubClassRuleCount; k++ )
2120 sr = &scs->SubClassRule[k];
2122 if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
2123 continue;
2125 if ( in->pos + sr->GlyphCount > in->length )
2126 continue; /* context is too long */
2128 s_in = &in->string[in->pos];
2129 cl = sr->Class;
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 )
2138 return error;
2140 if ( in->pos + j < in->length )
2141 j++;
2142 else
2143 break;
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 )
2152 return error;
2153 known_classes = i;
2156 if ( cl[i - 1] != classes[i] )
2157 break;
2160 if ( i == sr->GlyphCount )
2162 error = Do_ContextSubst( gsub, sr->GlyphCount,
2163 sr->SubstCount, sr->SubstLookupRecord,
2164 in, out,
2165 nesting_level );
2166 goto End;
2170 error = TTO_Err_Not_Covered;
2172 End:
2173 FREE( classes );
2174 return error;
2178 static TT_Error Lookup_ContextSubst3(
2179 TTO_GSUBHeader* gsub,
2180 TTO_ContextSubstFormat3* csf3,
2181 TTO_GSUB_String* in,
2182 TTO_GSUB_String* out,
2183 UShort flags,
2184 UShort context_length,
2185 int nesting_level )
2187 TT_Error error;
2188 UShort index, i, j, property;
2189 UShort* s_in;
2191 TTO_Coverage* c;
2192 TTO_GDEFHeader* gdef;
2195 gdef = gsub->gdef;
2197 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
2198 return error;
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];
2207 c = csf3->Coverage;
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 )
2214 return error;
2216 if ( in->pos + j < in->length )
2217 j++;
2218 else
2219 return TTO_Err_Not_Covered;
2222 error = Coverage_Index( &c[i], s_in[j], &index );
2223 if ( error )
2224 return error;
2227 return Do_ContextSubst( gsub, csf3->GlyphCount,
2228 csf3->SubstCount, csf3->SubstLookupRecord,
2229 in, out,
2230 nesting_level );
2234 static TT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub,
2235 TTO_ContextSubst* cs,
2236 TTO_GSUB_String* in,
2237 TTO_GSUB_String* out,
2238 UShort flags,
2239 UShort context_length,
2240 int nesting_level )
2242 switch ( cs->SubstFormat )
2244 case 1:
2245 return Lookup_ContextSubst1( gsub, &cs->csf.csf1, in, out,
2246 flags, context_length, nesting_level );
2248 case 2:
2249 return Lookup_ContextSubst2( gsub, &cs->csf.csf2, in, out,
2250 flags, context_length, nesting_level );
2252 case 3:
2253 return Lookup_ContextSubst3( gsub, &cs->csf.csf3, in, out,
2254 flags, context_length, nesting_level );
2256 default:
2257 return TTO_Err_Invalid_GSUB_SubTable_Format;
2260 return TT_Err_Ok; /* never reached */
2264 /* LookupType 6 */
2266 /* ChainSubRule */
2268 static TT_Error Load_ChainSubRule( TTO_ChainSubRule* csr,
2269 PFace input )
2271 DEFINE_LOAD_LOCALS( input->stream );
2273 UShort n, count;
2274 UShort* b;
2275 UShort* i;
2276 UShort* l;
2278 TTO_SubstLookupRecord* slr;
2281 if ( ACCESS_Frame( 2L ) )
2282 return error;
2284 csr->BacktrackGlyphCount = GET_UShort();
2286 FORGET_Frame();
2288 csr->Backtrack = NULL;
2290 count = csr->BacktrackGlyphCount;
2292 if ( ALLOC_ARRAY( csr->Backtrack, count, UShort ) )
2293 return error;
2295 b = csr->Backtrack;
2297 if ( ACCESS_Frame( count * 2L ) )
2298 goto Fail4;
2300 for ( n = 0; n < count; n++ )
2301 b[n] = GET_UShort();
2303 FORGET_Frame();
2305 if ( ACCESS_Frame( 2L ) )
2306 goto Fail4;
2308 csr->InputGlyphCount = GET_UShort();
2310 FORGET_Frame();
2312 csr->Input = NULL;
2314 count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2316 if ( ALLOC_ARRAY( csr->Input, count, UShort ) )
2317 goto Fail4;
2319 i = csr->Input;
2321 if ( ACCESS_Frame( count * 2L ) )
2322 goto Fail3;
2324 for ( n = 0; n < count; n++ )
2325 i[n] = GET_UShort();
2327 FORGET_Frame();
2329 if ( ACCESS_Frame( 2L ) )
2330 goto Fail3;
2332 csr->LookaheadGlyphCount = GET_UShort();
2334 FORGET_Frame();
2336 csr->Lookahead = NULL;
2338 count = csr->LookaheadGlyphCount;
2340 if ( ALLOC_ARRAY( csr->Lookahead, count, UShort ) )
2341 goto Fail3;
2343 l = csr->Lookahead;
2345 if ( ACCESS_Frame( count * 2L ) )
2346 goto Fail2;
2348 for ( n = 0; n < count; n++ )
2349 l[n] = GET_UShort();
2351 FORGET_Frame();
2353 if ( ACCESS_Frame( 2L ) )
2354 goto Fail2;
2356 csr->SubstCount = GET_UShort();
2358 FORGET_Frame();
2360 csr->SubstLookupRecord = NULL;
2362 count = csr->SubstCount;
2364 if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
2365 goto Fail2;
2367 slr = csr->SubstLookupRecord;
2369 if ( ACCESS_Frame( count * 4L ) )
2370 goto Fail1;
2372 for ( n = 0; n < count; n++ )
2374 slr[n].SequenceIndex = GET_UShort();
2375 slr[n].LookupListIndex = GET_UShort();
2378 FORGET_Frame();
2380 return TT_Err_Ok;
2382 Fail1:
2383 FREE( slr );
2385 Fail2:
2386 FREE( l );
2388 Fail3:
2389 FREE( i );
2391 Fail4:
2392 FREE( b );
2393 return error;
2397 static void Free_ChainSubRule( TTO_ChainSubRule* csr )
2399 FREE( csr->SubstLookupRecord );
2400 FREE( csr->Lookahead );
2401 FREE( csr->Input );
2402 FREE( csr->Backtrack );
2406 /* ChainSubRuleSet */
2408 static TT_Error Load_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs,
2409 PFace input )
2411 DEFINE_LOAD_LOCALS( input->stream );
2413 UShort n, count;
2414 ULong cur_offset, new_offset, base_offset;
2416 TTO_ChainSubRule* csr;
2419 base_offset = FILE_Pos();
2421 if ( ACCESS_Frame( 2L ) )
2422 return error;
2424 count = csrs->ChainSubRuleCount = GET_UShort();
2426 FORGET_Frame();
2428 csrs->ChainSubRule = NULL;
2430 if ( ALLOC_ARRAY( csrs->ChainSubRule, count, TTO_ChainSubRule ) )
2431 return error;
2433 csr = csrs->ChainSubRule;
2435 for ( n = 0; n < count; n++ )
2437 if ( ACCESS_Frame( 2L ) )
2438 goto Fail;
2440 new_offset = GET_UShort() + base_offset;
2442 FORGET_Frame();
2444 cur_offset = FILE_Pos();
2445 if ( FILE_Seek( new_offset ) ||
2446 ( error = Load_ChainSubRule( &csr[n], input ) ) != TT_Err_Ok )
2447 goto Fail;
2448 (void)FILE_Seek( cur_offset );
2451 return TT_Err_Ok;
2453 Fail:
2454 for ( n = 0; n < count; n++ )
2455 Free_ChainSubRule( &csr[n] );
2457 FREE( csr );
2458 return error;
2462 static void Free_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs )
2464 UShort n, count;
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] );
2477 FREE( csr );
2482 /* ChainContextSubstFormat1 */
2484 static TT_Error Load_ChainContextSubst1(
2485 TTO_ChainContextSubstFormat1* ccsf1,
2486 PFace input )
2488 DEFINE_LOAD_LOCALS( input->stream );
2490 UShort n, count;
2491 ULong cur_offset, new_offset, base_offset;
2493 TTO_ChainSubRuleSet* csrs;
2496 base_offset = FILE_Pos() - 2L;
2498 if ( ACCESS_Frame( 2L ) )
2499 return error;
2501 new_offset = GET_UShort() + base_offset;
2503 FORGET_Frame();
2505 cur_offset = FILE_Pos();
2506 if ( FILE_Seek( new_offset ) ||
2507 ( error = Load_Coverage( &ccsf1->Coverage, input ) ) != TT_Err_Ok )
2508 return error;
2509 (void)FILE_Seek( cur_offset );
2511 if ( ACCESS_Frame( 2L ) )
2512 goto Fail2;
2514 count = ccsf1->ChainSubRuleSetCount = GET_UShort();
2516 FORGET_Frame();
2518 ccsf1->ChainSubRuleSet = NULL;
2520 if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, TTO_ChainSubRuleSet ) )
2521 goto Fail2;
2523 csrs = ccsf1->ChainSubRuleSet;
2525 for ( n = 0; n < count; n++ )
2527 if ( ACCESS_Frame( 2L ) )
2528 goto Fail1;
2530 new_offset = GET_UShort() + base_offset;
2532 FORGET_Frame();
2534 cur_offset = FILE_Pos();
2535 if ( FILE_Seek( new_offset ) ||
2536 ( error = Load_ChainSubRuleSet( &csrs[n], input ) ) != TT_Err_Ok )
2537 goto Fail1;
2538 (void)FILE_Seek( cur_offset );
2541 return TT_Err_Ok;
2543 Fail1:
2544 for ( n = 0; n < count; n++ )
2545 Free_ChainSubRuleSet( &csrs[n] );
2547 FREE( csrs );
2549 Fail2:
2550 Free_Coverage( &ccsf1->Coverage );
2551 return error;
2555 static void Free_ChainContext1( TTO_ChainContextSubstFormat1* ccsf1 )
2557 UShort n, count;
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] );
2570 FREE( csrs );
2573 Free_Coverage( &ccsf1->Coverage );
2577 /* ChainSubClassRule */
2579 static TT_Error Load_ChainSubClassRule(
2580 TTO_ChainContextSubstFormat2* ccsf2,
2581 TTO_ChainSubClassRule* cscr,
2582 PFace input )
2584 DEFINE_LOAD_LOCALS( input->stream );
2586 UShort n, count;
2588 UShort* b;
2589 UShort* i;
2590 UShort* l;
2591 TTO_SubstLookupRecord* slr;
2592 Bool* d;
2595 if ( ACCESS_Frame( 2L ) )
2596 return error;
2598 cscr->BacktrackGlyphCount = GET_UShort();
2600 FORGET_Frame();
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 ) )
2610 return error;
2612 b = cscr->Backtrack;
2613 d = ccsf2->BacktrackClassDef.Defined;
2615 if ( ACCESS_Frame( count * 2L ) )
2616 goto Fail4;
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. */
2625 if ( !d[b[n]] )
2626 b[n] = 0;
2629 FORGET_Frame();
2631 if ( ACCESS_Frame( 2L ) )
2632 goto Fail4;
2634 cscr->InputGlyphCount = GET_UShort();
2636 FORGET_Frame();
2638 if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
2639 ccsf2->MaxInputLength = cscr->InputGlyphCount;
2641 cscr->Input = NULL;
2643 count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2645 if ( ALLOC_ARRAY( cscr->Input, count, UShort ) )
2646 goto Fail4;
2648 i = cscr->Input;
2649 d = ccsf2->InputClassDef.Defined;
2651 if ( ACCESS_Frame( count * 2L ) )
2652 goto Fail3;
2654 for ( n = 0; n < count; n++ )
2656 i[n] = GET_UShort();
2658 if ( !d[i[n]] )
2659 i[n] = 0;
2662 FORGET_Frame();
2664 if ( ACCESS_Frame( 2L ) )
2665 goto Fail3;
2667 cscr->LookaheadGlyphCount = GET_UShort();
2669 FORGET_Frame();
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 ) )
2679 goto Fail3;
2681 l = cscr->Lookahead;
2682 d = ccsf2->LookaheadClassDef.Defined;
2684 if ( ACCESS_Frame( count * 2L ) )
2685 goto Fail2;
2687 for ( n = 0; n < count; n++ )
2689 l[n] = GET_UShort();
2691 if ( !d[l[n]] )
2692 l[n] = 0;
2695 FORGET_Frame();
2697 if ( ACCESS_Frame( 2L ) )
2698 goto Fail2;
2700 cscr->SubstCount = GET_UShort();
2702 FORGET_Frame();
2704 cscr->SubstLookupRecord = NULL;
2706 count = cscr->SubstCount;
2708 if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
2709 TTO_SubstLookupRecord ) )
2710 goto Fail2;
2712 slr = cscr->SubstLookupRecord;
2714 if ( ACCESS_Frame( count * 4L ) )
2715 goto Fail1;
2717 for ( n = 0; n < count; n++ )
2719 slr[n].SequenceIndex = GET_UShort();
2720 slr[n].LookupListIndex = GET_UShort();
2723 FORGET_Frame();
2725 return TT_Err_Ok;
2727 Fail1:
2728 FREE( slr );
2730 Fail2:
2731 FREE( l );
2733 Fail3:
2734 FREE( i );
2736 Fail4:
2737 FREE( b );
2738 return error;
2742 static void Free_ChainSubClassRule( TTO_ChainSubClassRule* cscr )
2744 FREE( cscr->SubstLookupRecord );
2745 FREE( cscr->Lookahead );
2746 FREE( cscr->Input );
2747 FREE( cscr->Backtrack );
2751 /* SubClassSet */
2753 static TT_Error Load_ChainSubClassSet(
2754 TTO_ChainContextSubstFormat2* ccsf2,
2755 TTO_ChainSubClassSet* cscs,
2756 PFace input )
2758 DEFINE_LOAD_LOCALS( input->stream );
2760 UShort n, count;
2761 ULong cur_offset, new_offset, base_offset;
2763 TTO_ChainSubClassRule* cscr;
2766 base_offset = FILE_Pos();
2768 if ( ACCESS_Frame( 2L ) )
2769 return error;
2771 count = cscs->ChainSubClassRuleCount = GET_UShort();
2773 FORGET_Frame();
2775 cscs->ChainSubClassRule = NULL;
2777 if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
2778 TTO_ChainSubClassRule ) )
2779 return error;
2781 cscr = cscs->ChainSubClassRule;
2783 for ( n = 0; n < count; n++ )
2785 if ( ACCESS_Frame( 2L ) )
2786 goto Fail;
2788 new_offset = GET_UShort() + base_offset;
2790 FORGET_Frame();
2792 cur_offset = FILE_Pos();
2793 if ( FILE_Seek( new_offset ) ||
2794 ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
2795 input ) ) != TT_Err_Ok )
2796 goto Fail;
2797 (void)FILE_Seek( cur_offset );
2800 return TT_Err_Ok;
2802 Fail:
2803 for ( n = 0; n < count; n++ )
2804 Free_ChainSubClassRule( &cscr[n] );
2806 FREE( cscr );
2807 return error;
2811 static void Free_ChainSubClassSet( TTO_ChainSubClassSet* cscs )
2813 UShort n, count;
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] );
2826 FREE( cscr );
2831 /* ChainContextSubstFormat2 */
2833 static TT_Error Load_ChainContextSubst2(
2834 TTO_ChainContextSubstFormat2* ccsf2,
2835 PFace input )
2837 DEFINE_LOAD_LOCALS( input->stream );
2839 UShort n, count;
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 ) )
2849 return error;
2851 new_offset = GET_UShort() + base_offset;
2853 FORGET_Frame();
2855 cur_offset = FILE_Pos();
2856 if ( FILE_Seek( new_offset ) ||
2857 ( error = Load_Coverage( &ccsf2->Coverage, input ) ) != TT_Err_Ok )
2858 return error;
2859 (void)FILE_Seek( cur_offset );
2861 if ( ACCESS_Frame( 8L ) )
2862 goto Fail5;
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();
2873 FORGET_Frame();
2875 cur_offset = FILE_Pos();
2876 if ( FILE_Seek( backtrack_offset ) ||
2877 ( error = Load_ClassDefinition( &ccsf2->BacktrackClassDef, count,
2878 input ) ) != TT_Err_Ok )
2879 goto Fail5;
2880 if ( FILE_Seek( input_offset ) ||
2881 ( error = Load_ClassDefinition( &ccsf2->InputClassDef, count,
2882 input ) ) != TT_Err_Ok )
2883 goto Fail4;
2884 if ( FILE_Seek( lookahead_offset ) ||
2885 ( error = Load_ClassDefinition( &ccsf2->LookaheadClassDef, count,
2886 input ) ) != TT_Err_Ok )
2887 goto Fail3;
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 ) )
2896 goto Fail2;
2898 cscs = ccsf2->ChainSubClassSet;
2900 for ( n = 0; n < count; n++ )
2902 if ( ACCESS_Frame( 2L ) )
2903 goto Fail1;
2905 new_offset = GET_UShort() + base_offset;
2907 FORGET_Frame();
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 )
2915 goto Fail1;
2916 (void)FILE_Seek( cur_offset );
2918 else
2920 /* we create a ChainSubClassSet table with no entries */
2922 ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
2923 ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL;
2927 return TT_Err_Ok;
2929 Fail1:
2930 for ( n = 0; n < count; n++ )
2931 Free_ChainSubClassSet( &cscs[n] );
2933 FREE( cscs );
2935 Fail2:
2936 Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2938 Fail3:
2939 Free_ClassDefinition( &ccsf2->InputClassDef );
2941 Fail4:
2942 Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2944 Fail5:
2945 Free_Coverage( &ccsf2->Coverage );
2946 return error;
2950 static void Free_ChainContext2( TTO_ChainContextSubstFormat2* ccsf2 )
2952 UShort n, count;
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] );
2965 FREE( cscs );
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,
2980 PFace input )
2982 DEFINE_LOAD_LOCALS( input->stream );
2984 UShort n, count;
2985 UShort backtrack_count, input_count, lookahead_count;
2986 ULong cur_offset, new_offset, base_offset;
2988 TTO_Coverage* b;
2989 TTO_Coverage* i;
2990 TTO_Coverage* l;
2991 TTO_SubstLookupRecord* slr;
2994 base_offset = FILE_Pos() - 2L;
2996 if ( ACCESS_Frame( 2L ) )
2997 return error;
2999 ccsf3->BacktrackGlyphCount = GET_UShort();
3001 FORGET_Frame();
3003 ccsf3->BacktrackCoverage = NULL;
3005 backtrack_count = ccsf3->BacktrackGlyphCount;
3007 if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
3008 TTO_Coverage ) )
3009 return error;
3011 b = ccsf3->BacktrackCoverage;
3013 for ( n = 0; n < backtrack_count; n++ )
3015 if ( ACCESS_Frame( 2L ) )
3016 goto Fail4;
3018 new_offset = GET_UShort() + base_offset;
3020 FORGET_Frame();
3022 cur_offset = FILE_Pos();
3023 if ( FILE_Seek( new_offset ) ||
3024 ( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok )
3025 goto Fail4;
3026 (void)FILE_Seek( cur_offset );
3029 if ( ACCESS_Frame( 2L ) )
3030 goto Fail4;
3032 ccsf3->InputGlyphCount = GET_UShort();
3034 FORGET_Frame();
3036 ccsf3->InputCoverage = NULL;
3038 input_count = ccsf3->InputGlyphCount;
3040 if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, TTO_Coverage ) )
3041 goto Fail4;
3043 i = ccsf3->InputCoverage;
3045 for ( n = 0; n < input_count; n++ )
3047 if ( ACCESS_Frame( 2L ) )
3048 goto Fail3;
3050 new_offset = GET_UShort() + base_offset;
3052 FORGET_Frame();
3054 cur_offset = FILE_Pos();
3055 if ( FILE_Seek( new_offset ) ||
3056 ( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok )
3057 goto Fail3;
3058 (void)FILE_Seek( cur_offset );
3061 if ( ACCESS_Frame( 2L ) )
3062 goto Fail3;
3064 ccsf3->LookaheadGlyphCount = GET_UShort();
3066 FORGET_Frame();
3068 ccsf3->LookaheadCoverage = NULL;
3070 lookahead_count = ccsf3->LookaheadGlyphCount;
3072 if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
3073 TTO_Coverage ) )
3074 goto Fail3;
3076 l = ccsf3->LookaheadCoverage;
3078 for ( n = 0; n < lookahead_count; n++ )
3080 if ( ACCESS_Frame( 2L ) )
3081 goto Fail2;
3083 new_offset = GET_UShort() + base_offset;
3085 FORGET_Frame();
3087 cur_offset = FILE_Pos();
3088 if ( FILE_Seek( new_offset ) ||
3089 ( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok )
3090 goto Fail2;
3091 (void)FILE_Seek( cur_offset );
3094 if ( ACCESS_Frame( 2L ) )
3095 goto Fail2;
3097 ccsf3->SubstCount = GET_UShort();
3099 FORGET_Frame();
3101 ccsf3->SubstLookupRecord = NULL;
3103 count = ccsf3->SubstCount;
3105 if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
3106 TTO_SubstLookupRecord ) )
3107 goto Fail2;
3109 slr = ccsf3->SubstLookupRecord;
3111 if ( ACCESS_Frame( count * 4L ) )
3112 goto Fail1;
3114 for ( n = 0; n < count; n++ )
3116 slr[n].SequenceIndex = GET_UShort();
3117 slr[n].LookupListIndex = GET_UShort();
3120 FORGET_Frame();
3122 return TT_Err_Ok;
3124 Fail1:
3125 FREE( slr );
3127 Fail2:
3128 for ( n = 0; n < lookahead_count; n++ )
3129 Free_Coverage( &l[n] );
3131 FREE( l );
3133 Fail3:
3134 for ( n = 0; n < input_count; n++ )
3135 Free_Coverage( &i[n] );
3137 FREE( i );
3139 Fail4:
3140 for ( n = 0; n < backtrack_count; n++ )
3141 Free_Coverage( &b[n] );
3143 FREE( b );
3144 return error;
3148 static void Free_ChainContext3( TTO_ChainContextSubstFormat3* ccsf3 )
3150 UShort n, count;
3152 TTO_Coverage* c;
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] );
3165 FREE( c );
3168 if ( ccsf3->InputCoverage )
3170 count = ccsf3->InputGlyphCount;
3171 c = ccsf3->InputCoverage;
3173 for ( n = 0; n < count; n++ )
3174 Free_Coverage( &c[n] );
3176 FREE( c );
3179 if ( ccsf3->BacktrackCoverage )
3181 count = ccsf3->BacktrackGlyphCount;
3182 c = ccsf3->BacktrackCoverage;
3184 for ( n = 0; n < count; n++ )
3185 Free_Coverage( &c[n] );
3187 FREE( c );
3192 /* ChainContextSubst */
3194 TT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
3195 PFace input )
3197 DEFINE_LOAD_LOCALS( input->stream );
3200 if ( ACCESS_Frame( 2L ) )
3201 return error;
3203 ccs->SubstFormat = GET_UShort();
3205 FORGET_Frame();
3207 switch ( ccs->SubstFormat )
3209 case 1:
3210 return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, input );
3212 case 2:
3213 return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, input );
3215 case 3:
3216 return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, input );
3218 default:
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 )
3230 case 1:
3231 Free_ChainContext1( &ccs->ccsf.ccsf1 );
3232 break;
3234 case 2:
3235 Free_ChainContext2( &ccs->ccsf.ccsf2 );
3236 break;
3238 case 3:
3239 Free_ChainContext3( &ccs->ccsf.ccsf3 );
3240 break;
3245 static TT_Error Lookup_ChainContextSubst1(
3246 TTO_GSUBHeader* gsub,
3247 TTO_ChainContextSubstFormat1* ccsf1,
3248 TTO_GSUB_String* in,
3249 TTO_GSUB_String* out,
3250 UShort flags,
3251 UShort context_length,
3252 int nesting_level )
3254 UShort index, property;
3255 UShort i, j, k, num_csr, curr_pos;
3256 UShort bgc, igc, lgc;
3257 TT_Error error;
3258 UShort* s_in;
3260 TTO_ChainSubRule* csr;
3261 TTO_ChainSubRule curr_csr;
3262 TTO_GDEFHeader* gdef;
3265 gdef = gsub->gdef;
3267 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
3268 return error;
3270 error = Coverage_Index( &ccsf1->Coverage, in->string[in->pos], &index );
3271 if ( error )
3272 return error;
3274 csr = ccsf1->ChainSubRuleSet[index].ChainSubRule;
3275 num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
3277 for ( k = 0; k < num_csr; k++ )
3279 curr_csr = 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 )
3285 continue;
3287 /* check whether context is too long; it is a first guess only */
3289 if ( bgc > in->pos || in->pos + igc + lgc > in->length )
3290 continue;
3292 if ( bgc )
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 */
3297 curr_pos = 0;
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 )
3305 return error;
3307 if ( j > curr_pos )
3308 j--;
3309 else
3310 break;
3313 if ( s_in[j] != curr_csr.Backtrack[i - 1] )
3314 break;
3317 if ( i != 0 )
3318 continue;
3321 curr_pos = in->pos;
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 )
3331 return error;
3333 if ( curr_pos + j < in->length )
3334 j++;
3335 else
3336 break;
3339 if ( s_in[j] != curr_csr.Input[i - 1] )
3340 break;
3343 if ( i != igc )
3344 continue;
3346 /* we are starting to check for lookahead glyphs right after the
3347 last context glyph */
3349 curr_pos = j;
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 )
3357 return error;
3359 if ( curr_pos + j < in->length )
3360 j++;
3361 else
3362 break;
3365 if ( s_in[j] != curr_csr.Lookahead[i] )
3366 break;
3369 if ( i == lgc )
3370 return Do_ContextSubst( gsub, igc,
3371 curr_csr.SubstCount,
3372 curr_csr.SubstLookupRecord,
3373 in, out,
3374 nesting_level );
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,
3386 UShort flags,
3387 UShort context_length,
3388 int nesting_level )
3390 UShort index, property;
3391 TT_Error error;
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;
3402 UShort* s_in;
3404 UShort* bc;
3405 UShort* ic;
3406 UShort* lc;
3408 TTO_ChainSubClassSet* cscs;
3409 TTO_ChainSubClassRule ccsr;
3410 TTO_GDEFHeader* gdef;
3413 gdef = gsub->gdef;
3415 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
3416 return error;
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 );
3423 if ( error )
3424 return error;
3426 if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, UShort ) )
3427 return error;
3428 known_backtrack_classes = 0;
3430 if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, UShort ) )
3431 goto End3;
3432 known_input_classes = 1;
3434 if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, UShort ) )
3435 goto End2;
3436 known_lookahead_classes = 0;
3438 error = Get_Class( &ccsf2->InputClassDef, in->string[in->pos],
3439 &input_classes[0], NULL );
3440 if ( error )
3441 goto End1;
3443 cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
3444 if ( !cscs )
3446 error = TTO_Err_Invalid_GSUB_SubTable;
3447 goto End1;
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 )
3458 continue;
3460 /* check whether context is too long; it is a first guess only */
3462 if ( bgc > in->pos || in->pos + igc + lgc > in->length )
3463 continue;
3465 if ( bgc )
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. */
3471 curr_pos = 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 )
3480 return error;
3482 if ( j > curr_pos )
3483 j--;
3484 else
3485 break;
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 )
3495 goto End1;
3496 known_backtrack_classes = i;
3499 if ( bc[bgc - 1 - i] != backtrack_classes[i] )
3500 break;
3503 if ( i != bgc )
3504 continue;
3507 curr_pos = in->pos;
3508 s_in = &in->string[curr_pos];
3509 ic = ccsr.Input;
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 )
3518 goto End1;
3520 if ( curr_pos + j < in->length )
3521 j++;
3522 else
3523 break;
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 )
3531 goto End1;
3532 known_input_classes = i;
3535 if ( ic[i - 1] != input_classes[i] )
3536 break;
3539 if ( i != igc )
3540 continue;
3542 /* we are starting to check for lookahead glyphs right after the
3543 last context glyph */
3545 curr_pos = j;
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 )
3554 return error;
3556 if ( curr_pos + j < in->length )
3557 j++;
3558 else
3559 break;
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 )
3567 goto End1;
3568 known_lookahead_classes = i;
3571 if ( lc[i] != lookahead_classes[i] )
3572 break;
3575 if ( i == lgc )
3577 error = Do_ContextSubst( gsub, igc,
3578 ccsr.SubstCount,
3579 ccsr.SubstLookupRecord,
3580 in, out,
3581 nesting_level );
3582 goto End1;
3586 error = TTO_Err_Not_Covered;
3588 End1:
3589 FREE( lookahead_classes );
3591 End2:
3592 FREE( input_classes );
3594 End3:
3595 FREE( backtrack_classes );
3596 return error;
3600 static TT_Error Lookup_ChainContextSubst3(
3601 TTO_GSUBHeader* gsub,
3602 TTO_ChainContextSubstFormat3* ccsf3,
3603 TTO_GSUB_String* in,
3604 TTO_GSUB_String* out,
3605 UShort flags,
3606 UShort context_length,
3607 int nesting_level )
3609 UShort index, i, j, curr_pos, property;
3610 UShort bgc, igc, lgc;
3611 TT_Error error;
3612 UShort* s_in;
3614 TTO_Coverage* bc;
3615 TTO_Coverage* ic;
3616 TTO_Coverage* lc;
3617 TTO_GDEFHeader* gdef;
3620 gdef = gsub->gdef;
3622 if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
3623 return error;
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;
3637 if ( bgc )
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 */
3642 curr_pos = 0;
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 )
3651 return error;
3653 if ( j > curr_pos )
3654 j--;
3655 else
3656 return TTO_Err_Not_Covered;
3659 error = Coverage_Index( &bc[i - 1], s_in[j], &index );
3660 if ( error )
3661 return error;
3665 curr_pos = in->pos;
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 )
3676 return error;
3678 if ( curr_pos + j < in->length )
3679 j++;
3680 else
3681 return TTO_Err_Not_Covered;
3684 error = Coverage_Index( &ic[i], s_in[j], &index );
3685 if ( error )
3686 return error;
3689 /* we are starting for lookahead glyphs right after the last context
3690 glyph */
3692 curr_pos = j;
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 )
3701 return error;
3703 if ( curr_pos + j < in->length )
3704 j++;
3705 else
3706 return TTO_Err_Not_Covered;
3709 error = Coverage_Index( &lc[i], s_in[j], &index );
3710 if ( error )
3711 return error;
3714 return Do_ContextSubst( gsub, igc,
3715 ccsf3->SubstCount,
3716 ccsf3->SubstLookupRecord,
3717 in, out,
3718 nesting_level );
3722 static TT_Error Lookup_ChainContextSubst(
3723 TTO_GSUBHeader* gsub,
3724 TTO_ChainContextSubst* ccs,
3725 TTO_GSUB_String* in,
3726 TTO_GSUB_String* out,
3727 UShort flags,
3728 UShort context_length,
3729 int nesting_level )
3731 switch ( ccs->SubstFormat )
3733 case 1:
3734 return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, in, out,
3735 flags, context_length,
3736 nesting_level );
3738 case 2:
3739 return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, in, out,
3740 flags, context_length,
3741 nesting_level );
3743 case 3:
3744 return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, in, out,
3745 flags, context_length,
3746 nesting_level );
3748 default:
3749 return TTO_Err_Invalid_GSUB_SubTable_Format;
3752 return TT_Err_Ok; /* never reached */
3757 /***********
3758 * GSUB API
3759 ***********/
3762 EXPORT_FUNC
3763 TT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub,
3764 TT_ULong script_tag,
3765 TT_UShort* script_index )
3767 UShort n;
3769 TTO_ScriptList* sl;
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 )
3782 *script_index = n;
3784 return TT_Err_Ok;
3787 return TTO_Err_Not_Covered;
3791 EXPORT_FUNC
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 )
3798 UShort n;
3800 TTO_ScriptList* sl;
3801 TTO_ScriptRecord* sr;
3802 TTO_Script* s;
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;
3824 return TT_Err_Ok;
3827 return TTO_Err_Not_Covered;
3831 /* selecting 0xFFFF for language_index asks for the values of the
3832 default language (DefaultLangSys) */
3834 EXPORT_FUNC
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 )
3841 UShort n;
3843 TTO_ScriptList* sl;
3844 TTO_ScriptRecord* sr;
3845 TTO_Script* s;
3846 TTO_LangSysRecord* lsr;
3847 TTO_LangSys* ls;
3848 UShort* fi;
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;
3871 else
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];
3890 return TT_Err_Ok;
3894 return TTO_Err_Not_Covered;
3898 /* The next three functions return a null-terminated list */
3900 EXPORT_FUNC
3901 TT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub,
3902 TT_ULong** script_tag_list )
3904 UShort n;
3905 TT_Error error;
3906 ULong* stl;
3908 TTO_ScriptList* sl;
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 ) )
3919 return error;
3921 for ( n = 0; n < sl->ScriptCount; n++ )
3922 stl[n] = sr[n].ScriptTag;
3923 stl[n] = 0;
3925 *script_tag_list = stl;
3927 return TT_Err_Ok;
3931 EXPORT_FUNC
3932 TT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub,
3933 TT_UShort script_index,
3934 TT_ULong** language_tag_list )
3936 UShort n;
3937 TT_Error error;
3938 ULong* ltl;
3940 TTO_ScriptList* sl;
3941 TTO_ScriptRecord* sr;
3942 TTO_Script* s;
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 ) )
3959 return error;
3961 for ( n = 0; n < s->LangSysCount; n++ )
3962 ltl[n] = lsr[n].LangSysTag;
3963 ltl[n] = 0;
3965 *language_tag_list = ltl;
3967 return TT_Err_Ok;
3971 /* selecting 0xFFFF for language_index asks for the values of the
3972 default language (DefaultLangSys) */
3974 EXPORT_FUNC
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 )
3980 UShort n;
3981 TT_Error error;
3982 ULong* ftl;
3984 TTO_ScriptList* sl;
3985 TTO_ScriptRecord* sr;
3986 TTO_Script* s;
3987 TTO_LangSysRecord* lsr;
3988 TTO_LangSys* ls;
3989 UShort* fi;
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;
4012 else
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 ) )
4023 return error;
4025 for ( n = 0; n < ls->FeatureCount; n++ )
4027 if ( fi[n] >= fl->FeatureCount )
4029 FREE( ftl );
4030 return TTO_Err_Invalid_GSUB_SubTable_Format;
4032 ftl[n] = fr[fi[n]].FeatureTag;
4034 ftl[n] = 0;
4036 *feature_tag_list = ftl;
4038 return TT_Err_Ok;
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,
4050 int nesting_level )
4052 TT_Error error = TT_Err_Ok;
4053 UShort i, flags;
4054 TTO_Lookup* lo;
4057 nesting_level++;
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,
4071 in, out,
4072 flags, context_length, gsub->gdef );
4073 break;
4075 case GSUB_LOOKUP_MULTIPLE:
4076 error = Lookup_MultipleSubst( &lo->SubTable[i].st.gsub.multiple,
4077 in, out,
4078 flags, context_length, gsub->gdef );
4079 break;
4081 case GSUB_LOOKUP_ALTERNATE:
4082 error = Lookup_AlternateSubst( gsub,
4083 &lo->SubTable[i].st.gsub.alternate,
4084 in, out,
4085 flags, context_length, gsub->gdef );
4086 break;
4088 case GSUB_LOOKUP_LIGATURE:
4089 error = Lookup_LigatureSubst( &lo->SubTable[i].st.gsub.ligature,
4090 in, out,
4091 flags, context_length, gsub->gdef );
4092 break;
4094 case GSUB_LOOKUP_CONTEXT:
4095 error = Lookup_ContextSubst( gsub, &lo->SubTable[i].st.gsub.context,
4096 in, out,
4097 flags, context_length, nesting_level );
4098 break;
4100 case GSUB_LOOKUP_CHAIN:
4101 error = Lookup_ChainContextSubst( gsub,
4102 &lo->SubTable[i].st.gsub.chain,
4103 in, out,
4104 flags, context_length,
4105 nesting_level );
4106 break;
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 )
4113 return error;
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 )
4144 return error;
4146 else
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] ) )
4151 return error;
4154 return error;
4158 EXPORT_FUNC
4159 TT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
4160 TT_UShort feature_index,
4161 TT_UShort property )
4163 UShort i;
4165 TTO_Feature feature;
4166 UShort* properties;
4167 UShort* index;
4170 if ( !gsub ||
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;
4182 return TT_Err_Ok;
4186 EXPORT_FUNC
4187 TT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub )
4189 UShort i;
4191 UShort* properties;
4194 if ( !gsub )
4195 return TT_Err_Invalid_Argument;
4197 properties = gsub->LookupList.Properties;
4199 for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
4200 properties[i] = 0;
4202 return TT_Err_Ok;
4206 EXPORT_FUNC
4207 TT_Error TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader* gsub,
4208 TTO_AltFunction alt,
4209 void* data )
4211 if ( !gsub )
4212 return TT_Err_Invalid_Argument;
4214 gsub->alt = alt;
4215 gsub->data = data;
4217 return TT_Err_Ok;
4221 EXPORT_FUNC
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;
4227 UShort j;
4229 TTO_GSUB_String tmp1;
4230 TTO_GSUB_String* ptmp1;
4231 TTO_GSUB_String tmp2;
4232 TTO_GSUB_String* ptmp2;
4233 TTO_GSUB_String* t;
4235 UShort* properties;
4238 if ( !gsub ||
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;
4246 tmp1.pos = in->pos;
4248 if ( ALLOC_ARRAY( tmp1.string, tmp1.length, UShort ) )
4249 return error;
4250 MEM_Copy( tmp1.string, in->string, in->length * sizeof ( UShort ) );
4252 /* make sure that we always have a `properties' array in the string
4253 object */
4255 if ( ALLOC_ARRAY( tmp1.properties, tmp1.length, UShort ) )
4256 return error;
4257 if ( in->properties )
4258 MEM_Copy( tmp1.properties, in->properties,
4259 in->length * sizeof( UShort ) );
4261 tmp2.allocated = 0;
4262 tmp2.pos = 0;
4263 tmp2.string = NULL;
4264 tmp2.properties = NULL;
4266 ptmp1 = &tmp1;
4267 ptmp2 = &tmp2;
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 )
4274 return error;
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;
4282 t = ptmp2;
4283 ptmp2 = ptmp1;
4284 ptmp1 = t;
4287 out->length = ptmp1->length;
4288 out->pos = 0;
4289 out->allocated = ptmp1->allocated;
4290 out->string = ptmp1->string;
4292 if ( in->properties )
4293 out->properties = ptmp1->properties;
4294 else
4296 free( ptmp1->properties );
4297 out->properties = NULL;
4300 free( ptmp2->string );
4301 free( ptmp2->properties );
4303 return error;
4307 /* END */