--- /dev/null
- $(FREETYPE_CFLAGS)
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = \
+ -I $(srcdir) \
- harfbuzz.c
++ $(FREETYPE_CFLAGS) \
++ $(GLIB_CFLAGS)
++CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align
+
+noinst_LTLIBRARIES = libharfbuzz-1.la
+
+MAINSOURCES = \
- harfbuzz-gdef.c \
++ $(INCLUDEDSOURCES) \
++ hb-ot-layout.cc
++# harfbuzz.c
+
+# included from harfbuzz.c
+INCLUDEDSOURCES = \
+ harfbuzz-buffer.c \
- harfbuzz-gdef.h \
+ harfbuzz-gpos.c \
+ harfbuzz-gsub.c \
+ harfbuzz-impl.c \
+ harfbuzz-open.c \
+ harfbuzz-stream.c
+
+PUBLICHEADERS = \
+ harfbuzz.h \
+ harfbuzz-global.h \
+ harfbuzz-buffer.h \
- harfbuzz-gdef-private.h \
+ harfbuzz-gpos.h \
+ harfbuzz-gsub.h \
+ harfbuzz-open.h
+
+PRIVATEHEADERS = \
+ harfbuzz-impl.h \
+ harfbuzz-buffer-private.h \
- noinst_PROGRAMS = harfbuzz-dump
+ harfbuzz-gpos-private.h \
+ harfbuzz-gsub-private.h \
+ harfbuzz-open-private.h \
+ harfbuzz-stream-private.h
+
+libharfbuzz_1_la_SOURCES = \
+ $(MAINSOURCES) \
+ $(PUBLICHEADERS) \
+ $(PRIVATEHEADERS)
+
+libharfbuzz_1_la_LIBADD = \
+ $(FREETYPE_LIBS)
+
++noinst_PROGRAMS = harfbuzz-dump main
+
+harfbuzz_dump_SOURCES = \
+ harfbuzz-dump.c \
+ harfbuzz-dump.h \
+ harfbuzz-dump-main.c
+
+harfbuzz_dump_LDADD = \
+ $(libharfbuzz_1_la_LIBADD) \
+ libharfbuzz-1.la
+
++main_LDADD = \
++ $(GLIB_LIBS)
++
+EXTRA_DIST = \
+ README \
+ COPYING \
+ $(INCLUDEDSOURCES)
+
+-include $(top_srcdir)/git.mk
--- /dev/null
- #define CHECK_Property( gdef, index, flags, property ) \
- ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags), \
- (property) ) ) != HB_Err_Ok )
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,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): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HARFBUZZ_BUFFER_PRIVATE_H
+#define HARFBUZZ_BUFFER_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+#define HB_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
+
+HB_INTERNAL void
+_hb_buffer_swap( HB_Buffer buffer );
+
+HB_INTERNAL void
+_hb_buffer_clear_output( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_clear_positions( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyphs( HB_Buffer buffer,
+ HB_UShort num_in,
+ HB_UShort num_out,
+ HB_UShort *glyph_data,
+ HB_UShort component,
+ HB_UShort ligID );
+
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyph ( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_UShort component,
+ HB_UShort ligID );
+
+HB_INTERNAL HB_Error
+_hb_buffer_copy_output_glyph ( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_replace_output_glyph ( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_Bool inplace );
+
+HB_INTERNAL HB_UShort
+_hb_buffer_allocate_ligid( HB_Buffer buffer );
+
+
+/* convenience macros */
+
+#define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex)
+#define IN_ITEM( pos ) (&buffer->in_string[(pos)])
+#define IN_CURGLYPH() (buffer->in_string[buffer->in_pos].gindex)
+#define IN_CURITEM() (&buffer->in_string[buffer->in_pos])
+#define IN_PROPERTIES( pos ) (buffer->in_string[(pos)].properties)
+#define IN_LIGID( pos ) (buffer->in_string[(pos)].ligID)
+#define IN_COMPONENT( pos ) (buffer->in_string[(pos)].component)
+#define POSITION( pos ) (&buffer->positions[(pos)])
+#define OUT_GLYPH( pos ) (buffer->out_string[(pos)].gindex)
+#define OUT_ITEM( pos ) (&buffer->out_string[(pos)])
+
++#define CHECK_Property( layout, index, flags, property ) \
++ (error = _hb_ot_layout_check_glyph_properties((layout), (index), (flags), (property)) \
++ ? HB_Err_Ok : HB_Err_Not_Covered)
+
+#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \
+ ( ( error = _hb_buffer_add_output_glyphs( (buffer), \
+ (num_in), (num_out), \
+ (glyph_data), (component), (ligID) \
+ ) ) != HB_Err_Ok )
+#define ADD_Glyph( buffer, glyph_index, component, ligID ) \
+ ( ( error = _hb_buffer_add_output_glyph( (buffer), \
+ (glyph_index), (component), (ligID) \
+ ) ) != HB_Err_Ok )
+#define REPLACE_Glyph( buffer, glyph_index, nesting_level ) \
+ ( ( error = _hb_buffer_replace_output_glyph( (buffer), (glyph_index), \
+ (nesting_level) == 1 ) ) != HB_Err_Ok )
+#define COPY_Glyph( buffer ) \
+ ( (error = _hb_buffer_copy_output_glyph ( buffer ) ) != HB_Err_Ok )
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_BUFFER_PRIVATE_H */
--- /dev/null
+/*
+ * Copyright (C) 2007 Trolltech ASA
+ * 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
+ */
+
+#ifndef HARFBUZZ_GLOBAL_H
+#define HARFBUZZ_GLOBAL_H
+
++/* XXX */
++#include "hb-ot-layout.h"
++
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef __cplusplus
+#define HB_BEGIN_HEADER extern "C" {
+#define HB_END_HEADER }
+#else
+#define HB_BEGIN_HEADER /* nothing */
+#define HB_END_HEADER /* nothing */
+#endif
+
+HB_BEGIN_HEADER
+
+#define HB_MAKE_TAG(a,b,c,d) FT_MAKE_TAG(a,b,c,d)
+typedef FT_Pos HB_Fixed; /* 26.6 */
+typedef FT_Fixed HB_16Dot16; /* 16.6 */
+typedef FT_Face HB_Font;
+
+typedef unsigned char HB_Byte;
+typedef signed char HB_Char;
+typedef unsigned short HB_UShort;
+typedef signed short HB_Short;
+typedef unsigned int HB_UInt;
+typedef signed int HB_Int;
+typedef int HB_Bool;
+typedef void * HB_Pointer;
+
+
+typedef enum {
+ /* no error */
+ HB_Err_Ok = 0x0000,
+ HB_Err_Not_Covered = 0xFFFF,
+
+ /* _hb_err() is called whenever returning the following errors,
+ * and in a couple places for HB_Err_Not_Covered too. */
+
+ /* programmer error */
+ HB_Err_Invalid_Argument = 0x1A66,
+
+ /* font error */
+ HB_Err_Invalid_SubTable_Format = 0x157F,
+ HB_Err_Invalid_SubTable = 0x1570,
+ HB_Err_Read_Error = 0x6EAD,
+
+ /* system error */
+ HB_Err_Out_Of_Memory = 0xDEAD
+} HB_Error;
+
+HB_END_HEADER
+
+#endif
--- /dev/null
- HB_GDEFHeader* gdef )
+/*
+ * 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,
- if ( !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;
+
+
- gpos->gdef = gdef; /* can be NULL */
-
- if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
- gpos->LookupList.Lookup,
- gpos->LookupList.LookupCount ) ) )
- goto Fail1;
++ 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;
+
- Fail1:
- _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
-
++ gpos->layout = layout; /* can be NULL */
+
+ *retptr = gpos;
+
+ return HB_Err_Ok;
+
- if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+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->gdef, IN_CURITEM(), flags, &property ) )
++ 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;
+
- while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++ 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)++;
+
- if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
++ 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 properties will be ignored, i.e.,
+ gpi->last won't be reset (contrary to user defined properties). */
+
- if ( property == HB_GDEF_MARK )
++ 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 ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++ 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;
+
- error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
- &property );
- if ( error )
- return error;
++ 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 )
+ {
- if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++ property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++ if ( !property )
++ return HB_Err_Not_Covered;
+
- if ( property != HB_GDEF_BASE_GLYPH )
++ 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 ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
++ 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();
+
- error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
- &property );
- if ( error )
- return error;
++ 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 )
+ {
- if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++ property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++ if ( !property )
++ return HB_Err_Not_Covered;
+
- if ( property != HB_GDEF_LIGATURE )
++ 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 ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++ 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;
+
- error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
- &property );
- if ( error )
- return error;
++ 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 )
+ {
- if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++ property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++ if ( !property )
++ return HB_Err_Not_Covered;
+
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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++ )
+ {
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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++ )
+ {
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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++ )
+ {
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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( gdef, IN_ITEM( j ), flags, &property ) )
++ 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( gdef, IN_ITEM( j ), flags, &property ) )
++ 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++ )
+ {
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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( gdef, IN_ITEM( j ), flags, &property ) )
++ 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( gdef, IN_ITEM( j ), flags, &property ) )
++ 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++ )
+ {
- HB_GDEFHeader* gdef;
++ 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;
- gdef = gpos->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gpos->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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 ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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 ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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 */
--- /dev/null
- #include "harfbuzz-gdef.h"
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HARFBUZZ_GPOS_H
+#define HARFBUZZ_GPOS_H
+
- HB_GDEFHeader* gdef;
++#include "harfbuzz-open.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+
+/* Lookup types for glyph positioning */
+
+#define HB_GPOS_LOOKUP_SINGLE 1
+#define HB_GPOS_LOOKUP_PAIR 2
+#define HB_GPOS_LOOKUP_CURSIVE 3
+#define HB_GPOS_LOOKUP_MARKBASE 4
+#define HB_GPOS_LOOKUP_MARKLIG 5
+#define HB_GPOS_LOOKUP_MARKMARK 6
+#define HB_GPOS_LOOKUP_CONTEXT 7
+#define HB_GPOS_LOOKUP_CHAIN 8
+#define HB_GPOS_LOOKUP_EXTENSION 9
+
+
+/* A pointer to a function which loads a glyph. Its parameters are
+ the same as in a call to Load_Glyph() -- if no glyph loading
+ function will be registered with HB_GPOS_Register_Glyph_Function(),
+ Load_Glyph() will be called indeed. The purpose of this function
+ pointer is to provide a hook for caching glyph outlines and sbits
+ (using the instance's generic pointer to hold the data).
+
+ If for some reason no outline data is available (e.g. for an
+ embedded bitmap glyph), _glyph->outline.n_points should be set to
+ zero. */
+
+typedef HB_Error (*HB_GlyphFunction)(HB_Font font,
+ HB_UInt glyphIndex,
+ HB_Int loadFlags );
+
+
+/* A pointer to a function which accesses the PostScript interpreter.
+ Multiple Master fonts need this interface to convert a metric ID
+ (as stored in an OpenType font version 1.2 or higher) `metric_id'
+ into a metric value (returned in `metric_value').
+
+ `data' points to the user-defined structure specified during a
+ call to HB_GPOS_Register_MM_Function().
+
+ `metric_value' must be returned as a scaled value (but shouldn't
+ be rounded). */
+
+typedef HB_Error (*HB_MMFunction)(HB_Font font,
+ HB_UShort metric_id,
+ HB_Fixed* metric_value,
+ void* data );
+
+
+struct HB_GPOSHeader_
+{
+ HB_16Dot16 Version;
+
+ HB_ScriptList ScriptList;
+ HB_FeatureList FeatureList;
+ HB_LookupList LookupList;
+
- HB_GDEFHeader* gdef );
++ hb_ot_layout_t *layout;
+
+ /* the next field is used for a callback function to get the
+ glyph outline. */
+
+ HB_GlyphFunction gfunc;
+
+ /* this is OpenType 1.2 -- Multiple Master fonts need this
+ callback function to get various metric values from the
+ PostScript interpreter. */
+
+ HB_MMFunction mmfunc;
+ void* data;
+};
+
+typedef struct HB_GPOSHeader_ HB_GPOSHeader;
+typedef HB_GPOSHeader* HB_GPOS;
+
+
+HB_Error HB_Load_GPOS_Table( HB_Font font,
+ HB_GPOSHeader** gpos,
++ hb_ot_layout_t *layout );
+
+
+HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos );
+
+
+HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
+ HB_UInt script_tag,
+ HB_UShort* script_index );
+
+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_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_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
+ HB_UInt** script_tag_list );
+
+HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list );
+
+HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list );
+
+
+HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
+ HB_UShort feature_index,
+ HB_UInt property );
+
+HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos );
+
+
+HB_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos,
+ HB_GlyphFunction gfunc );
+
+
+HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
+ HB_MMFunction mmfunc,
+ void* data );
+
+/* 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_END_HEADER
+
+#endif /* HARFBUZZ_GPOS_H */
--- /dev/null
- HB_GDEFHeader* gdef )
+/*
+ * 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-gsub-private.h"
+#include "harfbuzz-open-private.h"
+#include "harfbuzz-gdef-private.h"
+
+static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
+ HB_UShort lookup_index,
+ HB_Buffer buffer,
+ HB_UShort context_length,
+ int nesting_level );
+
+
+
+/**********************
+ * Auxiliary functions
+ **********************/
+
+
+
+HB_Error HB_Load_GSUB_Table( HB_Font font,
+ HB_GSUBHeader** retptr,
- if ( !retptr )
++ hb_ot_layout_t *layout )
+{
+ HB_Stream stream = font->stream;
+ HB_Error error;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_GSUBHeader* gsub;
+
- gsub->gdef = gdef; /* can be NULL */
-
- if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
- gsub->LookupList.Lookup,
- gsub->LookupList.LookupCount ) ) )
- goto Fail1;
++ if ( !retptr || !layout )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( GOTO_Table( TTAG_GSUB ) )
+ return error;
+
+ base_offset = FILE_Pos();
+
+ if ( ALLOC ( gsub, sizeof( *gsub ) ) )
+ return error;
+
+
+ /* 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( &gsub->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( &gsub->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( &gsub->LookupList,
+ stream, HB_Type_GSUB ) ) != HB_Err_Ok )
+ goto Fail2;
+
- Fail1:
- _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
-
++ gsub->layout = layout; /* can be NULL */
+
+ *retptr = gsub;
+
+ return HB_Err_Ok;
+
- HB_GDEFHeader* gdef = gsub->gdef;
+Fail2:
+ _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
+
+Fail3:
+ _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
+
+Fail4:
+ FREE ( gsub );
+
+
+ return error;
+}
+
+
+HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
+{
+ _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
+ _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
+ _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
+
+ FREE( gsub );
+
+ return HB_Err_Ok;
+}
+
+/*****************************
+ * SubTable related functions
+ *****************************/
+
+
+/* LookupType 1 */
+
+/* SingleSubstFormat1 */
+/* SingleSubstFormat2 */
+
+static HB_Error Load_SingleSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_SingleSubst* ss = &st->single;
+
+ HB_UShort n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_UShort* s;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ss->SubstFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
+
+ FORGET_Frame();
+
+ break;
+
+ case 2:
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ss->ssf.ssf2.GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ss->ssf.ssf2.Substitute = NULL;
+
+ if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
+ goto Fail2;
+
+ s = ss->ssf.ssf2.Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ s[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( s );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ss->Coverage );
+ return error;
+}
+
+
+static void Free_SingleSubst( HB_GSUB_SubTable* st )
+{
+ HB_SingleSubst* ss = &st->single;
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ break;
+
+ case 2:
+ FREE( ss->ssf.ssf2.Substitute );
+ break;
+
+ default:
+ break;
+ }
+
+ _HB_OPEN_Free_Coverage( &ss->Coverage );
+}
+
+
+static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, value, property;
+ HB_Error error;
+ HB_SingleSubst* ss = &st->single;
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ hb_ot_layout_t* layout = gsub->layout;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
- if ( gdef && gdef->NewGlyphClasses )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ value = (IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+ break;
+
+ case 2:
+ if ( index >= ss->ssf.ssf2.GlyphCount )
+ return ERR(HB_Err_Invalid_SubTable);
+ value = ss->ssf.ssf2.Substitute[index];
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable);
+ }
+
- error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
- if ( error && error != HB_Err_Not_Covered )
- return error;
++ if ( _hb_ot_layout_has_new_glyph_classes (layout) )
+ {
+ /* we inherit the old glyph class to the substituted glyph */
+
- HB_GDEFHeader* gdef = gsub->gdef;
++ hb_ot_layout_set_glyph_class (layout, value, property);
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 2 */
+
+/* Sequence */
+
+static HB_Error Load_Sequence( HB_Sequence* s,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* sub;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = s->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ s->Substitute = NULL;
+
+ if ( count )
+ {
+ if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
+ return error;
+
+ sub = s->Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( sub );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ sub[n] = GET_UShort();
+
+ FORGET_Frame();
+ }
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Sequence( HB_Sequence* s )
+{
+ FREE( s->Substitute );
+}
+
+
+/* MultipleSubstFormat1 */
+
+static HB_Error Load_MultipleSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_MultipleSubst* ms = &st->multiple;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Sequence* s;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ms->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ms->SequenceCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ms->Sequence = NULL;
+
+ if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
+ goto Fail2;
+
+ s = ms->Sequence;
+
+ 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_Sequence( &s[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_Sequence( &s[m] );
+
+ FREE( s );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ms->Coverage );
+ return error;
+}
+
+
+static void Free_MultipleSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_MultipleSubst* ms = &st->multiple;
+
+ HB_Sequence* s;
+
+
+ if ( ms->Sequence )
+ {
+ count = ms->SequenceCount;
+ s = ms->Sequence;
+
+ for ( n = 0; n < count; n++ )
+ Free_Sequence( &s[n] );
+
+ FREE( s );
+ }
+
+ _HB_OPEN_Free_Coverage( &ms->Coverage );
+}
+
+
+static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, property, n, count;
+ HB_UShort*s;
+ HB_MultipleSubst* ms = &st->multiple;
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ hb_ot_layout_t* layout = gsub->layout;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
- if ( gdef && gdef->NewGlyphClasses )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( index >= ms->SequenceCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ count = ms->Sequence[index].GlyphCount;
+ s = ms->Sequence[index].Substitute;
+
+ if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
+ return error;
+
- if ( property == HB_GDEF_LIGATURE )
- property = HB_GDEF_BASE_GLYPH;
++ if ( _hb_ot_layout_has_new_glyph_classes (layout) )
+ {
+ /* this is a guess only ... */
+
- {
- error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
- if ( error && error != HB_Err_Not_Covered )
- return error;
- }
++ if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
++ property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
+
+ for ( n = 0; n < count; n++ )
- HB_GDEFHeader* gdef = gsub->gdef;
++ hb_ot_layout_set_glyph_class (layout, s[n], property);
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 3 */
+
+/* AlternateSet */
+
+static HB_Error Load_AlternateSet( HB_AlternateSet* as,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* a;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = as->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ as->Alternate = NULL;
+
+ if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
+ return error;
+
+ a = as->Alternate;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( a );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ a[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_AlternateSet( HB_AlternateSet* as )
+{
+ FREE( as->Alternate );
+}
+
+
+/* AlternateSubstFormat1 */
+
+static HB_Error Load_AlternateSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_AlternateSubst* as = &st->alternate;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_AlternateSet* aset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ as->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = as->AlternateSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ as->AlternateSet = NULL;
+
+ if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
+ goto Fail2;
+
+ aset = as->AlternateSet;
+
+ 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_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_AlternateSet( &aset[m] );
+
+ FREE( aset );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &as->Coverage );
+ return error;
+}
+
+
+static void Free_AlternateSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_AlternateSubst* as = &st->alternate;
+
+ HB_AlternateSet* aset;
+
+
+ if ( as->AlternateSet )
+ {
+ count = as->AlternateSetCount;
+ aset = as->AlternateSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_AlternateSet( &aset[n] );
+
+ FREE( aset );
+ }
+
+ _HB_OPEN_Free_Coverage( &as->Coverage );
+}
+
+
+static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, value, alt_index, property;
+ HB_AlternateSubst* as = &st->alternate;
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ hb_ot_layout_t* layout = gsub->layout;
+ HB_AlternateSet aset;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
- if ( gdef && gdef->NewGlyphClasses )
- {
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ aset = as->AlternateSet[index];
+
+ /* we use a user-defined callback function to get the alternate index */
+
+ if ( gsub->altfunc )
+ alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
+ aset.GlyphCount, aset.Alternate,
+ gsub->data );
+ else
+ alt_index = 0;
+
+ value = aset.Alternate[alt_index];
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+
-
- error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
- if ( error && error != HB_Err_Not_Covered )
- return error;
- }
++ if ( _hb_ot_layout_has_new_glyph_classes (layout) )
+ /* we inherit the old glyph class to the substituted glyph */
- HB_GDEFHeader* gdef = gsub->gdef;
++ hb_ot_layout_set_glyph_class (layout, value, property);
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 4 */
+
+/* Ligature */
+
+static HB_Error Load_Ligature( HB_Ligature* l,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* c;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ l->LigGlyph = GET_UShort();
+ l->ComponentCount = GET_UShort();
+
+ FORGET_Frame();
+
+ l->Component = NULL;
+
+ count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */
+
+ if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
+ return error;
+
+ c = l->Component;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( c );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ c[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Ligature( HB_Ligature* l )
+{
+ FREE( l->Component );
+}
+
+
+/* LigatureSet */
+
+static HB_Error Load_LigatureSet( HB_LigatureSet* ls,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Ligature* l;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ls->LigatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->Ligature = NULL;
+
+ if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
+ return error;
+
+ l = ls->Ligature;
+
+ 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_Ligature( &l[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_Ligature( &l[m] );
+
+ FREE( l );
+ return error;
+}
+
+
+static void Free_LigatureSet( HB_LigatureSet* ls )
+{
+ HB_UShort n, count;
+
+ HB_Ligature* l;
+
+
+ if ( ls->Ligature )
+ {
+ count = ls->LigatureCount;
+ l = ls->Ligature;
+
+ for ( n = 0; n < count; n++ )
+ Free_Ligature( &l[n] );
+
+ FREE( l );
+ }
+}
+
+
+/* LigatureSubstFormat1 */
+
+static HB_Error Load_LigatureSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_LigatureSubst* ls = &st->ligature;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LigatureSet* lset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ls->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ls->LigatureSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->LigatureSet = NULL;
+
+ if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
+ goto Fail2;
+
+ lset = ls->LigatureSet;
+
+ 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_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_LigatureSet( &lset[m] );
+
+ FREE( lset );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ls->Coverage );
+ return error;
+}
+
+
+static void Free_LigatureSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_LigatureSubst* ls = &st->ligature;
+
+ HB_LigatureSet* lset;
+
+
+ if ( ls->LigatureSet )
+ {
+ count = ls->LigatureSetCount;
+ lset = ls->LigatureSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_LigatureSet( &lset[n] );
+
+ FREE( lset );
+ }
+
+ _HB_OPEN_Free_Coverage( &ls->Coverage );
+}
+
+
+static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort numlig, i, j, is_mark, first_is_mark = FALSE;
+ HB_UShort* c;
+ HB_LigatureSubst* ls = &st->ligature;
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ hb_ot_layout_t* layout = gsub->layout;
+
+ HB_Ligature* lig;
+
+ HB_UNUSED(nesting_level);
+
- if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+ first_is_mark = TRUE;
+
+ error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( index >= ls->LigatureSetCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ lig = ls->LigatureSet[index].Ligature;
+
+ for ( numlig = ls->LigatureSet[index].LigatureCount;
+ numlig;
+ numlig--, lig++ )
+ {
+ if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
+ goto next_ligature; /* Not enough glyphs in input */
+
+ c = lig->Component;
+
+ is_mark = first_is_mark;
+
+ if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
+ break;
+
+ for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
+ {
- if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++ while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
+ goto next_ligature;
+ j++;
+ }
+
- if ( gdef && gdef->NewGlyphClasses )
- {
++ if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+ is_mark = FALSE;
+
+ if ( IN_GLYPH( j ) != c[i - 1] )
+ goto next_ligature;
+ }
+
-
- error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
- is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
- if ( error && error != HB_Err_Not_Covered )
- return error;
- }
++ if ( _hb_ot_layout_has_new_glyph_classes (layout) )
+ /* this is just a guess ... */
- while ( CHECK_Property( gdef, IN_CURITEM(),
++ hb_ot_layout_set_glyph_class (layout, lig->LigGlyph, is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
+
+ if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
+ {
+ /* We don't use a new ligature ID if there are no skipped
+ glyphs and the ligature already has an ID. */
+
+ if ( IN_LIGID( buffer->in_pos ) )
+ {
+ if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
+ 0xFFFF, 0xFFFF ) )
+ return error;
+ }
+ else
+ {
+ HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
+ if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
+ 0xFFFF, ligID ) )
+ return error;
+ }
+ }
+ else
+ {
+ HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
+ if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
+ return error;
+
+ /* Now we must do a second loop to copy the skipped glyphs to
+ `out' and assign component values to it. We start with the
+ glyph after the first component. Glyphs between component
+ i and i+1 belong to component i. Together with the ligID
+ value it is later possible to check whether a specific
+ component value really belongs to a given ligature. */
+
+ for ( i = 0; i < lig->ComponentCount - 1; i++ )
+ {
- HB_GDEFHeader* gdef;
++ while ( CHECK_Property( layout, IN_CURITEM(),
+ flags, &property ) )
+ if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
+ return error;
+
+ (buffer->in_pos)++;
+ }
+ }
+
+ return HB_Err_Ok;
+
+ next_ligature:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* Do the actual substitution for a context substitution (either format
+ 5 or 6). This is only called after we've determined that the input
+ matches the subrule. */
+
+static HB_Error Do_ContextSubst( HB_GSUBHeader* gsub,
+ HB_UShort GlyphCount,
+ HB_UShort SubstCount,
+ HB_SubstLookupRecord* subst,
+ HB_Buffer buffer,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UInt i, old_pos;
+
+
+ i = 0;
+
+ while ( i < GlyphCount )
+ {
+ if ( SubstCount && i == subst->SequenceIndex )
+ {
+ old_pos = buffer->in_pos;
+
+ /* Do a substitution */
+
+ error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
+ GlyphCount, nesting_level );
+
+ subst++;
+ SubstCount--;
+ i += buffer->in_pos - old_pos;
+
+ if ( error == HB_Err_Not_Covered )
+ {
+ if ( COPY_Glyph( buffer ) )
+ return error;
+ i++;
+ }
+ else if ( error )
+ return error;
+ }
+ else
+ {
+ /* No substitution for this index */
+
+ if ( COPY_Glyph( buffer ) )
+ return error;
+ i++;
+ }
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 5 */
+
+/* SubRule */
+
+static HB_Error Load_SubRule( HB_SubRule* sr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* i;
+
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ sr->GlyphCount = GET_UShort();
+ sr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ sr->Input = NULL;
+
+ count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
+ return error;
+
+ i = sr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ sr->SubstLookupRecord = NULL;
+
+ count = sr->SubstCount;
+
+ if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = sr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( i );
+ return error;
+}
+
+
+static void Free_SubRule( HB_SubRule* sr )
+{
+ FREE( sr->SubstLookupRecord );
+ FREE( sr->Input );
+}
+
+
+/* SubRuleSet */
+
+static HB_Error Load_SubRuleSet( HB_SubRuleSet* srs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubRule* sr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = srs->SubRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ srs->SubRule = NULL;
+
+ if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
+ return error;
+
+ sr = srs->SubRule;
+
+ 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_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubRule( &sr[m] );
+
+ FREE( sr );
+ return error;
+}
+
+
+static void Free_SubRuleSet( HB_SubRuleSet* srs )
+{
+ HB_UShort n, count;
+
+ HB_SubRule* sr;
+
+
+ if ( srs->SubRule )
+ {
+ count = srs->SubRuleCount;
+ sr = srs->SubRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubRule( &sr[n] );
+
+ FREE( sr );
+ }
+}
+
+
+/* ContextSubstFormat1 */
+
+static HB_Error Load_ContextSubst1( HB_ContextSubstFormat1* csf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubRuleSet* srs;
+
+
+ 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( &csf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = csf1->SubRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csf1->SubRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
+ goto Fail2;
+
+ srs = csf1->SubRuleSet;
+
+ 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_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_SubRuleSet( &srs[m] );
+
+ FREE( srs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &csf1->Coverage );
+ return error;
+}
+
+
+static void Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
+{
+ HB_UShort n, count;
+
+ HB_SubRuleSet* srs;
+
+
+ if ( csf1->SubRuleSet )
+ {
+ count = csf1->SubRuleSetCount;
+ srs = csf1->SubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubRuleSet( &srs[n] );
+
+ FREE( srs );
+ }
+
+ _HB_OPEN_Free_Coverage( &csf1->Coverage );
+}
+
+
+/* SubClassRule */
+
+static HB_Error Load_SubClassRule( HB_ContextSubstFormat2* csf2,
+ HB_SubClassRule* scr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* c;
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ scr->GlyphCount = GET_UShort();
+ scr->SubstCount = GET_UShort();
+
+ if ( scr->GlyphCount > csf2->MaxContextLength )
+ csf2->MaxContextLength = scr->GlyphCount;
+
+ FORGET_Frame();
+
+ scr->Class = NULL;
+
+ count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
+ return error;
+
+ c = scr->Class;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ c[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ scr->SubstLookupRecord = NULL;
+
+ count = scr->SubstCount;
+
+ if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = scr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( c );
+ return error;
+}
+
+
+static void Free_SubClassRule( HB_SubClassRule* scr )
+{
+ FREE( scr->SubstLookupRecord );
+ FREE( scr->Class );
+}
+
+
+/* SubClassSet */
+
+static HB_Error Load_SubClassSet( HB_ContextSubstFormat2* csf2,
+ HB_SubClassSet* scs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubClassRule* scr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = scs->SubClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ scs->SubClassRule = NULL;
+
+ if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
+ return error;
+
+ scr = scs->SubClassRule;
+
+ 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_SubClassRule( csf2, &scr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubClassRule( &scr[m] );
+
+ FREE( scr );
+ return error;
+}
+
+
+static void Free_SubClassSet( HB_SubClassSet* scs )
+{
+ HB_UShort n, count;
+
+ HB_SubClassRule* scr;
+
+
+ if ( scs->SubClassRule )
+ {
+ count = scs->SubClassRuleCount;
+ scr = scs->SubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubClassRule( &scr[n] );
+
+ FREE( scr );
+ }
+}
+
+
+/* ContextSubstFormat2 */
+
+static HB_Error Load_ContextSubst2( HB_ContextSubstFormat2* csf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubClassSet* scs;
+
+
+ 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( &csf2->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ /* `SubClassSetCount' is the upper limit for class values, thus we
+ read it now to make an additional safety check. */
+
+ count = csf2->SubClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ csf2->SubClassSet = NULL;
+ csf2->MaxContextLength = 0;
+
+ if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
+ goto Fail2;
+
+ scs = csf2->SubClassSet;
+
+ 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_SubClassSet( csf2, &scs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a SubClassSet table with no entries */
+
+ csf2->SubClassSet[n].SubClassRuleCount = 0;
+ csf2->SubClassSet[n].SubClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_SubClassSet( &scs[m] );
+
+ FREE( scs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &csf2->Coverage );
+ return error;
+}
+
+
+static void Free_ContextSubst2( HB_ContextSubstFormat2* csf2 )
+{
+ HB_UShort n, count;
+
+ HB_SubClassSet* scs;
+
+
+ if ( csf2->SubClassSet )
+ {
+ count = csf2->SubClassSetCount;
+ scs = csf2->SubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubClassSet( &scs[n] );
+
+ FREE( scs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
+ _HB_OPEN_Free_Coverage( &csf2->Coverage );
+}
+
+
+/* ContextSubstFormat3 */
+
+static HB_Error Load_ContextSubst3( HB_ContextSubstFormat3* csf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* c;
+ HB_SubstLookupRecord* slr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ csf3->GlyphCount = GET_UShort();
+ csf3->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csf3->Coverage = NULL;
+
+ count = csf3->GlyphCount;
+
+ if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
+ return error;
+
+ c = csf3->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 );
+ }
+
+ csf3->SubstLookupRecord = NULL;
+
+ count = csf3->SubstCount;
+
+ if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = csf3->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ for ( m = 0; m < n; m++ )
+ _HB_OPEN_Free_Coverage( &c[m] );
+
+ FREE( c );
+ return error;
+}
+
+
+static void Free_ContextSubst3( HB_ContextSubstFormat3* csf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( csf3->SubstLookupRecord );
+
+ if ( csf3->Coverage )
+ {
+ count = csf3->GlyphCount;
+ c = csf3->Coverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ContextSubst */
+
+static HB_Error Load_ContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ContextSubst* cs = &st->context;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: return Load_ContextSubst1( &cs->csf.csf1, stream );
+ case 2: return Load_ContextSubst2( &cs->csf.csf2, stream );
+ case 3: return Load_ContextSubst3( &cs->csf.csf3, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_ContextSubst* cs = &st->context;
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: Free_ContextSubst1( &cs->csf.csf1 ); break;
+ case 2: Free_ContextSubst2( &cs->csf.csf2 ); break;
+ case 3: Free_ContextSubst3( &cs->csf.csf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat1* csf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, numsr;
+ HB_Error error;
+
+ HB_SubRule* sr;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ sr = csf1->SubRuleSet[index].SubRule;
+ numsr = csf1->SubRuleSet[index].SubRuleCount;
+
+ for ( k = 0; k < numsr; k++ )
+ {
+ if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
+ goto next_subrule;
+
+ if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
+ goto next_subrule; /* context is too long */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
+ goto next_subrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
+ goto next_subrule;
+ }
+
+ return Do_ContextSubst( gsub, sr[k].GlyphCount,
+ sr[k].SubstCount, sr[k].SubstLookupRecord,
+ buffer,
+ nesting_level );
+ next_subrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat2* csf2,
+ 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_SubClassSet* scs;
+ HB_SubClassRule* sr;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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( &csf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if (csf2->MaxContextLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
+ return error;
+
+ error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
+ &classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+ known_classes = 0;
+
+ scs = &csf2->SubClassSet[classes[0]];
+ if ( !scs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End;
+ }
+
+ for ( k = 0; k < scs->SubClassRuleCount; k++ )
+ {
+ sr = &scs->SubClassRule[k];
+
+ if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
+ goto next_subclassrule;
+
+ if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
+ goto next_subclassrule; /* context is too long */
+
+ cl = sr->Class;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+
+ if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
+ goto next_subclassrule;
+ j++;
+ }
+
+ if ( i > known_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &csf2->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_subclassrule;
+ }
+
+ error = Do_ContextSubst( gsub, sr->GlyphCount,
+ sr->SubstCount, sr->SubstLookupRecord,
+ buffer,
+ nesting_level );
+ goto End;
+
+ next_subclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End:
+ FREE( classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat3* csf3,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, i, j, property;
+
+ HB_Coverage* c;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
+ return HB_Err_Not_Covered;
+
+ if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
+ return HB_Err_Not_Covered; /* context is too long */
+
+ c = csf3->Coverage;
+
+ for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + csf3->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_ContextSubst( gsub, csf3->GlyphCount,
+ csf3->SubstCount, csf3->SubstLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ContextSubst* cs = &st->context;
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
+ case 2: return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
+ case 3: return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+/* LookupType 6 */
+
+/* ChainSubRule */
+
+static HB_Error Load_ChainSubRule( HB_ChainSubRule* csr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ csr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Backtrack = NULL;
+
+ count = csr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = csr->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;
+
+ csr->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Input = NULL;
+
+ count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = csr->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;
+
+ csr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Lookahead = NULL;
+
+ count = csr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = csr->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;
+
+ csr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->SubstLookupRecord = NULL;
+
+ count = csr->SubstCount;
+
+ if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = csr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainSubRule( HB_ChainSubRule* csr )
+{
+ FREE( csr->SubstLookupRecord );
+ FREE( csr->Lookahead );
+ FREE( csr->Input );
+ FREE( csr->Backtrack );
+}
+
+
+/* ChainSubRuleSet */
+
+static HB_Error Load_ChainSubRuleSet( HB_ChainSubRuleSet* csrs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubRule* csr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = csrs->ChainSubRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csrs->ChainSubRule = NULL;
+
+ if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
+ return error;
+
+ csr = csrs->ChainSubRule;
+
+ 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_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubRule( &csr[m] );
+
+ FREE( csr );
+ return error;
+}
+
+
+static void Free_ChainSubRuleSet( HB_ChainSubRuleSet* csrs )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubRule* csr;
+
+
+ if ( csrs->ChainSubRule )
+ {
+ count = csrs->ChainSubRuleCount;
+ csr = csrs->ChainSubRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRule( &csr[n] );
+
+ FREE( csr );
+ }
+}
+
+
+/* ChainContextSubstFormat1 */
+
+static HB_Error Load_ChainContextSubst1(
+ HB_ChainContextSubstFormat1* ccsf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubRuleSet* csrs;
+
+
+ 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( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ccsf1->ChainSubRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf1->ChainSubRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
+ goto Fail2;
+
+ csrs = ccsf1->ChainSubRuleSet;
+
+ 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_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubRuleSet( &csrs[m] );
+
+ FREE( csrs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1* ccsf1 )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubRuleSet* csrs;
+
+
+ if ( ccsf1->ChainSubRuleSet )
+ {
+ count = ccsf1->ChainSubRuleSetCount;
+ csrs = ccsf1->ChainSubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRuleSet( &csrs[n] );
+
+ FREE( csrs );
+ }
+
+ _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
+}
+
+
+/* ChainSubClassRule */
+
+static HB_Error Load_ChainSubClassRule(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_ChainSubClassRule* cscr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cscr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
+ ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
+
+ cscr->Backtrack = NULL;
+
+ count = cscr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = cscr->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;
+
+ cscr->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
+ ccsf2->MaxInputLength = cscr->InputGlyphCount;
+
+ cscr->Input = NULL;
+
+ count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = cscr->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;
+
+ cscr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
+ ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
+
+ cscr->Lookahead = NULL;
+
+ count = cscr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = cscr->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;
+
+ cscr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cscr->SubstLookupRecord = NULL;
+
+ count = cscr->SubstCount;
+
+ if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = cscr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainSubClassRule( HB_ChainSubClassRule* cscr )
+{
+ FREE( cscr->SubstLookupRecord );
+ FREE( cscr->Lookahead );
+ FREE( cscr->Input );
+ FREE( cscr->Backtrack );
+}
+
+
+/* SubClassSet */
+
+static HB_Error Load_ChainSubClassSet(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_ChainSubClassSet* cscs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubClassRule* cscr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cscs->ChainSubClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cscs->ChainSubClassRule = NULL;
+
+ if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
+ HB_ChainSubClassRule ) )
+ return error;
+
+ cscr = cscs->ChainSubClassRule;
+
+ 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_ChainSubClassRule( ccsf2, &cscr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubClassRule( &cscr[m] );
+
+ FREE( cscr );
+ return error;
+}
+
+
+static void Free_ChainSubClassSet( HB_ChainSubClassSet* cscs )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubClassRule* cscr;
+
+
+ if ( cscs->ChainSubClassRule )
+ {
+ count = cscs->ChainSubClassRuleCount;
+ cscr = cscs->ChainSubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubClassRule( &cscr[n] );
+
+ FREE( cscr );
+ }
+}
+
+
+/* ChainContextSubstFormat2 */
+
+static HB_Error Load_ChainContextSubst2(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+ HB_UInt backtrack_offset, input_offset, lookahead_offset;
+
+ HB_ChainSubClassSet* cscs;
+
+
+ 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( &ccsf2->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();
+
+ /* `ChainSubClassSetCount' 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 = ccsf2->ChainSubClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
+ backtrack_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail5;
+
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
+ input_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
+ lookahead_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+
+ ccsf2->ChainSubClassSet = NULL;
+ ccsf2->MaxBacktrackLength = 0;
+ ccsf2->MaxInputLength = 0;
+ ccsf2->MaxLookaheadLength = 0;
+
+ if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
+ goto Fail2;
+
+ cscs = ccsf2->ChainSubClassSet;
+
+ 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_ChainSubClassSet( ccsf2, &cscs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a ChainSubClassSet table with no entries */
+
+ ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
+ ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubClassSet( &cscs[m] );
+
+ FREE( cscs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+
+Fail3:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
+
+Fail4:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+Fail5:
+ _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2* ccsf2 )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubClassSet* cscs;
+
+
+ if ( ccsf2->ChainSubClassSet )
+ {
+ count = ccsf2->ChainSubClassSetCount;
+ cscs = ccsf2->ChainSubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubClassSet( &cscs[n] );
+
+ FREE( cscs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+ _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
+}
+
+
+/* ChainContextSubstFormat3 */
+
+static HB_Error Load_ChainContextSubst3(
+ HB_ChainContextSubstFormat3* ccsf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, nb = 0, ni =0, nl = 0, 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_SubstLookupRecord* slr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccsf3->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->BacktrackCoverage = NULL;
+
+ backtrack_count = ccsf3->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
+ HB_Coverage ) )
+ return error;
+
+ b = ccsf3->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;
+
+ ccsf3->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->InputCoverage = NULL;
+
+ input_count = ccsf3->InputGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
+ goto Fail4;
+
+ i = ccsf3->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;
+
+ ccsf3->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->LookaheadCoverage = NULL;
+
+ lookahead_count = ccsf3->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
+ HB_Coverage ) )
+ goto Fail3;
+
+ l = ccsf3->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;
+
+ ccsf3->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->SubstLookupRecord = NULL;
+
+ count = ccsf3->SubstCount;
+
+ if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = ccsf3->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+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_ChainContextSubst3( HB_ChainContextSubstFormat3* ccsf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( ccsf3->SubstLookupRecord );
+
+ if ( ccsf3->LookaheadCoverage )
+ {
+ count = ccsf3->LookaheadGlyphCount;
+ c = ccsf3->LookaheadCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->InputCoverage )
+ {
+ count = ccsf3->InputGlyphCount;
+ c = ccsf3->InputCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->BacktrackCoverage )
+ {
+ count = ccsf3->BacktrackGlyphCount;
+ c = ccsf3->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ChainContextSubst */
+
+static HB_Error Load_ChainContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( ccs->SubstFormat ) {
+ case 1: return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
+ case 2: return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
+ case 3: return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ChainContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ switch ( ccs->SubstFormat ) {
+ case 1: Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
+ case 2: Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
+ case 3: Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat1* ccsf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, num_csr;
+ HB_UShort bgc, igc, lgc;
+ HB_Error error;
+
+ HB_ChainSubRule* csr;
+ HB_ChainSubRule curr_csr;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ csr = ccsf1->ChainSubRuleSet[index].ChainSubRule;
+ num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
+
+ for ( k = 0; k < num_csr; k++ )
+ {
+ curr_csr = csr[k];
+ bgc = curr_csr.BacktrackGlyphCount;
+ igc = curr_csr.InputGlyphCount;
+ lgc = curr_csr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainsubrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainsubrule;
+
+ 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->out_pos - 1; i < bgc; i++, j-- )
+ {
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainsubrule;
+ 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 ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
+ goto next_chainsubrule;
+ }
+ }
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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_chainsubrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
+ goto next_chainsubrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ 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_chainsubrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
+ goto next_chainsubrule;
+ }
+
+ return Do_ContextSubst( gsub, igc,
+ curr_csr.SubstCount,
+ curr_csr.SubstLookupRecord,
+ buffer,
+ nesting_level );
+
+ next_chainsubrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat2* ccsf2,
+ 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_ChainSubClassSet* cscs;
+ HB_ChainSubClassRule ccsr;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
++ 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( &ccsf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
+ return error;
+ known_backtrack_classes = 0;
+
+ if (ccsf2->MaxInputLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
+ goto End3;
+ known_input_classes = 1;
+
+ if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
+ goto End2;
+ known_lookahead_classes = 0;
+
+ error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
+ &input_classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
+ if ( !cscs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End1;
+ }
+
+ for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
+ {
+ ccsr = cscs->ChainSubClassRule[k];
+ bgc = ccsr.BacktrackGlyphCount;
+ igc = ccsr.InputGlyphCount;
+ lgc = ccsr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainsubclassrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainsubclassrule;
+
+ 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 = ccsr.Backtrack;
+
+ for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
+ {
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainsubclassrule;
+ j--;
+ }
+
+ if ( i >= known_backtrack_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_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_chainsubclassrule;
+ }
+ }
+
+ ic = ccsr.Input;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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_chainsubclassrule;
+ j++;
+ }
+
+ if ( i >= known_input_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccsf2->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_chainsubclassrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ lc = ccsr.Lookahead;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ 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_chainsubclassrule;
+ j++;
+ }
+
+ if ( i >= known_lookahead_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccsf2->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_chainsubclassrule;
+ }
+
+ error = Do_ContextSubst( gsub, igc,
+ ccsr.SubstCount,
+ ccsr.SubstLookupRecord,
+ buffer,
+ nesting_level );
+ goto End1;
+
+ next_chainsubclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End1:
+ FREE( lookahead_classes );
+
+End2:
+ FREE( input_classes );
+
+End3:
+ FREE( backtrack_classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat3* ccsf3,
+ 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_Coverage* bc;
+ HB_Coverage* ic;
+ HB_Coverage* lc;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ bgc = ccsf3->BacktrackGlyphCount;
+ igc = ccsf3->InputGlyphCount;
+ lgc = ccsf3->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->out_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 = ccsf3->BacktrackCoverage;
+
+ for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
+ {
- while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ while ( CHECK_Property( layout, OUT_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], OUT_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ ic = ccsf3->InputCoverage;
+
+ for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
+ {
+ /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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 for lookahead glyphs right after the last context
+ glyph */
+
+ lc = ccsf3->LookaheadCoverage;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
- HB_GDEFHeader* gdef;
++ 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_ContextSubst( gsub, igc,
+ ccsf3->SubstCount,
+ ccsf3->SubstLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ChainContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ switch ( ccs->SubstFormat ) {
+ case 1: return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
+ case 2: return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
+ case 3: return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+}
+
+
+static HB_Error Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+
+ HB_UShort m, count;
+
+ HB_UShort nb = 0, nl = 0, n;
+ HB_UShort backtrack_count, lookahead_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* b;
+ HB_Coverage* l;
+ HB_UShort* sub;
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ rccs->SubstFormat = GET_UShort();
+
+ if ( rccs->SubstFormat != 1 )
+ return ERR(HB_Err_Invalid_SubTable_Format);
+
+ FORGET_Frame();
+
+ 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( &rccs->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ rccs->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->BacktrackCoverage = NULL;
+
+ backtrack_count = rccs->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
+ HB_Coverage ) )
+ goto Fail4;
+
+ b = rccs->BacktrackCoverage;
+
+ for ( nb = 0; nb < backtrack_count; nb++ )
+ {
+ 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( &b[nb], stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+ }
+
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ rccs->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->LookaheadCoverage = NULL;
+
+ lookahead_count = rccs->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
+ HB_Coverage ) )
+ goto Fail3;
+
+ l = rccs->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;
+
+ rccs->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->Substitute = NULL;
+
+ count = rccs->GlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->Substitute, count,
+ HB_UShort ) )
+ goto Fail2;
+
+ sub = rccs->Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ sub[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( sub );
+
+Fail2:
+ for ( m = 0; m < nl; m++ )
+ _HB_OPEN_Free_Coverage( &l[m] );
+
+ FREE( l );
+
+Fail3:
+ for ( m = 0; m < nb; m++ )
+ _HB_OPEN_Free_Coverage( &b[m] );
+
+ FREE( b );
+
+Fail4:
+ _HB_OPEN_Free_Coverage( &rccs->Coverage );
+ return error;
+}
+
+
+static void Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+
+ HB_Coverage* c;
+
+ _HB_OPEN_Free_Coverage( &rccs->Coverage );
+
+ if ( rccs->LookaheadCoverage )
+ {
+ count = rccs->LookaheadGlyphCount;
+ c = rccs->LookaheadCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( rccs->BacktrackCoverage )
+ {
+ count = rccs->BacktrackGlyphCount;
+ c = rccs->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ FREE ( rccs->Substitute );
+}
+
+
+static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, input_index, i, j, property;
+ HB_UShort bgc, lgc;
+ HB_Error error;
+
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+ HB_Coverage* bc;
+ HB_Coverage* lc;
- gdef = gsub->gdef;
++ hb_ot_layout_t* layout;
+
+ if ( nesting_level != 1 || context_length != 0xFFFF )
+ return HB_Err_Not_Covered;
+
- if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++ layout = gsub->layout;
+
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ bgc = rccs->BacktrackGlyphCount;
+ lgc = rccs->LookaheadGlyphCount;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->in_pos || buffer->in_pos + 1 + 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 = rccs->BacktrackCoverage;
+
+ for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
+ {
- while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++ 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;
+ }
+ }
+
+ j = buffer->in_pos;
+
+ error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
+ if ( error )
+ return error;
+
+ lc = rccs->LookaheadCoverage;
+
+ for ( i = 0, j = buffer->in_pos + 1; 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;
+ }
+
+ IN_CURGLYPH() = rccs->Substitute[input_index];
+ buffer->in_pos--; /* Reverse! */
+
+ return error;
+}
+
+
+
+/***********
+ * GSUB API
+ ***********/
+
+
+
+HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub,
+ HB_UInt script_tag,
+ HB_UShort* script_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gsub || !script_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->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_GSUB_Select_Language( HB_GSUBHeader* gsub,
+ 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 ( !gsub || !language_index || !req_feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->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_GSUB_Select_Feature( HB_GSUBHeader* gsub,
+ 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 ( !gsub || !feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gsub->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_GSUB_Query_Scripts( HB_GSUBHeader* gsub,
+ HB_UInt** script_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* stl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gsub || !script_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->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_GSUB_Query_Languages( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* ltl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+
+
+ if ( !gsub || !language_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->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_GSUB_Query_Features( HB_GSUBHeader* gsub,
+ 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 ( !gsub || !feature_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gsub->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 substitution
+ has been done, or HB_Err_Not_Covered if not. */
+static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
+ 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_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 = gsub->LookupList.LookupCount;
+ if (lookup_index >= lookup_count)
+ return error;
+
+ lo = &gsub->LookupList.Lookup[lookup_index];
+ flags = lo->LookupFlag;
+ lookup_type = lo->LookupType;
+
+ for ( i = 0; i < lo->SubTableCount; i++ )
+ {
+ HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
+
+ switch (lookup_type) {
+ case HB_GSUB_LOOKUP_SINGLE:
+ error = Lookup_SingleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_MULTIPLE:
+ error = Lookup_MultipleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_ALTERNATE:
+ error = Lookup_AlternateSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_LIGATURE:
+ error = Lookup_LigatureSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_CONTEXT:
+ error = Lookup_ContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_CHAIN:
+ error = Lookup_ChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ /*case HB_GSUB_LOOKUP_EXTENSION:
+ error = Lookup_ExtensionSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN:
+ error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ default:
+ error = HB_Err_Not_Covered;
+ };
+
+ /* Check whether we have a successful substitution 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_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
+ HB_Stream stream,
+ HB_UShort lookup_type )
+{
+ switch (lookup_type) {
+ case HB_GSUB_LOOKUP_SINGLE: return Load_SingleSubst ( st, stream );
+ case HB_GSUB_LOOKUP_MULTIPLE: return Load_MultipleSubst ( st, stream );
+ case HB_GSUB_LOOKUP_ALTERNATE: return Load_AlternateSubst ( st, stream );
+ case HB_GSUB_LOOKUP_LIGATURE: return Load_LigatureSubst ( st, stream );
+ case HB_GSUB_LOOKUP_CONTEXT: return Load_ContextSubst ( st, stream );
+ case HB_GSUB_LOOKUP_CHAIN: return Load_ChainContextSubst ( st, stream );
+ /*case HB_GSUB_LOOKUP_EXTENSION: return Load_ExtensionSubst ( st, stream );*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN: return Load_ReverseChainContextSubst ( st, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ };
+}
+
+
+HB_INTERNAL void
+_HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
+ HB_UShort lookup_type )
+{
+ switch ( lookup_type ) {
+ case HB_GSUB_LOOKUP_SINGLE: Free_SingleSubst ( st ); return;
+ case HB_GSUB_LOOKUP_MULTIPLE: Free_MultipleSubst ( st ); return;
+ case HB_GSUB_LOOKUP_ALTERNATE: Free_AlternateSubst ( st ); return;
+ case HB_GSUB_LOOKUP_LIGATURE: Free_LigatureSubst ( st ); return;
+ case HB_GSUB_LOOKUP_CONTEXT: Free_ContextSubst ( st ); return;
+ case HB_GSUB_LOOKUP_CHAIN: Free_ChainContextSubst ( st ); return;
+ /*case HB_GSUB_LOOKUP_EXTENSION: Free_ExtensionSubst ( st ); return;*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN: Free_ReverseChainContextSubst ( st ); return;
+ default: return;
+ };
+}
+
+
+
+/* apply one lookup to the input string object */
+
+static HB_Error GSUB_Do_String_Lookup( HB_GSUBHeader* gsub,
+ HB_UShort lookup_index,
+ HB_Buffer buffer )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+
+ HB_UInt* properties = gsub->LookupList.Properties;
+ int lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
+
+ const int nesting_level = 0;
+ /* 0xFFFF indicates that we don't have a context length yet */
+ const HB_UShort context_length = 0xFFFF;
+
+ switch (lookup_type) {
+
+ case HB_GSUB_LOOKUP_SINGLE:
+ case HB_GSUB_LOOKUP_MULTIPLE:
+ case HB_GSUB_LOOKUP_ALTERNATE:
+ case HB_GSUB_LOOKUP_LIGATURE:
+ case HB_GSUB_LOOKUP_CONTEXT:
+ case HB_GSUB_LOOKUP_CHAIN:
+ /* in/out forward substitution (implemented lazy) */
+
+ _hb_buffer_clear_output ( buffer );
+ buffer->in_pos = 0;
+ while ( buffer->in_pos < buffer->in_length )
+ {
+ if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+ {
+ error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ else
+ error = HB_Err_Not_Covered;
+
+ if ( error == HB_Err_Not_Covered )
+ if ( COPY_Glyph ( buffer ) )
+ return error;
+ }
+ /* we shouldn't swap if error occurred.
+ *
+ * also don't swap if nothing changed (ie HB_Err_Not_Covered).
+ * shouldn't matter in that case though.
+ */
+ if ( retError == HB_Err_Ok )
+ _hb_buffer_swap( buffer );
+
+ return retError;
+
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN:
+ /* in-place backward substitution */
+
+ buffer->in_pos = buffer->in_length - 1;
+ do
+ {
+ if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+ {
+ error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ else
+ error = HB_Err_Not_Covered;
+
+ if ( error == HB_Err_Not_Covered )
+ buffer->in_pos--;
+ }
+ while ((HB_Int) buffer->in_pos >= 0);
+
+ return retError;
+
+ /*case HB_GSUB_LOOKUP_EXTENSION:*/
+ default:
+ return retError;
+ };
+}
+
+
+HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub,
+ 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 ( !gsub ||
+ feature_index >= gsub->FeatureList.FeatureCount ||
+ gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
+
+ properties = gsub->LookupList.Properties;
+
+ feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
+ index = feature.LookupListIndex;
+ lookup_count = gsub->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_GSUB_Clear_Features( HB_GSUBHeader* gsub )
+{
+ HB_UShort i;
+
+ HB_UInt* properties;
+
+
+ if ( !gsub )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->FeatureList.ApplyCount = 0;
+
+ properties = gsub->LookupList.Properties;
+
+ for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
+ properties[i] = 0;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub,
+ HB_AltFunction altfunc,
+ void* data )
+{
+ if ( !gsub )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->altfunc = altfunc;
+ gsub->data = data;
+
+ return HB_Err_Ok;
+}
+
+/* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
+ * feature were applied, or HB_Err_Ok otherwise.
+ */
+HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub,
+ HB_Buffer buffer )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+ int i, j, lookup_count, num_features;
+
+ if ( !gsub ||
+ !buffer)
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( buffer->in_length == 0 )
+ return retError;
+
+ lookup_count = gsub->LookupList.LookupCount;
+ num_features = gsub->FeatureList.ApplyCount;
+
+ for ( i = 0; i < num_features; i++)
+ {
+ HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i];
+ HB_Feature feature = gsub->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 = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ }
+
+ error = retError;
+
+ return error;
+}
+
+
+/* END */
--- /dev/null
- HB_GDEFHeader* gdef;
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HARFBUZZ_GSUB_H
+#define HARFBUZZ_GSUB_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+
+/* Lookup types for glyph substitution */
+
+#define HB_GSUB_LOOKUP_SINGLE 1
+#define HB_GSUB_LOOKUP_MULTIPLE 2
+#define HB_GSUB_LOOKUP_ALTERNATE 3
+#define HB_GSUB_LOOKUP_LIGATURE 4
+#define HB_GSUB_LOOKUP_CONTEXT 5
+#define HB_GSUB_LOOKUP_CHAIN 6
+#define HB_GSUB_LOOKUP_EXTENSION 7
+#define HB_GSUB_LOOKUP_REVERSE_CHAIN 8
+
+
+/* A pointer to a function which selects the alternate glyph. `pos' is
+ the position of the glyph with index `glyphID', `num_alternates'
+ gives the number of alternates in the `alternates' array. `data'
+ points to the user-defined structure specified during a call to
+ HB_GSUB_Register_Alternate_Function(). The function must return an
+ index into the `alternates' array. */
+
+typedef HB_UShort (*HB_AltFunction)(HB_UInt pos,
+ HB_UShort glyphID,
+ HB_UShort num_alternates,
+ HB_UShort* alternates,
+ void* data );
+
+
+struct HB_GSUBHeader_
+{
+ HB_UInt offset;
+
+ HB_16Dot16 Version;
+
+ HB_ScriptList ScriptList;
+ HB_FeatureList FeatureList;
+ HB_LookupList LookupList;
+
- HB_GDEFHeader* gdef );
++ hb_ot_layout_t *layout;
+
+ /* the next two fields are used for an alternate substitution callback
+ function to select the proper alternate glyph. */
+
+ HB_AltFunction altfunc;
+ void* data;
+};
+
+typedef struct HB_GSUBHeader_ HB_GSUBHeader;
+typedef HB_GSUBHeader* HB_GSUB;
+
+
+HB_Error HB_Load_GSUB_Table( HB_Font font,
+ HB_GSUBHeader** gsub,
++ hb_ot_layout_t *layout );
+
+
+HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub );
+
+
+HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub,
+ HB_UInt script_tag,
+ HB_UShort* script_index );
+
+HB_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub,
+ HB_UInt language_tag,
+ HB_UShort script_index,
+ HB_UShort* language_index,
+ HB_UShort* req_feature_index );
+
+HB_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub,
+ HB_UInt feature_tag,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UShort* feature_index );
+
+
+HB_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub,
+ HB_UInt** script_tag_list );
+
+HB_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list );
+
+HB_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list );
+
+
+HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub,
+ HB_UShort feature_index,
+ HB_UInt property );
+
+HB_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub );
+
+
+HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub,
+ HB_AltFunction altfunc,
+ void* data );
+
+
+HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub,
+ HB_Buffer buffer );
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GSUB_H */
--- /dev/null
- #define HB_LIKELY(cond) (cond)
- #define HB_UNLIKELY(cond) (cond)
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HARFBUZZ_IMPL_H
+#define HARFBUZZ_IMPL_H
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "harfbuzz-global.h"
+
+#include <stdlib.h>
+
++/* XXX */
++#include "hb-ot-layout-private.h"
++
+HB_BEGIN_HEADER
+
+#ifndef HB_INTERNAL
+# define HB_INTERNAL
+#endif
+
+#ifndef NULL
+# define NULL ((void *)0)
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef TTAG_GDEF
+# define TTAG_GDEF HB_MAKE_TAG( 'G', 'D', 'E', 'F' )
+#endif
+#ifndef TTAG_GPOS
+# define TTAG_GPOS HB_MAKE_TAG( 'G', 'P', 'O', 'S' )
+#endif
+#ifndef TTAG_GSUB
+# define TTAG_GSUB HB_MAKE_TAG( 'G', 'S', 'U', 'B' )
+#endif
+
+#ifndef HB_UNUSED
+# define HB_UNUSED(arg) ((arg) = (arg))
+#endif
+
++#ifndef HB_LIKELY
++# define HB_LIKELY(cond) (cond)
++#endif
++#ifndef HB_UNLIKELY
++# define HB_UNLIKELY(cond) (cond)
++#endif
+
+
+#define ALLOC(_ptr,_size) \
+ ( (_ptr) = _hb_alloc( _size, &error ), error != 0 )
+
+#define REALLOC(_ptr,_newsz) \
+ ( (_ptr) = _hb_realloc( (_ptr), (_newsz), &error ), error != 0 )
+
+#define FREE(_ptr) \
+ do { \
+ if ( (_ptr) ) \
+ { \
+ _hb_free( _ptr ); \
+ _ptr = NULL; \
+ } \
+ } while (0)
+
+#define ALLOC_ARRAY(_ptr,_count,_type) \
+ ALLOC(_ptr,(_count)*sizeof(_type))
+
+#define REALLOC_ARRAY(_ptr,_newcnt,_type) \
+ REALLOC(_ptr,(_newcnt)*sizeof(_type))
+
+#define MEM_Copy(dest,source,count) memcpy( (char*)(dest), (const char*)(source), (size_t)(count) )
+
+#define ERR(err) _hb_err (err)
+
+
+HB_INTERNAL HB_Pointer
+_hb_alloc( size_t size,
+ HB_Error *perror_ );
+
+HB_INTERNAL HB_Pointer
+_hb_realloc( HB_Pointer block,
+ size_t new_size,
+ HB_Error *perror_ );
+
+HB_INTERNAL void
+_hb_free( HB_Pointer block );
+
+
+/* helper func to set a breakpoint on */
+HB_INTERNAL HB_Error
+_hb_err (HB_Error code);
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_IMPL_H */
--- /dev/null
- /* safety check; otherwise the official handling of TrueType Open
- fonts won't work */
-
- if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
- {
- error = HB_Err_Not_Covered;
- goto Fail2;
- }
-
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-open-private.h"
+
+
+/***************************
+ * Script related functions
+ ***************************/
+
+
+/* LangSys */
+
+static HB_Error Load_LangSys( HB_LangSys* ls,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UShort n, count;
+ HB_UShort* fi;
+
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ ls->LookupOrderOffset = GET_UShort(); /* should be 0 */
+ ls->ReqFeatureIndex = GET_UShort();
+ count = ls->FeatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->FeatureIndex = NULL;
+
+ if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
+ return error;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( ls->FeatureIndex );
+ return error;
+ }
+
+ fi = ls->FeatureIndex;
+
+ for ( n = 0; n < count; n++ )
+ fi[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_LangSys( HB_LangSys* ls )
+{
+ FREE( ls->FeatureIndex );
+}
+
+
+/* Script */
+
+static HB_Error Load_Script( HB_ScriptTable* s,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LangSysRecord* lsr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ 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_LangSys( &s->DefaultLangSys,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a DefaultLangSys table with no entries */
+
+ s->DefaultLangSys.LookupOrderOffset = 0;
+ s->DefaultLangSys.ReqFeatureIndex = 0xFFFF;
+ s->DefaultLangSys.FeatureCount = 0;
+ s->DefaultLangSys.FeatureIndex = NULL;
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = s->LangSysCount = GET_UShort();
+
+ FORGET_Frame();
+
+ s->LangSysRecord = NULL;
+
+ if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
+ goto Fail2;
+
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail1;
+
+ lsr[n].LangSysTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_LangSys( &lsr[m].LangSys );
+
+ FREE( s->LangSysRecord );
+
+Fail2:
+ Free_LangSys( &s->DefaultLangSys );
+ return error;
+}
+
+
+static void Free_Script( HB_ScriptTable* s )
+{
+ HB_UShort n, count;
+
+ HB_LangSysRecord* lsr;
+
+
+ Free_LangSys( &s->DefaultLangSys );
+
+ if ( s->LangSysRecord )
+ {
+ count = s->LangSysCount;
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_LangSys( &lsr[n].LangSys );
+
+ FREE( lsr );
+ }
+}
+
+
+/* ScriptList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, script_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ScriptRecord* sr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ script_count = GET_UShort();
+
+ FORGET_Frame();
+
+ sl->ScriptRecord = NULL;
+
+ if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
+ return error;
+
+ sr = sl->ScriptRecord;
+
+ sl->ScriptCount= 0;
+ for ( n = 0; n < script_count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail;
+
+ sr[sl->ScriptCount].ScriptTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+
+ if ( FILE_Seek( new_offset ) )
+ goto Fail;
+
+ error = Load_Script( &sr[sl->ScriptCount].Script, stream );
+ if ( error == HB_Err_Ok )
+ sl->ScriptCount += 1;
+ else if ( error != HB_Err_Not_Covered )
+ goto Fail;
+
+ (void)FILE_Seek( cur_offset );
+ }
+
+ /* Empty tables are harmless and generated by fontforge.
+ * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
+ */
+#if 0
+ if ( sl->ScriptCount == 0 )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+#endif
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ Free_Script( &sr[n].Script );
+
+ FREE( sl->ScriptRecord );
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
+{
+ HB_UShort n, count;
+
+ HB_ScriptRecord* sr;
+
+
+ if ( sl->ScriptRecord )
+ {
+ count = sl->ScriptCount;
+ sr = sl->ScriptRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_Script( &sr[n].Script );
+
+ FREE( sr );
+ }
+}
+
+
+
+/*********************************
+ * Feature List related functions
+ *********************************/
+
+
+/* Feature */
+
+static HB_Error Load_Feature( HB_Feature* f,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* lli;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ f->FeatureParams = GET_UShort(); /* should be 0 */
+ count = f->LookupListCount = GET_UShort();
+
+ FORGET_Frame();
+
+ f->LookupListIndex = NULL;
+
+ if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
+ return error;
+
+ lli = f->LookupListIndex;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( f->LookupListIndex );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ lli[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Feature( HB_Feature* f )
+{
+ FREE( f->LookupListIndex );
+}
+
+
+/* FeatureList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_FeatureRecord* fr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = fl->FeatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ fl->FeatureRecord = NULL;
+
+ if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
+ return error;
+ if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
+ goto Fail2;
+
+ fl->ApplyCount = 0;
+
+ fr = fl->FeatureRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail1;
+
+ fr[n].FeatureTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_Feature( &fr[m].Feature );
+
+ FREE( fl->ApplyOrder );
+
+Fail2:
+ FREE( fl->FeatureRecord );
+
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_FeatureList( HB_FeatureList* fl )
+{
+ HB_UShort n, count;
+
+ HB_FeatureRecord* fr;
+
+
+ if ( fl->FeatureRecord )
+ {
+ count = fl->FeatureCount;
+ fr = fl->FeatureRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_Feature( &fr[n].Feature );
+
+ FREE( fr );
+ }
+
+ FREE( fl->ApplyOrder );
+}
+
+
+
+/********************************
+ * Lookup List related functions
+ ********************************/
+
+/* the subroutines of the following two functions are defined in
+ ftxgsub.c and ftxgpos.c respectively */
+
+
+/* SubTable */
+
+static HB_Error Load_SubTable( HB_SubTable* st,
+ HB_Stream stream,
+ HB_Type table_type,
+ HB_UShort lookup_type )
+{
+ if ( table_type == HB_Type_GSUB )
+ return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type );
+ else
+ return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type );
+}
+
+
+static void Free_SubTable( HB_SubTable* st,
+ HB_Type table_type,
+ HB_UShort lookup_type )
+{
+ if ( table_type == HB_Type_GSUB )
+ _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type );
+ else
+ _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type );
+}
+
+
+/* Lookup */
+
+static HB_Error Load_Lookup( HB_Lookup* l,
+ HB_Stream stream,
+ HB_Type type )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubTable* st;
+
+ HB_Bool is_extension = FALSE;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ l->LookupType = GET_UShort();
+ l->LookupFlag = GET_UShort();
+ count = l->SubTableCount = GET_UShort();
+
+ FORGET_Frame();
+
+ l->SubTable = NULL;
+
+ if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
+ return error;
+
+ st = l->SubTable;
+
+ if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) ||
+ ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) )
+ is_extension = TRUE;
+
+ 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 ( is_extension )
+ {
+ if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
+ goto Fail;
+
+ if (GET_UShort() != 1) /* format should be 1 */
+ goto Fail;
+
+ l->LookupType = GET_UShort();
+ new_offset += GET_ULong();
+
+ FORGET_Frame();
+ }
+
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubTable( &st[n], stream,
+ type, l->LookupType ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubTable( &st[m], type, l->LookupType );
+
+ FREE( l->SubTable );
+ return error;
+}
+
+
+static void Free_Lookup( HB_Lookup* l,
+ HB_Type type )
+{
+ HB_UShort n, count;
+
+ HB_SubTable* st;
+
+
+ if ( l->SubTable )
+ {
+ count = l->SubTableCount;
+ st = l->SubTable;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubTable( &st[n], type, l->LookupType );
+
+ FREE( st );
+ }
+}
+
+
+/* LookupList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_LookupList( HB_LookupList* ll,
+ HB_Stream stream,
+ HB_Type type )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Lookup* l;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ll->LookupCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ll->Lookup = NULL;
+
+ if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
+ return error;
+ if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
+ goto Fail2;
+
+ l = ll->Lookup;
+
+ 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_Lookup( &l[n], stream, type ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( ll->Properties );
+
+ for ( m = 0; m < n; m++ )
+ Free_Lookup( &l[m], type );
+
+Fail2:
+ FREE( ll->Lookup );
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_LookupList( HB_LookupList* ll,
+ HB_Type type )
+{
+ HB_UShort n, count;
+
+ HB_Lookup* l;
+
+
+ FREE( ll->Properties );
+
+ if ( ll->Lookup )
+ {
+ count = ll->LookupCount;
+ l = ll->Lookup;
+
+ for ( n = 0; n < count; n++ )
+ Free_Lookup( &l[n], type );
+
+ FREE( l );
+ }
+}
+
+
+
+/*****************************
+ * Coverage related functions
+ *****************************/
+
+
+/* CoverageFormat1 */
+
+static HB_Error Load_Coverage1( HB_CoverageFormat1* cf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* ga;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cf1->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cf1->GlyphArray = NULL;
+
+ if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
+ return error;
+
+ ga = cf1->GlyphArray;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( cf1->GlyphArray );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ ga[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Coverage1( HB_CoverageFormat1* cf1 )
+{
+ FREE( cf1->GlyphArray );
+}
+
+
+/* CoverageFormat2 */
+
+static HB_Error Load_Coverage2( HB_CoverageFormat2* cf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_RangeRecord* rr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cf2->RangeCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cf2->RangeRecord = NULL;
+
+ if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
+ return error;
+
+ rr = cf2->RangeRecord;
+
+ if ( ACCESS_Frame( count * 6L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ rr[n].Start = GET_UShort();
+ rr[n].End = GET_UShort();
+ rr[n].StartCoverageIndex = GET_UShort();
+
+ /* sanity check; we are limited to 16bit integers */
+ if ( rr[n].Start > rr[n].End ||
+ ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
+ 0x10000L )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( cf2->RangeRecord );
+ return error;
+}
+
+
+static void Free_Coverage2( HB_CoverageFormat2* cf2 )
+{
+ FREE( cf2->RangeRecord );
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Coverage( HB_Coverage* c,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ c->CoverageFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( c->CoverageFormat )
+ {
+ case 1: return Load_Coverage1( &c->cf.cf1, stream );
+ case 2: return Load_Coverage2( &c->cf.cf2, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_Coverage( HB_Coverage* c )
+{
+ switch ( c->CoverageFormat )
+ {
+ case 1: Free_Coverage1( &c->cf.cf1 ); break;
+ case 2: Free_Coverage2( &c->cf.cf2 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Coverage_Index1( HB_CoverageFormat1* cf1,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_UShort* array = cf1->GlyphArray;
+
+
+ /* binary search */
+
+ if ( cf1->GlyphCount == 0 )
+ return HB_Err_Not_Covered;
+
+ new_min = 0;
+ new_max = cf1->GlyphCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID == array[middle] )
+ {
+ *index = middle;
+ return HB_Err_Ok;
+ }
+ else if ( glyphID < array[middle] )
+ {
+ if ( middle == min )
+ break;
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ break;
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Coverage_Index2( HB_CoverageFormat2* cf2,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_RangeRecord* rr = cf2->RangeRecord;
+
+
+ /* binary search */
+
+ if ( cf2->RangeCount == 0 )
+ return HB_Err_Not_Covered;
+
+ new_min = 0;
+ new_max = cf2->RangeCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
+ {
+ *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
+ return HB_Err_Ok;
+ }
+ else if ( glyphID < rr[middle].Start )
+ {
+ if ( middle == min )
+ break;
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ break;
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ return HB_Err_Not_Covered;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Coverage_Index( HB_Coverage* c,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ switch ( c->CoverageFormat )
+ {
+ case 1: return Coverage_Index1( &c->cf.cf1, glyphID, index );
+ case 2: return Coverage_Index2( &c->cf.cf2, glyphID, index );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+
+/*************************************
+ * Class Definition related functions
+ *************************************/
+
+
+/* ClassDefFormat1 */
+
+static HB_Error Load_ClassDef1( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* cva;
+
+ HB_ClassDefFormat1* cdf1;
+
+
+ cdf1 = &cd->cd.cd1;
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ cdf1->StartGlyph = GET_UShort();
+ count = cdf1->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ /* sanity check; we are limited to 16bit integers */
+
+ if ( cdf1->StartGlyph + (long)count >= 0x10000L )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ cdf1->ClassValueArray = NULL;
+
+ if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
+ return error;
+
+ cva = cdf1->ClassValueArray;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ cva[n] = GET_UShort();
+ if ( cva[n] >= limit )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( cva );
+
+ return error;
+}
+
+
+static void Free_ClassDef1( HB_ClassDefFormat1* cdf1 )
+{
+ FREE( cdf1->ClassValueArray );
+}
+
+
+/* ClassDefFormat2 */
+
+static HB_Error Load_ClassDef2( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_ClassRangeRecord* crr;
+
+ HB_ClassDefFormat2* cdf2;
+
+
+ cdf2 = &cd->cd.cd2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = GET_UShort();
+ cdf2->ClassRangeCount = 0; /* zero for now. we fill with the number of good entries later */
+
+ FORGET_Frame();
+
+ cdf2->ClassRangeRecord = NULL;
+
+ if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
+ return error;
+
+ crr = cdf2->ClassRangeRecord;
+
+ if ( ACCESS_Frame( count * 6L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ crr[n].Start = GET_UShort();
+ crr[n].End = GET_UShort();
+ crr[n].Class = GET_UShort();
+
+ /* sanity check */
+
+ if ( crr[n].Start > crr[n].End ||
+ crr[n].Class >= limit )
+ {
+ /* XXX
+ * Corrupt entry. Skip it.
+ * This is hit by Nafees Nastaliq font for example
+ */
+ n--;
+ count--;
+ }
+ }
+
+ FORGET_Frame();
+
+ cdf2->ClassRangeCount = count;
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( crr );
+
+ return error;
+}
+
+
+static void Free_ClassDef2( HB_ClassDefFormat2* cdf2 )
+{
+ FREE( cdf2->ClassRangeRecord );
+}
+
+
+/* ClassDefinition */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cd->ClassFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cd->ClassFormat )
+ {
+ case 1: error = Load_ClassDef1( cd, limit, stream ); break;
+ case 2: error = Load_ClassDef2( cd, limit, stream ); break;
+ default: error = ERR(HB_Err_Invalid_SubTable_Format); break;
+ }
+
+ if ( error )
+ return error;
+
+ cd->loaded = TRUE;
+
+ return HB_Err_Ok;
+}
+
+
+static HB_Error
+_HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd )
+{
+ HB_Error error;
+
+ cd->ClassFormat = 1; /* Meaningless */
+
+ if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
+ return error;
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_UInt class_offset,
+ HB_UInt base_offset,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UInt cur_offset;
+
+ cur_offset = FILE_Pos();
+
+ if ( class_offset )
+ {
+ if ( !FILE_Seek( class_offset + base_offset ) )
+ error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
+ }
+ else
+ error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
+
+ if (error == HB_Err_Ok)
+ (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
+
+ return error;
+}
+
+HB_INTERNAL void
+_HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd )
+{
+ if ( !cd->loaded )
+ return;
+
+ switch ( cd->ClassFormat )
+ {
+ case 1: Free_ClassDef1( &cd->cd.cd1 ); break;
+ case 2: Free_ClassDef2( &cd->cd.cd2 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Get_Class1( HB_ClassDefFormat1* cdf1,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ HB_UShort* cva = cdf1->ClassValueArray;
+
+
+ if ( index )
+ *index = 0;
+
+ if ( glyphID >= cdf1->StartGlyph &&
+ glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
+ {
+ *klass = cva[glyphID - cdf1->StartGlyph];
+ return HB_Err_Ok;
+ }
+ else
+ {
+ *klass = 0;
+ return HB_Err_Not_Covered;
+ }
+}
+
+
+/* we need the index value of the last searched class range record
+ in case of failure for constructed GDEF tables */
+
+static HB_Error Get_Class2( HB_ClassDefFormat2* cdf2,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ HB_Error error = HB_Err_Ok;
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_ClassRangeRecord* crr = cdf2->ClassRangeRecord;
+
+
+ /* binary search */
+
+ if ( cdf2->ClassRangeCount == 0 )
+ {
+ *klass = 0;
+ if ( index )
+ *index = 0;
+
+ return HB_Err_Not_Covered;
+ }
+
+ new_min = 0;
+ new_max = cdf2->ClassRangeCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
+ {
+ *klass = crr[middle].Class;
+ error = HB_Err_Ok;
+ break;
+ }
+ else if ( glyphID < crr[middle].Start )
+ {
+ if ( middle == min )
+ {
+ *klass = 0;
+ error = HB_Err_Not_Covered;
+ break;
+ }
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ {
+ *klass = 0;
+ error = HB_Err_Not_Covered;
+ break;
+ }
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ if ( index )
+ *index = middle;
+
+ return error;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Class( HB_ClassDefinition* cd,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ switch ( cd->ClassFormat )
+ {
+ case 1: return Get_Class1( &cd->cd.cd1, glyphID, klass, index );
+ case 2: return Get_Class2( &cd->cd.cd2, glyphID, klass, index );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+
+/***************************
+ * Device related functions
+ ***************************/
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Device( HB_Device* d,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* dv;
+
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ d->StartSize = GET_UShort();
+ d->EndSize = GET_UShort();
+ d->DeltaFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ d->DeltaValue = NULL;
+
+ if ( d->StartSize > d->EndSize ||
+ d->DeltaFormat == 0 || d->DeltaFormat > 3 )
+ {
+ /* XXX
+ * I've seen fontforge generate DeltaFormat == 0.
+ * Just return Ok and let the NULL DeltaValue disable
+ * this table.
+ */
+ return HB_Err_Ok;
+ }
+
+ count = ( ( d->EndSize - d->StartSize + 1 ) >>
+ ( 4 - d->DeltaFormat ) ) + 1;
+
+ if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
+ return error;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( d->DeltaValue );
+ return error;
+ }
+
+ dv = d->DeltaValue;
+
+ for ( n = 0; n < count; n++ )
+ dv[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_Device( HB_Device* d )
+{
+ FREE( d->DeltaValue );
+}
+
+
+/* Since we have the delta values stored in compressed form, we must
+ uncompress it now. To simplify the interface, the function always
+ returns a meaningful value in `value'; the error is just for
+ information.
+ | |
+ format = 1: 0011223344556677|8899101112131415|...
+ | |
+ byte 1 byte 2
+
+ 00: (byte >> 14) & mask
+ 11: (byte >> 12) & mask
+ ...
+
+ mask = 0x0003
+ | |
+ format = 2: 0000111122223333|4444555566667777|...
+ | |
+ byte 1 byte 2
+
+ 0000: (byte >> 12) & mask
+ 1111: (byte >> 8) & mask
+ ...
+
+ mask = 0x000F
+ | |
+ format = 3: 0000000011111111|2222222233333333|...
+ | |
+ byte 1 byte 2
+
+ 00000000: (byte >> 8) & mask
+ 11111111: (byte >> 0) & mask
+ ....
+
+ mask = 0x00FF */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Device( HB_Device* d,
+ HB_UShort size,
+ HB_Short* value )
+{
+ HB_UShort byte, bits, mask, f, s;
+
+
+ f = d->DeltaFormat;
+
+ if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
+ {
+ s = size - d->StartSize;
+ byte = d->DeltaValue[s >> ( 4 - f )];
+ bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
+ mask = 0xFFFF >> ( 16 - ( 1 << f ) );
+
+ *value = (HB_Short)( bits & mask );
+
+ /* conversion to a signed value */
+
+ if ( *value >= ( ( mask + 1 ) >> 1 ) )
+ *value -= mask + 1;
+
+ return HB_Err_Ok;
+ }
+ else
+ {
+ *value = 0;
+ return HB_Err_Not_Covered;
+ }
+}
+
+
+/* END */
--- /dev/null
- #include "harfbuzz-gdef.h"
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HARFBUZZ_H
+#define HARFBUZZ_H
+
+#include "harfbuzz-global.h"
+#include "harfbuzz-buffer.h"
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-gpos.h"
+#include "harfbuzz-open.h"
+
+#endif /* HARFBUZZ_OPEN_H */
--- /dev/null
-
+ /*
+ * Copyright (C) 2007,2008 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
+ */
+
+ #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H
+ #define HB_OT_LAYOUT_GSUB_PRIVATE_H
+
+ #include "hb-ot-layout-private.h"
+
+ #include "hb-ot-layout-open-private.h"
+ #include "hb-ot-layout-gdef-private.h"
+
+
+ struct SingleSubstFormat1 {
+
+ friend struct SingleSubst;
+
+ private:
+ inline bool substitute (hb_ot_layout_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int context_length,
+ unsigned int nesting_level_left) const {
+ // if (get_coverage (IN_CURGLYPH()))
+ // return ;
+ }
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ SHORT deltaGlyphID; /* Add to original GlyphID to get
+ * substitute GlyphID */
+ };
+ ASSERT_SIZE (SingleSubstFormat1, 6);
+
+ struct SingleSubstFormat2 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 2 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT glyphCount; /* Number of GlyphIDs in the Substitute
+ * array */
+ GlyphID substitute[]; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+ };
+ ASSERT_SIZE (SingleSubstFormat2, 6);
+
+ struct MultipleSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT sequenceCount; /* Number of Sequence table offsets in
+ * the Sequence array */
+ Offset sequence[]; /* Array of offsets to Sequence
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * Coverage Index */
+ };
+ ASSERT_SIZE (MultipleSubstFormat1, 6);
+
+ struct Sequence {
+ /* TODO */
+
+ private:
+ USHORT glyphCount; /* Number of GlyphIDs in the Substitute
+ * array. This should always be
+ * greater than 0. */
+ GlyphID substitute[]; /* String of GlyphIDs to substitute */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
+
+ struct AlternateSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT alternateSetCount; /* Number of AlternateSet tables */
+ Offset alternateSet[]; /* Array of offsets to AlternateSet
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * Coverage Index */
+ };
+ ASSERT_SIZE (AlternateSubstFormat1, 6);
+
+ struct AlternateSet {
+ /* TODO */
+
+ private:
+ USHORT glyphCount; /* Number of GlyphIDs in the Alternate
+ * array */
+ GlyphID alternate[]; /* Array of alternate GlyphIDs--in
+ * arbitrary order */
+ };
+ DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
+
+ struct LigatureSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT ligSetCount; /* Number of LigatureSet tables */
+ Offset ligatureSet[]; /* Array of offsets to LigatureSet
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * Coverage Index */
+ };
+ ASSERT_SIZE (LigatureSubstFormat1, 6);
+
+ struct LigatureSet {
+ /* TODO */
+
+ private:
+ USHORT ligatureCount; /* Number of Ligature tables */
+ Offset ligature[]; /* Array of offsets to Ligature
+ * tables--from beginning of
+ * LigatureSet table--ordered by
+ * preference */
+ };
+ DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
+
+ struct Ligature {
+ /* TODO */
+
+ private:
+ GlyphID ligGlyph; /* GlyphID of ligature to substitute */
+ USHORT compCount; /* Number of components in the ligature */
+ GlyphID component[]; /* Array of component GlyphIDs--start
+ * with the second component--ordered
+ * in writing direction */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
+
+ struct SubstLookupRecord {
+ /* TODO */
+
+ private:
+ USHORT sequenceIndex; /* Index into current glyph
+ * sequence--first glyph = 0 */
+ USHORT lookupListIndex; /* Lookup to apply to that
+ * position--zero--based */
+ };
+ DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
+
+ struct ContextSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT subRuleSetCount; /* Number of SubRuleSet tables--must
+ * equal GlyphCount in Coverage table */
+ Offset subRuleSet[]; /* Array of offsets to SubRuleSet
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * Coverage Index */
+ };
+ ASSERT_SIZE (ContextSubstFormat1, 6);
+
+ struct SubRuleSet {
+ /* TODO */
+
+ private:
+ USHORT subRuleCount; /* Number of SubRule tables */
+ Offset subRule[]; /* Array of offsets to SubRule
+ * tables--from beginning of SubRuleSet
+ * table--ordered by preference */
+ };
+ DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
+
+ struct SubRule {
+ /* TODO */
+
+ private:
+ USHORT glyphCount; /* Total number of glyphs in input
+ * glyph sequence--includes the first
+ * glyph */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ GlyphID input[]; /* Array of input GlyphIDs--start with
+ * second glyph */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order */
+ };
+ DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
+
+ struct ContextSubstFormat2 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 2 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Offset classDef; /* Offset to glyph ClassDef table--from
+ * beginning of Substitution table */
+ USHORT subClassSetCnt; /* Number of SubClassSet tables */
+ Offset subClassSet[]; /* Array of offsets to SubClassSet
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * class--may be NULL */
+ };
+ ASSERT_SIZE (ContextSubstFormat2, 8);
+
+ struct SubClassSet {
+ /* TODO */
+
+ private:
+ USHORT subClassRuleCnt; /* Number of SubClassRule tables */
+ Offset subClassRule[]; /* Array of offsets to SubClassRule
+ * tables--from beginning of
+ * SubClassSet--ordered by preference */
+ };
+ DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
+
+ struct SubClassRule {
+ /* TODO */
+
+ private:
+ USHORT glyphCount; /* Total number of classes
+ * specified for the context in the
+ * rule--includes the first class */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ USHORT klass[]; /* Array of classes--beginning with the
+ * second class--to be matched to the
+ * input glyph class sequence */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order */
+ };
+ DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
+
+ struct ContextSubstFormat3 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 3 */
+ USHORT glyphCount; /* Number of glyphs in the input glyph
+ * sequence */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ Offset coverage[]; /* Array of offsets to Coverage
+ * table--from beginning of
+ * Substitution table--in glyph
+ * sequence order */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order */
+ };
+ ASSERT_SIZE (ContextSubstFormat3, 6);
+
+ struct ChainContextSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ USHORT chainSubRuleSetCount; /* Number of ChainSubRuleSet
+ * tables--must equal GlyphCount in
+ * Coverage table */
+ Offset chainSubRuleSet[]; /* Array of offsets to ChainSubRuleSet
+ * tables--from beginning of
+ * Substitution table--ordered by
+ * Coverage Index */
+ };
+ ASSERT_SIZE (ChainContextSubstFormat1, 6);
+
+ struct ChainSubRuleSet {
+ /* TODO */
+
+ private:
+ USHORT chainSubRuleCount; /* Number of ChainSubRule tables */
+ Offset chainSubRule[]; /* Array of offsets to ChainSubRule
+ * tables--from beginning of
+ * ChainSubRuleSet table--ordered
+ * by preference */
+ };
+ DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
+
+ struct ChainSubRule {
+ /* TODO */
+
+ private:
+ USHORT backtrackGlyphCount; /* Total number of glyphs in the
+ * backtrack sequence (number of
+ * glyphs to be matched before the
+ * first glyph) */
+ GlyphID backtrack[]; /* Array of backtracking GlyphID's
+ * (to be matched before the input
+ * sequence) */
+ USHORT inputGlyphCount; /* Total number of glyphs in the input
+ * sequence (includes the first glyph) */
+ GlyphID input[]; /* Array of input GlyphIDs (start with
+ * second glyph) */
+ USHORT lookaheadGlyphCount; /* Total number of glyphs in the look
+ * ahead sequence (number of glyphs to
+ * be matched after the input sequence) */
+ GlyphID lookAhead[]; /* Array of lookahead GlyphID's (to be
+ * matched after the input sequence) */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order) */
+ };
+ DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
+
+ struct ChainContextSubstFormat2 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 2 */
+ Offset coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ Offset backtrackClassDef; /* Offset to glyph ClassDef table
+ * containing backtrack sequence
+ * data--from beginning of Substitution
+ * table */
+ Offset inputClassDef; /* Offset to glyph ClassDef
+ * table containing input sequence
+ * data--from beginning of Substitution
+ * table */
+ Offset lookaheadClassDef; /* Offset to glyph ClassDef table
+ * containing lookahead sequence
+ * data--from beginning of Substitution
+ * table */
+ USHORT chainSubClassSetCnt; /* Number of ChainSubClassSet tables */
+ Offset chainSubClassSet[]; /* Array of offsets to ChainSubClassSet
+ * tables--from beginning of
+ * Substitution table--ordered by input
+ * class--may be NULL */
+ };
+ ASSERT_SIZE (ChainContextSubstFormat2, 12);
+
+ struct ChainSubClassSet {
+ /* TODO */
+
+ private:
+ USHORT chainSubClassRuleCnt; /* Number of ChainSubClassRule tables */
+ Offset chainSubClassRule[]; /* Array of offsets
+ * to ChainSubClassRule
+ * tables--from beginning of
+ * ChainSubClassSet--ordered by
+ * preference */
+ };
+ DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
+
+ struct ChainSubClassRule {
+ /* TODO */
+
+ private:
+ USHORT backtrackGlyphCount; /* Total number of glyphs in the
+ * backtrack sequence (number of
+ * glyphs to be matched before the
+ * first glyph) */
+ USHORT backtrack[]; /* Array of backtracking classes(to be
+ * matched before the input sequence) */
+ USHORT inputGlyphCount; /* Total number of classes in the input
+ * sequence (includes the first class) */
+ USHORT input[]; /* Array of input classes(start with
+ * second class; to be matched with
+ * the input glyph sequence) */
+ USHORT lookaheadGlyphCount; /* Total number of classes in the
+ * look ahead sequence (number of
+ * classes to be matched after the
+ * input sequence) */
+ USHORT lookAhead[]; /* Array of lookahead classes(to be
+ * matched after the input sequence) */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order) */
+ };
+ DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
+
+ struct ChainContextSubstFormat3 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 3 */
+ USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
+ * sequence */
+ Offset backtrackCoverage[]; /* Array of offsets to coverage tables
+ * in backtracking sequence, in glyph
+ * sequence order */
+ USHORT inputGlyphCount; /* Number of glyphs in input sequence */
+ Offset inputCoverage[]; /* Array of offsets to coverage
+ * tables in input sequence, in glyph
+ * sequence order */
+ USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
+ * sequence */
+ Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
+ * in lookahead sequence, in glyph
+ * sequence order */
+ USHORT substCount; /* Number of SubstLookupRecords */
+ SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+ * design order */
+ };
+ ASSERT_SIZE (ChainContextSubstFormat3, 10);
+
+ struct ExtensionSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier. Set to 1. */
+ USHORT extensionLookupType; /* Lookup type of subtable referenced
+ * by ExtensionOffset (i.e. the
+ * extension subtable). */
+ ULONG extensionOffset; /* Offset to the extension subtable,
+ * of lookup type subtable. */
+ };
+ ASSERT_SIZE (ExtensionSubstFormat1, 8);
+
+ struct ReverseChainSingleSubstFormat1 {
+ /* TODO */
+
+ private:
+ USHORT substFormat; /* Format identifier--format = 1 */
+ Offset coverage; /* Offset to Coverage table -- from
+ * beginning of Substitution table */
+ USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
+ * sequence */
+ Offset backtrackCoverage[]; /* Array of offsets to coverage tables
+ * in backtracking sequence, in glyph
+ * sequence order */
+ USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
+ * sequence */
+ Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
+ * in lookahead sequence, in glyph
+ * sequence order */
+ USHORT glyphCount; /* Number of GlyphIDs in the Substitute
+ * array */
+ GlyphID substitute[]; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+ };
+ ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
+
+ /*
+ * SubstLookup
+ */
+
+ struct SubstLookupSubTable {
+ DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
+
+ friend struct SubstLookup;
+
+ unsigned int get_size (unsigned int lookup_type) const {
+ switch (lookup_type) {
+ // case 1: return u.format1.get_size ();
+ // case 2: return u.format2.get_size ();
+ /*
+ case Single:
+ case Multiple:
+ case Alternate:
+ case Ligature:
+ case Context:
+ case ChainingContext:
+ case Extension:
+ case ReverseChainingContextSingle:
+ */
+ default:return sizeof (LookupSubTable);
+ }
+ }
+
+ inline bool substitute (hb_ot_layout_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int context_length,
+ unsigned int nesting_level_left,
+ unsigned int lookup_type) const {
+ }
+
+ private:
+ union {
+ USHORT substFormat;
+ CoverageFormat1 format1;
+ CoverageFormat2 format2;
+ } u;
+ };
+
+ struct SubstLookup : Lookup {
+
+ DEFINE_NON_INSTANTIABLE(SubstLookup);
+
+ static const unsigned int Single = 1;
+ static const unsigned int Multiple = 2;
+ static const unsigned int Alternate = 3;
+ static const unsigned int Ligature = 4;
+ static const unsigned int Context = 5;
+ static const unsigned int ChainingContext = 6;
+ static const unsigned int Extension = 7;
+ static const unsigned int ReverseChainingContextSingle = 8;
+
+ inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
+ return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
+ }
+
+ /* Like get_type(), but looks through extension lookups.
+ * Never returns SubstLookup::Extension */
+ inline unsigned int get_effective_type (void) const {
+ unsigned int type = get_type ();
+
+ if (HB_UNLIKELY (type == Extension)) {
+ /* Return lookup type of first extension subtable.
+ * The spec says all of them should have the same type.
+ * XXX check for that somehow */
+ //XXX type = get_subtable(0).v.extension.get_type ();
+ }
+
+ return type;
+ }
+
+ inline bool is_reverse (void) const {
+ switch (get_effective_type ()) {
+ case ReverseChainingContextSingle: return true;
+ default: return false;
+ }
+ }
+
+ inline bool substitute (hb_ot_layout_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int context_length,
+ unsigned int nesting_level_left) const {
+ unsigned int lookup_type = get_type ();
+
+ if (HB_UNLIKELY (nesting_level_left == 0))
+ return false;
+ nesting_level_left--;
-
++
+ for (unsigned int i = 0; i < get_subtable_count (); i++)
+ if (get_subtable (i).substitute (layout, buffer,
+ context_length, nesting_level_left,
+ lookup_type))
+ return true;
++
+ return false;
+ }
+ };
+ DEFINE_NULL_ALIAS (SubstLookup, Lookup);
+
+ /*
+ * GSUB
+ */
+
+ struct GSUB : GSUBGPOS {
+ static const hb_tag_t Tag = HB_TAG ('G','S','U','B');
+
+ STATIC_DEFINE_GET_FOR_DATA (GSUB);
+ /* XXX check version here? */
+
+ inline const SubstLookup& get_lookup (unsigned int i) const {
+ return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
+ }
+
+
+ };
+ DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
+
+
+ #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */
--- /dev/null
- * to the beginning of the Feature Table; = Null
+ /*
+ * Copyright (C) 2007,2008 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
+ */
+
+ #ifndef HB_OT_LAYOUT_OPEN_PRIVATE_H
+ #define HB_OT_LAYOUT_OPEN_PRIVATE_H
+
+ #ifndef HB_OT_LAYOUT_CC
+ #error "This file should only be included from hb-ot-layout.c"
+ #endif
+
+ #include "hb-ot-layout-private.h"
+
+
+ #define NO_INDEX ((unsigned int) 0xFFFF)
+ #define NO_CONTEXT ((unsigned int) -1)
+
+ /*
+ * Int types
+ */
+
+ /* XXX define these as structs of chars on machines that do not allow
+ * unaligned access */
+ #define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN) \
+ inline NAME& operator = (TYPE i) { v = BIG_ENDIAN(i); return *this; } \
+ inline operator TYPE(void) const { return BIG_ENDIAN(v); } \
+ inline bool operator== (NAME o) const { return v == o.v; } \
+ private: TYPE v; \
+ public:
+ #define DEFINE_INT_TYPE0(NAME, type) DEFINE_INT_TYPE1 (NAME, type, hb_be_##type)
+ #define DEFINE_INT_TYPE(NAME, u, w) DEFINE_INT_TYPE0 (NAME, u##int##w##_t)
+ #define DEFINE_INT_TYPE_STRUCT(NAME, u, w) \
+ struct NAME { \
+ DEFINE_INT_TYPE(NAME, u, w) \
+ }
+
+ /*
+ * Array types
+ */
+
+ /* get_len() is a method returning the number of items in an array-like object */
+ #define DEFINE_LEN(Type, array, num) \
+ inline unsigned int get_len(void) const { return num; } \
+
+ /* get_size() is a method returning the size in bytes of an array-like object */
+ #define DEFINE_SIZE(Type, array, num) \
+ inline unsigned int get_size(void) const { return sizeof (*this) + sizeof (Type) * num; }
+
+ #define DEFINE_LEN_AND_SIZE(Type, array, num) \
+ DEFINE_LEN(Type, array, num) \
+ DEFINE_SIZE(Type, array, num)
+
+ /* An array type is one that contains a variable number of objects
+ * as its last item. An array object is extended with len() and size()
+ * methods, as well as overloaded [] operator. */
+ #define DEFINE_ARRAY_TYPE(Type, array, num) \
+ DEFINE_INDEX_OPERATOR(Type, array, num) \
+ DEFINE_LEN_AND_SIZE(Type, array, num)
+ #define DEFINE_INDEX_OPERATOR(Type, array, num) \
+ inline const Type& operator[] (unsigned int i) const { \
+ if (HB_UNLIKELY (i >= num)) return Null##Type; \
+ return array[i]; \
+ }
+
+ /* An offset array type is like an array type, but it contains a table
+ * of offsets to the objects, relative to the beginning of the current
+ * object. */
+ #define DEFINE_OFFSET_ARRAY_TYPE(Type, array, num) \
+ DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \
+ DEFINE_LEN_AND_SIZE(Offset, array, num)
+ #define DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \
+ inline const Type& operator[] (unsigned int i) const { \
+ if (HB_UNLIKELY (i >= num)) return Null##Type; \
+ if (HB_UNLIKELY (!array[i])) return Null##Type; \
+ return *(const Type *)((const char*)this + array[i]); \
+ }
+
+ /* A record array type is like an array type, but it contains a table
+ * of records to the objects. Each record has a tag, and an offset
+ * relative to the beginning of the current object. */
+ #define DEFINE_RECORD_ARRAY_TYPE(Type, array, num) \
+ DEFINE_RECORD_ACCESSOR(Type, array, num) \
+ DEFINE_LEN_AND_SIZE(Record, array, num)
+ #define DEFINE_RECORD_ACCESSOR(Type, array, num) \
+ inline const Type& operator[] (unsigned int i) const { \
+ if (HB_UNLIKELY (i >= num)) return Null##Type; \
+ if (HB_UNLIKELY (!array[i].offset)) return Null##Type; \
+ return *(const Type *)((const char*)this + array[i].offset); \
+ } \
+ inline const Tag& get_tag (unsigned int i) const { \
+ if (HB_UNLIKELY (i >= num)) return NullTag; \
+ return array[i].tag; \
+ }
+
+
+ #define DEFINE_ARRAY_INTERFACE(Type, name) \
+ inline const Type& get_##name (unsigned int i) const { \
+ return (*this)[i]; \
+ } \
+ inline unsigned int get_##name##_count (void) const { \
+ return this->get_len (); \
+ }
+ #define DEFINE_INDEX_ARRAY_INTERFACE(name) \
+ inline unsigned int get_##name##_index (unsigned int i) const { \
+ if (HB_UNLIKELY (i >= get_len ())) return NO_INDEX; \
+ return (*this)[i]; \
+ } \
+ inline unsigned int get_##name##_count (void) const { \
+ return get_len (); \
+ }
+
+
+ /*
+ * List types
+ */
+
+ #define DEFINE_LIST_ARRAY(Type, name) \
+ inline const Type##List& get_##name##_list (void) const { \
+ if (HB_UNLIKELY (!name##List)) return Null##Type##List; \
+ return *(const Type##List *)((const char*)this + name##List); \
+ }
+
+ #define DEFINE_LIST_INTERFACE(Type, name) \
+ inline const Type& get_##name (unsigned int i) const { \
+ return get_##name##_list ()[i]; \
+ } \
+ inline unsigned int get_##name##_count (void) const { \
+ return get_##name##_list ().get_len (); \
+ }
+
+ /*
+ * Tag types
+ */
+
+ #define DEFINE_TAG_ARRAY_INTERFACE(Type, name) \
+ DEFINE_ARRAY_INTERFACE (Type, name); \
+ inline const Tag& get_##name##_tag (unsigned int i) const { \
+ return (*this)[i].tag; \
+ }
+ #define DEFINE_TAG_LIST_INTERFACE(Type, name) \
+ DEFINE_LIST_INTERFACE (Type, name); \
+ inline const Tag& get_##name##_tag (unsigned int i) const { \
+ return get_##name##_list ().get_tag (i); \
+ }
+
+ #define DEFINE_TAG_FIND_INTERFACE(Type, name) \
+ inline bool find_##name##_index (hb_tag_t tag, unsigned int *name##_index) const { \
+ const Tag t = tag; \
+ for (unsigned int i = 0; i < get_##name##_count (); i++) { \
+ if (t == get_##name##_tag (i)) { \
+ if (name##_index) *name##_index = i; \
+ return true; \
+ } \
+ } \
+ if (name##_index) *name##_index = NO_INDEX; \
+ return false; \
+ } \
+ inline const Type& get_##name##_by_tag (hb_tag_t tag) const { \
+ unsigned int i; \
+ if (find_##name##_index (tag, &i)) \
+ return get_##name (i); \
+ else \
+ return Null##Type; \
+ }
+
+ /*
+ * Class features
+ */
+
+ /* makes class uninstantiable. should be used for union classes that don't
+ * contain any complete type */
+ #define DEFINE_NON_INSTANTIABLE(Type) \
+ protected: inline Type() {} /* cannot be instantiated */ \
+ public:
+
+ // TODO use a global nul-array for most Null's
+ /* defines Null##Type as a safe nil instance of Type */
+ #define DEFINE_NULL_DATA(Type, size, data) \
+ static const unsigned char Null##Type##Data[size] = data; \
+ DEFINE_NULL_ALIAS (Type, Type)
+ #define DEFINE_NULL(Type, size) \
+ DEFINE_NULL_DATA(Type, size, "")
+ #define DEFINE_NULL_ASSERT_SIZE(Type, size) \
+ DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, "")
+ #define DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, data) \
+ ASSERT_SIZE (Type, size); \
+ DEFINE_NULL_DATA (Type, size, data)
+ #define DEFINE_NULL_ALIAS(NewType, OldType) \
+ /* XXX static */ const NewType &Null##NewType = *(NewType *)Null##OldType##Data
+
+ /* get_for_data() is a static class method returning a reference to an
+ * instance of Type located at the input data location. It's just a
+ * fancy, NULL-safe, cast! */
+ #define STATIC_DEFINE_GET_FOR_DATA(Type) \
+ static inline const Type& get_for_data (const char *data) { \
+ extern const Type &Null##Type; \
+ if (HB_UNLIKELY (data == NULL)) return Null##Type; \
+ return *(const Type*)data; \
+ } \
+ static inline Type& get_for_data (char *data) { \
+ return *(Type*)data; \
+ }
+
+
+ #define DEFINE_GET_ACCESSOR(Type, name, Name) \
+ inline const Type& get_##name (void) const { \
+ if (HB_UNLIKELY (!Name)) return Null##Type; \
+ return *(const Type*)((const char*)this + Name); \
+ }
+ #define DEFINE_GET_HAS_ACCESSOR(Type, name, Name) \
+ DEFINE_GET_ACCESSOR (Type, name, Name); \
+ inline bool has_##name (void) const { \
+ return Name != 0; \
+ }
+
+
+
+
+ /*
+ *
+ * The OpenType Font File
+ *
+ */
+
+
+
+ /*
+ * Data Types
+ */
+
+
+ /* "The following data types are used in the OpenType font file.
+ * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
+
+
+ DEFINE_INT_TYPE_STRUCT (BYTE, u, 8); /* 8-bit unsigned integer. */
+ DEFINE_NULL_ASSERT_SIZE (BYTE, 1);
+ DEFINE_INT_TYPE_STRUCT (CHAR, , 8); /* 8-bit signed integer. */
+ DEFINE_NULL_ASSERT_SIZE (CHAR, 1);
+ DEFINE_INT_TYPE_STRUCT (USHORT, u, 16); /* 16-bit unsigned integer. */
+ DEFINE_NULL_ASSERT_SIZE (USHORT, 2);
+ DEFINE_INT_TYPE_STRUCT (SHORT, , 16); /* 16-bit signed integer. */
+ DEFINE_NULL_ASSERT_SIZE (SHORT, 2);
+ DEFINE_INT_TYPE_STRUCT (ULONG, u, 32); /* 32-bit unsigned integer. */
+ DEFINE_NULL_ASSERT_SIZE (ULONG, 4);
+ DEFINE_INT_TYPE_STRUCT (LONG, , 32); /* 32-bit signed integer. */
+ DEFINE_NULL_ASSERT_SIZE (LONG, 4);
+
+ /* Date represented in number of seconds since 12:00 midnight, January 1,
+ * 1904. The value is represented as a signed 64-bit integer. */
+ DEFINE_INT_TYPE_STRUCT (LONGDATETIME, , 64);
+
+ /* 32-bit signed fixed-point number (16.16) */
+ struct Fixed {
+ inline Fixed& operator = (int32_t v) { i = (int16_t) (v >> 16); f = (uint16_t) v; return *this; } \
+ inline operator int32_t(void) const { return (((int32_t) i) << 16) + (uint16_t) f; } \
+ inline bool operator== (Fixed o) const { return i == o.i && f == o.f; } \
+
+ inline operator double(void) const { return (uint32_t) this / 65536.; }
+ inline int16_t int_part (void) const { return i; }
+ inline uint16_t frac_part (void) const { return f; }
+
+ private:
+ SHORT i;
+ USHORT f;
+ };
+ DEFINE_NULL_ASSERT_SIZE (Fixed, 4);
+
+ /* Smallest measurable distance in the em space. */
+ struct FUNIT;
+
+ /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
+ struct FWORD : SHORT {
+ };
+ DEFINE_NULL_ASSERT_SIZE (FWORD, 2);
+
+ /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
+ struct UFWORD : USHORT {
+ };
+ DEFINE_NULL_ASSERT_SIZE (UFWORD, 2);
+
+ /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+ struct F2DOT14 : SHORT {
+ inline operator double() const { return (uint32_t) this / 16384.; }
+ };
+ DEFINE_NULL_ASSERT_SIZE (F2DOT14, 2);
+
+ /* Array of four uint8s (length = 32 bits) used to identify a script, language
+ * system, feature, or baseline */
+ struct Tag {
+ inline Tag (void) { v[0] = v[1] = v[2] = v[3] = 0; }
+ inline Tag (uint32_t v) { (ULONG&)(*this) = v; }
+ inline Tag (const char *c) { v[0] = c[0]; v[1] = c[1]; v[2] = c[2]; v[3] = c[3]; }
+ inline bool operator== (Tag o) const { return v[0]==o.v[0]&&v[1]==o.v[1]&&v[2]==o.v[2]&&v[3]==o.v[3]; }
+ inline bool operator== (const char *c) const { return v[0]==c[0]&&v[1]==c[1]&&v[2]==c[2]&&v[3]==c[3]; }
+ inline bool operator== (uint32_t i) const { return i == (uint32_t) *this; }
+ inline operator uint32_t(void) const { return (v[0]<<24)+(v[1]<<16) +(v[2]<<8)+v[3]; }
+ /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
+ inline operator const char* (void) const { return (const char *)this; }
+ inline operator char* (void) { return (char *)this; }
+
+ private:
+ char v[4];
+ };
+ ASSERT_SIZE (Tag, 4);
+ DEFINE_NULL_DATA (Tag, 5, " ");
+
+ /* Glyph index number, same as uint16 (length = 16 bits) */
+ DEFINE_INT_TYPE_STRUCT (GlyphID, u, 16);
+ DEFINE_NULL_ASSERT_SIZE (GlyphID, 2);
+
+ /* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
+ DEFINE_INT_TYPE_STRUCT (Offset, u, 16);
+ DEFINE_NULL_ASSERT_SIZE (Offset, 2);
+
+ /* CheckSum */
+ struct CheckSum : ULONG {
+ static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) {
+ uint32_t Sum = 0L;
+ ULONG *EndPtr = Table+((Length+3) & ~3) / sizeof(ULONG);
+
+ while (Table < EndPtr)
+ Sum += *Table++;
+ return Sum;
+ }
+ };
+ DEFINE_NULL_ASSERT_SIZE (CheckSum, 4);
+
+
+ /*
+ * Version Numbers
+ */
+
+ struct USHORT_Version : USHORT {
+ };
+ DEFINE_NULL_ASSERT_SIZE (USHORT_Version, 2);
+
+ struct Fixed_Version : Fixed {
+ inline int16_t major (void) const { return this->int_part(); }
+ inline int16_t minor (void) const { return this->frac_part(); }
+ };
+ DEFINE_NULL_ASSERT_SIZE (Fixed_Version, 4);
+
+
+ /*
+ * Organization of an OpenType Font
+ */
+
+ struct OpenTypeFontFile;
+ struct OffsetTable;
+ struct TTCHeader;
+
+ typedef struct TableDirectory {
+
+ friend struct OpenTypeFontFile;
+ friend struct OffsetTable;
+
+ inline bool is_null (void) const { return length == 0; }
+ inline const Tag& get_tag (void) const { return tag; }
+ inline unsigned long get_checksum (void) const { return checkSum; }
+ inline unsigned long get_offset (void) const { return offset; }
+ inline unsigned long get_length (void) const { return length; }
+
+ private:
+ Tag tag; /* 4-byte identifier. */
+ CheckSum checkSum; /* CheckSum for this table. */
+ ULONG offset; /* Offset from beginning of TrueType font
+ * file. */
+ ULONG length; /* Length of this table. */
+ } OpenTypeTable;
+ DEFINE_NULL_ASSERT_SIZE (TableDirectory, 16);
+ DEFINE_NULL_ALIAS (OpenTypeTable, TableDirectory);
+
+ typedef struct OffsetTable {
+
+ friend struct OpenTypeFontFile;
+ friend struct TTCHeader;
+
+ DEFINE_TAG_ARRAY_INTERFACE (OpenTypeTable, table); /* get_table_count(), get_table(i), get_table_tag(i) */
+ DEFINE_TAG_FIND_INTERFACE (OpenTypeTable, table); /* find_table_index(tag), get_table_by_tag(tag) */
+
+ private:
+ /* OpenTypeTables, in no particular order */
+ DEFINE_ARRAY_TYPE (TableDirectory, tableDir, numTables);
+
+ private:
+ Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
+ USHORT numTables; /* Number of tables. */
+ USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */
+ USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */
+ USHORT rangeShift; /* NumTables x 16-searchRange. */
+ TableDirectory tableDir[]; /* TableDirectory entries. numTables items */
+ } OpenTypeFontFace;
+ DEFINE_NULL_ASSERT_SIZE (OffsetTable, 12);
+ DEFINE_NULL_ALIAS (OpenTypeFontFace, OffsetTable);
+
+ /*
+ * TrueType Collections
+ */
+
+ struct TTCHeader {
+
+ friend struct OpenTypeFontFile;
+
+ private:
+ /* OpenTypeFontFaces, in no particular order */
+ DEFINE_OFFSET_ARRAY_TYPE (OffsetTable, offsetTable, numFonts);
+ /* XXX check version here? */
+
+ private:
+ Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
+ ULONG version; /* Version of the TTC Header (1.0 or 2.0),
+ * 0x00010000 or 0x00020000 */
+ ULONG numFonts; /* Number of fonts in TTC */
+ ULONG offsetTable[]; /* Array of offsets to the OffsetTable for each font
+ * from the beginning of the file */
+ };
+ DEFINE_NULL_ASSERT_SIZE (TTCHeader, 12);
+
+
+ /*
+ * OpenType Font File
+ */
+
+ struct OpenTypeFontFile {
+ DEFINE_NON_INSTANTIABLE(OpenTypeFontFile);
+ static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 );
+ static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O');
+ static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f');
+
+ STATIC_DEFINE_GET_FOR_DATA (OpenTypeFontFile);
+
+ DEFINE_ARRAY_INTERFACE (OpenTypeFontFace, face); /* get_face_count(), get_face(i) */
+
+ inline const Tag& get_tag (void) const { return tag; }
+
+ /* This is how you get a table */
+ inline const char* get_table_data (const OpenTypeTable& table) const {
+ return (*this)[table];
+ }
+ inline char* get_table_data (const OpenTypeTable& table) {
+ return (*this)[table];
+ }
+
+ private:
+ inline const char* operator[] (const OpenTypeTable& table) const {
+ if (G_UNLIKELY (table.offset == 0)) return NULL;
+ return ((const char*)this) + table.offset;
+ }
+ inline char* operator[] (const OpenTypeTable& table) {
+ if (G_UNLIKELY (table.offset == 0)) return NULL;
+ return ((char*)this) + table.offset;
+ }
+
+ /* Array interface sans get_size() */
+ unsigned int get_len (void) const {
+ switch (tag) {
+ default: return 0;
+ case TrueTypeTag: case CFFTag: return 1;
+ case TTCTag: return ((const TTCHeader&)*this).get_len();
+ }
+ }
+ const OpenTypeFontFace& operator[] (unsigned int i) const {
+ if (HB_UNLIKELY (i >= get_len ())) return NullOpenTypeFontFace;
+ switch (tag) {
+ default: case TrueTypeTag: case CFFTag: return (const OffsetTable&)*this;
+ case TTCTag: return ((const TTCHeader&)*this)[i];
+ }
+ }
+
+ private:
+ Tag tag; /* 4-byte identifier. */
+ };
+ DEFINE_NULL_ASSERT_SIZE (OpenTypeFontFile, 4);
+
+
+
+ /*
+ *
+ * OpenType Layout Common Table Formats
+ *
+ */
+
+ /*
+ * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
+ */
+
+ typedef struct Record {
+ Tag tag; /* 4-byte Tag identifier */
+ Offset offset; /* Offset from beginning of object holding
+ * the Record */
+ } ScriptRecord, LangSysRecord, FeatureRecord;
+ DEFINE_NULL_ASSERT_SIZE (Record, 6);
+
+ struct LangSys {
+
+ DEFINE_INDEX_ARRAY_INTERFACE (feature);
+
+ inline const bool has_required_feature (void) const {
+ return reqFeatureIndex != 0xffff;
+ }
+ /* Returns NO_INDEX if none */
+ inline int get_required_feature_index (void) const {
+ if (reqFeatureIndex == 0xffff)
+ return NO_INDEX;
+ return reqFeatureIndex;;
+ }
+
+ private:
+ /* Feature indices, in no particular order */
+ DEFINE_ARRAY_TYPE (USHORT, featureIndex, featureCount);
+
+ private:
+ Offset lookupOrder; /* = Null (reserved for an offset to a
+ * reordering table) */
+ USHORT reqFeatureIndex;/* Index of a feature required for this
+ * language system--if no required features
+ * = 0xFFFF */
+ USHORT featureCount; /* Number of FeatureIndex values for this
+ * language system--excludes the required
+ * feature */
+ USHORT featureIndex[]; /* Array of indices into the FeatureList--in
+ * arbitrary order. featureCount entires long */
+ };
+ DEFINE_NULL_ASSERT_SIZE_DATA (LangSys, 6, "\0\0\xFF\xFF");
+
+ struct Script {
+
+ /* DEFINE_ARRAY_INTERFACE (LangSys, lang_sys) but handling defaultLangSys */
+
+ inline const LangSys& get_lang_sys (unsigned int i) const {
+ if (i == NO_INDEX) return get_default_lang_sys ();
+ return (*this)[i];
+ }
+ inline unsigned int get_lang_sys_count (void) const {
+ return this->get_len ();
+ }
+
+ inline const Tag& get_lang_sys_tag (unsigned int i) const {
+ return get_tag (i);
+ }
+
+ // LONGTERMTODO bsearch
+ DEFINE_TAG_FIND_INTERFACE (LangSys, lang_sys); /* find_lang_sys_index (), get_lang_sys_by_tag (tag) */
+
+ inline const bool has_default_lang_sys (void) const {
+ return defaultLangSys != 0;
+ }
+ inline const LangSys& get_default_lang_sys (void) const {
+ if (HB_UNLIKELY (!defaultLangSys))
+ return NullLangSys;
+ return *(LangSys*)((const char*)this + defaultLangSys);
+ }
+
+ private:
+ /* LangSys', in sorted alphabetical tag order */
+ DEFINE_RECORD_ARRAY_TYPE (LangSys, langSysRecord, langSysCount);
+
+ private:
+ Offset defaultLangSys; /* Offset to DefaultLangSys table--from
+ * beginning of Script table--may be Null */
+ USHORT langSysCount; /* Number of LangSysRecords for this script--
+ * excluding the DefaultLangSys */
+ LangSysRecord langSysRecord[];/* Array of LangSysRecords--listed
+ * alphabetically by LangSysTag */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Script, 4);
+
+ struct ScriptList {
+
+ friend struct GSUBGPOS;
+
+ private:
+ /* Scripts, in sorted alphabetical tag order */
+ DEFINE_RECORD_ARRAY_TYPE (Script, scriptRecord, scriptCount);
+
+ private:
+ USHORT scriptCount; /* Number of ScriptRecords */
+ ScriptRecord scriptRecord[]; /* Array of ScriptRecords--listed alphabetically
+ * by ScriptTag */
+ };
+ DEFINE_NULL_ASSERT_SIZE (ScriptList, 2);
+
+ struct Feature {
+
+ DEFINE_INDEX_ARRAY_INTERFACE (lookup); /* get_lookup_count(), get_lookup_index(i) */
+
+ private:
+ /* LookupList indices, in no particular order */
+ DEFINE_ARRAY_TYPE (USHORT, lookupIndex, lookupCount);
+
+ /* TODO: implement get_feature_parameters() */
+ /* TODO: implement FeatureSize and other special features? */
+
+ private:
+ Offset featureParams; /* Offset to Feature Parameters table (if one
+ * has been defined for the feature), relative
-
++ * to the beginning of the Feature Table; = Null
+ * if not required */
+ USHORT lookupCount; /* Number of LookupList indices for this
+ * feature */
+ USHORT lookupIndex[]; /* Array of LookupList indices for this
+ * feature--zero-based (first lookup is
+ * LookupListIndex = 0) */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Feature, 4);
+
+ struct FeatureList {
+
+ friend struct GSUBGPOS;
+
+ private:
+ /* Feature indices, in sorted alphabetical tag order */
+ DEFINE_RECORD_ARRAY_TYPE (Feature, featureRecord, featureCount);
+
+ private:
+ USHORT featureCount; /* Number of FeatureRecords in this table */
+ FeatureRecord featureRecord[];/* Array of FeatureRecords--zero-based (first
+ * feature has FeatureIndex = 0)--listed
+ * alphabetically by FeatureTag */
+ };
+ DEFINE_NULL_ASSERT_SIZE (FeatureList, 2);
+
+ struct LookupFlag : USHORT {
+ static const unsigned int RightToLeft = 0x0001u;
+ static const unsigned int IgnoreBaseGlyphs = 0x0002u;
+ static const unsigned int IgnoreLigatures = 0x0004u;
+ static const unsigned int IgnoreMarks = 0x0008u;
+ static const unsigned int Reserved = 0x00F0u;
+ static const unsigned int MarkAttachmentType = 0xFF00u;
+ };
+ DEFINE_NULL_ASSERT_SIZE (LookupFlag, 2);
+
+ struct LookupSubTable {
+ DEFINE_NON_INSTANTIABLE(LookupSubTable);
+
+ private:
+ USHORT format; /* Subtable format. Different for GSUB and GPOS */
+ };
+ DEFINE_NULL_ASSERT_SIZE (LookupSubTable, 2);
+
+
+ struct Lookup {
+ DEFINE_NON_INSTANTIABLE(Lookup);
+
+ DEFINE_ARRAY_INTERFACE (LookupSubTable, subtable); /* get_subtable_count(), get_subtable(i) */
+
+ inline bool is_right_to_left (void) const { return lookupFlag & LookupFlag::RightToLeft; }
+ inline bool ignore_base_glyphs(void) const { return lookupFlag & LookupFlag::IgnoreBaseGlyphs; }
+ inline bool ignore_ligatures (void) const { return lookupFlag & LookupFlag::IgnoreLigatures; }
+ inline bool ignore_marks (void) const { return lookupFlag & LookupFlag::IgnoreMarks; }
+ inline bool get_mark_attachment_type (void) const { return lookupFlag & LookupFlag::MarkAttachmentType; }
+
+ inline unsigned int get_type (void) const { return lookupType; }
+ inline unsigned int get_flag (void) const { return lookupFlag; }
+
+ private:
+ /* SubTables, in the desired order */
+ DEFINE_OFFSET_ARRAY_TYPE (LookupSubTable, subTableOffset, subTableCount);
+
+ protected:
+ USHORT lookupType; /* Different enumerations for GSUB and GPOS */
+ USHORT lookupFlag; /* Lookup qualifiers */
+ USHORT subTableCount; /* Number of SubTables for this lookup */
+ Offset subTableOffset[];/* Array of offsets to SubTables-from
+ * beginning of Lookup table */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Lookup, 6);
+
+ struct LookupList {
+
+ friend struct GSUBGPOS;
+
+ private:
+ /* Lookup indices, in sorted alphabetical tag order */
+ DEFINE_OFFSET_ARRAY_TYPE (Lookup, lookupOffset, lookupCount);
+
+ private:
+ USHORT lookupCount; /* Number of lookups in this table */
+ Offset lookupOffset[]; /* Array of offsets to Lookup tables--from
+ * beginning of LookupList--zero based (first
+ * lookup is Lookup index = 0) */
+ };
+ DEFINE_NULL_ASSERT_SIZE (LookupList, 2);
+
+ /*
+ * Coverage Table
+ */
+
+ struct CoverageFormat1 {
+
+ friend struct Coverage;
+
+ private:
+ /* GlyphIDs, in sorted numerical order */
+ DEFINE_ARRAY_TYPE (GlyphID, glyphArray, glyphCount);
+
+ inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+ GlyphID gid;
+ if (HB_UNLIKELY (glyph_id > 65535))
+ return -1;
+ gid = glyph_id;
+ // TODO: bsearch
+ for (unsigned int i = 0; i < glyphCount; i++)
+ if (gid == glyphArray[i])
+ return i;
+ return -1;
+ }
+
+ private:
+ USHORT coverageFormat; /* Format identifier--format = 1 */
+ USHORT glyphCount; /* Number of glyphs in the GlyphArray */
+ GlyphID glyphArray[]; /* Array of GlyphIDs--in numerical order */
+ };
+ ASSERT_SIZE (CoverageFormat1, 4);
+
+ struct CoverageRangeRecord {
+
+ friend struct CoverageFormat2;
+
+ private:
+ inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+ if (glyph_id >= start && glyph_id <= end)
+ return startCoverageIndex + (glyph_id - start);
+ return -1;
+ }
+
+ private:
+ GlyphID start; /* First GlyphID in the range */
+ GlyphID end; /* Last GlyphID in the range */
+ USHORT startCoverageIndex; /* Coverage Index of first GlyphID in
+ * range */
+ };
+ DEFINE_NULL_ASSERT_SIZE_DATA (CoverageRangeRecord, 6, "\001");
+
+ struct CoverageFormat2 {
+
+ friend struct Coverage;
+
+ private:
+ /* CoverageRangeRecords, in sorted numerical start order */
+ DEFINE_ARRAY_TYPE (CoverageRangeRecord, rangeRecord, rangeCount);
+
+ inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+ // TODO: bsearch
+ for (unsigned int i = 0; i < rangeCount; i++) {
+ int coverage = rangeRecord[i].get_coverage (glyph_id);
+ if (coverage >= 0)
+ return coverage;
+ }
+ return -1;
+ }
+
+ private:
+ USHORT coverageFormat; /* Format identifier--format = 2 */
+ USHORT rangeCount; /* Number of CoverageRangeRecords */
+ CoverageRangeRecord rangeRecord[]; /* Array of glyph ranges--ordered by
+ * Start GlyphID. rangeCount entries
+ * long */
+ };
+ ASSERT_SIZE (CoverageFormat2, 4);
+
+ struct Coverage {
+ DEFINE_NON_INSTANTIABLE(Coverage);
+
+ unsigned int get_size (void) const {
+ switch (u.coverageFormat) {
+ case 1: return u.format1.get_size ();
+ case 2: return u.format2.get_size ();
+ default:return sizeof (u.coverageFormat);
+ }
+ }
+
+ hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+ switch (u.coverageFormat) {
+ case 1: return u.format1.get_coverage(glyph_id);
+ case 2: return u.format2.get_coverage(glyph_id);
+ default:return -1;
+ }
+ }
+
+ private:
+ union {
+ USHORT coverageFormat; /* Format identifier */
+ CoverageFormat1 format1;
+ CoverageFormat2 format2;
+ } u;
+ };
+ DEFINE_NULL (Coverage, 2);
+
+ /*
+ * Class Definition Table
+ */
+
+ struct ClassDefFormat1 {
+
+ friend struct ClassDef;
+
+ private:
+ /* GlyphIDs, in sorted numerical order */
+ DEFINE_ARRAY_TYPE (USHORT, classValueArray, glyphCount);
+
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+ if (glyph_id >= startGlyph && glyph_id - startGlyph < glyphCount)
+ return classValueArray[glyph_id - startGlyph];
+ return 0;
+ }
+
+ private:
+ USHORT classFormat; /* Format identifier--format = 1 */
+ GlyphID startGlyph; /* First GlyphID of the classValueArray */
+ USHORT glyphCount; /* Size of the classValueArray */
+ USHORT classValueArray[]; /* Array of Class Values--one per GlyphID */
+ };
+ ASSERT_SIZE (ClassDefFormat1, 6);
+
+ struct ClassRangeRecord {
+
+ friend struct ClassDefFormat2;
+
+ private:
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+ if (glyph_id >= start && glyph_id <= end)
+ return classValue;
+ return 0;
+ }
+
+ private:
+ GlyphID start; /* First GlyphID in the range */
+ GlyphID end; /* Last GlyphID in the range */
+ USHORT classValue; /* Applied to all glyphs in the range */
+ };
+ DEFINE_NULL_ASSERT_SIZE_DATA (ClassRangeRecord, 6, "\001");
+
+ struct ClassDefFormat2 {
+
+ friend struct ClassDef;
+
+ private:
+ /* ClassRangeRecords, in sorted numerical start order */
+ DEFINE_ARRAY_TYPE (ClassRangeRecord, rangeRecord, rangeCount);
+
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+ // TODO: bsearch
+ for (unsigned int i = 0; i < rangeCount; i++) {
+ int classValue = rangeRecord[i].get_class (glyph_id);
+ if (classValue > 0)
+ return classValue;
+ }
+ return 0;
+ }
+
+ private:
+ USHORT classFormat; /* Format identifier--format = 2 */
+ USHORT rangeCount; /* Number of Number of ClassRangeRecords */
+ ClassRangeRecord rangeRecord[]; /* Array of glyph ranges--ordered by
+ * Start GlyphID */
+ };
+ ASSERT_SIZE (ClassDefFormat2, 4);
+
+ struct ClassDef {
+ DEFINE_NON_INSTANTIABLE(ClassDef);
+
+ unsigned int get_size (void) const {
+ switch (u.classFormat) {
+ case 1: return u.format1.get_size ();
+ case 2: return u.format2.get_size ();
+ default:return sizeof (u.classFormat);
+ }
+ }
+
+ hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+ switch (u.classFormat) {
+ case 1: return u.format1.get_class(glyph_id);
+ case 2: return u.format2.get_class(glyph_id);
+ default:return 0;
+ }
+ }
+
+ private:
+ union {
+ USHORT classFormat; /* Format identifier */
+ ClassDefFormat1 format1;
+ ClassDefFormat2 format2;
+ } u;
+ };
+ DEFINE_NULL (ClassDef, 2);
+
+ /*
+ * Device Tables
+ */
+
+ struct Device {
+ DEFINE_NON_INSTANTIABLE(Device);
+
+ unsigned int get_size (void) const {
+ int count = endSize - startSize + 1;
+ if (count < 0) count = 0;
+ switch (deltaFormat) {
+ case 1: return sizeof (Device) + sizeof (USHORT) * ((count+7)/8);
+ case 2: return sizeof (Device) + sizeof (USHORT) * ((count+3)/4);
+ case 3: return sizeof (Device) + sizeof (USHORT) * ((count+1)/2);
+ default:return sizeof (Device);
+ }
+ }
+
+ int get_delta (int ppem_size) const {
+ if (ppem_size >= startSize && ppem_size <= endSize &&
+ deltaFormat >= 1 && deltaFormat <= 3) {
+ int s = ppem_size - startSize;
+ int f = deltaFormat;
+
+ uint16_t byte = deltaValue[s >> (4 - f)];
+ uint16_t bits = byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f));
+ uint16_t mask = 0xFFFF >> (16 - (1 << f));
++
+ int delta = bits & mask;
+
+ if (delta >= ((mask + 1) >> 1))
+ delta -= mask + 1;
+
+ return delta;
+ }
+ return 0;
+ }
+
+ private:
+ USHORT startSize; /* Smallest size to correct--in ppem */
+ USHORT endSize; /* Largest size to correct--in ppem */
+ USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 */
+ USHORT deltaValue[]; /* Array of compressed data */
+ };
+ DEFINE_NULL_ASSERT_SIZE (Device, 6);
+
+ /*
+ * GSUB/GPOS Common
+ */
+
+ struct GSUBGPOS {
+ static const hb_tag_t GSUBTag = HB_TAG ('G','S','U','B');
+ static const hb_tag_t GPOSTag = HB_TAG ('G','P','O','S');
+
+ STATIC_DEFINE_GET_FOR_DATA (GSUBGPOS);
+ /* XXX check version here? */
+
+ DEFINE_TAG_LIST_INTERFACE (Script, script ); /* get_script_count (), get_script (i), get_script_tag (i) */
+ DEFINE_TAG_LIST_INTERFACE (Feature, feature); /* get_feature_count(), get_feature(i), get_feature_tag(i) */
+ DEFINE_LIST_INTERFACE (Lookup, lookup ); /* get_lookup_count (), get_lookup (i) */
+
+ // LONGTERMTODO bsearch
+ DEFINE_TAG_FIND_INTERFACE (Script, script ); /* find_script_index (), get_script_by_tag (tag) */
+ DEFINE_TAG_FIND_INTERFACE (Feature, feature); /* find_feature_index(), get_feature_by_tag(tag) */
+
+ private:
+ DEFINE_LIST_ARRAY(Script, script);
+ DEFINE_LIST_ARRAY(Feature, feature);
+ DEFINE_LIST_ARRAY(Lookup, lookup);
+
+ private:
+ Fixed_Version version; /* Version of the GSUB/GPOS table--initially set
+ * to 0x00010000 */
+ Offset scriptList; /* Offset to ScriptList table--from beginning of
+ * GSUB/GPOS table */
+ Offset featureList; /* Offset to FeatureList table--from beginning of
+ * GSUB/GPOS table */
+ Offset lookupList; /* Offset to LookupList table--from beginning of
+ * GSUB/GPOS table */
+ };
+ DEFINE_NULL_ASSERT_SIZE (GSUBGPOS, 10);
+
+ #endif /* HB_OT_LAYOUT_OPEN_PRIVATE_H */
--- /dev/null
-
+ /*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ * Copyright (C) 2007,2008 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
+ */
+
+ #define HB_OT_LAYOUT_CC
+
+ #include "hb-ot-layout.h"
+ #include "hb-ot-layout-private.h"
+
+ #include "hb-ot-layout-open-private.h"
+ #include "hb-ot-layout-gdef-private.h"
+ #include "hb-ot-layout-gsub-private.h"
+
+ /* XXX */
+ #include "harfbuzz-buffer-private.h"
+
+ #include <stdlib.h>
+ #include <string.h>
+
+
+ struct _hb_ot_layout_t {
+ const GDEF *gdef;
+ const GSUB *gsub;
+ const /*XXX*/GSUBGPOS *gpos;
+
+ struct {
+ unsigned char *klasses;
+ unsigned int len;
+ } new_gdef;
+
+ /* TODO add max-nesting-level here? */
+ };
+
+ hb_ot_layout_t *
+ hb_ot_layout_create (void)
+ {
+ hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+
+ layout->gdef = &NullGDEF;
+ layout->gsub = &NullGSUB;
+ layout->gpos = &/*XXX*/NullGSUBGPOS;
+
+ return layout;
+ }
+
+ hb_ot_layout_t *
+ hb_ot_layout_create_for_data (const char *font_data,
+ int face_index)
+ {
+ hb_ot_layout_t *layout;
+
+ if (HB_UNLIKELY (font_data == NULL))
+ return hb_ot_layout_create ();
+
+ layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+
+ const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data);
+ const OpenTypeFontFace &face = font.get_face (face_index);
+
+ layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table_by_tag (GDEF::Tag)));
+ layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table_by_tag (GSUB::Tag)));
+ layout->gpos = &/*XXX*/GSUBGPOS::get_for_data (font.get_table_data (face.get_table_by_tag (/*XXX*/GSUBGPOS::GPOSTag)));
+
+ return layout;
+ }
+
+ void
+ hb_ot_layout_destroy (hb_ot_layout_t *layout)
+ {
+ free (layout);
+ }
+
+ /*
+ * GDEF
+ */
+
+ hb_bool_t
+ hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout)
+ {
+ return layout->gdef->has_glyph_classes ();
+ }
+
+ HB_OT_LAYOUT_INTERNAL hb_bool_t
+ _hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout)
+ {
+ return layout->new_gdef.len > 0;
+ }
+
+ HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t
+ _hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout,
+ hb_codepoint_t glyph)
+ {
+ hb_ot_layout_class_t klass;
+
+ /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
+ * introduced without a version bump, so it may not be safe */
+ klass = layout->gdef->get_mark_attachment_type (glyph);
+ if (klass)
+ return klass << 8;
+
+ klass = layout->gdef->get_glyph_class (glyph);
+
+ if (!klass && glyph < layout->new_gdef.len)
+ klass = layout->new_gdef.klasses[glyph];
+
+ switch (klass) {
+ default:
+ case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
+ case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
+ case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
+ case GDEF::MarkGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+ case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
+ }
+ }
+
+ HB_OT_LAYOUT_INTERNAL hb_bool_t
+ _hb_ot_layout_check_glyph_properties (hb_ot_layout_t *layout,
+ HB_GlyphItem gitem,
+ hb_ot_layout_lookup_flags_t lookup_flags,
+ hb_ot_layout_glyph_properties_t *property)
+ {
+ hb_ot_layout_glyph_class_t basic_glyph_class;
+ hb_ot_layout_glyph_properties_t desired_attachment_class;
+
+ if (gitem->gproperties == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
+ {
+ gitem->gproperties = *property = _hb_ot_layout_get_glyph_properties (layout, gitem->gindex);
+ if (gitem->gproperties == HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
+ return false;
+ }
+
+ *property = gitem->gproperties;
+
+ /* If the glyph was found in the MarkAttachmentClass table,
+ * then that class value is the high byte of the result,
+ * otherwise the low byte contains the basic type of the glyph
+ * as defined by the GlyphClassDef table.
+ */
+ if (*property & LookupFlag::MarkAttachmentType)
+ basic_glyph_class = HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+ else
+ basic_glyph_class = (hb_ot_layout_glyph_class_t) *property;
+
+ /* Not covered, if, for example, basic_glyph_class
+ * is HB_GDEF_LIGATURE and lookup_flags includes LookupFlags::IgnoreLigatures
+ */
+ if (lookup_flags & basic_glyph_class)
+ return false;
+
+ /* The high byte of lookup_flags has the meaning
+ * "ignore marks of attachment type different than
+ * the attachment type specified."
+ */
+ desired_attachment_class = lookup_flags & LookupFlag::MarkAttachmentType;
+ if (desired_attachment_class)
+ {
+ if (basic_glyph_class == HB_OT_LAYOUT_GLYPH_CLASS_MARK &&
+ *property != desired_attachment_class )
+ return false;
+ }
+
+ return true;
+ }
+
+
+ hb_ot_layout_glyph_class_t
+ hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
+ hb_codepoint_t glyph)
+ {
+ hb_ot_layout_glyph_properties_t properties;
+ hb_ot_layout_class_t klass;
+
+ properties = _hb_ot_layout_get_glyph_properties (layout, glyph);
+
+ if (properties & 0xFF00)
+ return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+
+ return (hb_ot_layout_glyph_class_t) properties;
+ }
+
+ void
+ hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout,
+ hb_codepoint_t glyph,
+ hb_ot_layout_glyph_class_t klass)
+ {
+ /* TODO optimize this, similar to old harfbuzz code for example */
+
+ hb_ot_layout_class_t gdef_klass;
+ int len = layout->new_gdef.len;
+
+ if (glyph >= len) {
+ int new_len;
+ unsigned char *new_klasses;
+
+ new_len = len == 0 ? 120 : 2 * len;
+ if (new_len > 65535)
+ new_len = 65535;
+ new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
+
+ if (G_UNLIKELY (!new_klasses))
+ return;
++
+ memset (new_klasses + len, 0, new_len - len);
+
+ layout->new_gdef.klasses = new_klasses;
+ layout->new_gdef.len = new_len;
+ }
+
+ switch (klass) {
+ default:
+ case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break;
+ case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break;
+ case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break;
+ case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break;
+ case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break;
+ }
+
+ layout->new_gdef.klasses[glyph] = gdef_klass;
+ return;
+ }
+
+ void
+ hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
+ uint16_t num_total_glyphs,
+ hb_codepoint_t *glyphs,
+ unsigned char *klasses,
+ uint16_t count)
+ {
+ int i;
+
+ if (G_UNLIKELY (!count || !glyphs || !klasses))
+ return;
+
+ if (layout->new_gdef.len == 0) {
+ layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
+ layout->new_gdef.len = count;
+ }
+
+ for (i = 0; i < count; i++)
+ hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
+ }
+
+ /*
+ * GSUB/GPOS
+ */
+
+ static const GSUBGPOS&
+ get_gsubgpos_table (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type)
+ {
+ switch (table_type) {
+ case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub);
+ case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos);
+ default: return NullGSUBGPOS;
+ }
+ }
+
+
+ unsigned int
+ hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ return g.get_script_count ();
+ }
+
+ hb_tag_t
+ hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ return g.get_script_tag (script_index);
+ }
+
+ hb_bool_t
+ hb_ot_layout_table_find_script (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ hb_tag_t script_tag,
+ unsigned int *script_index)
+ {
+ ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ if (g.find_script_index (script_tag, script_index))
+ return TRUE;
+
+ /* try finding 'DFLT' */
+ if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
+ return FALSE;
+
+ /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+ if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
+ return FALSE;
+
+ if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+ return FALSE;
+ }
+
+ unsigned int
+ hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ return g.get_feature_count ();
+ }
+
+ hb_tag_t
+ hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int feature_index)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ return g.get_feature_tag (feature_index);
+ }
+
+ hb_bool_t
+ hb_ot_layout_table_find_feature (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ hb_tag_t feature_tag,
+ unsigned int *feature_index)
+ {
+ ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ if (g.find_feature_index (feature_tag, feature_index))
+ return TRUE;
+
+ if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+ return FALSE;
+ }
+
+ unsigned int
+ hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+ return g.get_lookup_count ();
+ }
+
+
+ unsigned int
+ hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index)
+ {
+ const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+ return s.get_lang_sys_count ();
+ }
+
+ hb_tag_t
+ hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index)
+ {
+ const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+ return s.get_lang_sys_tag (language_index);
+ }
+
+ hb_bool_t
+ hb_ot_layout_script_find_language (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ hb_tag_t language_tag,
+ unsigned int *language_index)
+ {
+ ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+ const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+ if (s.find_lang_sys_index (language_tag, language_index))
+ return TRUE;
+
+ /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+ if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
+ return FALSE;
+
+ if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+ return FALSE;
+ }
+
+ hb_bool_t
+ hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index)
+ {
+ const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
+
+ if (feature_index) *feature_index = l.get_required_feature_index ();
+
+ return l.has_required_feature ();
+ }
+
+ unsigned int
+ hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index)
+ {
+ const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
+
+ return l.get_feature_count ();
+ }
+
+ unsigned int
+ hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int num_feature)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+ const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+ return l.get_feature_index (num_feature);
+ }
+
+ hb_tag_t
+ hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int num_feature)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+ const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+ unsigned int feature_index = l.get_feature_index (num_feature);
+
+ return g.get_feature_tag (feature_index);
+ }
+
+
+ hb_bool_t
+ hb_ot_layout_language_find_feature (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int script_index,
+ unsigned int language_index,
+ hb_tag_t feature_tag,
+ unsigned int *feature_index)
+ {
+ ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+ const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+ unsigned int i;
+
+ for (i = 0; i < l.get_feature_count (); i++) {
+ unsigned int f_index = l.get_feature_index (i);
+
+ if (feature_tag == g.get_feature_tag (f_index)) {
+ if (feature_index) *feature_index = f_index;
+ return TRUE;
+ }
+ }
+
+ if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+ return FALSE;
+ }
+
+ unsigned int
+ hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int feature_index)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+ const Feature &f = g.get_feature (feature_index);
+
+ return f.get_lookup_count ();
+ }
+
+ unsigned int
+ hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout,
+ hb_ot_layout_table_type_t table_type,
+ unsigned int feature_index,
+ unsigned int num_lookup)
+ {
+ const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+ const Feature &f = g.get_feature (feature_index);
+
+ return f.get_lookup_index (num_lookup);
+ }
+
+ /*
+ * GSUB
+ */
+
+ hb_bool_t
+ hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int lookup_index,
+ hb_ot_layout_feature_mask_t mask)
+ {
+ const GSUB &gsub = *(layout->gsub);
+ const SubstLookup &l = gsub.get_lookup (lookup_index);
+ unsigned int lookup_type = l.get_type ();
+ unsigned int nesting_level_left = HB_OT_LAYOUT_MAX_NESTING_LEVEL;
+ unsigned int context_length = NO_CONTEXT;
+ bool handled, ret = false;
+
+ if (!l.is_reverse ()) {
+
+ /* in/out forward substitution */
+ _hb_buffer_clear_output (buffer);
+ buffer->in_pos = 0;
+ while (buffer->in_pos < buffer->in_length) {
+
+ if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
+ l.substitute (layout, buffer, context_length, nesting_level_left))
+ ret = true;
+ else
+ _hb_buffer_copy_output_glyph (buffer);
+
+ }
+ _hb_buffer_swap (buffer);
+
+ } else {
+
+ /* in-place backward substitution */
+ buffer->in_pos = buffer->in_length - 1;
+ do {
+
+ if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
+ l.substitute (layout, buffer, context_length, nesting_level_left))
+ ret = true;
+ else
+ buffer->in_pos--;
+
+ } while (buffer->in_pos);
+
+ }
+
+ return ret;
+ }
--- /dev/null
-
+ /*
+ * Copyright (C) 2007,2008 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
+ */
+
+ #define HB_OT_LAYOUT_CC
+ #include "hb-ot-layout-open-private.h"
+ #include "hb-ot-layout-gdef-private.h"
+ #include "hb-ot-layout-gsub-private.h"
+
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int
+ main (int argc, char **argv)
+ {
+ if (argc != 2) {
+ fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+ exit (1);
+ }
+
+ GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL);
+ const char *font_data = g_mapped_file_get_contents (mf);
+ int len = g_mapped_file_get_length (mf);
-
++
+ printf ("Opened font file %s: %d bytes long\n", argv[1], len);
++
+ const OpenTypeFontFile &ot = OpenTypeFontFile::get_for_data (font_data);
+
+ switch (ot.get_tag()) {
+ case OpenTypeFontFile::TrueTypeTag:
+ printf ("OpenType font with TrueType outlines\n");
+ break;
+ case OpenTypeFontFile::CFFTag:
+ printf ("OpenType font with CFF (Type1) outlines\n");
+ break;
+ case OpenTypeFontFile::TTCTag:
+ printf ("TrueType Collection of OpenType fonts\n");
+ break;
+ default:
+ printf ("Unknown font format\n");
+ break;
+ }
+
+ int num_fonts = ot.get_face_count ();
+ printf ("%d font(s) found in file\n", num_fonts);
+ for (int n_font = 0; n_font < num_fonts; n_font++) {
+ const OpenTypeFontFace &font = ot.get_face (n_font);
+ printf ("Font %d of %d:\n", n_font, num_fonts);
+
+ int num_tables = font.get_table_count ();
+ printf (" %d table(s) found in font\n", num_tables);
+ for (int n_table = 0; n_table < num_tables; n_table++) {
+ const OpenTypeTable &table = font.get_table (n_table);
+ printf (" Table %2d of %2d: %.4s (0x%08lx+0x%08lx)\n", n_table, num_tables,
+ (const char *)table.get_tag(), table.get_offset(), table.get_length());
+
+ switch (table.get_tag ()) {
+
+ case GSUBGPOS::GSUBTag:
+ case GSUBGPOS::GPOSTag:
+ {
+
+ const GSUBGPOS &g = GSUBGPOS::get_for_data (ot.get_table_data (table));
+
+ int num_scripts = g.get_script_count ();
+ printf (" %d script(s) found in table\n", num_scripts);
+ for (int n_script = 0; n_script < num_scripts; n_script++) {
+ const Script &script = g.get_script (n_script);
+ printf (" Script %2d of %2d: %.4s\n", n_script, num_scripts,
+ (const char *)g.get_script_tag(n_script));
+
+ if (!script.has_default_lang_sys())
+ printf (" No default language system\n");
+ int num_langsys = script.get_lang_sys_count ();
+ printf (" %d language system(s) found in script\n", num_langsys);
+ for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) {
+ const LangSys &langsys = n_langsys == -1
+ ? script.get_default_lang_sys ()
+ : script.get_lang_sys (n_langsys);
+ printf (n_langsys == -1
+ ? " Default Language System\n"
+ : " Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
+ (const char *)script.get_lang_sys_tag (n_langsys));
+ if (langsys.get_required_feature_index () == NO_INDEX)
+ printf (" No required feature\n");
+
+ int num_features = langsys.get_feature_count ();
+ printf (" %d feature(s) found in language system\n", num_features);
+ for (int n_feature = 0; n_feature < num_features; n_feature++) {
+ unsigned int feature_index = langsys.get_feature_index (n_feature);
+ printf (" Feature index %2d of %2d: %d\n", n_feature, num_features,
+ langsys.get_feature_index (n_feature));
+ }
+ }
+ }
+
+ int num_features = g.get_feature_count ();
+ printf (" %d feature(s) found in table\n", num_features);
+ for (int n_feature = 0; n_feature < num_features; n_feature++) {
+ const Feature &feature = g.get_feature (n_feature);
+ printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
+ (const char *)g.get_feature_tag(n_feature),
+ feature.get_lookup_count());
+
+ int num_lookups = feature.get_lookup_count ();
+ printf (" %d lookup(s) found in feature\n", num_lookups);
+ for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+ unsigned int lookup_index = feature.get_lookup_index (n_lookup);
+ printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
+ feature.get_lookup_index (n_lookup));
+ }
+ }
+
+ int num_lookups = g.get_lookup_count ();
+ printf (" %d lookup(s) found in table\n", num_lookups);
+ for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+ const Lookup &lookup = g.get_lookup (n_lookup);
+ printf (" Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups,
+ lookup.get_type(), lookup.get_flag());
+ }
+
+ }
+ break;
+
+ case GDEF::Tag:
+ {
+
+ const GDEF &gdef = GDEF::get_for_data (ot.get_table_data (table));
+
+ printf (" Has %sglyph classes\n",
+ gdef.has_glyph_classes () ? "" : "no ");
+ printf (" Has %smark attachment types\n",
+ gdef.has_mark_attachment_types () ? "" : "no ");
+ printf (" Has %sattach list\n",
+ gdef.has_attach_list () ? "" : "no ");
+ printf (" Has %slig caret list\n",
+ gdef.has_lig_caret_list () ? "" : "no ");
+
+ for (int glyph = 0; glyph < 1; glyph++)
+ printf (" glyph %d has class %d and mark attachment type %d\n",
+ glyph,
+ gdef.get_glyph_class (glyph),
+ gdef.get_mark_attachment_type (glyph));
+
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+ }