#include "harfbuzz-impl.h"
#include "harfbuzz-gpos-private.h"
#include "harfbuzz-open-private.h"
#include "harfbuzz-gdef-private.h"
#include "harfbuzz-shaper.h"
struct GPOS_Instance_
{
HB_GPOSHeader* gpos;
HB_Font font;
HB_Bool dvi;
HB_UShort load_flags;
HB_Bool r2l;
HB_UShort last;
HB_Fixed anchor_x;
HB_Fixed anchor_y;
};
typedef struct GPOS_Instance_ GPOS_Instance;
static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
HB_UShort lookup_index,
HB_Buffer buffer,
HB_UShort context_length,
int nesting_level );
static HB_Error default_mmfunc( HB_Font font,
HB_UShort metric_id,
HB_Fixed* metric_value,
void* data )
{
HB_UNUSED(font);
HB_UNUSED(metric_id);
HB_UNUSED(metric_value);
HB_UNUSED(data);
return ERR(HB_Err_Not_Covered);
}
HB_Error HB_Load_GPOS_Table( HB_Stream stream,
HB_GPOSHeader** retptr,
HB_GDEFHeader* gdef,
HB_Stream gdefStream )
{
HB_UInt cur_offset, new_offset, base_offset;
HB_GPOSHeader* gpos;
HB_Error error;
if ( !retptr )
return ERR(HB_Err_Invalid_Argument);
if ( GOTO_Table( TTAG_GPOS ) )
return error;
base_offset = FILE_Pos();
if ( ALLOC ( gpos, sizeof( *gpos ) ) )
return error;
gpos->mmfunc = default_mmfunc;
if ( FILE_Seek( base_offset + 4L ) ||
ACCESS_Frame( 2L ) )
goto Fail4;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
stream ) ) != HB_Err_Ok )
goto Fail4;
(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 = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
stream ) ) != HB_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 = _HB_OPEN_Load_LookupList( &gpos->LookupList,
stream, HB_Type_GPOS ) ) != HB_Err_Ok )
goto Fail2;
gpos->gdef = gdef;
if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
gpos->LookupList.Lookup,
gpos->LookupList.LookupCount ) ) )
goto Fail1;
*retptr = gpos;
return HB_Err_Ok;
Fail1:
_HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
Fail2:
_HB_OPEN_Free_FeatureList( &gpos->FeatureList );
Fail3:
_HB_OPEN_Free_ScriptList( &gpos->ScriptList );
Fail4:
FREE( gpos );
return error;
}
HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
{
_HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
_HB_OPEN_Free_FeatureList( &gpos->FeatureList );
_HB_OPEN_Free_ScriptList( &gpos->ScriptList );
FREE( gpos );
return HB_Err_Ok;
}
static HB_Error Load_ValueRecord( HB_ValueRecord* vr,
HB_UShort format,
HB_UInt base_offset,
HB_Stream stream )
{
HB_Error error;
HB_UInt cur_offset, new_offset;
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->XPlacement = GET_Short();
FORGET_Frame();
}
else
vr->XPlacement = 0;
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->YPlacement = GET_Short();
FORGET_Frame();
}
else
vr->YPlacement = 0;
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->XAdvance = GET_Short();
FORGET_Frame();
}
else
vr->XAdvance = 0;
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
return error;
vr->YAdvance = GET_Short();
FORGET_Frame();
}
else
vr->YAdvance = 0;
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
{
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 = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
stream ) ) != HB_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
}
else
goto empty1;
}
else
{
empty1:
vr->XPlacementDevice.StartSize = 0;
vr->XPlacementDevice.EndSize = 0;
vr->XPlacementDevice.DeltaValue = NULL;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
stream ) ) != HB_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
}
else
goto empty2;
}
else
{
empty2:
vr->YPlacementDevice.StartSize = 0;
vr->YPlacementDevice.EndSize = 0;
vr->YPlacementDevice.DeltaValue = NULL;
}
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
stream ) ) != HB_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
}
else
goto empty3;
}
else
{
empty3:
vr->XAdvanceDevice.StartSize = 0;
vr->XAdvanceDevice.EndSize = 0;
vr->XAdvanceDevice.DeltaValue = NULL;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
new_offset = GET_UShort();
FORGET_Frame();
if ( new_offset )
{
new_offset += base_offset;
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
stream ) ) != HB_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
goto empty4;
}
else
{
empty4:
vr->YAdvanceDevice.StartSize = 0;
vr->YAdvanceDevice.EndSize = 0;
vr->YAdvanceDevice.DeltaValue = NULL;
}
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->XIdPlacement = GET_UShort();
FORGET_Frame();
}
else
vr->XIdPlacement = 0;
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->YIdPlacement = GET_UShort();
FORGET_Frame();
}
else
vr->YIdPlacement = 0;
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->XIdAdvance = GET_UShort();
FORGET_Frame();
}
else
vr->XIdAdvance = 0;
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
{
if ( ACCESS_Frame( 2L ) )
goto Fail1;
vr->YIdAdvance = GET_UShort();
FORGET_Frame();
}
else
vr->YIdAdvance = 0;
return HB_Err_Ok;
Fail1:
_HB_OPEN_Free_Device( &vr->YAdvanceDevice );
Fail2:
_HB_OPEN_Free_Device( &vr->XAdvanceDevice );
Fail3:
_HB_OPEN_Free_Device( &vr->YPlacementDevice );
return error;
}
static void Free_ValueRecord( HB_ValueRecord* vr,
HB_UShort format )
{
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
_HB_OPEN_Free_Device( &vr->YAdvanceDevice );
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
_HB_OPEN_Free_Device( &vr->XAdvanceDevice );
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
_HB_OPEN_Free_Device( &vr->YPlacementDevice );
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
_HB_OPEN_Free_Device( &vr->XPlacementDevice );
}
static HB_Error Get_ValueRecord( GPOS_Instance* gpi,
HB_ValueRecord* vr,
HB_UShort format,
HB_Position gd )
{
HB_Fixed value;
HB_Short pixel_value;
HB_Error error = HB_Err_Ok;
HB_GPOSHeader* gpos = gpi->gpos;
HB_UShort x_ppem, y_ppem;
HB_16Dot16 x_scale, y_scale;
if ( !format )
return HB_Err_Ok;
x_ppem = gpi->font->x_ppem;
y_ppem = gpi->font->y_ppem;
x_scale = gpi->font->x_scale;
y_scale = gpi->font->y_scale;
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
gd->x_pos += x_scale * vr->XPlacement / 0x10000;
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
gd->y_pos += y_scale * vr->YPlacement / 0x10000;
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
gd->x_advance += x_scale * vr->XAdvance / 0x10000;
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
gd->y_advance += y_scale * vr->YAdvance / 0x10000;
if ( !gpi->dvi )
{
if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
{
_HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
gd->x_pos += pixel_value << 6;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
{
_HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
gd->y_pos += pixel_value << 6;
}
if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
{
_HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
gd->x_advance += pixel_value << 6;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
{
_HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
gd->y_advance += pixel_value << 6;
}
}
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
{
error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
&value, gpos->data );
if ( error )
return error;
gd->x_pos += value;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
{
error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
&value, gpos->data );
if ( error )
return error;
gd->y_pos += value;
}
if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
{
error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
&value, gpos->data );
if ( error )
return error;
gd->x_advance += value;
}
if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
{
error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
&value, gpos->data );
if ( error )
return error;
gd->y_advance += value;
}
return error;
}
static HB_Error Load_Anchor( HB_Anchor* an,
HB_Stream stream )
{
HB_Error error;
HB_UInt 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 = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
stream ) ) != HB_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 = NULL;
}
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 = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
stream ) ) != HB_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 = NULL;
}
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 ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
Fail:
_HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
return error;
}
static void Free_Anchor( HB_Anchor* an)
{
if ( an->PosFormat == 3 )
{
_HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
_HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
}
}
static HB_Error Get_Anchor( GPOS_Instance* gpi,
HB_Anchor* an,
HB_UShort glyph_index,
HB_Fixed* x_value,
HB_Fixed* y_value )
{
HB_Error error = HB_Err_Ok;
HB_GPOSHeader* gpos = gpi->gpos;
HB_UShort ap;
HB_Short pixel_value;
HB_UShort x_ppem, y_ppem;
HB_16Dot16 x_scale, y_scale;
x_ppem = gpi->font->x_ppem;
y_ppem = gpi->font->y_ppem;
x_scale = gpi->font->x_scale;
y_scale = gpi->font->y_scale;
switch ( an->PosFormat )
{
case 0:
default:
return HB_Err_Not_Covered;
case 1:
*x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
*y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
break;
case 2:
if ( !gpi->dvi )
{
hb_uint32 n_points = 0;
ap = an->af.af2.AnchorPoint;
if (!gpi->font->klass->getPointInOutline)
goto no_contour_point;
error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points);
if (error)
return error;
if (!n_points)
goto no_contour_point;
}
else
{
no_contour_point:
*x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
*y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
}
break;
case 3:
if ( !gpi->dvi )
{
_HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
*x_value = pixel_value << 6;
_HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
*y_value = pixel_value << 6;
}
else
*x_value = *y_value = 0;
*x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
*y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
break;
case 4:
error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
x_value, gpos->data );
if ( error )
return error;
error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
y_value, gpos->data );
if ( error )
return error;
break;
}
return error;
}
static HB_Error Load_MarkArray ( HB_MarkArray* ma,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_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, stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_Anchor( &mr[m].MarkAnchor );
FREE( mr );
return error;
}
static void Free_MarkArray( HB_MarkArray* ma )
{
HB_UShort n, count;
HB_MarkRecord* mr;
if ( ma->MarkRecord )
{
count = ma->MarkCount;
mr = ma->MarkRecord;
for ( n = 0; n < count; n++ )
Free_Anchor( &mr[n].MarkAnchor );
FREE( mr );
}
}
static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_SinglePos* sp = &st->single;
HB_UShort n, m, count, format;
HB_UInt cur_offset, new_offset, base_offset;
HB_ValueRecord* vr;
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 ERR(HB_Err_Invalid_SubTable);
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
switch ( sp->PosFormat )
{
case 1:
error = Load_ValueRecord( &sp->spf.spf1.Value, format,
base_offset, stream );
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, HB_ValueRecord ) )
goto Fail2;
vr = sp->spf.spf2.Value;
for ( n = 0; n < count; n++ )
{
error = Load_ValueRecord( &vr[n], format, base_offset, stream );
if ( error )
goto Fail1;
}
break;
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; m++ )
Free_ValueRecord( &vr[m], format );
FREE( vr );
Fail2:
_HB_OPEN_Free_Coverage( &sp->Coverage );
return error;
}
static void Free_SinglePos( HB_GPOS_SubTable* st )
{
HB_UShort n, count, format;
HB_SinglePos* sp = &st->single;
HB_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;
default:
break;
}
_HB_OPEN_Free_Coverage( &sp->Coverage );
}
static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_SinglePos* sp = &st->single;
HB_UNUSED(nesting_level);
if ( context_length != 0xFFFF && context_length < 1 )
return HB_Err_Not_Covered;
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
switch ( sp->PosFormat )
{
case 1:
error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
sp->ValueFormat, POSITION( buffer->in_pos ) );
if ( error )
return error;
break;
case 2:
if ( index >= sp->spf.spf2.ValueCount )
return ERR(HB_Err_Invalid_SubTable);
error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
sp->ValueFormat, POSITION( buffer->in_pos ) );
if ( error )
return error;
break;
default:
return ERR(HB_Err_Invalid_SubTable);
}
(buffer->in_pos)++;
return HB_Err_Ok;
}
static HB_Error Load_PairSet ( HB_PairSet* ps,
HB_UShort format1,
HB_UShort format2,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt base_offset;
HB_PairValueRecord* pvr;
base_offset = FILE_Pos();
if ( ACCESS_Frame( 2L ) )
return error;
count = ps->PairValueCount = GET_UShort();
FORGET_Frame();
ps->PairValueRecord = NULL;
if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_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,
base_offset, stream );
if ( error )
goto Fail;
}
if ( format2 )
{
error = Load_ValueRecord( &pvr[n].Value2, format2,
base_offset, stream );
if ( error )
{
if ( format1 )
Free_ValueRecord( &pvr[n].Value1, format1 );
goto Fail;
}
}
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
{
if ( format1 )
Free_ValueRecord( &pvr[m].Value1, format1 );
if ( format2 )
Free_ValueRecord( &pvr[m].Value2, format2 );
}
FREE( pvr );
return error;
}
static void Free_PairSet( HB_PairSet* ps,
HB_UShort format1,
HB_UShort format2 )
{
HB_UShort n, count;
HB_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 HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
HB_UShort format1,
HB_UShort format2,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_PairSet ) )
return error;
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, stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_PairSet( &ps[m], format1, format2 );
FREE( ps );
return error;
}
static void Free_PairPos1( HB_PairPosFormat1* ppf1,
HB_UShort format1,
HB_UShort format2 )
{
HB_UShort n, count;
HB_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 HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
HB_UShort format1,
HB_UShort format2,
HB_Stream stream )
{
HB_Error error;
HB_UShort m, n, k, count1, count2;
HB_UInt cur_offset, new_offset1, new_offset2, base_offset;
HB_Class1Record* c1r;
HB_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 = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
stream ) ) != HB_Err_Ok )
return error;
if ( FILE_Seek( new_offset2 ) ||
( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
stream ) ) != HB_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
ppf2->Class1Record = NULL;
if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
goto Fail2;
c1r = ppf2->Class1Record;
for ( m = 0; m < count1; m++ )
{
c1r[m].Class2Record = NULL;
if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
goto Fail1;
c2r = c1r[m].Class2Record;
for ( n = 0; n < count2; n++ )
{
if ( format1 )
{
error = Load_ValueRecord( &c2r[n].Value1, format1,
base_offset, stream );
if ( error )
goto Fail0;
}
if ( format2 )
{
error = Load_ValueRecord( &c2r[n].Value2, format2,
base_offset, stream );
if ( error )
{
if ( format1 )
Free_ValueRecord( &c2r[n].Value1, format1 );
goto Fail0;
}
}
}
continue;
Fail0:
for ( k = 0; k < n; k++ )
{
if ( format1 )
Free_ValueRecord( &c2r[k].Value1, format1 );
if ( format2 )
Free_ValueRecord( &c2r[k].Value2, format2 );
}
goto Fail1;
}
return HB_Err_Ok;
Fail1:
for ( k = 0; k < m; k++ )
{
c2r = c1r[k].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 );
Fail2:
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
Fail3:
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
return error;
}
static void Free_PairPos2( HB_PairPosFormat2* ppf2,
HB_UShort format1,
HB_UShort format2)
{
HB_UShort m, n, count1, count2;
HB_Class1Record* c1r;
HB_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 );
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
_HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
}
}
static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_PairPos* pp = &st->pair;
HB_UShort format1, format2;
HB_UInt 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 = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
switch ( pp->PosFormat )
{
case 1:
error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
if ( error )
goto Fail;
break;
case 2:
error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
if ( error )
goto Fail;
break;
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
Fail:
_HB_OPEN_Free_Coverage( &pp->Coverage );
return error;
}
static void Free_PairPos( HB_GPOS_SubTable* st )
{
HB_UShort format1, format2;
HB_PairPos* pp = &st->pair;
format1 = pp->ValueFormat1;
format2 = pp->ValueFormat2;
switch ( pp->PosFormat )
{
case 1:
Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
break;
case 2:
Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
break;
default:
break;
}
_HB_OPEN_Free_Coverage( &pp->Coverage );
}
static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
HB_PairPosFormat1* ppf1,
HB_Buffer buffer,
HB_UInt first_pos,
HB_UShort index,
HB_UShort format1,
HB_UShort format2 )
{
HB_Error error;
HB_UShort numpvr, glyph2;
HB_PairValueRecord* pvr;
if ( index >= ppf1->PairSetCount )
return ERR(HB_Err_Invalid_SubTable);
pvr = ppf1->PairSet[index].PairValueRecord;
if ( !pvr )
return ERR(HB_Err_Invalid_SubTable);
glyph2 = IN_CURGLYPH();
for ( numpvr = ppf1->PairSet[index].PairValueCount;
numpvr;
numpvr--, pvr++ )
{
if ( glyph2 == pvr->SecondGlyph )
{
error = Get_ValueRecord( gpi, &pvr->Value1, format1,
POSITION( first_pos ) );
if ( error )
return error;
return Get_ValueRecord( gpi, &pvr->Value2, format2,
POSITION( buffer->in_pos ) );
}
}
return HB_Err_Not_Covered;
}
static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
HB_PairPosFormat2* ppf2,
HB_Buffer buffer,
HB_UInt first_pos,
HB_UShort format1,
HB_UShort format2 )
{
HB_Error error;
HB_UShort cl1 = 0, cl2 = 0;
HB_Class1Record* c1r;
HB_Class2Record* c2r;
error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
&cl1, NULL );
if ( error && error != HB_Err_Not_Covered )
return error;
error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
&cl2, NULL );
if ( error && error != HB_Err_Not_Covered )
return error;
c1r = &ppf2->Class1Record[cl1];
if ( !c1r )
return ERR(HB_Err_Invalid_SubTable);
c2r = &c1r->Class2Record[cl2];
error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
if ( error )
return error;
return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
}
static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_Error error;
HB_UShort index, property;
HB_UInt first_pos;
HB_GPOSHeader* gpos = gpi->gpos;
HB_PairPos* pp = &st->pair;
HB_UNUSED(nesting_level);
if ( buffer->in_pos >= buffer->in_length - 1 )
return HB_Err_Not_Covered;
if ( context_length != 0xFFFF && context_length < 2 )
return HB_Err_Not_Covered;
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
first_pos = buffer->in_pos;
(buffer->in_pos)++;
while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( buffer->in_pos == buffer->in_length )
{
buffer->in_pos = first_pos;
return HB_Err_Not_Covered;
}
(buffer->in_pos)++;
}
switch ( pp->PosFormat )
{
case 1:
error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
first_pos, index,
pp->ValueFormat1, pp->ValueFormat2 );
break;
case 2:
error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
pp->ValueFormat1, pp->ValueFormat2 );
break;
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
if ( error == HB_Err_Not_Covered )
buffer->in_pos = first_pos;
if ( pp->ValueFormat2 )
(buffer->in_pos)++;
return error;
}
static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_CursivePos* cp = &st->cursive;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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 = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_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, HB_EntryExitRecord ) )
goto Fail2;
eer = cp->EntryExitRecord;
for ( n = 0; n < count; n++ )
{
HB_UInt entry_offset;
if ( ACCESS_Frame( 2L ) )
return error;
entry_offset = 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,
stream ) ) != HB_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,
stream ) ) != HB_Err_Ok )
{
if ( entry_offset )
Free_Anchor( &eer[n].EntryAnchor );
goto Fail1;
}
(void)FILE_Seek( cur_offset );
}
else
eer[n].ExitAnchor.PosFormat = 0;
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; m++ )
{
Free_Anchor( &eer[m].EntryAnchor );
Free_Anchor( &eer[m].ExitAnchor );
}
FREE( eer );
Fail2:
_HB_OPEN_Free_Coverage( &cp->Coverage );
return error;
}
static void Free_CursivePos( HB_GPOS_SubTable* st )
{
HB_UShort n, count;
HB_CursivePos* cp = &st->cursive;
HB_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 );
}
_HB_OPEN_Free_Coverage( &cp->Coverage );
}
static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_CursivePos* cp = &st->cursive;
HB_EntryExitRecord* eer;
HB_Fixed entry_x, entry_y;
HB_Fixed exit_x, exit_y;
HB_UNUSED(nesting_level);
if ( context_length != 0xFFFF && context_length < 1 )
{
gpi->last = 0xFFFF;
return HB_Err_Not_Covered;
}
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
return error;
if ( property == HB_GDEF_MARK )
{
gpi->last = 0xFFFF;
return HB_Err_Not_Covered;
}
error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
if ( error )
{
gpi->last = 0xFFFF;
return error;
}
if ( index >= cp->EntryExitCount )
return ERR(HB_Err_Invalid_SubTable);
eer = &cp->EntryExitRecord[index];
if ( gpi->last == 0xFFFF )
goto end;
error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
&entry_x, &entry_y );
if ( error == HB_Err_Not_Covered )
goto end;
if ( error )
return error;
if ( gpi->r2l )
{
POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
POSITION( buffer->in_pos )->new_advance = TRUE;
}
else
{
POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
POSITION( gpi->last )->new_advance = TRUE;
}
if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
{
POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
}
else
{
POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
}
end:
error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
&exit_x, &exit_y );
if ( error == HB_Err_Not_Covered )
gpi->last = 0xFFFF;
else
{
gpi->last = buffer->in_pos;
gpi->anchor_x = exit_x;
gpi->anchor_y = exit_y;
}
if ( error )
return error;
(buffer->in_pos)++;
return HB_Err_Ok;
}
static HB_Error Load_BaseArray( HB_BaseArray* ba,
HB_UShort num_classes,
HB_Stream stream )
{
HB_Error error;
HB_UShort m, n, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_BaseRecord *br;
HB_Anchor *ban, *bans;
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, HB_BaseRecord ) )
return error;
br = ba->BaseRecord;
bans = NULL;
if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
goto Fail;
for ( m = 0; m < count; m++ )
{
br[m].BaseAnchor = NULL;
ban = br[m].BaseAnchor = bans + m * num_classes;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
if (new_offset == base_offset) {
ban[n].PosFormat = 0;
continue;
}
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
}
return HB_Err_Ok;
Fail:
FREE( bans );
FREE( br );
return error;
}
static void Free_BaseArray( HB_BaseArray* ba,
HB_UShort num_classes )
{
HB_BaseRecord *br;
HB_Anchor *bans;
if ( ba->BaseRecord )
{
br = ba->BaseRecord;
if ( ba->BaseCount )
{
HB_UShort i, count;
count = num_classes * ba->BaseCount;
bans = br[0].BaseAnchor;
for (i = 0; i < count; i++)
Free_Anchor (&bans[i]);
FREE( bans );
}
FREE( br );
}
}
static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_MarkBasePos* mbp = &st->markbase;
HB_UInt 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();
if (mbp->PosFormat != 1)
return ERR(HB_Err_Invalid_SubTable_Format);
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_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 = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_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, stream ) ) != HB_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,
stream ) ) != HB_Err_Ok )
goto Fail1;
return HB_Err_Ok;
Fail1:
Free_MarkArray( &mbp->MarkArray );
Fail2:
_HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
Fail3:
_HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
return error;
}
static void Free_MarkBasePos( HB_GPOS_SubTable* st )
{
HB_MarkBasePos* mbp = &st->markbase;
Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
Free_MarkArray( &mbp->MarkArray );
_HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
_HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
}
static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort i, j, mark_index, base_index, property, class;
HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_MarkBasePos* mbp = &st->markbase;
HB_MarkArray* ma;
HB_BaseArray* ba;
HB_BaseRecord* br;
HB_Anchor* mark_anchor;
HB_Anchor* base_anchor;
HB_Position o;
HB_UNUSED(nesting_level);
if ( context_length != 0xFFFF && context_length < 1 )
return HB_Err_Not_Covered;
if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
return HB_Err_Not_Covered;
if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
&mark_index );
if ( error )
return error;
i = 1;
j = buffer->in_pos - 1;
while ( i <= buffer->in_pos )
{
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
&property );
if ( error )
return error;
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
break;
i++;
j--;
}
#if 0#endif
if ( i > buffer->in_pos )
return HB_Err_Not_Covered;
error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
&base_index );
if ( error )
return error;
ma = &mbp->MarkArray;
if ( mark_index >= ma->MarkCount )
return ERR(HB_Err_Invalid_SubTable);
class = ma->MarkRecord[mark_index].Class;
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
if ( class >= mbp->ClassCount )
return ERR(HB_Err_Invalid_SubTable);
ba = &mbp->BaseArray;
if ( base_index >= ba->BaseCount )
return ERR(HB_Err_Invalid_SubTable);
br = &ba->BaseRecord[base_index];
base_anchor = &br->BaseAnchor[class];
error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
&x_mark_value, &y_mark_value );
if ( error )
return error;
error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
&x_base_value, &y_base_value );
if ( error )
return error;
o = POSITION( buffer->in_pos );
o->x_pos = x_base_value - x_mark_value;
o->y_pos = y_base_value - y_mark_value;
o->x_advance = 0;
o->y_advance = 0;
o->back = i;
(buffer->in_pos)++;
return HB_Err_Ok;
}
static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
HB_UShort num_classes,
HB_Stream stream )
{
HB_Error error;
HB_UShort m, n, k, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_ComponentRecord* cr;
HB_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, HB_ComponentRecord ) )
return error;
cr = lat->ComponentRecord;
for ( m = 0; m < count; m++ )
{
cr[m].LigatureAnchor = NULL;
if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
goto Fail;
lan = cr[m].LigatureAnchor;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail0;
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], stream ) ) != HB_Err_Ok )
goto Fail0;
(void)FILE_Seek( cur_offset );
}
else
lan[n].PosFormat = 0;
}
continue;
Fail0:
for ( k = 0; k < n; k++ )
Free_Anchor( &lan[k] );
goto Fail;
}
return HB_Err_Ok;
Fail:
for ( k = 0; k < m; k++ )
{
lan = cr[k].LigatureAnchor;
for ( n = 0; n < num_classes; n++ )
Free_Anchor( &lan[n] );
FREE( lan );
}
FREE( cr );
return error;
}
static void Free_LigatureAttach( HB_LigatureAttach* lat,
HB_UShort num_classes )
{
HB_UShort m, n, count;
HB_ComponentRecord* cr;
HB_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 HB_Error Load_LigatureArray( HB_LigatureArray* la,
HB_UShort num_classes,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_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,
stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_LigatureAttach( &lat[m], num_classes );
FREE( lat );
return error;
}
static void Free_LigatureArray( HB_LigatureArray* la,
HB_UShort num_classes )
{
HB_UShort n, count;
HB_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 );
}
}
static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_MarkLigPos* mlp = &st->marklig;
HB_UInt 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 = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_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 = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
stream ) ) != HB_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, stream ) ) != HB_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,
stream ) ) != HB_Err_Ok )
goto Fail1;
return HB_Err_Ok;
Fail1:
Free_MarkArray( &mlp->MarkArray );
Fail2:
_HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
Fail3:
_HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
return error;
}
static void Free_MarkLigPos( HB_GPOS_SubTable* st)
{
HB_MarkLigPos* mlp = &st->marklig;
Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
Free_MarkArray( &mlp->MarkArray );
_HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
_HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
}
static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort i, j, mark_index, lig_index, property, class;
HB_UShort mark_glyph;
HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_MarkLigPos* mlp = &st->marklig;
HB_MarkArray* ma;
HB_LigatureArray* la;
HB_LigatureAttach* lat;
HB_ComponentRecord* cr;
HB_UShort comp_index;
HB_Anchor* mark_anchor;
HB_Anchor* lig_anchor;
HB_Position o;
HB_UNUSED(nesting_level);
if ( context_length != 0xFFFF && context_length < 1 )
return HB_Err_Not_Covered;
if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
return HB_Err_Not_Covered;
mark_glyph = IN_CURGLYPH();
if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
if ( error )
return error;
i = 1;
j = buffer->in_pos - 1;
while ( i <= buffer->in_pos )
{
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
&property );
if ( error )
return error;
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
break;
i++;
j--;
}
#if 0#endif
if ( i > buffer->in_pos )
return HB_Err_Not_Covered;
error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
&lig_index );
if ( error )
return error;
ma = &mlp->MarkArray;
if ( mark_index >= ma->MarkCount )
return ERR(HB_Err_Invalid_SubTable);
class = ma->MarkRecord[mark_index].Class;
mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
if ( class >= mlp->ClassCount )
return ERR(HB_Err_Invalid_SubTable);
la = &mlp->LigatureArray;
if ( lig_index >= la->LigatureCount )
return ERR(HB_Err_Invalid_SubTable);
lat = &la->LigatureAttach[lig_index];
if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
{
comp_index = IN_COMPONENT( buffer->in_pos );
if ( comp_index >= lat->ComponentCount )
return HB_Err_Not_Covered;
}
else
comp_index = lat->ComponentCount - 1;
cr = &lat->ComponentRecord[comp_index];
lig_anchor = &cr->LigatureAnchor[class];
error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
&x_mark_value, &y_mark_value );
if ( error )
return error;
error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
&x_lig_value, &y_lig_value );
if ( error )
return error;
o = POSITION( buffer->in_pos );
o->x_pos = x_lig_value - x_mark_value;
o->y_pos = y_lig_value - y_mark_value;
o->x_advance = 0;
o->y_advance = 0;
o->back = i;
(buffer->in_pos)++;
return HB_Err_Ok;
}
static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
HB_UShort num_classes,
HB_Stream stream )
{
HB_Error error;
HB_UShort m, n, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_Mark2Record *m2r;
HB_Anchor *m2an, *m2ans;
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, HB_Mark2Record ) )
return error;
m2r = m2a->Mark2Record;
m2ans = NULL;
if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
goto Fail;
for ( m = 0; m < count; m++ )
{
m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
for ( n = 0; n < num_classes; n++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
if (new_offset == base_offset) {
m2an[n].PosFormat = 0;
continue;
}
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
}
return HB_Err_Ok;
Fail:
FREE( m2ans );
FREE( m2r );
return error;
}
static void Free_Mark2Array( HB_Mark2Array* m2a,
HB_UShort num_classes )
{
HB_Mark2Record *m2r;
HB_Anchor *m2ans;
HB_UNUSED(num_classes);
if ( m2a->Mark2Record )
{
m2r = m2a->Mark2Record;
if ( m2a->Mark2Count )
{
m2ans = m2r[0].Mark2Anchor;
FREE( m2ans );
}
FREE( m2r );
}
}
static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_MarkMarkPos* mmp = &st->markmark;
HB_UInt 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 = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
stream ) ) != HB_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 = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
stream ) ) != HB_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, stream ) ) != HB_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,
stream ) ) != HB_Err_Ok )
goto Fail1;
return HB_Err_Ok;
Fail1:
Free_MarkArray( &mmp->Mark1Array );
Fail2:
_HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
Fail3:
_HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
return error;
}
static void Free_MarkMarkPos( HB_GPOS_SubTable* st)
{
HB_MarkMarkPos* mmp = &st->markmark;
Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
Free_MarkArray( &mmp->Mark1Array );
_HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
_HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
}
static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort i, j, mark1_index, mark2_index, property, class;
HB_Fixed x_mark1_value, y_mark1_value,
x_mark2_value, y_mark2_value;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_MarkMarkPos* mmp = &st->markmark;
HB_MarkArray* ma1;
HB_Mark2Array* ma2;
HB_Mark2Record* m2r;
HB_Anchor* mark1_anchor;
HB_Anchor* mark2_anchor;
HB_Position o;
HB_UNUSED(nesting_level);
if ( context_length != 0xFFFF && context_length < 1 )
return HB_Err_Not_Covered;
if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
return HB_Err_Not_Covered;
if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
&mark1_index );
if ( error )
return error;
if ( buffer->in_pos == 0 )
return HB_Err_Not_Covered;
i = 1;
j = buffer->in_pos - 1;
while ( i <= buffer->in_pos )
{
error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
&property );
if ( error )
return error;
if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
return HB_Err_Not_Covered;
if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
{
if ( property == (flags & 0xFF00) )
break;
}
else
break;
i++;
j--;
}
error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
&mark2_index );
if ( error )
return error;
ma1 = &mmp->Mark1Array;
if ( mark1_index >= ma1->MarkCount )
return ERR(HB_Err_Invalid_SubTable);
class = ma1->MarkRecord[mark1_index].Class;
mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
if ( class >= mmp->ClassCount )
return ERR(HB_Err_Invalid_SubTable);
ma2 = &mmp->Mark2Array;
if ( mark2_index >= ma2->Mark2Count )
return ERR(HB_Err_Invalid_SubTable);
m2r = &ma2->Mark2Record[mark2_index];
mark2_anchor = &m2r->Mark2Anchor[class];
error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
&x_mark1_value, &y_mark1_value );
if ( error )
return error;
error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
&x_mark2_value, &y_mark2_value );
if ( error )
return error;
o = POSITION( buffer->in_pos );
o->x_pos = x_mark2_value - x_mark1_value;
o->y_pos = y_mark2_value - y_mark1_value;
o->x_advance = 0;
o->y_advance = 0;
o->back = 1;
(buffer->in_pos)++;
return HB_Err_Ok;
}
static HB_Error Do_ContextPos( GPOS_Instance* gpi,
HB_UShort GlyphCount,
HB_UShort PosCount,
HB_PosLookupRecord* pos,
HB_Buffer buffer,
int nesting_level )
{
HB_Error error;
HB_UInt i, old_pos;
i = 0;
while ( i < GlyphCount )
{
if ( PosCount && i == pos->SequenceIndex )
{
old_pos = buffer->in_pos;
error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
GlyphCount, nesting_level );
if ( error )
return error;
pos++;
PosCount--;
i += buffer->in_pos - old_pos;
}
else
{
i++;
(buffer->in_pos)++;
}
}
return HB_Err_Ok;
}
static HB_Error Load_PosRule( HB_PosRule* pr,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, count;
HB_UShort* i;
HB_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, HB_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, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( i );
return error;
}
static void Free_PosRule( HB_PosRule* pr )
{
FREE( pr->PosLookupRecord );
FREE( pr->Input );
}
static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_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], stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_PosRule( &pr[m] );
FREE( pr );
return error;
}
static void Free_PosRuleSet( HB_PosRuleSet* prs )
{
HB_UShort n, count;
HB_PosRule* pr;
if ( prs->PosRule )
{
count = prs->PosRuleCount;
pr = prs->PosRule;
for ( n = 0; n < count; n++ )
Free_PosRule( &pr[n] );
FREE( pr );
}
}
static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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 = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_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, HB_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], stream ) ) != HB_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; m++ )
Free_PosRuleSet( &prs[m] );
FREE( prs );
Fail2:
_HB_OPEN_Free_Coverage( &cpf1->Coverage );
return error;
}
static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
{
HB_UShort n, count;
HB_PosRuleSet* prs;
if ( cpf1->PosRuleSet )
{
count = cpf1->PosRuleSetCount;
prs = cpf1->PosRuleSet;
for ( n = 0; n < count; n++ )
Free_PosRuleSet( &prs[n] );
FREE( prs );
}
_HB_OPEN_Free_Coverage( &cpf1->Coverage );
}
static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
HB_PosClassRule* pcr,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, count;
HB_UShort* c;
HB_PosLookupRecord* plr;
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, HB_UShort ) )
return error;
c = pcr->Class;
if ( ACCESS_Frame( count * 2L ) )
goto Fail2;
for ( n = 0; n < count; n++ )
c[n] = GET_UShort();
FORGET_Frame();
pcr->PosLookupRecord = NULL;
count = pcr->PosCount;
if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( c );
return error;
}
static void Free_PosClassRule( HB_PosClassRule* pcr )
{
FREE( pcr->PosLookupRecord );
FREE( pcr->Class );
}
static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
HB_PosClassSet* pcs,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_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],
stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_PosClassRule( &pcr[m] );
FREE( pcr );
return error;
}
static void Free_PosClassSet( HB_PosClassSet* pcs )
{
HB_UShort n, count;
HB_PosClassRule* pcr;
if ( pcs->PosClassRule )
{
count = pcs->PosClassRuleCount;
pcr = pcs->PosClassRule;
for ( n = 0; n < count; n++ )
Free_PosClassRule( &pcr[n] );
FREE( pcr );
}
}
static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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 = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_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 = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
stream ) ) != HB_Err_Ok )
goto Fail3;
(void)FILE_Seek( cur_offset );
cpf2->PosClassSet = NULL;
cpf2->MaxContextLength = 0;
if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_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],
stream ) ) != HB_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
{
cpf2->PosClassSet[n].PosClassRuleCount = 0;
cpf2->PosClassSet[n].PosClassRule = NULL;
}
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; n++ )
Free_PosClassSet( &pcs[m] );
FREE( pcs );
Fail2:
_HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
Fail3:
_HB_OPEN_Free_Coverage( &cpf2->Coverage );
return error;
}
static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
{
HB_UShort n, count;
HB_PosClassSet* pcs;
if ( cpf2->PosClassSet )
{
count = cpf2->PosClassSetCount;
pcs = cpf2->PosClassSet;
for ( n = 0; n < count; n++ )
Free_PosClassSet( &pcs[n] );
FREE( pcs );
}
_HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
_HB_OPEN_Free_Coverage( &cpf2->Coverage );
}
static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_Coverage* c;
HB_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, HB_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 = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
goto Fail2;
(void)FILE_Seek( cur_offset );
}
cpf3->PosLookupRecord = NULL;
count = cpf3->PosCount;
if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
for ( n = 0; n < count; n++ )
_HB_OPEN_Free_Coverage( &c[n] );
FREE( c );
return error;
}
static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
{
HB_UShort n, count;
HB_Coverage* c;
FREE( cpf3->PosLookupRecord );
if ( cpf3->Coverage )
{
count = cpf3->GlyphCount;
c = cpf3->Coverage;
for ( n = 0; n < count; n++ )
_HB_OPEN_Free_Coverage( &c[n] );
FREE( c );
}
}
static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_ContextPos* cp = &st->context;
if ( ACCESS_Frame( 2L ) )
return error;
cp->PosFormat = GET_UShort();
FORGET_Frame();
switch ( cp->PosFormat )
{
case 1:
return Load_ContextPos1( &cp->cpf.cpf1, stream );
case 2:
return Load_ContextPos2( &cp->cpf.cpf2, stream );
case 3:
return Load_ContextPos3( &cp->cpf.cpf3, stream );
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
}
static void Free_ContextPos( HB_GPOS_SubTable* st )
{
HB_ContextPos* cp = &st->context;
switch ( cp->PosFormat )
{
case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
default: break;
}
}
static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
HB_ContextPosFormat1* cpf1,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_UShort i, j, k, numpr;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_PosRule* pr;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
pr = cpf1->PosRuleSet[index].PosRule;
numpr = cpf1->PosRuleSet[index].PosRuleCount;
for ( k = 0; k < numpr; k++ )
{
if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
goto next_posrule;
if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
goto next_posrule;
for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
goto next_posrule;
j++;
}
if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
goto next_posrule;
}
return Do_ContextPos( gpi, pr[k].GlyphCount,
pr[k].PosCount, pr[k].PosLookupRecord,
buffer,
nesting_level );
next_posrule:
;
}
return HB_Err_Not_Covered;
}
static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
HB_ContextPosFormat2* cpf2,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_Error error;
HB_UShort i, j, k, known_classes;
HB_UShort* classes;
HB_UShort* cl;
HB_GPOSHeader* gpos = gpi->gpos;
HB_PosClassSet* pcs;
HB_PosClassRule* pr;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
if (cpf2->MaxContextLength < 1)
return HB_Err_Not_Covered;
if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
return error;
error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
&classes[0], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End;
known_classes = 0;
pcs = &cpf2->PosClassSet[classes[0]];
if ( !pcs )
{
error = ERR(HB_Err_Invalid_SubTable);
goto End;
}
for ( k = 0; k < pcs->PosClassRuleCount; k++ )
{
pr = &pcs->PosClassRule[k];
if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
goto next_posclassrule;
if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
goto next_posclassrule;
cl = pr->Class;
for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
goto End;
if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
goto next_posclassrule;
j++;
}
if ( i > known_classes )
{
error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End;
known_classes = i;
}
if ( cl[i - 1] != classes[i] )
goto next_posclassrule;
}
error = Do_ContextPos( gpi, pr->GlyphCount,
pr->PosCount, pr->PosLookupRecord,
buffer,
nesting_level );
goto End;
next_posclassrule:
;
}
error = HB_Err_Not_Covered;
End:
FREE( classes );
return error;
}
static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
HB_ContextPosFormat3* cpf3,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_Error error;
HB_UShort index, i, j, property;
HB_GPOSHeader* gpos = gpi->gpos;
HB_Coverage* c;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
return HB_Err_Not_Covered;
if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
return HB_Err_Not_Covered;
c = cpf3->Coverage;
for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
return HB_Err_Not_Covered;
j++;
}
error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
if ( error )
return error;
}
return Do_ContextPos( gpi, cpf3->GlyphCount,
cpf3->PosCount, cpf3->PosLookupRecord,
buffer,
nesting_level );
}
static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_ContextPos* cp = &st->context;
switch ( cp->PosFormat )
{
case 1:
return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
flags, context_length, nesting_level );
case 2:
return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
flags, context_length, nesting_level );
case 3:
return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
flags, context_length, nesting_level );
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
}
static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, count;
HB_UShort* b;
HB_UShort* i;
HB_UShort* l;
HB_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, HB_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, HB_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, HB_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, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( l );
Fail3:
FREE( i );
Fail4:
FREE( b );
return error;
}
static void Free_ChainPosRule( HB_ChainPosRule* cpr )
{
FREE( cpr->PosLookupRecord );
FREE( cpr->Lookahead );
FREE( cpr->Input );
FREE( cpr->Backtrack );
}
static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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, HB_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], stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_ChainPosRule( &cpr[m] );
FREE( cpr );
return error;
}
static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
{
HB_UShort n, count;
HB_ChainPosRule* cpr;
if ( cprs->ChainPosRule )
{
count = cprs->ChainPosRuleCount;
cpr = cprs->ChainPosRule;
for ( n = 0; n < count; n++ )
Free_ChainPosRule( &cpr[n] );
FREE( cpr );
}
}
static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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 = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_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, HB_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], stream ) ) != HB_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; m++ )
Free_ChainPosRuleSet( &cprs[m] );
FREE( cprs );
Fail2:
_HB_OPEN_Free_Coverage( &ccpf1->Coverage );
return error;
}
static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
{
HB_UShort n, count;
HB_ChainPosRuleSet* cprs;
if ( ccpf1->ChainPosRuleSet )
{
count = ccpf1->ChainPosRuleSetCount;
cprs = ccpf1->ChainPosRuleSet;
for ( n = 0; n < count; n++ )
Free_ChainPosRuleSet( &cprs[n] );
FREE( cprs );
}
_HB_OPEN_Free_Coverage( &ccpf1->Coverage );
}
static HB_Error Load_ChainPosClassRule(
HB_ChainContextPosFormat2* ccpf2,
HB_ChainPosClassRule* cpcr,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, count;
HB_UShort* b;
HB_UShort* i;
HB_UShort* l;
HB_PosLookupRecord* plr;
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, HB_UShort ) )
return error;
b = cpcr->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;
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, HB_UShort ) )
goto Fail4;
i = cpcr->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;
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, HB_UShort ) )
goto Fail3;
l = cpcr->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;
cpcr->PosCount = GET_UShort();
FORGET_Frame();
cpcr->PosLookupRecord = NULL;
count = cpcr->PosCount;
if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
FREE( l );
Fail3:
FREE( i );
Fail4:
FREE( b );
return error;
}
static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
{
FREE( cpcr->PosLookupRecord );
FREE( cpcr->Lookahead );
FREE( cpcr->Input );
FREE( cpcr->Backtrack );
}
static HB_Error Load_ChainPosClassSet(
HB_ChainContextPosFormat2* ccpf2,
HB_ChainPosClassSet* cpcs,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_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,
HB_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],
stream ) ) != HB_Err_Ok )
goto Fail;
(void)FILE_Seek( cur_offset );
}
return HB_Err_Ok;
Fail:
for ( m = 0; m < n; m++ )
Free_ChainPosClassRule( &cpcr[m] );
FREE( cpcr );
return error;
}
static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
{
HB_UShort n, count;
HB_ChainPosClassRule* cpcr;
if ( cpcs->ChainPosClassRule )
{
count = cpcs->ChainPosClassRuleCount;
cpcr = cpcs->ChainPosClassRule;
for ( n = 0; n < count; n++ )
Free_ChainPosClassRule( &cpcr[n] );
FREE( cpcr );
}
}
static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, m, count;
HB_UInt cur_offset, new_offset, base_offset;
HB_UInt backtrack_offset, input_offset, lookahead_offset;
HB_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 = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
return error;
(void)FILE_Seek( cur_offset );
if ( ACCESS_Frame( 8L ) )
goto Fail5;
backtrack_offset = GET_UShort();
input_offset = GET_UShort();
lookahead_offset = GET_UShort();
count = ccpf2->ChainPosClassSetCount = GET_UShort();
FORGET_Frame();
if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
backtrack_offset, base_offset,
stream ) ) != HB_Err_Ok )
goto Fail5;
if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
input_offset, base_offset,
stream ) ) != HB_Err_Ok )
goto Fail4;
if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
lookahead_offset, base_offset,
stream ) ) != HB_Err_Ok )
goto Fail3;
ccpf2->ChainPosClassSet = NULL;
ccpf2->MaxBacktrackLength = 0;
ccpf2->MaxInputLength = 0;
ccpf2->MaxLookaheadLength = 0;
if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_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],
stream ) ) != HB_Err_Ok )
goto Fail1;
(void)FILE_Seek( cur_offset );
}
else
{
ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
}
}
return HB_Err_Ok;
Fail1:
for ( m = 0; m < n; m++ )
Free_ChainPosClassSet( &cpcs[m] );
FREE( cpcs );
Fail2:
_HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
Fail3:
_HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
Fail4:
_HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
Fail5:
_HB_OPEN_Free_Coverage( &ccpf2->Coverage );
return error;
}
static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
{
HB_UShort n, count;
HB_ChainPosClassSet* cpcs;
if ( ccpf2->ChainPosClassSet )
{
count = ccpf2->ChainPosClassSetCount;
cpcs = ccpf2->ChainPosClassSet;
for ( n = 0; n < count; n++ )
Free_ChainPosClassSet( &cpcs[n] );
FREE( cpcs );
}
_HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
_HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
_HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
_HB_OPEN_Free_Coverage( &ccpf2->Coverage );
}
static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
HB_Stream stream )
{
HB_Error error;
HB_UShort n, nb, ni, nl, m, count;
HB_UShort backtrack_count, input_count, lookahead_count;
HB_UInt cur_offset, new_offset, base_offset;
HB_Coverage* b;
HB_Coverage* i;
HB_Coverage* l;
HB_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,
HB_Coverage ) )
return error;
b = ccpf3->BacktrackCoverage;
for ( nb = 0; nb < backtrack_count; nb++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail4;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_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, HB_Coverage ) )
goto Fail4;
i = ccpf3->InputCoverage;
for ( ni = 0; ni < input_count; ni++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail3;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_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,
HB_Coverage ) )
goto Fail3;
l = ccpf3->LookaheadCoverage;
for ( nl = 0; nl < lookahead_count; nl++ )
{
if ( ACCESS_Frame( 2L ) )
goto Fail2;
new_offset = GET_UShort() + base_offset;
FORGET_Frame();
cur_offset = FILE_Pos();
if ( FILE_Seek( new_offset ) ||
( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_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, HB_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 HB_Err_Ok;
Fail1:
FREE( plr );
Fail2:
for ( m = 0; m < nl; m++ )
_HB_OPEN_Free_Coverage( &l[m] );
FREE( l );
Fail3:
for ( m = 0; m < ni; m++ )
_HB_OPEN_Free_Coverage( &i[m] );
FREE( i );
Fail4:
for ( m = 0; m < nb; m++ )
_HB_OPEN_Free_Coverage( &b[m] );
FREE( b );
return error;
}
static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
{
HB_UShort n, count;
HB_Coverage* c;
FREE( ccpf3->PosLookupRecord );
if ( ccpf3->LookaheadCoverage )
{
count = ccpf3->LookaheadGlyphCount;
c = ccpf3->LookaheadCoverage;
for ( n = 0; n < count; n++ )
_HB_OPEN_Free_Coverage( &c[n] );
FREE( c );
}
if ( ccpf3->InputCoverage )
{
count = ccpf3->InputGlyphCount;
c = ccpf3->InputCoverage;
for ( n = 0; n < count; n++ )
_HB_OPEN_Free_Coverage( &c[n] );
FREE( c );
}
if ( ccpf3->BacktrackCoverage )
{
count = ccpf3->BacktrackGlyphCount;
c = ccpf3->BacktrackCoverage;
for ( n = 0; n < count; n++ )
_HB_OPEN_Free_Coverage( &c[n] );
FREE( c );
}
}
static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
HB_Stream stream )
{
HB_Error error;
HB_ChainContextPos* ccp = &st->chain;
if ( ACCESS_Frame( 2L ) )
return error;
ccp->PosFormat = GET_UShort();
FORGET_Frame();
switch ( ccp->PosFormat )
{
case 1:
return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
case 2:
return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
case 3:
return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
}
static void Free_ChainContextPos( HB_GPOS_SubTable* st )
{
HB_ChainContextPos* ccp = &st->chain;
switch ( ccp->PosFormat )
{
case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
default: break;
}
}
static HB_Error Lookup_ChainContextPos1(
GPOS_Instance* gpi,
HB_ChainContextPosFormat1* ccpf1,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_UShort i, j, k, num_cpr;
HB_UShort bgc, igc, lgc;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_ChainPosRule* cpr;
HB_ChainPosRule curr_cpr;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
for ( k = 0; k < num_cpr; k++ )
{
curr_cpr = cpr[k];
bgc = curr_cpr.BacktrackGlyphCount;
igc = curr_cpr.InputGlyphCount;
lgc = curr_cpr.LookaheadGlyphCount;
if ( context_length != 0xFFFF && context_length < igc )
goto next_chainposrule;
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
goto next_chainposrule;
if ( bgc )
{
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + 1 == bgc - i )
goto next_chainposrule;
j--;
}
if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
goto next_chainposrule;
}
}
for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
goto next_chainposrule;
j++;
}
if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
goto next_chainposrule;
}
for ( i = 0; i < lgc; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + lgc - i == (HB_Int)buffer->in_length )
goto next_chainposrule;
j++;
}
if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
goto next_chainposrule;
}
return Do_ContextPos( gpi, igc,
curr_cpr.PosCount,
curr_cpr.PosLookupRecord,
buffer,
nesting_level );
next_chainposrule:
;
}
return HB_Err_Not_Covered;
}
static HB_Error Lookup_ChainContextPos2(
GPOS_Instance* gpi,
HB_ChainContextPosFormat2* ccpf2,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, property;
HB_Error error;
HB_UShort i, j, k;
HB_UShort bgc, igc, lgc;
HB_UShort known_backtrack_classes,
known_input_classes,
known_lookahead_classes;
HB_UShort* backtrack_classes;
HB_UShort* input_classes;
HB_UShort* lookahead_classes;
HB_UShort* bc;
HB_UShort* ic;
HB_UShort* lc;
HB_GPOSHeader* gpos = gpi->gpos;
HB_ChainPosClassSet* cpcs;
HB_ChainPosClassRule cpcr;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
if ( error )
return error;
if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
return error;
known_backtrack_classes = 0;
if (ccpf2->MaxInputLength < 1)
return HB_Err_Not_Covered;
if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
goto End3;
known_input_classes = 1;
if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
goto End2;
known_lookahead_classes = 0;
error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
&input_classes[0], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End1;
cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
if ( !cpcs )
{
error = ERR(HB_Err_Invalid_SubTable);
goto End1;
}
for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
{
cpcr = cpcs->ChainPosClassRule[k];
bgc = cpcr.BacktrackGlyphCount;
igc = cpcr.InputGlyphCount;
lgc = cpcr.LookaheadGlyphCount;
if ( context_length != 0xFFFF && context_length < igc )
goto next_chainposclassrule;
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
goto next_chainposclassrule;
if ( bgc )
{
bc = cpcr.Backtrack;
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
goto End1;
if ( j + 1 == bgc - i )
goto next_chainposclassrule;
j++;
}
if ( i >= known_backtrack_classes )
{
error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
&backtrack_classes[i], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End1;
known_backtrack_classes = i;
}
if ( bc[i] != backtrack_classes[i] )
goto next_chainposclassrule;
}
}
ic = cpcr.Input;
for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
goto End1;
if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
goto next_chainposclassrule;
j++;
}
if ( i >= known_input_classes )
{
error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
&input_classes[i], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End1;
known_input_classes = i;
}
if ( ic[i - 1] != input_classes[i] )
goto next_chainposclassrule;
}
lc = cpcr.Lookahead;
for ( i = 0; i < lgc; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
goto End1;
if ( j + lgc - i == (HB_Int)buffer->in_length )
goto next_chainposclassrule;
j++;
}
if ( i >= known_lookahead_classes )
{
error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
&lookahead_classes[i], NULL );
if ( error && error != HB_Err_Not_Covered )
goto End1;
known_lookahead_classes = i;
}
if ( lc[i] != lookahead_classes[i] )
goto next_chainposclassrule;
}
error = Do_ContextPos( gpi, igc,
cpcr.PosCount,
cpcr.PosLookupRecord,
buffer,
nesting_level );
goto End1;
next_chainposclassrule:
;
}
error = HB_Err_Not_Covered;
End1:
FREE( lookahead_classes );
End2:
FREE( input_classes );
End3:
FREE( backtrack_classes );
return error;
}
static HB_Error Lookup_ChainContextPos3(
GPOS_Instance* gpi,
HB_ChainContextPosFormat3* ccpf3,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_UShort index, i, j, property;
HB_UShort bgc, igc, lgc;
HB_Error error;
HB_GPOSHeader* gpos = gpi->gpos;
HB_Coverage* bc;
HB_Coverage* ic;
HB_Coverage* lc;
HB_GDEFHeader* gdef;
gdef = gpos->gdef;
if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
return error;
bgc = ccpf3->BacktrackGlyphCount;
igc = ccpf3->InputGlyphCount;
lgc = ccpf3->LookaheadGlyphCount;
if ( context_length != 0xFFFF && context_length < igc )
return HB_Err_Not_Covered;
if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
return HB_Err_Not_Covered;
if ( bgc )
{
bc = ccpf3->BacktrackCoverage;
for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + 1 == bgc - i )
return HB_Err_Not_Covered;
j--;
}
error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
if ( error )
return error;
}
}
ic = ccpf3->InputCoverage;
for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
{
while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
return HB_Err_Not_Covered;
j++;
}
error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
if ( error )
return error;
}
lc = ccpf3->LookaheadCoverage;
for ( i = 0; i < lgc; i++, j++ )
{
while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
{
if ( error && error != HB_Err_Not_Covered )
return error;
if ( j + lgc - i == (HB_Int)buffer->in_length )
return HB_Err_Not_Covered;
j++;
}
error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
if ( error )
return error;
}
return Do_ContextPos( gpi, igc,
ccpf3->PosCount,
ccpf3->PosLookupRecord,
buffer,
nesting_level );
}
static HB_Error Lookup_ChainContextPos(
GPOS_Instance* gpi,
HB_GPOS_SubTable* st,
HB_Buffer buffer,
HB_UShort flags,
HB_UShort context_length,
int nesting_level )
{
HB_ChainContextPos* ccp = &st->chain;
switch ( ccp->PosFormat )
{
case 1:
return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
flags, context_length,
nesting_level );
case 2:
return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
flags, context_length,
nesting_level );
case 3:
return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
flags, context_length,
nesting_level );
default:
return ERR(HB_Err_Invalid_SubTable_Format);
}
return HB_Err_Ok;
}
HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
HB_UInt script_tag,
HB_UShort* script_index )
{
HB_UShort n;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
if ( !gpos || !script_index )
return ERR(HB_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 HB_Err_Ok;
}
return HB_Err_Not_Covered;
}
HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
HB_UInt language_tag,
HB_UShort script_index,
HB_UShort* language_index,
HB_UShort* req_feature_index )
{
HB_UShort n;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
HB_ScriptTable* s;
HB_LangSysRecord* lsr;
if ( !gpos || !language_index || !req_feature_index )
return ERR(HB_Err_Invalid_Argument);
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( script_index >= sl->ScriptCount )
return ERR(HB_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 HB_Err_Ok;
}
return HB_Err_Not_Covered;
}
HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
HB_UInt feature_tag,
HB_UShort script_index,
HB_UShort language_index,
HB_UShort* feature_index )
{
HB_UShort n;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
HB_ScriptTable* s;
HB_LangSysRecord* lsr;
HB_LangSys* ls;
HB_UShort* fi;
HB_FeatureList* fl;
HB_FeatureRecord* fr;
if ( !gpos || !feature_index )
return ERR(HB_Err_Invalid_Argument);
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
fl = &gpos->FeatureList;
fr = fl->FeatureRecord;
if ( script_index >= sl->ScriptCount )
return ERR(HB_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 ERR(HB_Err_Invalid_Argument);
ls = &lsr[language_index].LangSys;
}
fi = ls->FeatureIndex;
for ( n = 0; n < ls->FeatureCount; n++ )
{
if ( fi[n] >= fl->FeatureCount )
return ERR(HB_Err_Invalid_SubTable_Format);
if ( feature_tag == fr[fi[n]].FeatureTag )
{
*feature_index = fi[n];
return HB_Err_Ok;
}
}
return HB_Err_Not_Covered;
}
HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
HB_UInt** script_tag_list )
{
HB_Error error;
HB_UShort n;
HB_UInt* stl;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
if ( !gpos || !script_tag_list )
return ERR(HB_Err_Invalid_Argument);
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
return error;
for ( n = 0; n < sl->ScriptCount; n++ )
stl[n] = sr[n].ScriptTag;
stl[n] = 0;
*script_tag_list = stl;
return HB_Err_Ok;
}
HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
HB_UShort script_index,
HB_UInt** language_tag_list )
{
HB_Error error;
HB_UShort n;
HB_UInt* ltl;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
HB_ScriptTable* s;
HB_LangSysRecord* lsr;
if ( !gpos || !language_tag_list )
return ERR(HB_Err_Invalid_Argument);
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
if ( script_index >= sl->ScriptCount )
return ERR(HB_Err_Invalid_Argument);
s = &sr[script_index].Script;
lsr = s->LangSysRecord;
if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
return error;
for ( n = 0; n < s->LangSysCount; n++ )
ltl[n] = lsr[n].LangSysTag;
ltl[n] = 0;
*language_tag_list = ltl;
return HB_Err_Ok;
}
HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
HB_UShort script_index,
HB_UShort language_index,
HB_UInt** feature_tag_list )
{
HB_UShort n;
HB_Error error;
HB_UInt* ftl;
HB_ScriptList* sl;
HB_ScriptRecord* sr;
HB_ScriptTable* s;
HB_LangSysRecord* lsr;
HB_LangSys* ls;
HB_UShort* fi;
HB_FeatureList* fl;
HB_FeatureRecord* fr;
if ( !gpos || !feature_tag_list )
return ERR(HB_Err_Invalid_Argument);
sl = &gpos->ScriptList;
sr = sl->ScriptRecord;
fl = &gpos->FeatureList;
fr = fl->FeatureRecord;
if ( script_index >= sl->ScriptCount )
return ERR(HB_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 ERR(HB_Err_Invalid_Argument);
ls = &lsr[language_index].LangSys;
}
fi = ls->FeatureIndex;
if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
return error;
for ( n = 0; n < ls->FeatureCount; n++ )
{
if ( fi[n] >= fl->FeatureCount )
{
FREE( ftl );
return ERR(HB_Err_Invalid_SubTable_Format);
}
ftl[n] = fr[fi[n]].FeatureTag;
}
ftl[n] = 0;
*feature_tag_list = ftl;
return HB_Err_Ok;
}
static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
HB_UShort lookup_index,
HB_Buffer buffer,
HB_UShort context_length,
int nesting_level )
{
HB_Error error = HB_Err_Not_Covered;
HB_UShort i, flags, lookup_count;
HB_GPOSHeader* gpos = gpi->gpos;
HB_Lookup* lo;
int lookup_type;
nesting_level++;
if ( nesting_level > HB_MAX_NESTING_LEVEL )
return ERR(HB_Err_Not_Covered);
lookup_count = gpos->LookupList.LookupCount;
if (lookup_index >= lookup_count)
return error;
lo = &gpos->LookupList.Lookup[lookup_index];
flags = lo->LookupFlag;
lookup_type = lo->LookupType;
for ( i = 0; i < lo->SubTableCount; i++ )
{
HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
switch (lookup_type) {
case HB_GPOS_LOOKUP_SINGLE:
error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_PAIR:
error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_CURSIVE:
error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_MARKBASE:
error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_MARKLIG:
error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_MARKMARK:
error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_CONTEXT:
error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
case HB_GPOS_LOOKUP_CHAIN:
error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
default:
error = HB_Err_Not_Covered;
}
if ( error != HB_Err_Not_Covered )
return error;
}
return HB_Err_Not_Covered;
}
HB_INTERNAL HB_Error
_HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
HB_Stream stream,
HB_UShort lookup_type )
{
switch ( lookup_type ) {
case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
default: return ERR(HB_Err_Invalid_SubTable_Format);
}
}
HB_INTERNAL void
_HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
HB_UShort lookup_type )
{
switch ( lookup_type ) {
case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
default: return;
}
}
static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
HB_UShort lookup_index,
HB_Buffer buffer )
{
HB_Error error, retError = HB_Err_Not_Covered;
HB_GPOSHeader* gpos = gpi->gpos;
HB_UInt* properties = gpos->LookupList.Properties;
const int nesting_level = 0;
const HB_UShort context_length = 0xFFFF;
gpi->last = 0xFFFF;
buffer->in_pos = 0;
while ( buffer->in_pos < buffer->in_length )
{
if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
{
error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
if ( error && error != HB_Err_Not_Covered )
return error;
}
else
{
gpi->last = 0xFFFF;
error = HB_Err_Not_Covered;
}
if ( error == HB_Err_Not_Covered )
(buffer->in_pos)++;
else
retError = error;
}
return retError;
}
static HB_Error Position_CursiveChain ( HB_Buffer buffer )
{
HB_UInt i, j;
HB_Position positions = buffer->positions;
for (j = 0; j < buffer->in_length; j++)
{
if (positions[j].cursive_chain > 0)
positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
}
for (i = buffer->in_length; i > 0; i--)
{
j = i - 1;
if (positions[j].cursive_chain < 0)
positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
}
return HB_Err_Ok;
}
HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
HB_UShort feature_index,
HB_UInt property )
{
HB_UShort i;
HB_Feature feature;
HB_UInt* properties;
HB_UShort* index;
HB_UShort lookup_count;
if ( !gpos ||
feature_index >= gpos->FeatureList.FeatureCount ||
gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
return ERR(HB_Err_Invalid_Argument);
gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
properties = gpos->LookupList.Properties;
feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
index = feature.LookupListIndex;
lookup_count = gpos->LookupList.LookupCount;
for ( i = 0; i < feature.LookupListCount; i++ )
{
HB_UShort lookup_index = index[i];
if (lookup_index < lookup_count)
properties[lookup_index] |= property;
}
return HB_Err_Ok;
}
HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
{
HB_UShort i;
HB_UInt* properties;
if ( !gpos )
return ERR(HB_Err_Invalid_Argument);
gpos->FeatureList.ApplyCount = 0;
properties = gpos->LookupList.Properties;
for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
properties[i] = 0;
return HB_Err_Ok;
}
HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
HB_MMFunction mmfunc,
void* data )
{
if ( !gpos )
return ERR(HB_Err_Invalid_Argument);
gpos->mmfunc = mmfunc;
gpos->data = data;
return HB_Err_Ok;
}
HB_Error HB_GPOS_Apply_String( HB_Font font,
HB_GPOSHeader* gpos,
HB_UShort load_flags,
HB_Buffer buffer,
HB_Bool dvi,
HB_Bool r2l )
{
HB_Error error, retError = HB_Err_Not_Covered;
GPOS_Instance gpi;
int i, j, lookup_count, num_features;
if ( !font || !gpos || !buffer )
return ERR(HB_Err_Invalid_Argument);
if ( buffer->in_length == 0 )
return HB_Err_Not_Covered;
gpi.font = font;
gpi.gpos = gpos;
gpi.load_flags = load_flags;
gpi.r2l = r2l;
gpi.dvi = dvi;
lookup_count = gpos->LookupList.LookupCount;
num_features = gpos->FeatureList.ApplyCount;
if ( num_features )
{
error = _hb_buffer_clear_positions( buffer );
if ( error )
return error;
}
for ( i = 0; i < num_features; i++ )
{
HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
for ( j = 0; j < feature.LookupListCount; j++ )
{
HB_UShort lookup_index = feature.LookupListIndex[j];
if (lookup_index >= lookup_count)
continue;
error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
if ( error )
{
if ( error != HB_Err_Not_Covered )
return error;
}
else
retError = error;
}
}
if ( num_features )
{
error = Position_CursiveChain ( buffer );
if ( error )
return error;
}
return retError;
}