contrib/OWB: add correct SDL dependency, fix compilers used
[AROS-Contrib.git] / freetype1 / lib / extend / ftxgpos.c
blob76a52b7e4728ce032ecfc99bdef165be177df04d
1 /*******************************************************************
3 * ftxgpos.c
5 * TrueType Open GPOS 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 7 and 8), 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 GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' )
39 /**********************
40 * Extension Functions
41 **********************/
44 static TT_Error GPOS_Create( void* ext,
45 PFace face )
47 DEFINE_LOAD_LOCALS( face->stream );
49 TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
50 Long table;
53 /* by convention */
55 if ( !gpos )
56 return TT_Err_Ok;
58 /* a null offset indicates that there is no GPOS table */
60 gpos->offset = 0;
62 /* we store the start offset and the size of the subtable */
64 table = TT_LookUp_Table( face, TTAG_GPOS );
65 if ( table < 0 )
66 return TT_Err_Ok; /* The table is optional */
68 if ( FILE_Seek( face->dirTables[table].Offset ) ||
69 ACCESS_Frame( 4L ) )
70 return error;
72 gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
73 gpos->Version = GET_ULong();
75 FORGET_Frame();
77 gpos->loaded = FALSE;
79 return TT_Err_Ok;
83 static TT_Error GPOS_Destroy( void* ext,
84 PFace face )
86 TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
89 /* by convention */
91 if ( !gpos )
92 return TT_Err_Ok;
94 if ( gpos->loaded )
96 Free_LookupList( &gpos->LookupList, GPOS );
97 Free_FeatureList( &gpos->FeatureList );
98 Free_ScriptList( &gpos->ScriptList );
101 return TT_Err_Ok;
105 EXPORT_FUNC
106 TT_Error TT_Init_GPOS_Extension( TT_Engine engine )
108 PEngine_Instance _engine = HANDLE_Engine( engine );
111 if ( !_engine )
112 return TT_Err_Invalid_Engine;
114 return TT_Register_Extension( _engine,
115 GPOS_ID,
116 sizeof ( TTO_GPOSHeader ),
117 GPOS_Create,
118 GPOS_Destroy );
122 EXPORT_FUNC
123 TT_Error TT_Load_GPOS_Table( TT_Face face,
124 TTO_GPOSHeader* retptr,
125 TTO_GDEFHeader* gdef )
127 ULong cur_offset, new_offset, base_offset;
129 TT_UShort i, num_lookups;
130 TT_Error error;
131 TT_Stream stream;
132 TTO_GPOSHeader* gpos;
133 TTO_Lookup* lo;
135 PFace faze = HANDLE_Face( face );
138 if ( !retptr )
139 return TT_Err_Invalid_Argument;
141 if ( !faze )
142 return TT_Err_Invalid_Face_Handle;
144 error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos );
145 if ( error )
146 return error;
148 if ( gpos->offset == 0 )
149 return TT_Err_Table_Missing; /* no GPOS table; nothing to do */
151 /* now access stream */
153 if ( USE_Stream( faze->stream, stream ) )
154 return error;
156 base_offset = gpos->offset;
158 /* skip version */
160 if ( FILE_Seek( base_offset + 4L ) ||
161 ACCESS_Frame( 2L ) )
162 return error;
164 new_offset = GET_UShort() + base_offset;
166 FORGET_Frame();
168 cur_offset = FILE_Pos();
169 if ( FILE_Seek( new_offset ) ||
170 ( error = Load_ScriptList( &gpos->ScriptList,
171 faze ) ) != TT_Err_Ok )
172 return error;
173 (void)FILE_Seek( cur_offset );
175 if ( ACCESS_Frame( 2L ) )
176 goto Fail3;
178 new_offset = GET_UShort() + base_offset;
180 FORGET_Frame();
182 cur_offset = FILE_Pos();
183 if ( FILE_Seek( new_offset ) ||
184 ( error = Load_FeatureList( &gpos->FeatureList,
185 faze ) ) != TT_Err_Ok )
186 goto Fail3;
187 (void)FILE_Seek( cur_offset );
189 if ( ACCESS_Frame( 2L ) )
190 goto Fail2;
192 new_offset = GET_UShort() + base_offset;
194 FORGET_Frame();
196 cur_offset = FILE_Pos();
197 if ( FILE_Seek( new_offset ) ||
198 ( error = Load_LookupList( &gpos->LookupList,
199 faze, GPOS ) ) != TT_Err_Ok )
200 goto Fail2;
202 gpos->gdef = gdef; /* can be NULL */
204 /* We now check the LookupFlags for values larger than 0xFF to find
205 out whether we need to load the `MarkAttachClassDef' field of the
206 GDEF table -- this hack is necessary for OpenType 1.2 tables since
207 the version field of the GDEF table hasn't been incremented.
209 For constructed GDEF tables, we only load it if
210 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
211 a constructed mark attach table is not supported currently). */
213 if ( gdef &&
214 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
216 lo = gpos->LookupList.Lookup;
217 num_lookups = gpos->LookupList.LookupCount;
219 for ( i = 0; i < num_lookups; i++ )
221 if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
223 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
224 ACCESS_Frame( 2L ) )
225 goto Fail1;
227 new_offset = GET_UShort();
229 FORGET_Frame();
231 if ( !new_offset )
232 return TTO_Err_Invalid_GDEF_SubTable;
234 new_offset += base_offset;
236 if ( FILE_Seek( new_offset ) ||
237 ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
238 256, faze ) ) != TT_Err_Ok )
239 goto Fail1;
241 break;
246 gpos->loaded = TRUE;
247 *retptr = *gpos;
248 DONE_Stream( stream );
250 return TT_Err_Ok;
252 Fail1:
253 Free_LookupList( &gpos->LookupList, GPOS );
255 Fail2:
256 Free_FeatureList( &gpos->FeatureList );
258 Fail3:
259 Free_ScriptList( &gpos->ScriptList );
261 /* release stream */
263 DONE_Stream( stream );
265 return error;
270 /*****************************
271 * SubTable related functions
272 *****************************/
274 /* shared tables */
276 /* ValueRecord */
278 static TT_Error Load_ValueRecord( TTO_ValueRecord* vr,
279 TT_UShort format,
280 PFace input )
282 DEFINE_LOAD_LOCALS( input->stream );
284 ULong cur_offset, new_offset, base_offset;
287 base_offset = FILE_Pos();
289 if ( format & HAVE_X_PLACEMENT )
291 if ( ACCESS_Frame( 2L ) )
292 return error;
294 vr->XPlacement = GET_Short();
296 FORGET_Frame();
298 else
299 vr->XPlacement = 0;
301 if ( format & HAVE_Y_PLACEMENT )
303 if ( ACCESS_Frame( 2L ) )
304 return error;
306 vr->YPlacement = GET_Short();
308 FORGET_Frame();
310 else
311 vr->YPlacement = 0;
313 if ( format & HAVE_X_ADVANCE )
315 if ( ACCESS_Frame( 2L ) )
316 return error;
318 vr->XAdvance = GET_Short();
320 FORGET_Frame();
322 else
323 vr->XAdvance = 0;
325 if ( format & HAVE_Y_ADVANCE )
327 if ( ACCESS_Frame( 2L ) )
328 return error;
330 vr->YAdvance = GET_Short();
332 FORGET_Frame();
334 else
335 vr->YAdvance = 0;
337 if ( format & HAVE_X_PLACEMENT_DEVICE )
339 if ( ACCESS_Frame( 2L ) )
340 return error;
342 new_offset = GET_UShort() + base_offset;
344 FORGET_Frame();
346 cur_offset = FILE_Pos();
347 if ( FILE_Seek( new_offset ) ||
348 ( error = Load_Device( &vr->XPlacementDevice,
349 input ) ) != TT_Err_Ok )
350 return error;
351 (void)FILE_Seek( cur_offset );
353 else
355 vr->XPlacementDevice.StartSize = 0;
356 vr->XPlacementDevice.EndSize = 0;
357 vr->XPlacementDevice.DeltaValue = NULL;
360 if ( format & HAVE_Y_PLACEMENT_DEVICE )
362 if ( ACCESS_Frame( 2L ) )
363 goto Fail3;
365 new_offset = GET_UShort() + base_offset;
367 FORGET_Frame();
369 cur_offset = FILE_Pos();
370 if ( FILE_Seek( new_offset ) ||
371 ( error = Load_Device( &vr->YPlacementDevice,
372 input ) ) != TT_Err_Ok )
373 goto Fail3;
374 (void)FILE_Seek( cur_offset );
376 else
378 vr->YPlacementDevice.StartSize = 0;
379 vr->YPlacementDevice.EndSize = 0;
380 vr->YPlacementDevice.DeltaValue = NULL;
383 if ( format & HAVE_X_ADVANCE_DEVICE )
385 if ( ACCESS_Frame( 2L ) )
386 goto Fail2;
388 new_offset = GET_UShort() + base_offset;
390 FORGET_Frame();
392 cur_offset = FILE_Pos();
393 if ( FILE_Seek( new_offset ) ||
394 ( error = Load_Device( &vr->XAdvanceDevice,
395 input ) ) != TT_Err_Ok )
396 goto Fail2;
397 (void)FILE_Seek( cur_offset );
399 else
401 vr->XAdvanceDevice.StartSize = 0;
402 vr->XAdvanceDevice.EndSize = 0;
403 vr->XAdvanceDevice.DeltaValue = NULL;
406 if ( format & HAVE_Y_ADVANCE_DEVICE )
408 if ( ACCESS_Frame( 2L ) )
409 goto Fail1;
411 new_offset = GET_UShort() + base_offset;
413 FORGET_Frame();
415 cur_offset = FILE_Pos();
416 if ( FILE_Seek( new_offset ) ||
417 ( error = Load_Device( &vr->YAdvanceDevice,
418 input ) ) != TT_Err_Ok )
419 goto Fail1;
420 (void)FILE_Seek( cur_offset );
422 else
424 vr->YAdvanceDevice.StartSize = 0;
425 vr->YAdvanceDevice.EndSize = 0;
426 vr->YAdvanceDevice.DeltaValue = NULL;
429 if ( format & HAVE_X_ID_PLACEMENT )
431 if ( ACCESS_Frame( 2L ) )
432 goto Fail1;
434 vr->XIdPlacement = GET_UShort();
436 FORGET_Frame();
438 else
439 vr->XIdPlacement = 0;
441 if ( format & HAVE_Y_ID_PLACEMENT )
443 if ( ACCESS_Frame( 2L ) )
444 goto Fail1;
446 vr->YIdPlacement = GET_UShort();
448 FORGET_Frame();
450 else
451 vr->YIdPlacement = 0;
453 if ( format & HAVE_X_ID_ADVANCE )
455 if ( ACCESS_Frame( 2L ) )
456 goto Fail1;
458 vr->XIdAdvance = GET_UShort();
460 FORGET_Frame();
462 else
463 vr->XIdAdvance = 0;
465 if ( format & HAVE_Y_ID_ADVANCE )
467 if ( ACCESS_Frame( 2L ) )
468 goto Fail1;
470 vr->YIdAdvance = GET_UShort();
472 FORGET_Frame();
474 else
475 vr->YIdAdvance = 0;
477 return TT_Err_Ok;
479 Fail1:
480 Free_Device( &vr->YAdvanceDevice );
482 Fail2:
483 Free_Device( &vr->XAdvanceDevice );
485 Fail3:
486 Free_Device( &vr->YPlacementDevice );
487 return error;
491 static void Free_ValueRecord( TTO_ValueRecord* vr,
492 UShort format )
494 if ( format & HAVE_Y_ADVANCE_DEVICE )
495 Free_Device( &vr->YAdvanceDevice );
496 if ( format & HAVE_X_ADVANCE_DEVICE )
497 Free_Device( &vr->XAdvanceDevice );
498 if ( format & HAVE_Y_PLACEMENT_DEVICE )
499 Free_Device( &vr->YPlacementDevice );
500 if ( format & HAVE_X_PLACEMENT_DEVICE )
501 Free_Device( &vr->XPlacementDevice );
505 /* AnchorFormat1 */
506 /* AnchorFormat2 */
507 /* AnchorFormat3 */
508 /* AnchorFormat4 */
510 static TT_Error Load_Anchor( TTO_Anchor* an,
511 PFace input )
513 DEFINE_LOAD_LOCALS( input->stream );
515 ULong cur_offset, new_offset, base_offset;
518 base_offset = FILE_Pos();
520 if ( ACCESS_Frame( 2L ) )
521 return error;
523 an->PosFormat = GET_UShort();
525 FORGET_Frame();
527 switch ( an->PosFormat )
529 case 1:
530 if ( ACCESS_Frame( 4L ) )
531 return error;
533 an->af.af1.XCoordinate = GET_Short();
534 an->af.af1.YCoordinate = GET_Short();
536 FORGET_Frame();
537 break;
539 case 2:
540 if ( ACCESS_Frame( 6L ) )
541 return error;
543 an->af.af2.XCoordinate = GET_Short();
544 an->af.af2.YCoordinate = GET_Short();
545 an->af.af2.AnchorPoint = GET_UShort();
547 FORGET_Frame();
548 break;
550 case 3:
551 if ( ACCESS_Frame( 6L ) )
552 return error;
554 an->af.af3.XCoordinate = GET_Short();
555 an->af.af3.YCoordinate = GET_Short();
557 new_offset = GET_UShort();
559 FORGET_Frame();
561 if ( new_offset )
563 new_offset += base_offset;
565 cur_offset = FILE_Pos();
566 if ( FILE_Seek( new_offset ) ||
567 ( error = Load_Device( &an->af.af3.XDeviceTable,
568 input ) ) != TT_Err_Ok )
569 return error;
570 (void)FILE_Seek( cur_offset );
572 else
574 an->af.af3.XDeviceTable.StartSize = 0;
575 an->af.af3.XDeviceTable.EndSize = 0;
576 an->af.af3.XDeviceTable.DeltaValue = 0;
579 if ( ACCESS_Frame( 2L ) )
580 goto Fail;
582 new_offset = GET_UShort();
584 FORGET_Frame();
586 if ( new_offset )
588 new_offset += base_offset;
590 cur_offset = FILE_Pos();
591 if ( FILE_Seek( new_offset ) ||
592 ( error = Load_Device( &an->af.af3.YDeviceTable,
593 input ) ) != TT_Err_Ok )
594 goto Fail;
595 (void)FILE_Seek( cur_offset );
597 else
599 an->af.af3.YDeviceTable.StartSize = 0;
600 an->af.af3.YDeviceTable.EndSize = 0;
601 an->af.af3.YDeviceTable.DeltaValue = 0;
603 break;
605 case 4:
606 if ( ACCESS_Frame( 4L ) )
607 return error;
609 an->af.af4.XIdAnchor = GET_UShort();
610 an->af.af4.YIdAnchor = GET_UShort();
612 FORGET_Frame();
613 break;
615 default:
616 return TTO_Err_Invalid_GPOS_SubTable_Format;
619 return TT_Err_Ok;
621 Fail:
622 Free_Device( &an->af.af3.XDeviceTable );
623 return error;
627 static void Free_Anchor( TTO_Anchor* an )
629 if ( an->PosFormat == 3 )
631 Free_Device( &an->af.af3.YDeviceTable );
632 Free_Device( &an->af.af3.XDeviceTable );
637 /* MarkArray */
639 static TT_Error Load_MarkArray ( TTO_MarkArray* ma,
640 PFace input )
642 DEFINE_LOAD_LOCALS( input->stream );
644 UShort n, count;
645 ULong cur_offset, new_offset, base_offset;
647 TTO_MarkRecord* mr;
650 base_offset = FILE_Pos();
652 if ( ACCESS_Frame( 2L ) )
653 return error;
655 count = ma->MarkCount = GET_UShort();
657 FORGET_Frame();
659 ma->MarkRecord = NULL;
661 if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) )
662 return error;
664 mr = ma->MarkRecord;
666 for ( n = 0; n < count; n++ )
668 if ( ACCESS_Frame( 4L ) )
669 goto Fail;
671 mr[n].Class = GET_UShort();
672 new_offset = GET_UShort() + base_offset;
674 FORGET_Frame();
676 cur_offset = FILE_Pos();
677 if ( FILE_Seek( new_offset ) ||
678 ( error = Load_Anchor( &mr[n].MarkAnchor, input ) ) != TT_Err_Ok )
679 goto Fail;
680 (void)FILE_Seek( cur_offset );
683 return TT_Err_Ok;
685 Fail:
686 for ( n = 0; n < count; n++ )
687 Free_Anchor( &mr[n].MarkAnchor );
689 FREE( mr );
690 return error;
694 static void Free_MarkArray( TTO_MarkArray* ma )
696 UShort n, count;
698 TTO_MarkRecord* mr;
701 if ( ma->MarkRecord )
703 count = ma->MarkCount;
704 mr = ma->MarkRecord;
706 for ( n = 0; n < count; n++ )
707 Free_Anchor( &mr[n].MarkAnchor );
709 FREE( mr );
714 /* LookupType 1 */
716 /* SinglePosFormat1 */
717 /* SinglePosFormat2 */
719 TT_Error Load_SinglePos( TTO_SinglePos* sp,
720 PFace input )
722 DEFINE_LOAD_LOCALS( input->stream );
724 UShort n, count, format;
725 ULong cur_offset, new_offset, base_offset;
727 TTO_ValueRecord* v;
730 base_offset = FILE_Pos();
732 if ( ACCESS_Frame( 6L ) )
733 return error;
735 sp->PosFormat = GET_UShort();
736 new_offset = GET_UShort() + base_offset;
738 format = sp->ValueFormat = GET_UShort();
740 FORGET_Frame();
742 if ( !format )
743 return TTO_Err_Invalid_GPOS_SubTable;
745 cur_offset = FILE_Pos();
746 if ( FILE_Seek( new_offset ) ||
747 ( error = Load_Coverage( &sp->Coverage, input ) ) != TT_Err_Ok )
748 return error;
749 (void)FILE_Seek( cur_offset );
751 switch ( sp->PosFormat )
753 case 1:
754 error = Load_ValueRecord( &sp->spf.spf1.Value, format, input );
755 if ( error )
756 goto Fail2;
757 break;
759 case 2:
760 if ( ACCESS_Frame( 2L ) )
761 goto Fail2;
763 count = sp->spf.spf2.ValueCount = GET_UShort();
765 FORGET_Frame();
767 sp->spf.spf2.Value = NULL;
769 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) )
770 goto Fail2;
772 v = sp->spf.spf2.Value;
774 for ( n = 0; n < count; n++ )
776 error = Load_ValueRecord( &v[n], format, input );
777 if ( error )
778 goto Fail1;
780 break;
782 default:
783 return TTO_Err_Invalid_GPOS_SubTable_Format;
786 return TT_Err_Ok;
788 Fail1:
789 for ( n = 0; n < count; n++ )
790 Free_ValueRecord( &v[n], format );
792 FREE( v );
794 Fail2:
795 Free_Coverage( &sp->Coverage );
796 return error;
800 void Free_SinglePos( TTO_SinglePos* sp )
802 UShort n, count, format;
804 TTO_ValueRecord* v;
807 format = sp->ValueFormat;
809 switch ( sp->PosFormat )
811 case 1:
812 Free_ValueRecord( &sp->spf.spf1.Value, format );
813 break;
815 case 2:
816 if ( sp->spf.spf2.Value )
818 count = sp->spf.spf2.ValueCount;
819 v = sp->spf.spf2.Value;
821 for ( n = 0; n < count; n++ )
822 Free_ValueRecord( &v[n], format );
824 FREE( v );
826 break;
829 Free_Coverage( &sp->Coverage );
833 /* LookupType 2 */
835 /* PairSet */
837 static TT_Error Load_PairSet ( TTO_PairSet* ps,
838 UShort format1,
839 UShort format2,
840 PFace input )
842 DEFINE_LOAD_LOCALS( input->stream );
844 UShort n, count;
846 TTO_PairValueRecord* pvr;
849 if ( ACCESS_Frame( 2L ) )
850 return error;
852 count = ps->PairValueCount = GET_UShort();
854 FORGET_Frame();
856 ps->PairValueRecord = NULL;
858 if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) )
859 return error;
861 pvr = ps->PairValueRecord;
863 for ( n = 0; n < count; n++ )
865 if ( ACCESS_Frame( 2L ) )
866 goto Fail;
868 pvr[n].SecondGlyph = GET_UShort();
870 FORGET_Frame();
872 if ( format1 )
874 error = Load_ValueRecord( &pvr[n].Value1, format1, input );
875 if ( error )
876 goto Fail;
878 if ( format2 )
880 error = Load_ValueRecord( &pvr[n].Value2, format2, input );
881 if ( error )
882 goto Fail;
886 return TT_Err_Ok;
888 Fail:
889 for ( n = 0; n < count; n++ )
891 if ( format1 )
892 Free_ValueRecord( &pvr[n].Value1, format1 );
893 if ( format2 )
894 Free_ValueRecord( &pvr[n].Value2, format2 );
897 FREE( pvr );
898 return error;
902 static void Free_PairSet( TTO_PairSet* ps,
903 UShort format1,
904 UShort format2 )
906 UShort n, count;
908 TTO_PairValueRecord* pvr;
911 if ( ps->PairValueRecord )
913 count = ps->PairValueCount;
914 pvr = ps->PairValueRecord;
916 for ( n = 0; n < count; n++ )
918 if ( format1 )
919 Free_ValueRecord( &pvr[n].Value1, format1 );
920 if ( format2 )
921 Free_ValueRecord( &pvr[n].Value2, format2 );
924 FREE( pvr );
929 /* PairPosFormat1 */
931 static TT_Error Load_PairPosFormat1( TTO_PairPosFormat1* ppf1,
932 UShort format1,
933 UShort format2,
934 PFace input )
936 DEFINE_LOAD_LOCALS( input->stream );
938 UShort n, count;
939 ULong cur_offset, new_offset, base_offset;
941 TTO_PairSet* ps;
944 base_offset = FILE_Pos() - 8L;
946 if ( ACCESS_Frame( 2L ) )
947 return error;
949 count = ppf1->PairSetCount = GET_UShort();
951 FORGET_Frame();
953 ppf1->PairSet = NULL;
955 if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) )
956 goto Fail;
958 ps = ppf1->PairSet;
960 for ( n = 0; n < count; n++ )
962 if ( ACCESS_Frame( 2L ) )
963 goto Fail;
965 new_offset = GET_UShort() + base_offset;
967 FORGET_Frame();
969 cur_offset = FILE_Pos();
970 if ( FILE_Seek( new_offset ) ||
971 ( error = Load_PairSet( &ps[n], format1,
972 format2, input ) ) != TT_Err_Ok )
973 goto Fail;
974 (void)FILE_Seek( cur_offset );
977 return TT_Err_Ok;
979 Fail:
980 for ( n = 0; n < count; n++ )
981 Free_PairSet( &ps[n], format1, format2 );
983 FREE( ps );
984 return error;
988 static void Free_PairPosFormat1( TTO_PairPosFormat1* ppf1,
989 UShort format1,
990 UShort format2 )
992 UShort n, count;
994 TTO_PairSet* ps;
997 if ( ppf1->PairSet )
999 count = ppf1->PairSetCount;
1000 ps = ppf1->PairSet;
1002 for ( n = 0; n < count; n++ )
1003 Free_PairSet( &ps[n], format1, format2 );
1005 FREE( ps );
1010 /* PairPosFormat2 */
1012 static TT_Error Load_PairPosFormat2( TTO_PairPosFormat2* ppf2,
1013 UShort format1,
1014 UShort format2,
1015 PFace input )
1017 DEFINE_LOAD_LOCALS( input->stream );
1019 UShort m, n, count1, count2;
1020 ULong cur_offset, new_offset1, new_offset2, base_offset;
1022 TTO_Class1Record* c1r;
1023 TTO_Class2Record* c2r;
1026 base_offset = FILE_Pos() - 8L;
1028 if ( ACCESS_Frame( 8L ) )
1029 return error;
1031 new_offset1 = GET_UShort() + base_offset;
1032 new_offset2 = GET_UShort() + base_offset;
1034 /* `Class1Count' and `Class2Count' are the upper limits for class
1035 values, thus we read it now to make additional safety checks. */
1037 count1 = ppf2->Class1Count = GET_UShort();
1038 count2 = ppf2->Class2Count = GET_UShort();
1040 FORGET_Frame();
1042 cur_offset = FILE_Pos();
1043 if ( FILE_Seek( new_offset1 ) ||
1044 ( error = Load_ClassDefinition( &ppf2->ClassDef1, count1,
1045 input ) ) != TT_Err_Ok )
1046 return error;
1047 (void)FILE_Seek( cur_offset );
1049 cur_offset = FILE_Pos();
1050 if ( FILE_Seek( new_offset2 ) ||
1051 ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
1052 input ) ) != TT_Err_Ok )
1053 goto Fail2;
1054 (void)FILE_Seek( cur_offset );
1056 ppf2->Class1Record = NULL;
1058 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
1059 goto Fail1;
1061 c1r = ppf2->Class1Record;
1063 for ( m = 0; m < count1; m++ )
1065 c1r[m].Class2Record = NULL;
1067 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) )
1068 goto Fail1;
1070 c2r = c1r[m].Class2Record;
1072 for ( n = 0; n < count2; n++ )
1074 if ( format1 )
1076 Load_ValueRecord( &c2r[n].Value1, format1, input );
1077 if ( error )
1078 goto Fail1;
1080 if ( format2 )
1082 Load_ValueRecord( &c2r[n].Value2, format2, input );
1083 if ( error )
1084 goto Fail1;
1089 return TT_Err_Ok;
1091 Fail1:
1092 for ( m = 0; m < count1; m++ )
1094 c2r = c1r[m].Class2Record;
1096 for ( n = 0; n < count2; n++ )
1098 if ( format1 )
1099 Free_ValueRecord( &c2r[n].Value1, format1 );
1100 if ( format2 )
1101 Free_ValueRecord( &c2r[n].Value2, format2 );
1104 FREE( c2r );
1107 FREE( c1r );
1109 Free_ClassDefinition( &ppf2->ClassDef2 );
1111 Fail2:
1112 Free_ClassDefinition( &ppf2->ClassDef1 );
1113 return error;
1117 static void Free_PairPosFormat2( TTO_PairPosFormat2* ppf2,
1118 UShort format1,
1119 UShort format2 )
1121 UShort m, n, count1, count2;
1123 TTO_Class1Record* c1r;
1124 TTO_Class2Record* c2r;
1127 if ( ppf2->Class1Record )
1129 c1r = ppf2->Class1Record;
1130 count1 = ppf2->Class1Count;
1131 count2 = ppf2->Class2Count;
1133 for ( m = 0; m < count1; m++ )
1135 c2r = c1r[m].Class2Record;
1137 for ( n = 0; n < count2; n++ )
1139 if ( format1 )
1140 Free_ValueRecord( &c2r[n].Value1, format1 );
1141 if ( format2 )
1142 Free_ValueRecord( &c2r[n].Value2, format2 );
1145 FREE( c2r );
1148 FREE( c1r );
1150 Free_ClassDefinition( &ppf2->ClassDef2 );
1151 Free_ClassDefinition( &ppf2->ClassDef1 );
1156 TT_Error Load_PairPos( TTO_PairPos* pp,
1157 PFace input )
1159 DEFINE_LOAD_LOCALS( input->stream );
1161 UShort format1, format2;
1162 ULong cur_offset, new_offset, base_offset;
1165 base_offset = FILE_Pos();
1167 if ( ACCESS_Frame( 8L ) )
1168 return error;
1170 pp->PosFormat = GET_UShort();
1171 new_offset = GET_UShort() + base_offset;
1173 format1 = pp->ValueFormat1 = GET_UShort();
1174 format2 = pp->ValueFormat2 = GET_UShort();
1176 FORGET_Frame();
1178 cur_offset = FILE_Pos();
1179 if ( FILE_Seek( new_offset ) ||
1180 ( error = Load_Coverage( &pp->Coverage, input ) ) != TT_Err_Ok )
1181 return error;
1182 (void)FILE_Seek( cur_offset );
1184 switch ( pp->PosFormat )
1186 case 1:
1187 error = Load_PairPosFormat1( &pp->ppf.ppf1, format1, format2, input );
1188 if ( error )
1189 goto Fail;
1190 break;
1192 case 2:
1193 error = Load_PairPosFormat2( &pp->ppf.ppf2, format1, format2, input );
1194 if ( error )
1195 goto Fail;
1196 break;
1198 default:
1199 return TTO_Err_Invalid_GPOS_SubTable_Format;
1202 return TT_Err_Ok;
1204 Fail:
1205 Free_Coverage( &pp->Coverage );
1206 return error;
1210 void Free_PairPos( TTO_PairPos* pp )
1212 UShort format1, format2;
1215 format1 = pp->ValueFormat1;
1216 format2 = pp->ValueFormat2;
1218 switch ( pp->PosFormat )
1220 case 1:
1221 Free_PairPosFormat1( &pp->ppf.ppf1, format1, format2 );
1222 break;
1224 case 2:
1225 Free_PairPosFormat2( &pp->ppf.ppf2, format1, format2 );
1226 break;
1229 Free_Coverage( &pp->Coverage );
1233 /* LookupType 3 */
1235 /* CursivePosFormat1 */
1237 TT_Error Load_CursivePos( TTO_CursivePos* cp,
1238 PFace input )
1240 DEFINE_LOAD_LOCALS( input->stream );
1242 UShort n, count;
1243 ULong cur_offset, new_offset, base_offset;
1245 TTO_EntryExitRecord* eer;
1248 base_offset = FILE_Pos();
1250 if ( ACCESS_Frame( 4L ) )
1251 return error;
1253 cp->PosFormat = GET_UShort();
1254 new_offset = GET_UShort() + base_offset;
1256 FORGET_Frame();
1258 cur_offset = FILE_Pos();
1259 if ( FILE_Seek( new_offset ) ||
1260 ( error = Load_Coverage( &cp->Coverage, input ) ) != TT_Err_Ok )
1261 return error;
1262 (void)FILE_Seek( cur_offset );
1264 if ( ACCESS_Frame( 2L ) )
1265 goto Fail2;
1267 count = cp->EntryExitCount = GET_UShort();
1269 FORGET_Frame();
1271 cp->EntryExitRecord = NULL;
1273 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) )
1274 goto Fail2;
1276 eer = cp->EntryExitRecord;
1278 for ( n = 0; n < count; n++ )
1280 if ( ACCESS_Frame( 2L ) )
1281 return error;
1283 new_offset = GET_UShort();
1285 FORGET_Frame();
1287 if ( new_offset )
1289 new_offset += base_offset;
1291 cur_offset = FILE_Pos();
1292 if ( FILE_Seek( new_offset ) ||
1293 ( error = Load_Anchor( &eer[n].EntryAnchor,
1294 input ) ) != TT_Err_Ok )
1295 goto Fail1;
1296 (void)FILE_Seek( cur_offset );
1298 else
1299 eer[n].EntryAnchor.PosFormat = 0;
1301 if ( ACCESS_Frame( 2L ) )
1302 return error;
1304 new_offset = GET_UShort();
1306 FORGET_Frame();
1308 if ( new_offset )
1310 new_offset += base_offset;
1312 cur_offset = FILE_Pos();
1313 if ( FILE_Seek( new_offset ) ||
1314 ( error = Load_Anchor( &eer[n].ExitAnchor,
1315 input ) ) != TT_Err_Ok )
1316 goto Fail1;
1317 (void)FILE_Seek( cur_offset );
1319 else
1320 eer[n].ExitAnchor.PosFormat = 0;
1323 return TT_Err_Ok;
1325 Fail1:
1326 for ( n = 0; n < count; n++ )
1328 Free_Anchor( &eer[n].EntryAnchor );
1329 Free_Anchor( &eer[n].ExitAnchor );
1332 FREE( eer );
1334 Fail2:
1335 Free_Coverage( &cp->Coverage );
1336 return error;
1340 void Free_CursivePos( TTO_CursivePos* cp )
1342 UShort n, count;
1344 TTO_EntryExitRecord* eer;
1347 if ( cp->EntryExitRecord )
1349 count = cp->EntryExitCount;
1350 eer = cp->EntryExitRecord;
1352 for ( n = 0; n < count; n++ )
1354 Free_Anchor( &eer[n].EntryAnchor );
1355 Free_Anchor( &eer[n].ExitAnchor );
1358 FREE( eer );
1361 Free_Coverage( &cp->Coverage );
1365 /* LookupType 4 */
1367 /* BaseArray */
1369 static TT_Error Load_BaseArray( TTO_BaseArray* ba,
1370 UShort num_classes,
1371 PFace input )
1373 DEFINE_LOAD_LOCALS( input->stream );
1375 UShort m, n, count;
1376 ULong cur_offset, new_offset, base_offset;
1378 TTO_BaseRecord* br;
1379 TTO_Anchor* ban;
1382 base_offset = FILE_Pos();
1384 if ( ACCESS_Frame( 2L ) )
1385 return error;
1387 count = ba->BaseCount = GET_UShort();
1389 FORGET_Frame();
1391 ba->BaseRecord = NULL;
1393 if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) )
1394 return error;
1396 br = ba->BaseRecord;
1398 for ( m = 0; m < count; m++ )
1400 br[m].BaseAnchor = NULL;
1402 if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
1403 goto Fail;
1405 ban = br[m].BaseAnchor;
1407 for ( n = 0; n < num_classes; n++ )
1409 if ( ACCESS_Frame( 2L ) )
1410 goto Fail;
1412 new_offset = GET_UShort() + base_offset;
1414 FORGET_Frame();
1416 cur_offset = FILE_Pos();
1417 if ( FILE_Seek( new_offset ) ||
1418 ( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok )
1419 goto Fail;
1420 (void)FILE_Seek( cur_offset );
1424 return TT_Err_Ok;
1426 Fail:
1427 for ( m = 0; m < count; m++ )
1429 ban = br[m].BaseAnchor;
1431 for ( n = 0; n < num_classes; n++ )
1432 Free_Anchor( &ban[n] );
1434 FREE( ban );
1437 FREE( br );
1438 return error;
1442 static void Free_BaseArray( TTO_BaseArray* ba,
1443 UShort num_classes )
1445 UShort m, n, count;
1447 TTO_BaseRecord* br;
1448 TTO_Anchor* ban;
1451 if ( ba->BaseRecord )
1453 count = ba->BaseCount;
1454 br = ba->BaseRecord;
1456 for ( m = 0; m < count; m++ )
1458 ban = br[m].BaseAnchor;
1460 for ( n = 0; n < num_classes; n++ )
1461 Free_Anchor( &ban[n] );
1463 FREE( ban );
1466 FREE( br );
1471 /* MarkBasePosFormat1 */
1473 TT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp,
1474 PFace input )
1476 DEFINE_LOAD_LOCALS( input->stream );
1478 ULong cur_offset, new_offset, base_offset;
1481 base_offset = FILE_Pos();
1483 if ( ACCESS_Frame( 4L ) )
1484 return error;
1486 mbp->PosFormat = GET_UShort();
1487 new_offset = GET_UShort() + base_offset;
1489 FORGET_Frame();
1491 cur_offset = FILE_Pos();
1492 if ( FILE_Seek( new_offset ) ||
1493 ( error = Load_Coverage( &mbp->MarkCoverage, input ) ) != TT_Err_Ok )
1494 return error;
1495 (void)FILE_Seek( cur_offset );
1497 if ( ACCESS_Frame( 2L ) )
1498 goto Fail3;
1500 new_offset = GET_UShort() + base_offset;
1502 FORGET_Frame();
1504 cur_offset = FILE_Pos();
1505 if ( FILE_Seek( new_offset ) ||
1506 ( error = Load_Coverage( &mbp->BaseCoverage, input ) ) != TT_Err_Ok )
1507 goto Fail3;
1508 (void)FILE_Seek( cur_offset );
1510 if ( ACCESS_Frame( 4L ) )
1511 goto Fail2;
1513 mbp->ClassCount = GET_UShort();
1514 new_offset = GET_UShort() + base_offset;
1516 FORGET_Frame();
1518 cur_offset = FILE_Pos();
1519 if ( FILE_Seek( new_offset ) ||
1520 ( error = Load_MarkArray( &mbp->MarkArray, input ) ) != TT_Err_Ok )
1521 goto Fail2;
1522 (void)FILE_Seek( cur_offset );
1524 if ( ACCESS_Frame( 2L ) )
1525 goto Fail1;
1527 new_offset = GET_UShort() + base_offset;
1529 FORGET_Frame();
1531 cur_offset = FILE_Pos();
1532 if ( FILE_Seek( new_offset ) ||
1533 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
1534 input ) ) != TT_Err_Ok )
1535 goto Fail1;
1537 return TT_Err_Ok;
1539 Fail1:
1540 Free_MarkArray( &mbp->MarkArray );
1542 Fail2:
1543 Free_Coverage( &mbp->BaseCoverage );
1545 Fail3:
1546 Free_Coverage( &mbp->MarkCoverage );
1547 return error;
1551 void Free_MarkBasePos( TTO_MarkBasePos* mbp )
1553 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
1554 Free_MarkArray( &mbp->MarkArray );
1555 Free_Coverage( &mbp->BaseCoverage );
1556 Free_Coverage( &mbp->MarkCoverage );
1560 /* LookupType 5 */
1562 /* LigatureAttach */
1564 static TT_Error Load_LigatureAttach( TTO_LigatureAttach* lat,
1565 UShort num_classes,
1566 PFace input )
1568 DEFINE_LOAD_LOCALS( input->stream );
1570 UShort m, n, count;
1571 ULong cur_offset, new_offset, base_offset;
1573 TTO_ComponentRecord* cr;
1574 TTO_Anchor* lan;
1577 base_offset = FILE_Pos();
1579 if ( ACCESS_Frame( 2L ) )
1580 return error;
1582 count = lat->ComponentCount = GET_UShort();
1584 FORGET_Frame();
1586 lat->ComponentRecord = NULL;
1588 if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) )
1589 return error;
1591 cr = lat->ComponentRecord;
1593 for ( m = 0; m < count; m++ )
1595 cr[m].LigatureAnchor = NULL;
1597 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) )
1598 goto Fail;
1600 lan = cr[m].LigatureAnchor;
1602 for ( n = 0; n < num_classes; n++ )
1604 if ( ACCESS_Frame( 2L ) )
1605 goto Fail;
1607 new_offset = GET_UShort();
1609 FORGET_Frame();
1611 if ( new_offset )
1613 new_offset += base_offset;
1615 cur_offset = FILE_Pos();
1616 if ( FILE_Seek( new_offset ) ||
1617 ( error = Load_Anchor( &lan[n], input ) ) != TT_Err_Ok )
1618 goto Fail;
1619 (void)FILE_Seek( cur_offset );
1621 else
1622 lan[n].PosFormat = 0;
1626 return TT_Err_Ok;
1628 Fail:
1629 for ( m = 0; m < count; m++ )
1631 lan = cr[m].LigatureAnchor;
1633 for ( n = 0; n < num_classes; n++ )
1634 Free_Anchor( &lan[n] );
1636 FREE( lan );
1639 FREE( cr );
1640 return error;
1644 static void Free_LigatureAttach( TTO_LigatureAttach* lat,
1645 UShort num_classes )
1647 UShort m, n, count;
1649 TTO_ComponentRecord* cr;
1650 TTO_Anchor* lan;
1653 if ( lat->ComponentRecord )
1655 count = lat->ComponentCount;
1656 cr = lat->ComponentRecord;
1658 for ( m = 0; m < count; m++ )
1660 lan = cr[m].LigatureAnchor;
1662 for ( n = 0; n < num_classes; n++ )
1663 Free_Anchor( &lan[n] );
1665 FREE( lan );
1668 FREE( cr );
1673 /* LigatureArray */
1675 static TT_Error Load_LigatureArray( TTO_LigatureArray* la,
1676 UShort num_classes,
1677 PFace input )
1679 DEFINE_LOAD_LOCALS( input->stream );
1681 UShort n, count;
1682 ULong cur_offset, new_offset, base_offset;
1684 TTO_LigatureAttach* lat;
1687 base_offset = FILE_Pos();
1689 if ( ACCESS_Frame( 2L ) )
1690 return error;
1692 count = la->LigatureCount = GET_UShort();
1694 FORGET_Frame();
1696 la->LigatureAttach = NULL;
1698 if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) )
1699 return error;
1701 lat = la->LigatureAttach;
1703 for ( n = 0; n < count; n++ )
1705 if ( ACCESS_Frame( 2L ) )
1706 goto Fail;
1708 new_offset = GET_UShort() + base_offset;
1710 FORGET_Frame();
1712 cur_offset = FILE_Pos();
1713 if ( FILE_Seek( new_offset ) ||
1714 ( error = Load_LigatureAttach( &lat[n], num_classes,
1715 input ) ) != TT_Err_Ok )
1716 goto Fail;
1717 (void)FILE_Seek( cur_offset );
1720 return TT_Err_Ok;
1722 Fail:
1723 for ( n = 0; n < count; n++ )
1724 Free_LigatureAttach( &lat[n], num_classes );
1726 FREE( lat );
1727 return error;
1731 static void Free_LigatureArray( TTO_LigatureArray* la,
1732 UShort num_classes )
1734 UShort n, count;
1736 TTO_LigatureAttach* lat;
1739 if ( la->LigatureAttach )
1741 count = la->LigatureCount;
1742 lat = la->LigatureAttach;
1744 for ( n = 0; n < count; n++ )
1745 Free_LigatureAttach( &lat[n], num_classes );
1747 FREE( lat );
1752 /* MarkLigPosFormat1 */
1754 TT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp,
1755 PFace input )
1757 DEFINE_LOAD_LOCALS( input->stream );
1759 ULong cur_offset, new_offset, base_offset;
1762 base_offset = FILE_Pos();
1764 if ( ACCESS_Frame( 4L ) )
1765 return error;
1767 mlp->PosFormat = GET_UShort();
1768 new_offset = GET_UShort() + base_offset;
1770 FORGET_Frame();
1772 cur_offset = FILE_Pos();
1773 if ( FILE_Seek( new_offset ) ||
1774 ( error = Load_Coverage( &mlp->MarkCoverage, input ) ) != TT_Err_Ok )
1775 return error;
1776 (void)FILE_Seek( cur_offset );
1778 if ( ACCESS_Frame( 2L ) )
1779 goto Fail3;
1781 new_offset = GET_UShort() + base_offset;
1783 FORGET_Frame();
1785 cur_offset = FILE_Pos();
1786 if ( FILE_Seek( new_offset ) ||
1787 ( error = Load_Coverage( &mlp->LigatureCoverage,
1788 input ) ) != TT_Err_Ok )
1789 goto Fail3;
1790 (void)FILE_Seek( cur_offset );
1792 if ( ACCESS_Frame( 4L ) )
1793 goto Fail2;
1795 mlp->ClassCount = GET_UShort();
1796 new_offset = GET_UShort() + base_offset;
1798 FORGET_Frame();
1800 cur_offset = FILE_Pos();
1801 if ( FILE_Seek( new_offset ) ||
1802 ( error = Load_MarkArray( &mlp->MarkArray, input ) ) != TT_Err_Ok )
1803 goto Fail2;
1804 (void)FILE_Seek( cur_offset );
1806 if ( ACCESS_Frame( 2L ) )
1807 goto Fail1;
1809 new_offset = GET_UShort() + base_offset;
1811 FORGET_Frame();
1813 cur_offset = FILE_Pos();
1814 if ( FILE_Seek( new_offset ) ||
1815 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
1816 input ) ) != TT_Err_Ok )
1817 goto Fail1;
1819 return TT_Err_Ok;
1821 Fail1:
1822 Free_MarkArray( &mlp->MarkArray );
1824 Fail2:
1825 Free_Coverage( &mlp->LigatureCoverage );
1827 Fail3:
1828 Free_Coverage( &mlp->MarkCoverage );
1829 return error;
1833 void Free_MarkLigPos( TTO_MarkLigPos* mlp )
1835 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
1836 Free_MarkArray( &mlp->MarkArray );
1837 Free_Coverage( &mlp->LigatureCoverage );
1838 Free_Coverage( &mlp->MarkCoverage );
1842 /* LookupType 6 */
1844 /* Mark2Array */
1846 static TT_Error Load_Mark2Array( TTO_Mark2Array* m2a,
1847 UShort num_classes,
1848 PFace input )
1850 DEFINE_LOAD_LOCALS( input->stream );
1852 UShort m, n, count;
1853 ULong cur_offset, new_offset, base_offset;
1855 TTO_Mark2Record* m2r;
1856 TTO_Anchor* m2an;
1859 base_offset = FILE_Pos();
1861 if ( ACCESS_Frame( 2L ) )
1862 return error;
1864 count = m2a->Mark2Count = GET_UShort();
1866 FORGET_Frame();
1868 m2a->Mark2Record = NULL;
1870 if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) )
1871 return error;
1873 m2r = m2a->Mark2Record;
1875 for ( m = 0; m < count; m++ )
1877 m2r[m].Mark2Anchor = NULL;
1879 if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
1880 goto Fail;
1882 m2an = m2r[m].Mark2Anchor;
1884 for ( n = 0; n < num_classes; n++ )
1886 if ( ACCESS_Frame( 2L ) )
1887 goto Fail;
1889 new_offset = GET_UShort() + base_offset;
1891 FORGET_Frame();
1893 cur_offset = FILE_Pos();
1894 if ( FILE_Seek( new_offset ) ||
1895 ( error = Load_Anchor( &m2an[n], input ) ) != TT_Err_Ok )
1896 goto Fail;
1897 (void)FILE_Seek( cur_offset );
1901 return TT_Err_Ok;
1903 Fail:
1904 for ( m = 0; m < count; m++ )
1906 m2an = m2r[m].Mark2Anchor;
1908 for ( n = 0; n < num_classes; n++ )
1909 Free_Anchor( &m2an[n] );
1911 FREE( m2an );
1914 FREE( m2r );
1915 return error;
1919 static void Free_Mark2Array( TTO_Mark2Array* m2a,
1920 UShort num_classes )
1922 UShort m, n, count;
1924 TTO_Mark2Record* m2r;
1925 TTO_Anchor* m2an;
1928 if ( m2a->Mark2Record )
1930 count = m2a->Mark2Count;
1931 m2r = m2a->Mark2Record;
1933 for ( m = 0; m < count; m++ )
1935 m2an = m2r[m].Mark2Anchor;
1937 for ( n = 0; n < num_classes; n++ )
1938 Free_Anchor( &m2an[n] );
1940 FREE( m2an );
1943 FREE( m2r );
1948 /* MarkMarkPosFormat1 */
1950 TT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp,
1951 PFace input )
1953 DEFINE_LOAD_LOCALS( input->stream );
1955 ULong cur_offset, new_offset, base_offset;
1958 base_offset = FILE_Pos();
1960 if ( ACCESS_Frame( 4L ) )
1961 return error;
1963 mmp->PosFormat = GET_UShort();
1964 new_offset = GET_UShort() + base_offset;
1966 FORGET_Frame();
1968 cur_offset = FILE_Pos();
1969 if ( FILE_Seek( new_offset ) ||
1970 ( error = Load_Coverage( &mmp->Mark1Coverage,
1971 input ) ) != TT_Err_Ok )
1972 return error;
1973 (void)FILE_Seek( cur_offset );
1975 if ( ACCESS_Frame( 2L ) )
1976 goto Fail3;
1978 new_offset = GET_UShort() + base_offset;
1980 FORGET_Frame();
1982 cur_offset = FILE_Pos();
1983 if ( FILE_Seek( new_offset ) ||
1984 ( error = Load_Coverage( &mmp->Mark2Coverage,
1985 input ) ) != TT_Err_Ok )
1986 goto Fail3;
1987 (void)FILE_Seek( cur_offset );
1989 if ( ACCESS_Frame( 4L ) )
1990 goto Fail2;
1992 mmp->ClassCount = GET_UShort();
1993 new_offset = GET_UShort() + base_offset;
1995 FORGET_Frame();
1997 cur_offset = FILE_Pos();
1998 if ( FILE_Seek( new_offset ) ||
1999 ( error = Load_MarkArray( &mmp->Mark1Array, input ) ) != TT_Err_Ok )
2000 goto Fail2;
2001 (void)FILE_Seek( cur_offset );
2003 if ( ACCESS_Frame( 2L ) )
2004 goto Fail1;
2006 new_offset = GET_UShort() + base_offset;
2008 FORGET_Frame();
2010 cur_offset = FILE_Pos();
2011 if ( FILE_Seek( new_offset ) ||
2012 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2013 input ) ) != TT_Err_Ok )
2014 goto Fail1;
2016 return TT_Err_Ok;
2018 Fail1:
2019 Free_MarkArray( &mmp->Mark1Array );
2021 Fail2:
2022 Free_Coverage( &mmp->Mark2Coverage );
2024 Fail3:
2025 Free_Coverage( &mmp->Mark1Coverage );
2026 return error;
2030 void Free_MarkMarkPos( TTO_MarkMarkPos* mmp )
2032 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2033 Free_MarkArray( &mmp->Mark1Array );
2034 Free_Coverage( &mmp->Mark2Coverage );
2035 Free_Coverage( &mmp->Mark1Coverage );
2039 /* LookupType 7 */
2041 /* PosRule */
2043 static TT_Error Load_PosRule( TTO_PosRule* pr,
2044 PFace input )
2046 DEFINE_LOAD_LOCALS( input->stream );
2048 UShort n, count;
2049 UShort* i;
2051 TTO_PosLookupRecord* plr;
2054 if ( ACCESS_Frame( 4L ) )
2055 return error;
2057 pr->GlyphCount = GET_UShort();
2058 pr->PosCount = GET_UShort();
2060 FORGET_Frame();
2062 pr->Input = NULL;
2064 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
2066 if ( ALLOC_ARRAY( pr->Input, count, UShort ) )
2067 return error;
2069 i = pr->Input;
2071 if ( ACCESS_Frame( count * 2L ) )
2072 goto Fail2;
2074 for ( n = 0; n < count; n++ )
2075 i[n] = GET_UShort();
2077 FORGET_Frame();
2079 pr->PosLookupRecord = NULL;
2081 count = pr->PosCount;
2083 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2084 goto Fail2;
2086 plr = pr->PosLookupRecord;
2088 if ( ACCESS_Frame( count * 4L ) )
2089 goto Fail1;
2091 for ( n = 0; n < count; n++ )
2093 plr[n].SequenceIndex = GET_UShort();
2094 plr[n].LookupListIndex = GET_UShort();
2097 FORGET_Frame();
2099 return TT_Err_Ok;
2101 Fail1:
2102 FREE( plr );
2104 Fail2:
2105 FREE( i );
2106 return error;
2110 static void Free_PosRule( TTO_PosRule* pr )
2112 FREE( pr->PosLookupRecord );
2113 FREE( pr->Input );
2117 /* PosRuleSet */
2119 static TT_Error Load_PosRuleSet( TTO_PosRuleSet* prs,
2120 PFace input )
2122 DEFINE_LOAD_LOCALS( input->stream );
2124 UShort n, count;
2125 ULong cur_offset, new_offset, base_offset;
2127 TTO_PosRule* pr;
2130 base_offset = FILE_Pos();
2132 if ( ACCESS_Frame( 2L ) )
2133 return error;
2135 count = prs->PosRuleCount = GET_UShort();
2137 FORGET_Frame();
2139 prs->PosRule = NULL;
2141 if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) )
2142 return error;
2144 pr = prs->PosRule;
2146 for ( n = 0; n < count; n++ )
2148 if ( ACCESS_Frame( 2L ) )
2149 goto Fail;
2151 new_offset = GET_UShort() + base_offset;
2153 FORGET_Frame();
2155 cur_offset = FILE_Pos();
2156 if ( FILE_Seek( new_offset ) ||
2157 ( error = Load_PosRule( &pr[n], input ) ) != TT_Err_Ok )
2158 goto Fail;
2159 (void)FILE_Seek( cur_offset );
2162 return TT_Err_Ok;
2164 Fail:
2165 for ( n = 0; n < count; n++ )
2166 Free_PosRule( &pr[n] );
2168 FREE( pr );
2169 return error;
2173 static void Free_PosRuleSet( TTO_PosRuleSet* prs )
2175 UShort n, count;
2177 TTO_PosRule* pr;
2180 if ( prs->PosRule )
2182 count = prs->PosRuleCount;
2183 pr = prs->PosRule;
2185 for ( n = 0; n < count; n++ )
2186 Free_PosRule( &pr[n] );
2188 FREE( pr );
2193 /* ContextPosFormat1 */
2195 static TT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1,
2196 PFace input )
2198 DEFINE_LOAD_LOCALS( input->stream );
2200 UShort n, count;
2201 ULong cur_offset, new_offset, base_offset;
2203 TTO_PosRuleSet* prs;
2206 base_offset = FILE_Pos() - 2L;
2208 if ( ACCESS_Frame( 2L ) )
2209 return error;
2211 new_offset = GET_UShort() + base_offset;
2213 FORGET_Frame();
2215 cur_offset = FILE_Pos();
2216 if ( FILE_Seek( new_offset ) ||
2217 ( error = Load_Coverage( &cpf1->Coverage, input ) ) != TT_Err_Ok )
2218 return error;
2219 (void)FILE_Seek( cur_offset );
2221 if ( ACCESS_Frame( 2L ) )
2222 goto Fail2;
2224 count = cpf1->PosRuleSetCount = GET_UShort();
2226 FORGET_Frame();
2228 cpf1->PosRuleSet = NULL;
2230 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) )
2231 goto Fail2;
2233 prs = cpf1->PosRuleSet;
2235 for ( n = 0; n < count; n++ )
2237 if ( ACCESS_Frame( 2L ) )
2238 goto Fail1;
2240 new_offset = GET_UShort() + base_offset;
2242 FORGET_Frame();
2244 cur_offset = FILE_Pos();
2245 if ( FILE_Seek( new_offset ) ||
2246 ( error = Load_PosRuleSet( &prs[n], input ) ) != TT_Err_Ok )
2247 goto Fail1;
2248 (void)FILE_Seek( cur_offset );
2251 return TT_Err_Ok;
2253 Fail1:
2254 for ( n = 0; n < count; n++ )
2255 Free_PosRuleSet( &prs[n] );
2257 FREE( prs );
2259 Fail2:
2260 Free_Coverage( &cpf1->Coverage );
2261 return error;
2265 static void Free_Context1( TTO_ContextPosFormat1* cpf1 )
2267 UShort n, count;
2269 TTO_PosRuleSet* prs;
2272 if ( cpf1->PosRuleSet )
2274 count = cpf1->PosRuleSetCount;
2275 prs = cpf1->PosRuleSet;
2277 for ( n = 0; n < count; n++ )
2278 Free_PosRuleSet( &prs[n] );
2280 FREE( prs );
2283 Free_Coverage( &cpf1->Coverage );
2287 /* PosClassRule */
2289 static TT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2,
2290 TTO_PosClassRule* pcr,
2291 PFace input )
2293 DEFINE_LOAD_LOCALS( input->stream );
2295 UShort n, count;
2297 UShort* c;
2298 TTO_PosLookupRecord* plr;
2299 Bool* d;
2302 if ( ACCESS_Frame( 4L ) )
2303 return error;
2305 pcr->GlyphCount = GET_UShort();
2306 pcr->PosCount = GET_UShort();
2308 FORGET_Frame();
2310 if ( pcr->GlyphCount > cpf2->MaxContextLength )
2311 cpf2->MaxContextLength = pcr->GlyphCount;
2313 pcr->Class = NULL;
2315 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
2317 if ( ALLOC_ARRAY( pcr->Class, count, UShort ) )
2318 return error;
2320 c = pcr->Class;
2321 d = cpf2->ClassDef.Defined;
2323 if ( ACCESS_Frame( count * 2L ) )
2324 goto Fail2;
2326 for ( n = 0; n < count; n++ )
2328 c[n] = GET_UShort();
2330 /* We check whether the specific class is used at all. If not,
2331 class 0 is used instead. */
2333 if ( !d[c[n]] )
2334 c[n] = 0;
2337 FORGET_Frame();
2339 pcr->PosLookupRecord = NULL;
2341 count = pcr->PosCount;
2343 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2344 goto Fail2;
2346 plr = pcr->PosLookupRecord;
2348 if ( ACCESS_Frame( count * 4L ) )
2349 goto Fail1;
2351 for ( n = 0; n < count; n++ )
2353 plr[n].SequenceIndex = GET_UShort();
2354 plr[n].LookupListIndex = GET_UShort();
2357 FORGET_Frame();
2359 return TT_Err_Ok;
2361 Fail1:
2362 FREE( plr );
2364 Fail2:
2365 FREE( c );
2366 return error;
2370 static void Free_PosClassRule( TTO_PosClassRule* pcr )
2372 FREE( pcr->PosLookupRecord );
2373 FREE( pcr->Class );
2377 /* PosClassSet */
2379 static TT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2,
2380 TTO_PosClassSet* pcs,
2381 PFace input )
2383 DEFINE_LOAD_LOCALS( input->stream );
2385 UShort n, count;
2386 ULong cur_offset, new_offset, base_offset;
2388 TTO_PosClassRule* pcr;
2391 base_offset = FILE_Pos();
2393 if ( ACCESS_Frame( 2L ) )
2394 return error;
2396 count = pcs->PosClassRuleCount = GET_UShort();
2398 FORGET_Frame();
2400 pcs->PosClassRule = NULL;
2402 if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) )
2403 return error;
2405 pcr = pcs->PosClassRule;
2407 for ( n = 0; n < count; n++ )
2409 if ( ACCESS_Frame( 2L ) )
2410 goto Fail;
2412 new_offset = GET_UShort() + base_offset;
2414 FORGET_Frame();
2416 cur_offset = FILE_Pos();
2417 if ( FILE_Seek( new_offset ) ||
2418 ( error = Load_PosClassRule( cpf2, &pcr[n],
2419 input ) ) != TT_Err_Ok )
2420 goto Fail;
2421 (void)FILE_Seek( cur_offset );
2424 return TT_Err_Ok;
2426 Fail:
2427 for ( n = 0; n < count; n++ )
2428 Free_PosClassRule( &pcr[n] );
2430 FREE( pcr );
2431 return error;
2435 static void Free_PosClassSet( TTO_PosClassSet* pcs )
2437 UShort n, count;
2439 TTO_PosClassRule* pcr;
2442 if ( pcs->PosClassRule )
2444 count = pcs->PosClassRuleCount;
2445 pcr = pcs->PosClassRule;
2447 for ( n = 0; n < count; n++ )
2448 Free_PosClassRule( &pcr[n] );
2450 FREE( pcr );
2455 /* ContextPosFormat2 */
2457 static TT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2,
2458 PFace input )
2460 DEFINE_LOAD_LOCALS( input->stream );
2462 UShort n, count;
2463 ULong cur_offset, new_offset, base_offset;
2465 TTO_PosClassSet* pcs;
2468 base_offset = FILE_Pos() - 2;
2470 if ( ACCESS_Frame( 2L ) )
2471 return error;
2473 new_offset = GET_UShort() + base_offset;
2475 FORGET_Frame();
2477 cur_offset = FILE_Pos();
2478 if ( FILE_Seek( new_offset ) ||
2479 ( error = Load_Coverage( &cpf2->Coverage, input ) ) != TT_Err_Ok )
2480 return error;
2481 (void)FILE_Seek( cur_offset );
2483 if ( ACCESS_Frame( 4L ) )
2484 goto Fail3;
2486 new_offset = GET_UShort() + base_offset;
2488 /* `PosClassSetCount' is the upper limit for class values, thus we
2489 read it now to make an additional safety check. */
2491 count = cpf2->PosClassSetCount = GET_UShort();
2493 FORGET_Frame();
2495 cur_offset = FILE_Pos();
2496 if ( FILE_Seek( new_offset ) ||
2497 ( error = Load_ClassDefinition( &cpf2->ClassDef, count,
2498 input ) ) != TT_Err_Ok )
2499 goto Fail3;
2500 (void)FILE_Seek( cur_offset );
2502 cpf2->PosClassSet = NULL;
2503 cpf2->MaxContextLength = 0;
2505 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) )
2506 goto Fail2;
2508 pcs = cpf2->PosClassSet;
2510 for ( n = 0; n < count; n++ )
2512 if ( ACCESS_Frame( 2L ) )
2513 goto Fail1;
2515 new_offset = GET_UShort() + base_offset;
2517 FORGET_Frame();
2519 if ( new_offset != base_offset ) /* not a NULL offset */
2521 cur_offset = FILE_Pos();
2522 if ( FILE_Seek( new_offset ) ||
2523 ( error = Load_PosClassSet( cpf2, &pcs[n],
2524 input ) ) != TT_Err_Ok )
2525 goto Fail1;
2526 (void)FILE_Seek( cur_offset );
2528 else
2530 /* we create a PosClassSet table with no entries */
2532 cpf2->PosClassSet[n].PosClassRuleCount = 0;
2533 cpf2->PosClassSet[n].PosClassRule = NULL;
2537 return TT_Err_Ok;
2539 Fail1:
2540 for ( n = 0; n < count; n++ )
2541 Free_PosClassSet( &pcs[n] );
2543 FREE( pcs );
2545 Fail2:
2546 Free_ClassDefinition( &cpf2->ClassDef );
2548 Fail3:
2549 Free_Coverage( &cpf2->Coverage );
2550 return error;
2554 static void Free_Context2( TTO_ContextPosFormat2* cpf2 )
2556 UShort n, count;
2558 TTO_PosClassSet* pcs;
2561 if ( cpf2->PosClassSet )
2563 count = cpf2->PosClassSetCount;
2564 pcs = cpf2->PosClassSet;
2566 for ( n = 0; n < count; n++ )
2567 Free_PosClassSet( &pcs[n] );
2569 FREE( pcs );
2572 Free_ClassDefinition( &cpf2->ClassDef );
2573 Free_Coverage( &cpf2->Coverage );
2577 /* ContextPosFormat3 */
2579 static TT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3,
2580 PFace input )
2582 DEFINE_LOAD_LOCALS( input->stream );
2584 UShort n, count;
2585 ULong cur_offset, new_offset, base_offset;
2587 TTO_Coverage* c;
2588 TTO_PosLookupRecord* plr;
2591 base_offset = FILE_Pos() - 2L;
2593 if ( ACCESS_Frame( 4L ) )
2594 return error;
2596 cpf3->GlyphCount = GET_UShort();
2597 cpf3->PosCount = GET_UShort();
2599 FORGET_Frame();
2601 cpf3->Coverage = NULL;
2603 count = cpf3->GlyphCount;
2605 if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) )
2606 return error;
2608 c = cpf3->Coverage;
2610 for ( n = 0; n < count; n++ )
2612 if ( ACCESS_Frame( 2L ) )
2613 goto Fail2;
2615 new_offset = GET_UShort() + base_offset;
2617 FORGET_Frame();
2619 cur_offset = FILE_Pos();
2620 if ( FILE_Seek( new_offset ) ||
2621 ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok )
2622 goto Fail2;
2623 (void)FILE_Seek( cur_offset );
2626 cpf3->PosLookupRecord = NULL;
2628 count = cpf3->PosCount;
2630 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
2631 goto Fail2;
2633 plr = cpf3->PosLookupRecord;
2635 if ( ACCESS_Frame( count * 4L ) )
2636 goto Fail1;
2638 for ( n = 0; n < count; n++ )
2640 plr[n].SequenceIndex = GET_UShort();
2641 plr[n].LookupListIndex = GET_UShort();
2644 FORGET_Frame();
2646 return TT_Err_Ok;
2648 Fail1:
2649 FREE( plr );
2651 Fail2:
2652 for ( n = 0; n < count; n++ )
2653 Free_Coverage( &c[n] );
2655 FREE( c );
2656 return error;
2660 static void Free_Context3( TTO_ContextPosFormat3* cpf3 )
2662 UShort n, count;
2664 TTO_Coverage* c;
2667 FREE( cpf3->PosLookupRecord );
2669 if ( cpf3->Coverage )
2671 count = cpf3->GlyphCount;
2672 c = cpf3->Coverage;
2674 for ( n = 0; n < count; n++ )
2675 Free_Coverage( &c[n] );
2677 FREE( c );
2682 /* ContextPos */
2684 TT_Error Load_ContextPos( TTO_ContextPos* cp,
2685 PFace input )
2687 DEFINE_LOAD_LOCALS( input->stream );
2690 if ( ACCESS_Frame( 2L ) )
2691 return error;
2693 cp->PosFormat = GET_UShort();
2695 FORGET_Frame();
2697 switch ( cp->PosFormat )
2699 case 1:
2700 return Load_ContextPos1( &cp->cpf.cpf1, input );
2702 case 2:
2703 return Load_ContextPos2( &cp->cpf.cpf2, input );
2705 case 3:
2706 return Load_ContextPos3( &cp->cpf.cpf3, input );
2708 default:
2709 return TTO_Err_Invalid_GPOS_SubTable_Format;
2712 return TT_Err_Ok; /* never reached */
2716 void Free_ContextPos( TTO_ContextPos* cp )
2718 switch ( cp->PosFormat )
2720 case 1:
2721 Free_Context1( &cp->cpf.cpf1 );
2722 break;
2724 case 2:
2725 Free_Context2( &cp->cpf.cpf2 );
2726 break;
2728 case 3:
2729 Free_Context3( &cp->cpf.cpf3 );
2730 break;
2735 /* LookupType 8 */
2737 /* ChainPosRule */
2739 static TT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr,
2740 PFace input )
2742 DEFINE_LOAD_LOCALS( input->stream );
2744 UShort n, count;
2745 UShort* b;
2746 UShort* i;
2747 UShort* l;
2749 TTO_PosLookupRecord* plr;
2752 if ( ACCESS_Frame( 2L ) )
2753 return error;
2755 cpr->BacktrackGlyphCount = GET_UShort();
2757 FORGET_Frame();
2759 cpr->Backtrack = NULL;
2761 count = cpr->BacktrackGlyphCount;
2763 if ( ALLOC_ARRAY( cpr->Backtrack, count, UShort ) )
2764 return error;
2766 b = cpr->Backtrack;
2768 if ( ACCESS_Frame( count * 2L ) )
2769 goto Fail4;
2771 for ( n = 0; n < count; n++ )
2772 b[n] = GET_UShort();
2774 FORGET_Frame();
2776 if ( ACCESS_Frame( 2L ) )
2777 goto Fail4;
2779 cpr->InputGlyphCount = GET_UShort();
2781 FORGET_Frame();
2783 cpr->Input = NULL;
2785 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2787 if ( ALLOC_ARRAY( cpr->Input, count, UShort ) )
2788 goto Fail4;
2790 i = cpr->Input;
2792 if ( ACCESS_Frame( count * 2L ) )
2793 goto Fail3;
2795 for ( n = 0; n < count; n++ )
2796 i[n] = GET_UShort();
2798 FORGET_Frame();
2800 if ( ACCESS_Frame( 2L ) )
2801 goto Fail3;
2803 cpr->LookaheadGlyphCount = GET_UShort();
2805 FORGET_Frame();
2807 cpr->Lookahead = NULL;
2809 count = cpr->LookaheadGlyphCount;
2811 if ( ALLOC_ARRAY( cpr->Lookahead, count, UShort ) )
2812 goto Fail3;
2814 l = cpr->Lookahead;
2816 if ( ACCESS_Frame( count * 2L ) )
2817 goto Fail2;
2819 for ( n = 0; n < count; n++ )
2820 l[n] = GET_UShort();
2822 FORGET_Frame();
2824 if ( ACCESS_Frame( 2L ) )
2825 goto Fail2;
2827 cpr->PosCount = GET_UShort();
2829 FORGET_Frame();
2831 cpr->PosLookupRecord = NULL;
2833 count = cpr->PosCount;
2835 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2836 goto Fail2;
2838 plr = cpr->PosLookupRecord;
2840 if ( ACCESS_Frame( count * 4L ) )
2841 goto Fail1;
2843 for ( n = 0; n < count; n++ )
2845 plr[n].SequenceIndex = GET_UShort();
2846 plr[n].LookupListIndex = GET_UShort();
2849 FORGET_Frame();
2851 return TT_Err_Ok;
2853 Fail1:
2854 FREE( plr );
2856 Fail2:
2857 FREE( l );
2859 Fail3:
2860 FREE( i );
2862 Fail4:
2863 FREE( b );
2864 return error;
2868 static void Free_ChainPosRule( TTO_ChainPosRule* cpr )
2870 FREE( cpr->PosLookupRecord );
2871 FREE( cpr->Lookahead );
2872 FREE( cpr->Input );
2873 FREE( cpr->Backtrack );
2877 /* ChainPosRuleSet */
2879 static TT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs,
2880 PFace input )
2882 DEFINE_LOAD_LOCALS( input->stream );
2884 UShort n, count;
2885 ULong cur_offset, new_offset, base_offset;
2887 TTO_ChainPosRule* cpr;
2890 base_offset = FILE_Pos();
2892 if ( ACCESS_Frame( 2L ) )
2893 return error;
2895 count = cprs->ChainPosRuleCount = GET_UShort();
2897 FORGET_Frame();
2899 cprs->ChainPosRule = NULL;
2901 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) )
2902 return error;
2904 cpr = cprs->ChainPosRule;
2906 for ( n = 0; n < count; n++ )
2908 if ( ACCESS_Frame( 2L ) )
2909 goto Fail;
2911 new_offset = GET_UShort() + base_offset;
2913 FORGET_Frame();
2915 cur_offset = FILE_Pos();
2916 if ( FILE_Seek( new_offset ) ||
2917 ( error = Load_ChainPosRule( &cpr[n], input ) ) != TT_Err_Ok )
2918 goto Fail;
2919 (void)FILE_Seek( cur_offset );
2922 return TT_Err_Ok;
2924 Fail:
2925 for ( n = 0; n < count; n++ )
2926 Free_ChainPosRule( &cpr[n] );
2928 FREE( cpr );
2929 return error;
2933 static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs )
2935 UShort n, count;
2937 TTO_ChainPosRule* cpr;
2940 if ( cprs->ChainPosRule )
2942 count = cprs->ChainPosRuleCount;
2943 cpr = cprs->ChainPosRule;
2945 for ( n = 0; n < count; n++ )
2946 Free_ChainPosRule( &cpr[n] );
2948 FREE( cpr );
2953 /* ChainContextPosFormat1 */
2955 static TT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1,
2956 PFace input )
2958 DEFINE_LOAD_LOCALS( input->stream );
2960 UShort n, count;
2961 ULong cur_offset, new_offset, base_offset;
2963 TTO_ChainPosRuleSet* cprs;
2966 base_offset = FILE_Pos() - 2L;
2968 if ( ACCESS_Frame( 2L ) )
2969 return error;
2971 new_offset = GET_UShort() + base_offset;
2973 FORGET_Frame();
2975 cur_offset = FILE_Pos();
2976 if ( FILE_Seek( new_offset ) ||
2977 ( error = Load_Coverage( &ccpf1->Coverage, input ) ) != TT_Err_Ok )
2978 return error;
2979 (void)FILE_Seek( cur_offset );
2981 if ( ACCESS_Frame( 2L ) )
2982 goto Fail2;
2984 count = ccpf1->ChainPosRuleSetCount = GET_UShort();
2986 FORGET_Frame();
2988 ccpf1->ChainPosRuleSet = NULL;
2990 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) )
2991 goto Fail2;
2993 cprs = ccpf1->ChainPosRuleSet;
2995 for ( n = 0; n < count; n++ )
2997 if ( ACCESS_Frame( 2L ) )
2998 goto Fail1;
3000 new_offset = GET_UShort() + base_offset;
3002 FORGET_Frame();
3004 cur_offset = FILE_Pos();
3005 if ( FILE_Seek( new_offset ) ||
3006 ( error = Load_ChainPosRuleSet( &cprs[n], input ) ) != TT_Err_Ok )
3007 goto Fail1;
3008 (void)FILE_Seek( cur_offset );
3011 return TT_Err_Ok;
3013 Fail1:
3014 for ( n = 0; n < count; n++ )
3015 Free_ChainPosRuleSet( &cprs[n] );
3017 FREE( cprs );
3019 Fail2:
3020 Free_Coverage( &ccpf1->Coverage );
3021 return error;
3025 static void Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1 )
3027 UShort n, count;
3029 TTO_ChainPosRuleSet* cprs;
3032 if ( ccpf1->ChainPosRuleSet )
3034 count = ccpf1->ChainPosRuleSetCount;
3035 cprs = ccpf1->ChainPosRuleSet;
3037 for ( n = 0; n < count; n++ )
3038 Free_ChainPosRuleSet( &cprs[n] );
3040 FREE( cprs );
3043 Free_Coverage( &ccpf1->Coverage );
3047 /* ChainPosClassRule */
3049 static TT_Error Load_ChainPosClassRule(
3050 TTO_ChainContextPosFormat2* ccpf2,
3051 TTO_ChainPosClassRule* cpcr,
3052 PFace input )
3054 DEFINE_LOAD_LOCALS( input->stream );
3056 UShort n, count;
3058 UShort* b;
3059 UShort* i;
3060 UShort* l;
3061 TTO_PosLookupRecord* plr;
3062 Bool* d;
3065 if ( ACCESS_Frame( 2L ) )
3066 return error;
3068 cpcr->BacktrackGlyphCount = GET_UShort();
3070 FORGET_Frame();
3072 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
3073 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
3075 cpcr->Backtrack = NULL;
3077 count = cpcr->BacktrackGlyphCount;
3079 if ( ALLOC_ARRAY( cpcr->Backtrack, count, UShort ) )
3080 return error;
3082 b = cpcr->Backtrack;
3083 d = ccpf2->BacktrackClassDef.Defined;
3085 if ( ACCESS_Frame( count * 2L ) )
3086 goto Fail4;
3088 for ( n = 0; n < count; n++ )
3090 b[n] = GET_UShort();
3092 /* We check whether the specific class is used at all. If not,
3093 class 0 is used instead. */
3095 if ( !d[b[n]] )
3096 b[n] = 0;
3099 FORGET_Frame();
3101 if ( ACCESS_Frame( 2L ) )
3102 goto Fail4;
3104 cpcr->InputGlyphCount = GET_UShort();
3106 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
3107 ccpf2->MaxInputLength = cpcr->InputGlyphCount;
3109 FORGET_Frame();
3111 cpcr->Input = NULL;
3113 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
3115 if ( ALLOC_ARRAY( cpcr->Input, count, UShort ) )
3116 goto Fail4;
3118 i = cpcr->Input;
3119 d = ccpf2->InputClassDef.Defined;
3121 if ( ACCESS_Frame( count * 2L ) )
3122 goto Fail3;
3124 for ( n = 0; n < count; n++ )
3126 i[n] = GET_UShort();
3128 if ( !d[i[n]] )
3129 i[n] = 0;
3132 FORGET_Frame();
3134 if ( ACCESS_Frame( 2L ) )
3135 goto Fail3;
3137 cpcr->LookaheadGlyphCount = GET_UShort();
3139 FORGET_Frame();
3141 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
3142 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
3144 cpcr->Lookahead = NULL;
3146 count = cpcr->LookaheadGlyphCount;
3148 if ( ALLOC_ARRAY( cpcr->Lookahead, count, UShort ) )
3149 goto Fail3;
3151 l = cpcr->Lookahead;
3152 d = ccpf2->LookaheadClassDef.Defined;
3154 if ( ACCESS_Frame( count * 2L ) )
3155 goto Fail2;
3157 for ( n = 0; n < count; n++ )
3159 l[n] = GET_UShort();
3161 if ( !d[l[n]] )
3162 l[n] = 0;
3165 FORGET_Frame();
3167 if ( ACCESS_Frame( 2L ) )
3168 goto Fail2;
3170 cpcr->PosCount = GET_UShort();
3172 FORGET_Frame();
3174 cpcr->PosLookupRecord = NULL;
3176 count = cpcr->PosCount;
3178 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
3179 goto Fail2;
3181 plr = cpcr->PosLookupRecord;
3183 if ( ACCESS_Frame( count * 4L ) )
3184 goto Fail1;
3186 for ( n = 0; n < count; n++ )
3188 plr[n].SequenceIndex = GET_UShort();
3189 plr[n].LookupListIndex = GET_UShort();
3192 FORGET_Frame();
3194 return TT_Err_Ok;
3196 Fail1:
3197 FREE( plr );
3199 Fail2:
3200 FREE( l );
3202 Fail3:
3203 FREE( i );
3205 Fail4:
3206 FREE( b );
3207 return error;
3211 static void Free_ChainPosClassRule( TTO_ChainPosClassRule* cpcr )
3213 FREE( cpcr->PosLookupRecord );
3214 FREE( cpcr->Lookahead );
3215 FREE( cpcr->Input );
3216 FREE( cpcr->Backtrack );
3220 /* PosClassSet */
3222 static TT_Error Load_ChainPosClassSet(
3223 TTO_ChainContextPosFormat2* ccpf2,
3224 TTO_ChainPosClassSet* cpcs,
3225 PFace input )
3227 DEFINE_LOAD_LOCALS( input->stream );
3229 UShort n, count;
3230 ULong cur_offset, new_offset, base_offset;
3232 TTO_ChainPosClassRule* cpcr;
3235 base_offset = FILE_Pos();
3237 if ( ACCESS_Frame( 2L ) )
3238 return error;
3240 count = cpcs->ChainPosClassRuleCount = GET_UShort();
3242 FORGET_Frame();
3244 cpcs->ChainPosClassRule = NULL;
3246 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
3247 TTO_ChainPosClassRule ) )
3248 return error;
3250 cpcr = cpcs->ChainPosClassRule;
3252 for ( n = 0; n < count; n++ )
3254 if ( ACCESS_Frame( 2L ) )
3255 goto Fail;
3257 new_offset = GET_UShort() + base_offset;
3259 FORGET_Frame();
3261 cur_offset = FILE_Pos();
3262 if ( FILE_Seek( new_offset ) ||
3263 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
3264 input ) ) != TT_Err_Ok )
3265 goto Fail;
3266 (void)FILE_Seek( cur_offset );
3269 return TT_Err_Ok;
3271 Fail:
3272 for ( n = 0; n < count; n++ )
3273 Free_ChainPosClassRule( &cpcr[n] );
3275 FREE( cpcr );
3276 return error;
3280 static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs )
3282 UShort n, count;
3284 TTO_ChainPosClassRule* cpcr;
3287 if ( cpcs->ChainPosClassRule )
3289 count = cpcs->ChainPosClassRuleCount;
3290 cpcr = cpcs->ChainPosClassRule;
3292 for ( n = 0; n < count; n++ )
3293 Free_ChainPosClassRule( &cpcr[n] );
3295 FREE( cpcr );
3300 /* ChainContextPosFormat2 */
3302 static TT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2,
3303 PFace input )
3305 DEFINE_LOAD_LOCALS( input->stream );
3307 UShort n, count;
3308 ULong cur_offset, new_offset, base_offset;
3309 ULong backtrack_offset, input_offset, lookahead_offset;
3311 TTO_ChainPosClassSet* cpcs;
3314 base_offset = FILE_Pos() - 2;
3316 if ( ACCESS_Frame( 2L ) )
3317 return error;
3319 new_offset = GET_UShort() + base_offset;
3321 FORGET_Frame();
3323 cur_offset = FILE_Pos();
3324 if ( FILE_Seek( new_offset ) ||
3325 ( error = Load_Coverage( &ccpf2->Coverage, input ) ) != TT_Err_Ok )
3326 return error;
3327 (void)FILE_Seek( cur_offset );
3329 if ( ACCESS_Frame( 8L ) )
3330 goto Fail5;
3332 backtrack_offset = GET_UShort() + base_offset;
3333 input_offset = GET_UShort() + base_offset;
3334 lookahead_offset = GET_UShort() + base_offset;
3336 /* `ChainPosClassSetCount' is the upper limit for input class values,
3337 thus we read it now to make an additional safety check. */
3339 count = ccpf2->ChainPosClassSetCount = GET_UShort();
3341 FORGET_Frame();
3343 cur_offset = FILE_Pos();
3344 if ( FILE_Seek( backtrack_offset ) ||
3345 ( error = Load_ClassDefinition( &ccpf2->BacktrackClassDef, count,
3346 input ) ) != TT_Err_Ok )
3347 goto Fail5;
3348 if ( FILE_Seek( input_offset ) ||
3349 ( error = Load_ClassDefinition( &ccpf2->InputClassDef, count,
3350 input ) ) != TT_Err_Ok )
3351 goto Fail4;
3352 if ( FILE_Seek( lookahead_offset ) ||
3353 ( error = Load_ClassDefinition( &ccpf2->LookaheadClassDef, count,
3354 input ) ) != TT_Err_Ok )
3355 goto Fail3;
3356 (void)FILE_Seek( cur_offset );
3358 ccpf2->ChainPosClassSet = NULL;
3359 ccpf2->MaxBacktrackLength = 0;
3360 ccpf2->MaxInputLength = 0;
3361 ccpf2->MaxLookaheadLength = 0;
3363 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) )
3364 goto Fail2;
3366 cpcs = ccpf2->ChainPosClassSet;
3368 for ( n = 0; n < count; n++ )
3370 if ( ACCESS_Frame( 2L ) )
3371 goto Fail1;
3373 new_offset = GET_UShort() + base_offset;
3375 FORGET_Frame();
3377 if ( new_offset != base_offset ) /* not a NULL offset */
3379 cur_offset = FILE_Pos();
3380 if ( FILE_Seek( new_offset ) ||
3381 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
3382 input ) ) != TT_Err_Ok )
3383 goto Fail1;
3384 (void)FILE_Seek( cur_offset );
3386 else
3388 /* we create a ChainPosClassSet table with no entries */
3390 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
3391 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
3395 return TT_Err_Ok;
3397 Fail1:
3398 for ( n = 0; n < count; n++ )
3399 Free_ChainPosClassSet( &cpcs[n] );
3401 FREE( cpcs );
3403 Fail2:
3404 Free_ClassDefinition( &ccpf2->LookaheadClassDef );
3406 Fail3:
3407 Free_ClassDefinition( &ccpf2->InputClassDef );
3409 Fail4:
3410 Free_ClassDefinition( &ccpf2->BacktrackClassDef );
3412 Fail5:
3413 Free_Coverage( &ccpf2->Coverage );
3414 return error;
3418 static void Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2 )
3420 UShort n, count;
3422 TTO_ChainPosClassSet* cpcs;
3425 if ( ccpf2->ChainPosClassSet )
3427 count = ccpf2->ChainPosClassSetCount;
3428 cpcs = ccpf2->ChainPosClassSet;
3430 for ( n = 0; n < count; n++ )
3431 Free_ChainPosClassSet( &cpcs[n] );
3433 FREE( cpcs );
3436 Free_ClassDefinition( &ccpf2->LookaheadClassDef );
3437 Free_ClassDefinition( &ccpf2->InputClassDef );
3438 Free_ClassDefinition( &ccpf2->BacktrackClassDef );
3440 Free_Coverage( &ccpf2->Coverage );
3444 /* ChainContextPosFormat3 */
3446 static TT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3,
3447 PFace input )
3449 DEFINE_LOAD_LOCALS( input->stream );
3451 UShort n, count;
3452 UShort backtrack_count, input_count, lookahead_count;
3453 ULong cur_offset, new_offset, base_offset;
3455 TTO_Coverage* b;
3456 TTO_Coverage* i;
3457 TTO_Coverage* l;
3458 TTO_PosLookupRecord* plr;
3461 base_offset = FILE_Pos() - 2L;
3463 if ( ACCESS_Frame( 2L ) )
3464 return error;
3466 ccpf3->BacktrackGlyphCount = GET_UShort();
3468 FORGET_Frame();
3470 ccpf3->BacktrackCoverage = NULL;
3472 backtrack_count = ccpf3->BacktrackGlyphCount;
3474 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
3475 TTO_Coverage ) )
3476 return error;
3478 b = ccpf3->BacktrackCoverage;
3480 for ( n = 0; n < backtrack_count; n++ )
3482 if ( ACCESS_Frame( 2L ) )
3483 goto Fail4;
3485 new_offset = GET_UShort() + base_offset;
3487 FORGET_Frame();
3489 cur_offset = FILE_Pos();
3490 if ( FILE_Seek( new_offset ) ||
3491 ( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok )
3492 goto Fail4;
3493 (void)FILE_Seek( cur_offset );
3496 if ( ACCESS_Frame( 2L ) )
3497 goto Fail4;
3499 ccpf3->InputGlyphCount = GET_UShort();
3501 FORGET_Frame();
3503 ccpf3->InputCoverage = NULL;
3505 input_count = ccpf3->InputGlyphCount;
3507 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) )
3508 goto Fail4;
3510 i = ccpf3->InputCoverage;
3512 for ( n = 0; n < input_count; n++ )
3514 if ( ACCESS_Frame( 2L ) )
3515 goto Fail3;
3517 new_offset = GET_UShort() + base_offset;
3519 FORGET_Frame();
3521 cur_offset = FILE_Pos();
3522 if ( FILE_Seek( new_offset ) ||
3523 ( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok )
3524 goto Fail3;
3525 (void)FILE_Seek( cur_offset );
3528 if ( ACCESS_Frame( 2L ) )
3529 goto Fail3;
3531 ccpf3->LookaheadGlyphCount = GET_UShort();
3533 FORGET_Frame();
3535 ccpf3->LookaheadCoverage = NULL;
3537 lookahead_count = ccpf3->LookaheadGlyphCount;
3539 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
3540 TTO_Coverage ) )
3541 goto Fail3;
3543 l = ccpf3->LookaheadCoverage;
3545 for ( n = 0; n < lookahead_count; n++ )
3547 if ( ACCESS_Frame( 2L ) )
3548 goto Fail2;
3550 new_offset = GET_UShort() + base_offset;
3552 FORGET_Frame();
3554 cur_offset = FILE_Pos();
3555 if ( FILE_Seek( new_offset ) ||
3556 ( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok )
3557 goto Fail2;
3558 (void)FILE_Seek( cur_offset );
3561 if ( ACCESS_Frame( 2L ) )
3562 goto Fail2;
3564 ccpf3->PosCount = GET_UShort();
3566 FORGET_Frame();
3568 ccpf3->PosLookupRecord = NULL;
3570 count = ccpf3->PosCount;
3572 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
3573 goto Fail2;
3575 plr = ccpf3->PosLookupRecord;
3577 if ( ACCESS_Frame( count * 4L ) )
3578 goto Fail1;
3580 for ( n = 0; n < count; n++ )
3582 plr[n].SequenceIndex = GET_UShort();
3583 plr[n].LookupListIndex = GET_UShort();
3586 FORGET_Frame();
3588 return TT_Err_Ok;
3590 Fail1:
3591 FREE( plr );
3593 Fail2:
3594 for ( n = 0; n < lookahead_count; n++ )
3595 Free_Coverage( &l[n] );
3597 FREE( l );
3599 Fail3:
3600 for ( n = 0; n < input_count; n++ )
3601 Free_Coverage( &i[n] );
3603 FREE( i );
3605 Fail4:
3606 for ( n = 0; n < backtrack_count; n++ )
3607 Free_Coverage( &b[n] );
3609 FREE( b );
3610 return error;
3614 static void Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3 )
3616 UShort n, count;
3618 TTO_Coverage* c;
3621 FREE( ccpf3->PosLookupRecord );
3623 if ( ccpf3->LookaheadCoverage )
3625 count = ccpf3->LookaheadGlyphCount;
3626 c = ccpf3->LookaheadCoverage;
3628 for ( n = 0; n < count; n++ )
3629 Free_Coverage( &c[n] );
3631 FREE( c );
3634 if ( ccpf3->InputCoverage )
3636 count = ccpf3->InputGlyphCount;
3637 c = ccpf3->InputCoverage;
3639 for ( n = 0; n < count; n++ )
3640 Free_Coverage( &c[n] );
3642 FREE( c );
3645 if ( ccpf3->BacktrackCoverage )
3647 count = ccpf3->BacktrackGlyphCount;
3648 c = ccpf3->BacktrackCoverage;
3650 for ( n = 0; n < count; n++ )
3651 Free_Coverage( &c[n] );
3653 FREE( c );
3658 /* ChainContextPos */
3660 TT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp,
3661 PFace input )
3663 DEFINE_LOAD_LOCALS( input->stream );
3666 if ( ACCESS_Frame( 2L ) )
3667 return error;
3669 ccp->PosFormat = GET_UShort();
3671 FORGET_Frame();
3673 switch ( ccp->PosFormat )
3675 case 1:
3676 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, input );
3678 case 2:
3679 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, input );
3681 case 3:
3682 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, input );
3684 default:
3685 return TTO_Err_Invalid_GPOS_SubTable_Format;
3688 return TT_Err_Ok; /* never reached */
3692 void Free_ChainContextPos( TTO_ChainContextPos* ccp )
3694 switch ( ccp->PosFormat )
3696 case 1:
3697 Free_ChainContext1( &ccp->ccpf.ccpf1 );
3698 break;
3700 case 2:
3701 Free_ChainContext2( &ccp->ccpf.ccpf2 );
3702 break;
3704 case 3:
3705 Free_ChainContext3( &ccp->ccpf.ccpf3 );
3706 break;
3712 /***********
3713 * GPOS API
3714 ***********/
3717 EXPORT_FUNC
3718 TT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos,
3719 TT_ULong script_tag,
3720 TT_UShort* script_index )
3722 UShort n;
3724 TTO_ScriptList* sl;
3725 TTO_ScriptRecord* sr;
3728 if ( !gpos || !script_index )
3729 return TT_Err_Invalid_Argument;
3731 sl = &gpos->ScriptList;
3732 sr = sl->ScriptRecord;
3734 for ( n = 0; n < sl->ScriptCount; n++ )
3735 if ( script_tag == sr[n].ScriptTag )
3737 *script_index = n;
3739 return TT_Err_Ok;
3742 return TTO_Err_Not_Covered;
3746 EXPORT_FUNC
3747 TT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos,
3748 TT_ULong language_tag,
3749 TT_UShort script_index,
3750 TT_UShort* language_index,
3751 TT_UShort* req_feature_index )
3753 UShort n;
3755 TTO_ScriptList* sl;
3756 TTO_ScriptRecord* sr;
3757 TTO_Script* s;
3758 TTO_LangSysRecord* lsr;
3761 if ( !gpos || !language_index || !req_feature_index )
3762 return TT_Err_Invalid_Argument;
3764 sl = &gpos->ScriptList;
3765 sr = sl->ScriptRecord;
3767 if ( script_index >= sl->ScriptCount )
3768 return TT_Err_Invalid_Argument;
3770 s = &sr[script_index].Script;
3771 lsr = s->LangSysRecord;
3773 for ( n = 0; n < s->LangSysCount; n++ )
3774 if ( language_tag == lsr[n].LangSysTag )
3776 *language_index = n;
3777 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
3779 return TT_Err_Ok;
3782 return TTO_Err_Not_Covered;
3786 /* selecting 0xFFFF for language_index asks for the values of the
3787 default language (DefaultLangSys) */
3789 EXPORT_FUNC
3790 TT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos,
3791 TT_ULong feature_tag,
3792 TT_UShort script_index,
3793 TT_UShort language_index,
3794 TT_UShort* feature_index )
3796 UShort n;
3798 TTO_ScriptList* sl;
3799 TTO_ScriptRecord* sr;
3800 TTO_Script* s;
3801 TTO_LangSysRecord* lsr;
3802 TTO_LangSys* ls;
3803 UShort* fi;
3805 TTO_FeatureList* fl;
3806 TTO_FeatureRecord* fr;
3809 if ( !gpos || !feature_index )
3810 return TT_Err_Invalid_Argument;
3812 sl = &gpos->ScriptList;
3813 sr = sl->ScriptRecord;
3815 fl = &gpos->FeatureList;
3816 fr = fl->FeatureRecord;
3818 if ( script_index >= sl->ScriptCount )
3819 return TT_Err_Invalid_Argument;
3821 s = &sr[script_index].Script;
3822 lsr = s->LangSysRecord;
3824 if ( language_index == 0xFFFF )
3825 ls = &s->DefaultLangSys;
3826 else
3828 if ( language_index >= s->LangSysCount )
3829 return TT_Err_Invalid_Argument;
3831 ls = &lsr[language_index].LangSys;
3834 fi = ls->FeatureIndex;
3836 for ( n = 0; n < ls->FeatureCount; n++ )
3838 if ( fi[n] >= fl->FeatureCount )
3839 return TTO_Err_Invalid_GPOS_SubTable_Format;
3841 if ( feature_tag == fr[fi[n]].FeatureTag )
3843 *feature_index = fi[n];
3845 return TT_Err_Ok;
3849 return TTO_Err_Not_Covered;
3853 /* The next three functions return a null-terminated list */
3855 EXPORT_FUNC
3856 TT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos,
3857 TT_ULong** script_tag_list )
3859 UShort n;
3860 TT_Error error;
3861 ULong* stl;
3863 TTO_ScriptList* sl;
3864 TTO_ScriptRecord* sr;
3867 if ( !gpos || !script_tag_list )
3868 return TT_Err_Invalid_Argument;
3870 sl = &gpos->ScriptList;
3871 sr = sl->ScriptRecord;
3873 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, ULong ) )
3874 return error;
3876 for ( n = 0; n < sl->ScriptCount; n++ )
3877 stl[n] = sr[n].ScriptTag;
3878 stl[n] = 0;
3880 *script_tag_list = stl;
3882 return TT_Err_Ok;
3886 EXPORT_FUNC
3887 TT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos,
3888 TT_UShort script_index,
3889 TT_ULong** language_tag_list )
3891 UShort n;
3892 TT_Error error;
3893 ULong* ltl;
3895 TTO_ScriptList* sl;
3896 TTO_ScriptRecord* sr;
3897 TTO_Script* s;
3898 TTO_LangSysRecord* lsr;
3901 if ( !gpos || !language_tag_list )
3902 return TT_Err_Invalid_Argument;
3904 sl = &gpos->ScriptList;
3905 sr = sl->ScriptRecord;
3907 if ( script_index >= sl->ScriptCount )
3908 return TT_Err_Invalid_Argument;
3910 s = &sr[script_index].Script;
3911 lsr = s->LangSysRecord;
3913 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, ULong ) )
3914 return error;
3916 for ( n = 0; n < s->LangSysCount; n++ )
3917 ltl[n] = lsr[n].LangSysTag;
3918 ltl[n] = 0;
3920 *language_tag_list = ltl;
3922 return TT_Err_Ok;
3926 /* selecting 0xFFFF for language_index asks for the values of the
3927 default language (DefaultLangSys) */
3929 EXPORT_FUNC
3930 TT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos,
3931 TT_UShort script_index,
3932 TT_UShort language_index,
3933 TT_ULong** feature_tag_list )
3935 UShort n;
3936 TT_Error error;
3937 ULong* ftl;
3939 TTO_ScriptList* sl;
3940 TTO_ScriptRecord* sr;
3941 TTO_Script* s;
3942 TTO_LangSysRecord* lsr;
3943 TTO_LangSys* ls;
3944 UShort* fi;
3946 TTO_FeatureList* fl;
3947 TTO_FeatureRecord* fr;
3950 if ( !gpos || !feature_tag_list )
3951 return TT_Err_Invalid_Argument;
3953 sl = &gpos->ScriptList;
3954 sr = sl->ScriptRecord;
3956 fl = &gpos->FeatureList;
3957 fr = fl->FeatureRecord;
3959 if ( script_index >= sl->ScriptCount )
3960 return TT_Err_Invalid_Argument;
3962 s = &sr[script_index].Script;
3963 lsr = s->LangSysRecord;
3965 if ( language_index == 0xFFFF )
3966 ls = &s->DefaultLangSys;
3967 else
3969 if ( language_index >= s->LangSysCount )
3970 return TT_Err_Invalid_Argument;
3972 ls = &lsr[language_index].LangSys;
3975 fi = ls->FeatureIndex;
3977 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, ULong ) )
3978 return error;
3980 for ( n = 0; n < ls->FeatureCount; n++ )
3982 if ( fi[n] >= fl->FeatureCount )
3984 FREE( ftl );
3985 return TTO_Err_Invalid_GPOS_SubTable_Format;
3987 ftl[n] = fr[fi[n]].FeatureTag;
3989 ftl[n] = 0;
3991 *feature_tag_list = ftl;
3993 return TT_Err_Ok;
3997 EXPORT_FUNC
3998 TT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos,
3999 TT_UShort feature_index,
4000 TT_UShort property )
4002 UShort i;
4004 TTO_Feature feature;
4005 UShort* properties;
4006 UShort* index;
4009 if ( !gpos ||
4010 feature_index >= gpos->FeatureList.FeatureCount )
4011 return TT_Err_Invalid_Argument;
4013 properties = gpos->LookupList.Properties;
4015 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
4016 index = feature.LookupListIndex;
4018 for ( i = 0; i < feature.LookupListCount; i++ )
4019 properties[index[i]] |= property;
4021 return TT_Err_Ok;
4025 EXPORT_FUNC
4026 TT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos )
4028 UShort i;
4030 UShort* properties;
4033 if ( !gpos )
4034 return TT_Err_Invalid_Argument;
4036 properties = gpos->LookupList.Properties;
4038 for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
4039 properties[i] = 0;
4041 return TT_Err_Ok;
4045 /* END */