#include "tttypes.h"
#include "tttags.h"
#include "ttload.h"
#include "ttextend.h"
#include "ttmemory.h"
#include "ttfile.h"
#include "ftxopen.h"
#include "ftxopenf.h"
#define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' )
static TT_Error GPOS_Create( void* ext,
PFace face )
{
DEFINE_LOAD_LOCALS( face->stream );
TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
Long table;
if ( !gpos )
return TT_Err_Ok;
gpos->offset = 0;
table = TT_LookUp_Table( face, TTAG_GPOS );
if ( table < 0 )
return TT_Err_Ok;
if ( FILE_Seek( face->dirTables[table].Offset ) ||
ACCESS_Frame( 4L ) )
return error;
gpos->offset = FILE_Pos() - 4L;
gpos->Version = GET_ULong();
FORGET_Frame();
gpos->loaded = FALSE;
return TT_Err_Ok;
}
static TT_Error GPOS_Destroy( void* ext,
PFace face )
{
TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
if ( !gpos )
return TT_Err_Ok;
if ( gpos->loaded )
{
Free_LookupList( &gpos->LookupList, GPOS );
Free_FeatureList( &gpos->FeatureList );
Free_ScriptList( &gpos->ScriptList );
}
return TT_Err_Ok;
}
EXPORT_FUNC
TT_Error TT_Init_GPOS_Extension( TT_Engine engine )
{
PEngine_Instance _engine = HANDLE_Engine( engine );
if ( !_engine )
return TT_Err_Invalid_Engine;
return TT_Register_Extension( _engine,
GPOS_ID,
sizeof ( TTO_GPOSHeader ),
GPOS_Create,
GPOS_Destroy );
}
EXPORT_FUNC
TT_Error TT_Load_GPOS_Table( TT_Face face,
TTO_GPOSHeader* retptr,
TTO_GDEFHeader* gdef )
{
ULong cur_offset, new_offset, base_offset;
TT_UShort i, num_lookups;
TT_Error error;
TT_Stream stream;
TTO_GPOSHeader* gpos;
TTO_Lookup* lo;
PFace faze = HANDLE_Face( face );
if ( !retptr )
return TT_Err_Invalid_Argument;
if ( !faze )
return TT_Err_Invalid_Face_Handle;
error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos );
if ( error )
return error;
if ( gpos->offset == 0 )
return TT_Err_Table_Missing;
if ( USE_Stream( faze->stream, stream ) )
return error;
base_offset = gpos->offset;
if ( FILE_Seek( base_offset + 4L ) ||
ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ScriptList( &gpos->ScriptList,
faze ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_FeatureList( &gpos->FeatureList,
faze ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_LookupList( &gpos->LookupList,
faze, GPOS ) ) != TT_Err_Ok )
goto Fail2;
gpos->gdef = gdef;
if ( gdef &&
gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
{
lo = gpos->LookupList.Lookup;
num_lookups = gpos->LookupList.LookupCount;
for ( i = 0; i < num_lookups; i++ )
{
if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
{
if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort();
FORGET_Frame();
if ( !new_offset )
return TTO_Err_Invalid_GDEF_SubTable;
new_offset += base_offset;
if ( FILE_Seek( new_offset ) ||
( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
256, faze ) ) != TT_Err_Ok )
goto Fail1;
break;
}
}
}
gpos->loaded = TRUE;
*retptr = *gpos;
DONE_Stream( stream );
return TT_Err_Ok;
Fail1:
Free_LookupList( &gpos->LookupList, GPOS );
Fail2:
Free_FeatureList( &gpos->FeatureList );
Fail3:
Free_ScriptList( &gpos->ScriptList );
DONE_Stream( stream );
return error;
}
static TT_Error Load_ValueRecord( TTO_ValueRecord* vr,
TT_UShort format,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( format & HAVE_X_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->XPlacement = GET_Short();
FORGET_Frame();
}
else
vr->XPlacement = 0;
if ( format & HAVE_Y_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->YPlacement = GET_Short();
FORGET_Frame();
}
else
vr->YPlacement = 0;
if ( format & HAVE_X_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->XAdvance = GET_Short();
FORGET_Frame();
}
else
vr->XAdvance = 0;
if ( format & HAVE_Y_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->YAdvance = GET_Short();
FORGET_Frame();
}
else
vr->YAdvance = 0;
if ( format & HAVE_X_PLACEMENT_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &vr->XPlacementDevice,
input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
}
else
{
vr->XPlacementDevice.StartSize = 0;
vr->XPlacementDevice.EndSize = 0;
vr->XPlacementDevice.DeltaValue = NULL;
}
if ( format & HAVE_Y_PLACEMENT_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &vr->YPlacementDevice,
input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
}
else
{
vr->YPlacementDevice.StartSize = 0;
vr->YPlacementDevice.EndSize = 0;
vr->YPlacementDevice.DeltaValue = NULL;
}
if ( format & HAVE_X_ADVANCE_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &vr->XAdvanceDevice,
input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
}
else
{
vr->XAdvanceDevice.StartSize = 0;
vr->XAdvanceDevice.EndSize = 0;
vr->XAdvanceDevice.DeltaValue = NULL;
}
if ( format & HAVE_Y_ADVANCE_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &vr->YAdvanceDevice,
input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
{
vr->YAdvanceDevice.StartSize = 0;
vr->YAdvanceDevice.EndSize = 0;
vr->YAdvanceDevice.DeltaValue = NULL;
}
if ( format & HAVE_X_ID_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->XIdPlacement = GET_UShort();
FORGET_Frame();
}
else
vr->XIdPlacement = 0;
if ( format & HAVE_Y_ID_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->YIdPlacement = GET_UShort();
FORGET_Frame();
}
else
vr->YIdPlacement = 0;
if ( format & HAVE_X_ID_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->XIdAdvance = GET_UShort();
FORGET_Frame();
}
else
vr->XIdAdvance = 0;
if ( format & HAVE_Y_ID_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->YIdAdvance = GET_UShort();
FORGET_Frame();
}
else
vr->YIdAdvance = 0;
return TT_Err_Ok;
Fail1:
Free_Device( &vr->YAdvanceDevice );
Fail2:
Free_Device( &vr->XAdvanceDevice );
Fail3:
Free_Device( &vr->YPlacementDevice );
return error;
}
static void Free_ValueRecord( TTO_ValueRecord* vr,
UShort format )
{
if ( format & HAVE_Y_ADVANCE_DEVICE )
Free_Device( &vr->YAdvanceDevice );
if ( format & HAVE_X_ADVANCE_DEVICE )
Free_Device( &vr->XAdvanceDevice );
if ( format & HAVE_Y_PLACEMENT_DEVICE )
Free_Device( &vr->YPlacementDevice );
if ( format & HAVE_X_PLACEMENT_DEVICE )
Free_Device( &vr->XPlacementDevice );
}
static TT_Error Load_Anchor( TTO_Anchor* an,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
an->PosFormat = GET_UShort();
FORGET_Frame();
switch ( an->PosFormat )
{
case 1:
if ( ACCESS_Frame( 4L ) )
return error;
an->af.af1.XCoordinate = GET_Short();
an->af.af1.YCoordinate = GET_Short();
FORGET_Frame();
break;
case 2:
if ( ACCESS_Frame( 6L ) )
return error;
an->af.af2.XCoordinate = GET_Short();
an->af.af2.YCoordinate = GET_Short();
an->af.af2.AnchorPoint = GET_UShort();
FORGET_Frame();
break;
case 3:
if ( ACCESS_Frame( 6L ) )
return error;
an->af.af3.XCoordinate = GET_Short();
an->af.af3.YCoordinate = GET_Short();
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &an->af.af3.XDeviceTable,
input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
}
else
{
an->af.af3.XDeviceTable.StartSize = 0;
an->af.af3.XDeviceTable.EndSize = 0;
an->af.af3.XDeviceTable.DeltaValue = 0;
}
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Device( &an->af.af3.YDeviceTable,
input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
else
{
an->af.af3.YDeviceTable.StartSize = 0;
an->af.af3.YDeviceTable.EndSize = 0;
an->af.af3.YDeviceTable.DeltaValue = 0;
}
break;
case 4:
if ( ACCESS_Frame( 4L ) )
return error;
an->af.af4.XIdAnchor = GET_UShort();
an->af.af4.YIdAnchor = GET_UShort();
FORGET_Frame();
break;
default:
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
return TT_Err_Ok;
Fail:
Free_Device( &an->af.af3.XDeviceTable );
return error;
}
static void Free_Anchor( TTO_Anchor* an )
{
if ( an->PosFormat == 3 )
{
Free_Device( &an->af.af3.YDeviceTable );
Free_Device( &an->af.af3.XDeviceTable );
}
}
static TT_Error Load_MarkArray ( TTO_MarkArray* ma,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_MarkRecord* mr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = ma->MarkCount = GET_UShort();
FORGET_Frame();
ma->MarkRecord = NULL;
if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) )
return error;
mr = ma->MarkRecord;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 4L ) )
goto Fail;
mr[n].Class = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &mr[n].MarkAnchor, input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_Anchor( &mr[n].MarkAnchor );
FREE( mr );
return error;
}
static void Free_MarkArray( TTO_MarkArray* ma )
{
UShort n, count;
TTO_MarkRecord* mr;
if ( ma->MarkRecord )
{
count = ma->MarkCount;
mr = ma->MarkRecord;
for ( n = 0; n < count; n++ )
Free_Anchor( &mr[n].MarkAnchor );
FREE( mr );
}
}
TT_Error Load_SinglePos( TTO_SinglePos* sp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count, format;
ULong cur_offset, new_offset, base_offset;
TTO_ValueRecord* v;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 6L ) )
return error;
sp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
format = sp->ValueFormat = GET_UShort();
FORGET_Frame();
if ( !format )
return TTO_Err_Invalid_GPOS_SubTable;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &sp->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
switch ( sp->PosFormat )
{
case 1:
error = Load_ValueRecord( &sp->spf.spf1.Value, format, input );
if ( error )
goto Fail2;
break;
case 2:
if ( ACCESS_Frame( 2L ) )
goto Fail2;
count = sp->spf.spf2.ValueCount = GET_UShort();
FORGET_Frame();
sp->spf.spf2.Value = NULL;
if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) )
goto Fail2;
v = sp->spf.spf2.Value;
for ( n = 0; n < count; n++ )
{
error = Load_ValueRecord( &v[n], format, input );
if ( error )
goto Fail1;
}
break;
default:
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
Free_ValueRecord( &v[n], format );
FREE( v );
Fail2:
Free_Coverage( &sp->Coverage );
return error;
}
void Free_SinglePos( TTO_SinglePos* sp )
{
UShort n, count, format;
TTO_ValueRecord* v;
format = sp->ValueFormat;
switch ( sp->PosFormat )
{
case 1:
Free_ValueRecord( &sp->spf.spf1.Value, format );
break;
case 2:
if ( sp->spf.spf2.Value )
{
count = sp->spf.spf2.ValueCount;
v = sp->spf.spf2.Value;
for ( n = 0; n < count; n++ )
Free_ValueRecord( &v[n], format );
FREE( v );
}
break;
}
Free_Coverage( &sp->Coverage );
}
static TT_Error Load_PairSet ( TTO_PairSet* ps,
UShort format1,
UShort format2,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
TTO_PairValueRecord* pvr;
if ( ACCESS_Frame( 2L ) )
return error;
count = ps->PairValueCount = GET_UShort();
FORGET_Frame();
ps->PairValueRecord = NULL;
if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) )
return error;
pvr = ps->PairValueRecord;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
pvr[n].SecondGlyph = GET_UShort();
FORGET_Frame();
if ( format1 )
{
error = Load_ValueRecord( &pvr[n].Value1, format1, input );
if ( error )
goto Fail;
}
if ( format2 )
{
error = Load_ValueRecord( &pvr[n].Value2, format2, input );
if ( error )
goto Fail;
}
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
{
if ( format1 )
Free_ValueRecord( &pvr[n].Value1, format1 );
if ( format2 )
Free_ValueRecord( &pvr[n].Value2, format2 );
}
FREE( pvr );
return error;
}
static void Free_PairSet( TTO_PairSet* ps,
UShort format1,
UShort format2 )
{
UShort n, count;
TTO_PairValueRecord* pvr;
if ( ps->PairValueRecord )
{
count = ps->PairValueCount;
pvr = ps->PairValueRecord;
for ( n = 0; n < count; n++ )
{
if ( format1 )
Free_ValueRecord( &pvr[n].Value1, format1 );
if ( format2 )
Free_ValueRecord( &pvr[n].Value2, format2 );
}
FREE( pvr );
}
}
static TT_Error Load_PairPosFormat1( TTO_PairPosFormat1* ppf1,
UShort format1,
UShort format2,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_PairSet* ps;
base_offset = FILE_Pos() - 8L;
if ( ACCESS_Frame( 2L ) )
return error;
count = ppf1->PairSetCount = GET_UShort();
FORGET_Frame();
ppf1->PairSet = NULL;
if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) )
goto Fail;
ps = ppf1->PairSet;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_PairSet( &ps[n], format1,
format2, input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_PairSet( &ps[n], format1, format2 );
FREE( ps );
return error;
}
static void Free_PairPosFormat1( TTO_PairPosFormat1* ppf1,
UShort format1,
UShort format2 )
{
UShort n, count;
TTO_PairSet* ps;
if ( ppf1->PairSet )
{
count = ppf1->PairSetCount;
ps = ppf1->PairSet;
for ( n = 0; n < count; n++ )
Free_PairSet( &ps[n], format1, format2 );
FREE( ps );
}
}
static TT_Error Load_PairPosFormat2( TTO_PairPosFormat2* ppf2,
UShort format1,
UShort format2,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort m, n, count1, count2;
ULong cur_offset, new_offset1, new_offset2, base_offset;
TTO_Class1Record* c1r;
TTO_Class2Record* c2r;
base_offset = FILE_Pos() - 8L;
if ( ACCESS_Frame( 8L ) )
return error;
new_offset1 = GET_UShort() + base_offset;
new_offset2 = GET_UShort() + base_offset;
count1 = ppf2->Class1Count = GET_UShort();
count2 = ppf2->Class2Count = GET_UShort();
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset1 ) ||
( error = Load_ClassDefinition( &ppf2->ClassDef1, count1,
input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset2 ) ||
( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
ppf2->Class1Record = NULL;
if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
goto Fail1;
c1r = ppf2->Class1Record;
for ( m = 0; m < count1; m++ )
{
c1r[m].Class2Record = NULL;
if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) )
goto Fail1;
c2r = c1r[m].Class2Record;
for ( n = 0; n < count2; n++ )
{
if ( format1 )
{
Load_ValueRecord( &c2r[n].Value1, format1, input );
if ( error )
goto Fail1;
}
if ( format2 )
{
Load_ValueRecord( &c2r[n].Value2, format2, input );
if ( error )
goto Fail1;
}
}
}
return TT_Err_Ok;
Fail1:
for ( m = 0; m < count1; m++ )
{
c2r = c1r[m].Class2Record;
for ( n = 0; n < count2; n++ )
{
if ( format1 )
Free_ValueRecord( &c2r[n].Value1, format1 );
if ( format2 )
Free_ValueRecord( &c2r[n].Value2, format2 );
}
FREE( c2r );
}
FREE( c1r );
Free_ClassDefinition( &ppf2->ClassDef2 );
Fail2:
Free_ClassDefinition( &ppf2->ClassDef1 );
return error;
}
static void Free_PairPosFormat2( TTO_PairPosFormat2* ppf2,
UShort format1,
UShort format2 )
{
UShort m, n, count1, count2;
TTO_Class1Record* c1r;
TTO_Class2Record* c2r;
if ( ppf2->Class1Record )
{
c1r = ppf2->Class1Record;
count1 = ppf2->Class1Count;
count2 = ppf2->Class2Count;
for ( m = 0; m < count1; m++ )
{
c2r = c1r[m].Class2Record;
for ( n = 0; n < count2; n++ )
{
if ( format1 )
Free_ValueRecord( &c2r[n].Value1, format1 );
if ( format2 )
Free_ValueRecord( &c2r[n].Value2, format2 );
}
FREE( c2r );
}
FREE( c1r );
Free_ClassDefinition( &ppf2->ClassDef2 );
Free_ClassDefinition( &ppf2->ClassDef1 );
}
}
TT_Error Load_PairPos( TTO_PairPos* pp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort format1, format2;
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 8L ) )
return error;
pp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
format1 = pp->ValueFormat1 = GET_UShort();
format2 = pp->ValueFormat2 = GET_UShort();
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &pp->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
switch ( pp->PosFormat )
{
case 1:
error = Load_PairPosFormat1( &pp->ppf.ppf1, format1, format2, input );
if ( error )
goto Fail;
break;
case 2:
error = Load_PairPosFormat2( &pp->ppf.ppf2, format1, format2, input );
if ( error )
goto Fail;
break;
default:
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
return TT_Err_Ok;
Fail:
Free_Coverage( &pp->Coverage );
return error;
}
void Free_PairPos( TTO_PairPos* pp )
{
UShort format1, format2;
format1 = pp->ValueFormat1;
format2 = pp->ValueFormat2;
switch ( pp->PosFormat )
{
case 1:
Free_PairPosFormat1( &pp->ppf.ppf1, format1, format2 );
break;
case 2:
Free_PairPosFormat2( &pp->ppf.ppf2, format1, format2 );
break;
}
Free_Coverage( &pp->Coverage );
}
TT_Error Load_CursivePos( TTO_CursivePos* cp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_EntryExitRecord* eer;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 4L ) )
return error;
cp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &cp->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail2;
count = cp->EntryExitCount = GET_UShort();
FORGET_Frame();
cp->EntryExitRecord = NULL;
if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) )
goto Fail2;
eer = cp->EntryExitRecord;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &eer[n].EntryAnchor,
input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
eer[n].EntryAnchor.PosFormat = 0;
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &eer[n].ExitAnchor,
input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
eer[n].ExitAnchor.PosFormat = 0;
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
{
Free_Anchor( &eer[n].EntryAnchor );
Free_Anchor( &eer[n].ExitAnchor );
}
FREE( eer );
Fail2:
Free_Coverage( &cp->Coverage );
return error;
}
void Free_CursivePos( TTO_CursivePos* cp )
{
UShort n, count;
TTO_EntryExitRecord* eer;
if ( cp->EntryExitRecord )
{
count = cp->EntryExitCount;
eer = cp->EntryExitRecord;
for ( n = 0; n < count; n++ )
{
Free_Anchor( &eer[n].EntryAnchor );
Free_Anchor( &eer[n].ExitAnchor );
}
FREE( eer );
}
Free_Coverage( &cp->Coverage );
}
static TT_Error Load_BaseArray( TTO_BaseArray* ba,
UShort num_classes,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort m, n, count;
ULong cur_offset, new_offset, base_offset;
TTO_BaseRecord* br;
TTO_Anchor* ban;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = ba->BaseCount = GET_UShort();
FORGET_Frame();
ba->BaseRecord = NULL;
if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) )
return error;
br = ba->BaseRecord;
for ( m = 0; m < count; m++ )
{
br[m].BaseAnchor = NULL;
if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
goto Fail;
ban = br[m].BaseAnchor;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
}
return TT_Err_Ok;
Fail:
for ( m = 0; m < count; m++ )
{
ban = br[m].BaseAnchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &ban[n] );
FREE( ban );
}
FREE( br );
return error;
}
static void Free_BaseArray( TTO_BaseArray* ba,
UShort num_classes )
{
UShort m, n, count;
TTO_BaseRecord* br;
TTO_Anchor* ban;
if ( ba->BaseRecord )
{
count = ba->BaseCount;
br = ba->BaseRecord;
for ( m = 0; m < count; m++ )
{
ban = br[m].BaseAnchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &ban[n] );
FREE( ban );
}
FREE( br );
}
}
TT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 4L ) )
return error;
mbp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mbp->MarkCoverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mbp->BaseCoverage, input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 4L ) )
goto Fail2;
mbp->ClassCount = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_MarkArray( &mbp->MarkArray, input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
input ) ) != TT_Err_Ok )
goto Fail1;
return TT_Err_Ok;
Fail1:
Free_MarkArray( &mbp->MarkArray );
Fail2:
Free_Coverage( &mbp->BaseCoverage );
Fail3:
Free_Coverage( &mbp->MarkCoverage );
return error;
}
void Free_MarkBasePos( TTO_MarkBasePos* mbp )
{
Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
Free_MarkArray( &mbp->MarkArray );
Free_Coverage( &mbp->BaseCoverage );
Free_Coverage( &mbp->MarkCoverage );
}
static TT_Error Load_LigatureAttach( TTO_LigatureAttach* lat,
UShort num_classes,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort m, n, count;
ULong cur_offset, new_offset, base_offset;
TTO_ComponentRecord* cr;
TTO_Anchor* lan;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = lat->ComponentCount = GET_UShort();
FORGET_Frame();
lat->ComponentRecord = NULL;
if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) )
return error;
cr = lat->ComponentRecord;
for ( m = 0; m < count; m++ )
{
cr[m].LigatureAnchor = NULL;
if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) )
goto Fail;
lan = cr[m].LigatureAnchor;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &lan[n], input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
else
lan[n].PosFormat = 0;
}
}
return TT_Err_Ok;
Fail:
for ( m = 0; m < count; m++ )
{
lan = cr[m].LigatureAnchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &lan[n] );
FREE( lan );
}
FREE( cr );
return error;
}
static void Free_LigatureAttach( TTO_LigatureAttach* lat,
UShort num_classes )
{
UShort m, n, count;
TTO_ComponentRecord* cr;
TTO_Anchor* lan;
if ( lat->ComponentRecord )
{
count = lat->ComponentCount;
cr = lat->ComponentRecord;
for ( m = 0; m < count; m++ )
{
lan = cr[m].LigatureAnchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &lan[n] );
FREE( lan );
}
FREE( cr );
}
}
static TT_Error Load_LigatureArray( TTO_LigatureArray* la,
UShort num_classes,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_LigatureAttach* lat;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = la->LigatureCount = GET_UShort();
FORGET_Frame();
la->LigatureAttach = NULL;
if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) )
return error;
lat = la->LigatureAttach;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_LigatureAttach( &lat[n], num_classes,
input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_LigatureAttach( &lat[n], num_classes );
FREE( lat );
return error;
}
static void Free_LigatureArray( TTO_LigatureArray* la,
UShort num_classes )
{
UShort n, count;
TTO_LigatureAttach* lat;
if ( la->LigatureAttach )
{
count = la->LigatureCount;
lat = la->LigatureAttach;
for ( n = 0; n < count; n++ )
Free_LigatureAttach( &lat[n], num_classes );
FREE( lat );
}
}
TT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 4L ) )
return error;
mlp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mlp->MarkCoverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mlp->LigatureCoverage,
input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 4L ) )
goto Fail2;
mlp->ClassCount = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_MarkArray( &mlp->MarkArray, input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
input ) ) != TT_Err_Ok )
goto Fail1;
return TT_Err_Ok;
Fail1:
Free_MarkArray( &mlp->MarkArray );
Fail2:
Free_Coverage( &mlp->LigatureCoverage );
Fail3:
Free_Coverage( &mlp->MarkCoverage );
return error;
}
void Free_MarkLigPos( TTO_MarkLigPos* mlp )
{
Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
Free_MarkArray( &mlp->MarkArray );
Free_Coverage( &mlp->LigatureCoverage );
Free_Coverage( &mlp->MarkCoverage );
}
static TT_Error Load_Mark2Array( TTO_Mark2Array* m2a,
UShort num_classes,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort m, n, count;
ULong cur_offset, new_offset, base_offset;
TTO_Mark2Record* m2r;
TTO_Anchor* m2an;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = m2a->Mark2Count = GET_UShort();
FORGET_Frame();
m2a->Mark2Record = NULL;
if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) )
return error;
m2r = m2a->Mark2Record;
for ( m = 0; m < count; m++ )
{
m2r[m].Mark2Anchor = NULL;
if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
goto Fail;
m2an = m2r[m].Mark2Anchor;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &m2an[n], input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
}
return TT_Err_Ok;
Fail:
for ( m = 0; m < count; m++ )
{
m2an = m2r[m].Mark2Anchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &m2an[n] );
FREE( m2an );
}
FREE( m2r );
return error;
}
static void Free_Mark2Array( TTO_Mark2Array* m2a,
UShort num_classes )
{
UShort m, n, count;
TTO_Mark2Record* m2r;
TTO_Anchor* m2an;
if ( m2a->Mark2Record )
{
count = m2a->Mark2Count;
m2r = m2a->Mark2Record;
for ( m = 0; m < count; m++ )
{
m2an = m2r[m].Mark2Anchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &m2an[n] );
FREE( m2an );
}
FREE( m2r );
}
}
TT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
ULong cur_offset, new_offset, base_offset;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 4L ) )
return error;
mmp->PosFormat = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mmp->Mark1Coverage,
input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &mmp->Mark2Coverage,
input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 4L ) )
goto Fail2;
mmp->ClassCount = GET_UShort();
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_MarkArray( &mmp->Mark1Array, input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
input ) ) != TT_Err_Ok )
goto Fail1;
return TT_Err_Ok;
Fail1:
Free_MarkArray( &mmp->Mark1Array );
Fail2:
Free_Coverage( &mmp->Mark2Coverage );
Fail3:
Free_Coverage( &mmp->Mark1Coverage );
return error;
}
void Free_MarkMarkPos( TTO_MarkMarkPos* mmp )
{
Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
Free_MarkArray( &mmp->Mark1Array );
Free_Coverage( &mmp->Mark2Coverage );
Free_Coverage( &mmp->Mark1Coverage );
}
static TT_Error Load_PosRule( TTO_PosRule* pr,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
UShort* i;
TTO_PosLookupRecord* plr;
if ( ACCESS_Frame( 4L ) )
return error;
pr->GlyphCount = GET_UShort();
pr->PosCount = GET_UShort();
FORGET_Frame();
pr->Input = NULL;
count = pr->GlyphCount - 1;
if ( ALLOC_ARRAY( pr->Input, count, UShort ) )
return error;
i = pr->Input;
if ( ACCESS_Frame( count * 2L ) )
goto Fail2;
for ( n = 0; n < count; n++ )
i[n] = GET_UShort();
FORGET_Frame();
pr->PosLookupRecord = NULL;
count = pr->PosCount;
if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = pr->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( i );
return error;
}
static void Free_PosRule( TTO_PosRule* pr )
{
FREE( pr->PosLookupRecord );
FREE( pr->Input );
}
static TT_Error Load_PosRuleSet( TTO_PosRuleSet* prs,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_PosRule* pr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = prs->PosRuleCount = GET_UShort();
FORGET_Frame();
prs->PosRule = NULL;
if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) )
return error;
pr = prs->PosRule;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_PosRule( &pr[n], input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_PosRule( &pr[n] );
FREE( pr );
return error;
}
static void Free_PosRuleSet( TTO_PosRuleSet* prs )
{
UShort n, count;
TTO_PosRule* pr;
if ( prs->PosRule )
{
count = prs->PosRuleCount;
pr = prs->PosRule;
for ( n = 0; n < count; n++ )
Free_PosRule( &pr[n] );
FREE( pr );
}
}
static TT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_PosRuleSet* prs;
base_offset = FILE_Pos() - 2L;
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &cpf1->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail2;
count = cpf1->PosRuleSetCount = GET_UShort();
FORGET_Frame();
cpf1->PosRuleSet = NULL;
if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) )
goto Fail2;
prs = cpf1->PosRuleSet;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_PosRuleSet( &prs[n], input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
Free_PosRuleSet( &prs[n] );
FREE( prs );
Fail2:
Free_Coverage( &cpf1->Coverage );
return error;
}
static void Free_Context1( TTO_ContextPosFormat1* cpf1 )
{
UShort n, count;
TTO_PosRuleSet* prs;
if ( cpf1->PosRuleSet )
{
count = cpf1->PosRuleSetCount;
prs = cpf1->PosRuleSet;
for ( n = 0; n < count; n++ )
Free_PosRuleSet( &prs[n] );
FREE( prs );
}
Free_Coverage( &cpf1->Coverage );
}
static TT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2,
TTO_PosClassRule* pcr,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
UShort* c;
TTO_PosLookupRecord* plr;
Bool* d;
if ( ACCESS_Frame( 4L ) )
return error;
pcr->GlyphCount = GET_UShort();
pcr->PosCount = GET_UShort();
FORGET_Frame();
if ( pcr->GlyphCount > cpf2->MaxContextLength )
cpf2->MaxContextLength = pcr->GlyphCount;
pcr->Class = NULL;
count = pcr->GlyphCount - 1;
if ( ALLOC_ARRAY( pcr->Class, count, UShort ) )
return error;
c = pcr->Class;
d = cpf2->ClassDef.Defined;
if ( ACCESS_Frame( count * 2L ) )
goto Fail2;
for ( n = 0; n < count; n++ )
{
c[n] = GET_UShort();
if ( !d[c[n]] )
c[n] = 0;
}
FORGET_Frame();
pcr->PosLookupRecord = NULL;
count = pcr->PosCount;
if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = pcr->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( c );
return error;
}
static void Free_PosClassRule( TTO_PosClassRule* pcr )
{
FREE( pcr->PosLookupRecord );
FREE( pcr->Class );
}
static TT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2,
TTO_PosClassSet* pcs,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_PosClassRule* pcr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = pcs->PosClassRuleCount = GET_UShort();
FORGET_Frame();
pcs->PosClassRule = NULL;
if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) )
return error;
pcr = pcs->PosClassRule;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_PosClassRule( cpf2, &pcr[n],
input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_PosClassRule( &pcr[n] );
FREE( pcr );
return error;
}
static void Free_PosClassSet( TTO_PosClassSet* pcs )
{
UShort n, count;
TTO_PosClassRule* pcr;
if ( pcs->PosClassRule )
{
count = pcs->PosClassRuleCount;
pcr = pcs->PosClassRule;
for ( n = 0; n < count; n++ )
Free_PosClassRule( &pcr[n] );
FREE( pcr );
}
}
static TT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_PosClassSet* pcs;
base_offset = FILE_Pos() - 2;
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &cpf2->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 4L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
count = cpf2->PosClassSetCount = GET_UShort();
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ClassDefinition( &cpf2->ClassDef, count,
input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
cpf2->PosClassSet = NULL;
cpf2->MaxContextLength = 0;
if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) )
goto Fail2;
pcs = cpf2->PosClassSet;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
if ( new_offset != base_offset )
{
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_PosClassSet( cpf2, &pcs[n],
input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
{
cpf2->PosClassSet[n].PosClassRuleCount = 0;
cpf2->PosClassSet[n].PosClassRule = NULL;
}
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
Free_PosClassSet( &pcs[n] );
FREE( pcs );
Fail2:
Free_ClassDefinition( &cpf2->ClassDef );
Fail3:
Free_Coverage( &cpf2->Coverage );
return error;
}
static void Free_Context2( TTO_ContextPosFormat2* cpf2 )
{
UShort n, count;
TTO_PosClassSet* pcs;
if ( cpf2->PosClassSet )
{
count = cpf2->PosClassSetCount;
pcs = cpf2->PosClassSet;
for ( n = 0; n < count; n++ )
Free_PosClassSet( &pcs[n] );
FREE( pcs );
}
Free_ClassDefinition( &cpf2->ClassDef );
Free_Coverage( &cpf2->Coverage );
}
static TT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_Coverage* c;
TTO_PosLookupRecord* plr;
base_offset = FILE_Pos() - 2L;
if ( ACCESS_Frame( 4L ) )
return error;
cpf3->GlyphCount = GET_UShort();
cpf3->PosCount = GET_UShort();
FORGET_Frame();
cpf3->Coverage = NULL;
count = cpf3->GlyphCount;
if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) )
return error;
c = cpf3->Coverage;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
}
cpf3->PosLookupRecord = NULL;
count = cpf3->PosCount;
if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = cpf3->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
for ( n = 0; n < count; n++ )
Free_Coverage( &c[n] );
FREE( c );
return error;
}
static void Free_Context3( TTO_ContextPosFormat3* cpf3 )
{
UShort n, count;
TTO_Coverage* c;
FREE( cpf3->PosLookupRecord );
if ( cpf3->Coverage )
{
count = cpf3->GlyphCount;
c = cpf3->Coverage;
for ( n = 0; n < count; n++ )
Free_Coverage( &c[n] );
FREE( c );
}
}
TT_Error Load_ContextPos( TTO_ContextPos* cp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
if ( ACCESS_Frame( 2L ) )
return error;
cp->PosFormat = GET_UShort();
FORGET_Frame();
switch ( cp->PosFormat )
{
case 1:
return Load_ContextPos1( &cp->cpf.cpf1, input );
case 2:
return Load_ContextPos2( &cp->cpf.cpf2, input );
case 3:
return Load_ContextPos3( &cp->cpf.cpf3, input );
default:
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
return TT_Err_Ok;
}
void Free_ContextPos( TTO_ContextPos* cp )
{
switch ( cp->PosFormat )
{
case 1:
Free_Context1( &cp->cpf.cpf1 );
break;
case 2:
Free_Context2( &cp->cpf.cpf2 );
break;
case 3:
Free_Context3( &cp->cpf.cpf3 );
break;
}
}
static TT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
UShort* b;
UShort* i;
UShort* l;
TTO_PosLookupRecord* plr;
if ( ACCESS_Frame( 2L ) )
return error;
cpr->BacktrackGlyphCount = GET_UShort();
FORGET_Frame();
cpr->Backtrack = NULL;
count = cpr->BacktrackGlyphCount;
if ( ALLOC_ARRAY( cpr->Backtrack, count, UShort ) )
return error;
b = cpr->Backtrack;
if ( ACCESS_Frame( count * 2L ) )
goto Fail4;
for ( n = 0; n < count; n++ )
b[n] = GET_UShort();
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail4;
cpr->InputGlyphCount = GET_UShort();
FORGET_Frame();
cpr->Input = NULL;
count = cpr->InputGlyphCount - 1;
if ( ALLOC_ARRAY( cpr->Input, count, UShort ) )
goto Fail4;
i = cpr->Input;
if ( ACCESS_Frame( count * 2L ) )
goto Fail3;
for ( n = 0; n < count; n++ )
i[n] = GET_UShort();
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail3;
cpr->LookaheadGlyphCount = GET_UShort();
FORGET_Frame();
cpr->Lookahead = NULL;
count = cpr->LookaheadGlyphCount;
if ( ALLOC_ARRAY( cpr->Lookahead, count, UShort ) )
goto Fail3;
l = cpr->Lookahead;
if ( ACCESS_Frame( count * 2L ) )
goto Fail2;
for ( n = 0; n < count; n++ )
l[n] = GET_UShort();
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail2;
cpr->PosCount = GET_UShort();
FORGET_Frame();
cpr->PosLookupRecord = NULL;
count = cpr->PosCount;
if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = cpr->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( l );
Fail3:
FREE( i );
Fail4:
FREE( b );
return error;
}
static void Free_ChainPosRule( TTO_ChainPosRule* cpr )
{
FREE( cpr->PosLookupRecord );
FREE( cpr->Lookahead );
FREE( cpr->Input );
FREE( cpr->Backtrack );
}
static TT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_ChainPosRule* cpr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = cprs->ChainPosRuleCount = GET_UShort();
FORGET_Frame();
cprs->ChainPosRule = NULL;
if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) )
return error;
cpr = cprs->ChainPosRule;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ChainPosRule( &cpr[n], input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_ChainPosRule( &cpr[n] );
FREE( cpr );
return error;
}
static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs )
{
UShort n, count;
TTO_ChainPosRule* cpr;
if ( cprs->ChainPosRule )
{
count = cprs->ChainPosRuleCount;
cpr = cprs->ChainPosRule;
for ( n = 0; n < count; n++ )
Free_ChainPosRule( &cpr[n] );
FREE( cpr );
}
}
static TT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_ChainPosRuleSet* cprs;
base_offset = FILE_Pos() - 2L;
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &ccpf1->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 2L ) )
goto Fail2;
count = ccpf1->ChainPosRuleSetCount = GET_UShort();
FORGET_Frame();
ccpf1->ChainPosRuleSet = NULL;
if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) )
goto Fail2;
cprs = ccpf1->ChainPosRuleSet;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ChainPosRuleSet( &cprs[n], input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
Free_ChainPosRuleSet( &cprs[n] );
FREE( cprs );
Fail2:
Free_Coverage( &ccpf1->Coverage );
return error;
}
static void Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1 )
{
UShort n, count;
TTO_ChainPosRuleSet* cprs;
if ( ccpf1->ChainPosRuleSet )
{
count = ccpf1->ChainPosRuleSetCount;
cprs = ccpf1->ChainPosRuleSet;
for ( n = 0; n < count; n++ )
Free_ChainPosRuleSet( &cprs[n] );
FREE( cprs );
}
Free_Coverage( &ccpf1->Coverage );
}
static TT_Error Load_ChainPosClassRule(
TTO_ChainContextPosFormat2* ccpf2,
TTO_ChainPosClassRule* cpcr,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
UShort* b;
UShort* i;
UShort* l;
TTO_PosLookupRecord* plr;
Bool* d;
if ( ACCESS_Frame( 2L ) )
return error;
cpcr->BacktrackGlyphCount = GET_UShort();
FORGET_Frame();
if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
cpcr->Backtrack = NULL;
count = cpcr->BacktrackGlyphCount;
if ( ALLOC_ARRAY( cpcr->Backtrack, count, UShort ) )
return error;
b = cpcr->Backtrack;
d = ccpf2->BacktrackClassDef.Defined;
if ( ACCESS_Frame( count * 2L ) )
goto Fail4;
for ( n = 0; n < count; n++ )
{
b[n] = GET_UShort();
if ( !d[b[n]] )
b[n] = 0;
}
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail4;
cpcr->InputGlyphCount = GET_UShort();
if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
ccpf2->MaxInputLength = cpcr->InputGlyphCount;
FORGET_Frame();
cpcr->Input = NULL;
count = cpcr->InputGlyphCount - 1;
if ( ALLOC_ARRAY( cpcr->Input, count, UShort ) )
goto Fail4;
i = cpcr->Input;
d = ccpf2->InputClassDef.Defined;
if ( ACCESS_Frame( count * 2L ) )
goto Fail3;
for ( n = 0; n < count; n++ )
{
i[n] = GET_UShort();
if ( !d[i[n]] )
i[n] = 0;
}
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail3;
cpcr->LookaheadGlyphCount = GET_UShort();
FORGET_Frame();
if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
cpcr->Lookahead = NULL;
count = cpcr->LookaheadGlyphCount;
if ( ALLOC_ARRAY( cpcr->Lookahead, count, UShort ) )
goto Fail3;
l = cpcr->Lookahead;
d = ccpf2->LookaheadClassDef.Defined;
if ( ACCESS_Frame( count * 2L ) )
goto Fail2;
for ( n = 0; n < count; n++ )
{
l[n] = GET_UShort();
if ( !d[l[n]] )
l[n] = 0;
}
FORGET_Frame();
if ( ACCESS_Frame( 2L ) )
goto Fail2;
cpcr->PosCount = GET_UShort();
FORGET_Frame();
cpcr->PosLookupRecord = NULL;
count = cpcr->PosCount;
if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = cpcr->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( l );
Fail3:
FREE( i );
Fail4:
FREE( b );
return error;
}
static void Free_ChainPosClassRule( TTO_ChainPosClassRule* cpcr )
{
FREE( cpcr->PosLookupRecord );
FREE( cpcr->Lookahead );
FREE( cpcr->Input );
FREE( cpcr->Backtrack );
}
static TT_Error Load_ChainPosClassSet(
TTO_ChainContextPosFormat2* ccpf2,
TTO_ChainPosClassSet* cpcs,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
TTO_ChainPosClassRule* cpcr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = cpcs->ChainPosClassRuleCount = GET_UShort();
FORGET_Frame();
cpcs->ChainPosClassRule = NULL;
if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
TTO_ChainPosClassRule ) )
return error;
cpcr = cpcs->ChainPosClassRule;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
input ) ) != TT_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return TT_Err_Ok;
Fail:
for ( n = 0; n < count; n++ )
Free_ChainPosClassRule( &cpcr[n] );
FREE( cpcr );
return error;
}
static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs )
{
UShort n, count;
TTO_ChainPosClassRule* cpcr;
if ( cpcs->ChainPosClassRule )
{
count = cpcs->ChainPosClassRuleCount;
cpcr = cpcs->ChainPosClassRule;
for ( n = 0; n < count; n++ )
Free_ChainPosClassRule( &cpcr[n] );
FREE( cpcr );
}
}
static TT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
ULong cur_offset, new_offset, base_offset;
ULong backtrack_offset, input_offset, lookahead_offset;
TTO_ChainPosClassSet* cpcs;
base_offset = FILE_Pos() - 2;
if ( ACCESS_Frame( 2L ) )
return error;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &ccpf2->Coverage, input ) ) != TT_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 8L ) )
goto Fail5;
backtrack_offset = GET_UShort() + base_offset;
input_offset = GET_UShort() + base_offset;
lookahead_offset = GET_UShort() + base_offset;
count = ccpf2->ChainPosClassSetCount = GET_UShort();
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( backtrack_offset ) ||
( error = Load_ClassDefinition( &ccpf2->BacktrackClassDef, count,
input ) ) != TT_Err_Ok )
goto Fail5;
if ( FILE_Seek( input_offset ) ||
( error = Load_ClassDefinition( &ccpf2->InputClassDef, count,
input ) ) != TT_Err_Ok )
goto Fail4;
if ( FILE_Seek( lookahead_offset ) ||
( error = Load_ClassDefinition( &ccpf2->LookaheadClassDef, count,
input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
ccpf2->ChainPosClassSet = NULL;
ccpf2->MaxBacktrackLength = 0;
ccpf2->MaxInputLength = 0;
ccpf2->MaxLookaheadLength = 0;
if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) )
goto Fail2;
cpcs = ccpf2->ChainPosClassSet;
for ( n = 0; n < count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
if ( new_offset != base_offset )
{
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
input ) ) != TT_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
{
ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
}
}
return TT_Err_Ok;
Fail1:
for ( n = 0; n < count; n++ )
Free_ChainPosClassSet( &cpcs[n] );
FREE( cpcs );
Fail2:
Free_ClassDefinition( &ccpf2->LookaheadClassDef );
Fail3:
Free_ClassDefinition( &ccpf2->InputClassDef );
Fail4:
Free_ClassDefinition( &ccpf2->BacktrackClassDef );
Fail5:
Free_Coverage( &ccpf2->Coverage );
return error;
}
static void Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2 )
{
UShort n, count;
TTO_ChainPosClassSet* cpcs;
if ( ccpf2->ChainPosClassSet )
{
count = ccpf2->ChainPosClassSetCount;
cpcs = ccpf2->ChainPosClassSet;
for ( n = 0; n < count; n++ )
Free_ChainPosClassSet( &cpcs[n] );
FREE( cpcs );
}
Free_ClassDefinition( &ccpf2->LookaheadClassDef );
Free_ClassDefinition( &ccpf2->InputClassDef );
Free_ClassDefinition( &ccpf2->BacktrackClassDef );
Free_Coverage( &ccpf2->Coverage );
}
static TT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
UShort n, count;
UShort backtrack_count, input_count, lookahead_count;
ULong cur_offset, new_offset, base_offset;
TTO_Coverage* b;
TTO_Coverage* i;
TTO_Coverage* l;
TTO_PosLookupRecord* plr;
base_offset = FILE_Pos() - 2L;
if ( ACCESS_Frame( 2L ) )
return error;
ccpf3->BacktrackGlyphCount = GET_UShort();
FORGET_Frame();
ccpf3->BacktrackCoverage = NULL;
backtrack_count = ccpf3->BacktrackGlyphCount;
if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
TTO_Coverage ) )
return error;
b = ccpf3->BacktrackCoverage;
for ( n = 0; n < backtrack_count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail4;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok )
goto Fail4;
(void)FILE_Seek( cur_offset );
}
if ( ACCESS_Frame( 2L ) )
goto Fail4;
ccpf3->InputGlyphCount = GET_UShort();
FORGET_Frame();
ccpf3->InputCoverage = NULL;
input_count = ccpf3->InputGlyphCount;
if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) )
goto Fail4;
i = ccpf3->InputCoverage;
for ( n = 0; n < input_count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
}
if ( ACCESS_Frame( 2L ) )
goto Fail3;
ccpf3->LookaheadGlyphCount = GET_UShort();
FORGET_Frame();
ccpf3->LookaheadCoverage = NULL;
lookahead_count = ccpf3->LookaheadGlyphCount;
if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
TTO_Coverage ) )
goto Fail3;
l = ccpf3->LookaheadCoverage;
for ( n = 0; n < lookahead_count; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
}
if ( ACCESS_Frame( 2L ) )
goto Fail2;
ccpf3->PosCount = GET_UShort();
FORGET_Frame();
ccpf3->PosLookupRecord = NULL;
count = ccpf3->PosCount;
if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
goto Fail2;
plr = ccpf3->PosLookupRecord;
if ( ACCESS_Frame( count * 4L ) )
goto Fail1;
for ( n = 0; n < count; n++ )
{
plr[n].SequenceIndex = GET_UShort();
plr[n].LookupListIndex = GET_UShort();
}
FORGET_Frame();
return TT_Err_Ok;
Fail1:
FREE( plr );
Fail2:
for ( n = 0; n < lookahead_count; n++ )
Free_Coverage( &l[n] );
FREE( l );
Fail3:
for ( n = 0; n < input_count; n++ )
Free_Coverage( &i[n] );
FREE( i );
Fail4:
for ( n = 0; n < backtrack_count; n++ )
Free_Coverage( &b[n] );
FREE( b );
return error;
}
static void Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3 )
{
UShort n, count;
TTO_Coverage* c;
FREE( ccpf3->PosLookupRecord );
if ( ccpf3->LookaheadCoverage )
{
count = ccpf3->LookaheadGlyphCount;
c = ccpf3->LookaheadCoverage;
for ( n = 0; n < count; n++ )
Free_Coverage( &c[n] );
FREE( c );
}
if ( ccpf3->InputCoverage )
{
count = ccpf3->InputGlyphCount;
c = ccpf3->InputCoverage;
for ( n = 0; n < count; n++ )
Free_Coverage( &c[n] );
FREE( c );
}
if ( ccpf3->BacktrackCoverage )
{
count = ccpf3->BacktrackGlyphCount;
c = ccpf3->BacktrackCoverage;
for ( n = 0; n < count; n++ )
Free_Coverage( &c[n] );
FREE( c );
}
}
TT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp,
PFace input )
{
DEFINE_LOAD_LOCALS( input->stream );
if ( ACCESS_Frame( 2L ) )
return error;
ccp->PosFormat = GET_UShort();
FORGET_Frame();
switch ( ccp->PosFormat )
{
case 1:
return Load_ChainContextPos1( &ccp->ccpf.ccpf1, input );
case 2:
return Load_ChainContextPos2( &ccp->ccpf.ccpf2, input );
case 3:
return Load_ChainContextPos3( &ccp->ccpf.ccpf3, input );
default:
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
return TT_Err_Ok;
}
void Free_ChainContextPos( TTO_ChainContextPos* ccp )
{
switch ( ccp->PosFormat )
{
case 1:
Free_ChainContext1( &ccp->ccpf.ccpf1 );
break;
case 2:
Free_ChainContext2( &ccp->ccpf.ccpf2 );
break;
case 3:
Free_ChainContext3( &ccp->ccpf.ccpf3 );
break;
}
}
EXPORT_FUNC
TT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos,
TT_ULong script_tag,
TT_UShort* script_index )
{
UShort n;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
if ( !gpos || !script_index )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
for ( n = 0; n < sl->ScriptCount; n++ )
if ( script_tag == sr[n].ScriptTag )
{
*script_index = n;
return TT_Err_Ok;
}
return TTO_Err_Not_Covered;
}
EXPORT_FUNC
TT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos,
TT_ULong language_tag,
TT_UShort script_index,
TT_UShort* language_index,
TT_UShort* req_feature_index )
{
UShort n;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
TTO_Script* s;
TTO_LangSysRecord* lsr;
if ( !gpos || !language_index || !req_feature_index )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( script_index >= sl->ScriptCount )
return TT_Err_Invalid_Argument;
s = &sr[script_index].Script;
lsr = s->LangSysRecord;
for ( n = 0; n < s->LangSysCount; n++ )
if ( language_tag == lsr[n].LangSysTag )
{
*language_index = n;
*req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
return TT_Err_Ok;
}
return TTO_Err_Not_Covered;
}
EXPORT_FUNC
TT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos,
TT_ULong feature_tag,
TT_UShort script_index,
TT_UShort language_index,
TT_UShort* feature_index )
{
UShort n;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
TTO_Script* s;
TTO_LangSysRecord* lsr;
TTO_LangSys* ls;
UShort* fi;
TTO_FeatureList* fl;
TTO_FeatureRecord* fr;
if ( !gpos || !feature_index )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
fl = &gpos->FeatureList;
fr = fl->FeatureRecord;
if ( script_index >= sl->ScriptCount )
return TT_Err_Invalid_Argument;
s = &sr[script_index].Script;
lsr = s->LangSysRecord;
if ( language_index == 0xFFFF )
ls = &s->DefaultLangSys;
else
{
if ( language_index >= s->LangSysCount )
return TT_Err_Invalid_Argument;
ls = &lsr[language_index].LangSys;
}
fi = ls->FeatureIndex;
for ( n = 0; n < ls->FeatureCount; n++ )
{
if ( fi[n] >= fl->FeatureCount )
return TTO_Err_Invalid_GPOS_SubTable_Format;
if ( feature_tag == fr[fi[n]].FeatureTag )
{
*feature_index = fi[n];
return TT_Err_Ok;
}
}
return TTO_Err_Not_Covered;
}
EXPORT_FUNC
TT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos,
TT_ULong** script_tag_list )
{
UShort n;
TT_Error error;
ULong* stl;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
if ( !gpos || !script_tag_list )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, ULong ) )
return error;
for ( n = 0; n < sl->ScriptCount; n++ )
stl[n] = sr[n].ScriptTag;
stl[n] = 0;
*script_tag_list = stl;
return TT_Err_Ok;
}
EXPORT_FUNC
TT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos,
TT_UShort script_index,
TT_ULong** language_tag_list )
{
UShort n;
TT_Error error;
ULong* ltl;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
TTO_Script* s;
TTO_LangSysRecord* lsr;
if ( !gpos || !language_tag_list )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( script_index >= sl->ScriptCount )
return TT_Err_Invalid_Argument;
s = &sr[script_index].Script;
lsr = s->LangSysRecord;
if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, ULong ) )
return error;
for ( n = 0; n < s->LangSysCount; n++ )
ltl[n] = lsr[n].LangSysTag;
ltl[n] = 0;
*language_tag_list = ltl;
return TT_Err_Ok;
}
EXPORT_FUNC
TT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos,
TT_UShort script_index,
TT_UShort language_index,
TT_ULong** feature_tag_list )
{
UShort n;
TT_Error error;
ULong* ftl;
TTO_ScriptList* sl;
TTO_ScriptRecord* sr;
TTO_Script* s;
TTO_LangSysRecord* lsr;
TTO_LangSys* ls;
UShort* fi;
TTO_FeatureList* fl;
TTO_FeatureRecord* fr;
if ( !gpos || !feature_tag_list )
return TT_Err_Invalid_Argument;
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
fl = &gpos->FeatureList;
fr = fl->FeatureRecord;
if ( script_index >= sl->ScriptCount )
return TT_Err_Invalid_Argument;
s = &sr[script_index].Script;
lsr = s->LangSysRecord;
if ( language_index == 0xFFFF )
ls = &s->DefaultLangSys;
else
{
if ( language_index >= s->LangSysCount )
return TT_Err_Invalid_Argument;
ls = &lsr[language_index].LangSys;
}
fi = ls->FeatureIndex;
if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, ULong ) )
return error;
for ( n = 0; n < ls->FeatureCount; n++ )
{
if ( fi[n] >= fl->FeatureCount )
{
FREE( ftl );
return TTO_Err_Invalid_GPOS_SubTable_Format;
}
ftl[n] = fr[fi[n]].FeatureTag;
}
ftl[n] = 0;
*feature_tag_list = ftl;
return TT_Err_Ok;
}
EXPORT_FUNC
TT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos,
TT_UShort feature_index,
TT_UShort property )
{
UShort i;
TTO_Feature feature;
UShort* properties;
UShort* index;
if ( !gpos ||
feature_index >= gpos->FeatureList.FeatureCount )
return TT_Err_Invalid_Argument;
properties = gpos->LookupList.Properties;
feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
index = feature.LookupListIndex;
for ( i = 0; i < feature.LookupListCount; i++ )
properties[index[i]] |= property;
return TT_Err_Ok;
}
EXPORT_FUNC
TT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos )
{
UShort i;
UShort* properties;
if ( !gpos )
return TT_Err_Invalid_Argument;
properties = gpos->LookupList.Properties;
for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
properties[i] = 0;
return TT_Err_Ok;
}