diff options
author | Behdad Esfahbod <behdad@behdad.org> | 2009-05-24 14:22:22 -0400 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2009-11-02 14:40:17 -0500 |
commit | da2c52abcd75d46929b34cad55c4fb2c8892bc08 (patch) | |
tree | a593461a7b29a1aceda3b09084f7de61c50189b4 /src/harfbuzz-gpos.c | |
parent | e5372f1621602dcee4e14a4b22dc182c21502a50 (diff) |
[HB] Remove old code!
Goodbye 16 thousand lines of ten-year old code!
Diffstat (limited to 'src/harfbuzz-gpos.c')
-rw-r--r-- | src/harfbuzz-gpos.c | 6071 |
1 files changed, 0 insertions, 6071 deletions
diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c deleted file mode 100644 index c4e8a786..00000000 --- a/src/harfbuzz-gpos.c +++ /dev/null @@ -1,6071 +0,0 @@ -/* - * Copyright (C) 1998-2004 David Turner and Werner Lemberg - * Copyright (C) 2006 Behdad Esfahbod - * Copyright (C) 2007 Red Hat, Inc. - * - * This is part of HarfBuzz, an OpenType Layout engine library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Red Hat Author(s): Behdad Esfahbod - */ - -#include "harfbuzz-impl.h" -#include "harfbuzz-gpos-private.h" -#include "harfbuzz-open-private.h" -#include "harfbuzz-gdef-private.h" - -struct GPOS_Instance_ -{ - HB_GPOSHeader* gpos; - HB_Font font; - HB_Bool dvi; - HB_UShort load_flags; /* how the glyph should be loaded */ - HB_Bool r2l; - - HB_UShort last; /* the last valid glyph -- used - with cursive positioning */ - HB_Fixed anchor_x; /* the coordinates of the anchor point */ - HB_Fixed anchor_y; /* of the last valid glyph */ -}; - -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 ); - - - -/* the client application must replace this with something more - meaningful if multiple master fonts are to be supported. */ - -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); /* ERR() call intended */ -} - - - -HB_Error HB_Load_GPOS_Table( HB_Font font, - HB_GPOSHeader** retptr, - hb_ot_layout_t *layout ) -{ - HB_UInt cur_offset, new_offset, base_offset; - - HB_GPOSHeader* gpos; - - HB_Stream stream = font->stream; - HB_Error error; - - - if ( !retptr || !layout ) - 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->gfunc = (HB_GlyphFunction) FT_Load_Glyph; - gpos->mmfunc = default_mmfunc; - - /* skip version */ - - 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->layout = layout; /* can be NULL */ - - *retptr = gpos; - - return HB_Err_Ok; - -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; -} - - -/***************************** - * SubTable related functions - *****************************/ - -/* shared tables */ - -/* ValueRecord */ - -/* There is a subtle difference in the specs between a `table' and a - `record' -- offsets for device tables in ValueRecords are taken from - the parent table and not the parent record. */ - -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->size->metrics.x_ppem; - y_ppem = gpi->font->size->metrics.y_ppem; - x_scale = gpi->font->size->metrics.x_scale; - y_scale = gpi->font->size->metrics.y_scale; - - /* design units -> fractional pixel */ - - 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 ) - { - /* pixel -> fractional pixel */ - - 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; - } - } - - /* values returned from mmfunc() are already in fractional pixels */ - - 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; -} - - -/* AnchorFormat1 */ -/* AnchorFormat2 */ -/* AnchorFormat3 */ -/* AnchorFormat4 */ - -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; - - FT_Outline outline; - HB_GPOSHeader* gpos = gpi->gpos; - HB_UShort ap; - - HB_Short pixel_value; - HB_UShort load_flags; - - HB_UShort x_ppem, y_ppem; - HB_16Dot16 x_scale, y_scale; - - - x_ppem = gpi->font->size->metrics.x_ppem; - y_ppem = gpi->font->size->metrics.y_ppem; - x_scale = gpi->font->size->metrics.x_scale; - y_scale = gpi->font->size->metrics.y_scale; - - switch ( an->PosFormat ) - { - case 0: - /* The special case of an empty AnchorTable */ - 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: - /* glyphs must be scaled */ - - load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE; - - if ( !gpi->dvi ) - { - error = (gpos->gfunc)( gpi->font, glyph_index, load_flags ); - if ( error ) - return error; - - if ( gpi->font->glyph->format != ft_glyph_format_outline ) - return ERR(HB_Err_Invalid_SubTable); - - ap = an->af.af2.AnchorPoint; - - outline = gpi->font->glyph->outline; - - /* if n_points is set to zero, we use the design coordinate value pair. - * This can happen e.g. for sbit glyphs. */ - if ( !outline.n_points ) - goto no_contour_point; - - if ( ap >= outline.n_points ) - return ERR(HB_Err_Invalid_SubTable); - - *x_value = outline.points[ap].x; - *y_value = outline.points[ap].y; - } - 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; -} - - -/* MarkArray */ - -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 ); - } -} - - -/* LookupType 1 */ - -/* SinglePosFormat1 */ -/* SinglePosFormat2 */ - -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->layout, 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; -} - - -/* LookupType 2 */ - -/* PairSet */ - -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 ); - } -} - - -/* PairPosFormat1 */ - -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 ); - } -} - - -/* PairPosFormat2 */ - -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; - - /* `Class1Count' and `Class2Count' are the upper limits for class - values, thus we read it now to make additional safety checks. */ - - 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; /* shut compiler up */ - - 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; /* Not enough glyphs in stream */ - - if ( context_length != 0xFFFF && context_length < 2 ) - return HB_Err_Not_Covered; - - if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) - return error; - - error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - /* second glyph */ - - first_pos = buffer->in_pos; - (buffer->in_pos)++; - - while ( CHECK_Property( gpos->layout, 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 we don't have coverage for the second glyph don't skip it for - further lookups but reset in_pos back to the first_glyph and let - the caller in Do_String_Lookup increment in_pos */ - if ( error == HB_Err_Not_Covered ) - buffer->in_pos = first_pos; - - /* adjusting the `next' glyph */ - - if ( pp->ValueFormat2 ) - (buffer->in_pos)++; - - return error; -} - - -/* LookupType 3 */ - -/* CursivePosFormat1 */ - -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; - } - - /* Glyphs not having the right GDEF property will be ignored, i.e., - gpi->last won't be reset (contrary to user defined properties). */ - - if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) - return error; - - /* We don't handle mark glyphs here. According to Andrei, this isn't - possible, but who knows... */ - - if ( property == HB_OT_LAYOUT_GLYPH_CLASS_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]; - - /* Now comes the messiest part of the whole OpenType - specification. At first glance, cursive connections seem easy - to understand, but there are pitfalls! The reason is that - the specs don't mention how to compute the advance values - resp. glyph offsets. I was told it would be an omission, to - be fixed in the next OpenType version... Again many thanks to - Andrei Burago <andreib@microsoft.com> for clarifications. - - Consider the following example: - - | xadv1 | - +---------+ - | | - +-----+--+ 1 | - | | .| | - | 0+--+------+ - | 2 | - | | - 0+--------+ - | xadv2 | - - glyph1: advance width = 12 - anchor point = (3,1) - - glyph2: advance width = 11 - anchor point = (9,4) - - LSB is 1 for both glyphs (so the boxes drawn above are glyph - bboxes). Writing direction is R2L; `0' denotes the glyph's - coordinate origin. - - Now the surprising part: The advance width of the *left* glyph - (resp. of the *bottom* glyph) will be modified, no matter - whether the writing direction is L2R or R2L (resp. T2B or - B2T)! This assymetry is caused by the fact that the glyph's - coordinate origin is always the lower left corner for all - writing directions. - - Continuing the above example, we can compute the new - (horizontal) advance width of glyph2 as - - 9 - 3 = 6 , - - and the new vertical offset of glyph2 as - - 1 - 4 = -3 . - - - Vertical writing direction is far more complicated: - - a) Assuming that we recompute the advance height of the lower glyph: - - -- - +---------+ - -- | | - +-----+--+ 1 | yadv1 - | | .| | - yadv2 | 0+--+------+ -- BSB1 -- - | 2 | -- -- y_offset - | | - BSB2 -- 0+--------+ -- - -- -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - - BSB1 = yadv1 - (TSB1 + ymax1) - BSB2 = yadv2 - (TSB2 + ymax2) - y_offset = y2 - y1 - - vertical advance width of glyph2 - = y_offset + BSB2 - BSB1 - = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) - = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) - = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 - - - b) Assuming that we recompute the advance height of the upper glyph: - - -- -- - +---------+ -- TSB1 - -- -- | | - TSB2 -- +-----+--+ 1 | yadv1 ymax1 - | | .| | - yadv2 | 0+--+------+ -- -- - ymax2 | 2 | -- y_offset - | | - -- 0+--------+ -- - -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - y_offset = y2 - y1 - - vertical advance width of glyph2 - = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) - = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 - - - Comparing a) with b) shows that b) is easier to compute. I'll wait - for a reply from Andrei to see what should really be implemented... - - Since horizontal advance widths or vertical advance heights - can be used alone but not together, no ambiguity occurs. */ - - if ( gpi->last == 0xFFFF ) - goto end; - - /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor - table. */ - - 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; -} - - -/* LookupType 4 */ - -/* BaseArray */ - -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) { - /* XXX - * Doulos SIL Regular is buggy and has zero offsets here. - * Skip it - */ - 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; - - HB_UNUSED(num_classes); - - if ( ba->BaseRecord ) - { - br = ba->BaseRecord; - - if ( ba->BaseCount ) - { - bans = br[0].BaseAnchor; - FREE( bans ); - } - - FREE( br ); - } -} - - -/* MarkBasePosFormat1 */ - -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->layout, IN_CURITEM(), - flags, &property ) ) - return error; - - error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(), - &mark_index ); - if ( error ) - return error; - - /* now we search backwards for a non-mark glyph */ - - i = 1; - j = buffer->in_pos - 1; - - while ( i <= buffer->in_pos ) - { - property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j)); - if ( !property ) - return HB_Err_Not_Covered; - - if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) - break; - - i++; - j--; - } - - /* The following assertion is too strong -- at least for mangal.ttf. */ -#if 0 - if ( property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH ) - return HB_Err_Not_Covered; -#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; - - /* anchor points are not cumulative */ - - 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; -} - - -/* LookupType 5 */ - -/* LigatureAttach */ - -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 ); - } -} - - -/* LigatureArray */ - -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 ); - } -} - - -/* MarkLigPosFormat1 */ - -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->layout, IN_CURITEM(), flags, &property ) ) - return error; - - error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index ); - if ( error ) - return error; - - /* now we search backwards for a non-mark glyph */ - - i = 1; - j = buffer->in_pos - 1; - - while ( i <= buffer->in_pos ) - { - property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j)); - if ( !property ) - return HB_Err_Not_Covered; - - if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) - break; - - i++; - j--; - } - - /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is - too strong, thus it is commented out. */ -#if 0 - if ( property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ) - return HB_Err_Not_Covered; -#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]; - - /* We must now check whether the ligature ID of the current mark glyph - is identical to the ligature ID of the found ligature. If yes, we - can directly use the component index. If not, we attach the mark - glyph to the last component of the ligature. */ - - 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; - - /* anchor points are not cumulative */ - - 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; -} - - -/* LookupType 6 */ - -/* Mark2Array */ - -static HB_Error Load_Mark2Array( HB_Mark2Array* m2a, - HB_UShort num_classes, - HB_Stream stream ) -{ - HB_Error error; - - HB_UShort k, 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) { - /* Anchor table not provided. Skip loading. - * Some versions of FreeSans hit this. */ - 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 ); - } -} - - -/* MarkMarkPosFormat1 */ - -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->layout, IN_CURITEM(), - flags, &property ) ) - return error; - - error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(), - &mark1_index ); - if ( error ) - return error; - - /* now we search backwards for a suitable mark glyph until a non-mark - glyph */ - - if ( buffer->in_pos == 0 ) - return HB_Err_Not_Covered; - - i = 1; - j = buffer->in_pos - 1; - while ( i <= buffer->in_pos ) - { - property = _hb_ot_layout_get_glyph_property (gpos->layout, IN_GLYPH(j)); - if ( !property ) - return HB_Err_Not_Covered; - - if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_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; - - /* anchor points are not cumulative */ - - 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; -} - - -/* Do the actual positioning for a context positioning (either format - 7 or 8). This is only called after we've determined that the stream - matches the subrule. */ - -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; - - /* Do a positioning */ - - 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; -} - - -/* LookupType 7 */ - -/* PosRule */ - -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; /* only GlyphCount - 1 elements */ - - 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 ); -} - - -/* PosRuleSet */ - -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 ); - } -} - - -/* ContextPosFormat1 */ - -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 ); -} - - -/* PosClassRule */ - -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; /* only GlyphCount - 1 elements */ - - 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 ); -} - - -/* PosClassSet */ - -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 ); - } -} - - -/* ContextPosFormat2 */ - -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; - - /* `PosClassSetCount' is the upper limit for class values, thus we - read it now to make an additional safety check. */ - - 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 ) /* not a NULL 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 - { - /* we create a PosClassSet table with no entries */ - - 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 ); -} - - -/* ContextPosFormat3 */ - -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 ); - } -} - - -/* ContextPos */ - -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; /* never reached */ -} - - -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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, 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; /* context is too long */ - - for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) - { - while ( CHECK_Property( layout, 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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - 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; /* context is too long */ - - cl = pr->Class; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( layout, 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 ) - { - /* Keeps us from having to do this for each rule */ - - 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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, 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; /* context is too long */ - - c = cpf3->Coverage; - - for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( layout, 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; /* never reached */ -} - - -/* LookupType 8 */ - -/* ChainPosRule */ - -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; /* only InputGlyphCount - 1 elements */ - - 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 ); -} - - -/* ChainPosRuleSet */ - -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 ); - } -} - - -/* ChainContextPosFormat1 */ - -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 ); -} - - -/* ChainPosClassRule */ - -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; /* only InputGlyphCount - 1 elements */ - - 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 ); -} - - -/* PosClassSet */ - -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 ); - } -} - - -/* ChainContextPosFormat2 */ - -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(); - - /* `ChainPosClassSetCount' is the upper limit for input class values, - thus we read it now to make an additional safety check. No limit - is known or needed for the other two class definitions */ - - 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 ) /* not a NULL 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 - { - /* we create a ChainPosClassSet table with no entries */ - - 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 ); -} - - -/* ChainContextPosFormat3 */ - -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 ); - } -} - - -/* ChainContextPos */ - -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; /* never reached */ -} - - -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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, 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; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainposrule; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != HB_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - goto next_chainposrule; - j--; - } - - /* In OpenType 1.3, it is undefined whether the offsets of - backtrack glyphs is in logical order or not. Version 1.4 - will clarify this: - - Logical order - a b c d e f g h i j - i - Input offsets - 0 1 - Backtrack offsets - 3 2 1 0 - Lookahead offsets - 0 1 2 3 */ - - if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) - goto next_chainposrule; - } - } - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( layout, 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; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( layout, 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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - 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; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainposclassrule; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array. - Note that `known_backtrack_classes' starts at index 0. */ - - bc = cpcr.Backtrack; - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( layout, 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 ) - { - /* Keeps us from having to do this for each rule */ - - 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; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( layout, 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; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - lc = cpcr.Lookahead; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( layout, 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_ot_layout_t* layout; - - - layout = gpos->layout; - - if ( CHECK_Property( layout, 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; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - return HB_Err_Not_Covered; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - bc = ccpf3->BacktrackCoverage; - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( layout, 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++ ) - { - /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ - while ( j > buffer->in_pos && CHECK_Property( layout, 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; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - lc = ccpf3->LookaheadCoverage; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( layout, 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; /* never reached */ -} - - - -/*********** - * GPOS API - ***********/ - - - -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; -} - - -/* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - -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; -} - - -/* The next three functions return a null-terminated list */ - - -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; -} - - -/* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - -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; -} - - -/* Do an individual subtable lookup. Returns HB_Err_Ok if positioning - has been done, or HB_Err_Not_Covered if not. */ -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); /* ERR() call intended */ - - 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; - /*case HB_GPOS_LOOKUP_EXTENSION: - error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/ - default: - error = HB_Err_Not_Covered; - } - - /* Check whether we have a successful positioning or an error other - than 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 ); - /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( 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; - /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/ - default: return; - } -} - - -/* apply one lookup to the input string object */ - -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; - /* 0xFFFF indicates that we don't have a context length yet */ - const HB_UShort context_length = 0xFFFF; - - - gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ - - buffer->in_pos = 0; - while ( buffer->in_pos < buffer->in_length ) - { - if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) - { - /* Note that the connection between mark and base glyphs hold - exactly one (string) lookup. For example, it would be possible - that in the first lookup, mark glyph X is attached to base - glyph A, and in the next lookup it is attached to base glyph B. - It is up to the font designer to provide meaningful lookups and - lookup order. */ - - error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level ); - if ( error && error != HB_Err_Not_Covered ) - return error; - } - else - { - /* Contrary to properties defined in GDEF, user-defined properties - will always stop a possible cursive positioning. */ - 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; - - /* First handle all left-to-right connections */ - 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; - } - - /* Then handle all right-to-left connections */ - 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; - - /* Each feature can only be added once */ - - 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_Glyph_Function( HB_GPOSHeader* gpos, - HB_GlyphFunction gfunc ) -{ - if ( !gpos ) - return ERR(HB_Err_Invalid_Argument); - - gpos->gfunc = gfunc; - - 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; -} - -/* If `dvi' is TRUE, glyph contour points for anchor points and device - tables are ignored -- you will get device independent values. */ - - -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]; - - /* Skip nonexistant lookups */ - 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; -} - -/* END */ |