From a7e096c5de3ec5319bf9333c9ace0732d97c52c3 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Sun, 29 Feb 2004 15:44:50 +0000 Subject: [PATCH] Rework opentype interfaces and other changes to make GPOS work for Arabic. Sun Feb 29 09:25:13 2004 Owen Taylor Rework opentype interfaces and other changes to make GPOS work for Arabic. (Most of #117282, #121060) * pango/opentype/otlbuffer.[ch]: OTL_Buffer that acts as a replacement for the separate GSUB and GPOS string structures and hides many of the internal details. * pango/opentype/ftxgsub.[ch] pango/opentype/ftxgpos.[ch]: Adapt to OTL_Buffer. * pango/opentype/ftxgpos.c: Redo handling of cursive chains so that it actually works. * pango/pango-ot.h pango/opentype/pango-ot-buffer.c: Pango wrapper around OTL_Buffer. * pango/pango-ot.h pango/pango-ot-ruleset.c pango/pango-ot-buffer.c: Split pango_ot_ruleset_shape() into pango_ot_ruleset_substitute(), pango_ot_ruleset_position(), make them act on PangoOTBuffer, add a separate pango_ot_buffer_output() which does the default positioning and writes to a PangoGlyphString. * modules/arabic/arabic-fc.c modules/indic/indic-fc.c modules/indic/mprefixups.[ch]: Adapt to new OpenType interfaces; add GPOS features for Arabic. * pango/opentype/pango-ot-info.c: Don't derive class information from Unicode properties for Arabic presentation forms, let the shaping process derive the properties. --- src/Makefile.am | 3 + src/ftxgdef.c | 4 +- src/ftxgpos.c | 573 +++++++++++++------------------- src/ftxgpos.h | 23 +- src/ftxgsub.c | 719 ++++++++++------------------------------- src/ftxgsub.h | 40 +-- src/ftxopen.h | 1 + src/otlbuffer.c | 213 ++++++++++++ src/otlbuffer.h | 97 ++++++ src/ottest.c | 2 + src/pango-ot-buffer.c | 265 +++++++++++++++ src/pango-ot-info.c | 27 +- src/pango-ot-private.h | 8 + src/pango-ot-ruleset.c | 166 +++------- 14 files changed, 1048 insertions(+), 1093 deletions(-) create mode 100644 src/otlbuffer.c create mode 100644 src/otlbuffer.h create mode 100644 src/pango-ot-buffer.c diff --git a/src/Makefile.am b/src/Makefile.am index 969b2dbcc..4634b8ca7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,9 @@ libpango_ot_la_SOURCES = \ ftxgpos.h \ ftxgsub.c \ ftxgsub.h \ + otlbuffer.c \ + otlbuffer.h \ + pango-ot-buffer.c \ pango-ot-info.c \ pango-ot-private.h \ pango-ot-ruleset.c diff --git a/src/ftxgdef.c b/src/ftxgdef.c index 36146970d..9077490b2 100644 --- a/src/ftxgdef.c +++ b/src/ftxgdef.c @@ -761,7 +761,7 @@ if ( glyphID < gcrr[index].Start ) { - array_index = 0; + array_index = index; if ( index == 0 ) glyph_index = glyphID; else @@ -1129,7 +1129,7 @@ if ( glyphID < gcrr[index].Start ) { - array_index = 0; + array_index = index; if ( index == 0 ) glyph_index = glyphID; else diff --git a/src/ftxgpos.c b/src/ftxgpos.c index 8d9a7d483..8bbddcddb 100644 --- a/src/ftxgpos.c +++ b/src/ftxgpos.c @@ -42,8 +42,6 @@ FT_UShort load_flags; /* how the glyph should be loaded */ FT_Bool r2l; - FT_UShort first; /* the first glyph in a chain of - cursive connections */ FT_UShort last; /* the last valid glyph -- used with cursive positioning */ FT_Pos anchor_x; /* the coordinates of the anchor point */ @@ -55,13 +53,19 @@ static FT_Error Do_Glyph_Lookup( GPOS_Instance* gpi, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort context_length, int nesting_level ); - /* the client application must replace this with something more +#define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex) +#define IN_CURGLYPH( pos ) (buffer->in_string[(pos) + buffer->in_pos].gindex) +#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)]) + +/* the client application must replace this with something more meaningful if multiple master fonts are to be supported. */ static FT_Error default_mmfunc( FT_Face face, @@ -73,100 +77,6 @@ } -#if 0 -#define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' ) - - /********************** - * Extension Functions - **********************/ - - static FT_Error GPOS_Create( void* ext, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; - FT_Long table; - - - /* by convention */ - - if ( !gpos ) - return TT_Err_Ok; - - /* a null offset indicates that there is no GPOS table */ - - gpos->offset = 0; - - /* we store the start offset and the size of the subtable */ - - table = face->lookup_table ( face, TTAG_GPOS ); - if ( table < 0 ) - return TT_Err_Ok; /* The table is optional */ - - if ( FILE_Seek( face->dirTables[table].Offset ) || - ACCESS_Frame( 4L ) ) - return error; - - gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ - gpos->Version = GET_ULong(); - - FORGET_Frame(); - - /* a default mmfunc() handler which just returns an error */ - - gpos->mmfunc = default_mmfunc; - - /* the default glyph function is TT_Load_Glyph() */ - - gpos->gfunc = FT_Load_Glyph; - - gpos->loaded = FALSE; - - return TT_Err_Ok; - } - - - static FT_Error GPOS_Destroy( void* ext, - PFace face ) - { - TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; - - - /* by convention */ - - if ( !gpos ) - return TT_Err_Ok; - - if ( gpos->loaded ) - { - Free_LookupList( &gpos->LookupList, GPOS ); - Free_FeatureList( &gpos->FeatureList ); - Free_ScriptList( &gpos->ScriptList ); - } - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_Init_GPOS_Extension( TT_Engine engine ) - { - PEngine_Instance _engine = HANDLE_Engine( engine ); - - - if ( !_engine ) - return TT_Err_Invalid_Engine; - - return TT_Register_Extension( _engine, - GPOS_ID, - sizeof ( TTO_GPOSHeader ), - GPOS_Create, - GPOS_Destroy ); - } -#endif - EXPORT_FUNC FT_Error TT_Load_GPOS_Table( FT_Face face, TTO_GPOSHeader** retptr, @@ -584,7 +494,7 @@ static FT_Error Get_ValueRecord( GPOS_Instance* gpi, TTO_ValueRecord* vr, FT_UShort format, - TTO_GPOS_Data* gd ) + OTL_Position gd ) { FT_Pos value; FT_Short pixel_value; @@ -1123,8 +1033,7 @@ static FT_Error Lookup_SinglePos( GPOS_Instance* gpi, TTO_SinglePos* sp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -1136,10 +1045,10 @@ if ( context_length != 0xFFFF && context_length < 1 ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &sp->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &sp->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -1147,7 +1056,7 @@ { case 1: error = Get_ValueRecord( gpi, &sp->spf.spf1.Value, - sp->ValueFormat, &out[in->pos] ); + sp->ValueFormat, POSITION( buffer->in_pos ) ); if ( error ) return error; break; @@ -1156,7 +1065,7 @@ if ( index >= sp->spf.spf2.ValueCount ) return TTO_Err_Invalid_GPOS_SubTable; error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index], - sp->ValueFormat, &out[in->pos] ); + sp->ValueFormat, POSITION( buffer->in_pos ) ); if ( error ) return error; break; @@ -1165,7 +1074,7 @@ return TTO_Err_Invalid_GPOS_SubTable; } - (in->pos)++; + (buffer->in_pos)++; return TT_Err_Ok; } @@ -1606,8 +1515,7 @@ static FT_Error Lookup_PairPos1( GPOS_Instance* gpi, TTO_PairPosFormat1* ppf1, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort first_pos, FT_UShort index, FT_UShort format1, @@ -1626,7 +1534,7 @@ if ( !pvr ) return TTO_Err_Invalid_GPOS_SubTable; - glyph2 = in->string[in->pos]; + glyph2 = IN_CURGLYPH( 0 ); for ( numpvr = ppf1->PairSet[index].PairValueCount; numpvr; @@ -1635,11 +1543,11 @@ if ( glyph2 == pvr->SecondGlyph ) { error = Get_ValueRecord( gpi, &pvr->Value1, format1, - &out[first_pos] ); + POSITION( first_pos ) ); if ( error ) return error; return Get_ValueRecord( gpi, &pvr->Value2, format2, - &out[in->pos] ); + POSITION( buffer->in_pos ) ); } } @@ -1649,8 +1557,7 @@ static FT_Error Lookup_PairPos2( GPOS_Instance* gpi, TTO_PairPosFormat2* ppf2, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort first_pos, FT_UShort format1, FT_UShort format2 ) @@ -1662,11 +1569,11 @@ TTO_Class2Record* c2r; - error = Get_Class( &ppf2->ClassDef1, in->string[first_pos], + error = Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ), &cl1, NULL ); if ( error && error != TTO_Err_Not_Covered ) return error; - error = Get_Class( &ppf2->ClassDef2, in->string[in->pos], + error = Get_Class( &ppf2->ClassDef2, IN_CURGLYPH( 0 ), &cl2, NULL ); if ( error && error != TTO_Err_Not_Covered ) return error; @@ -1676,17 +1583,16 @@ return TTO_Err_Invalid_GPOS_SubTable; c2r = &c1r->Class2Record[cl2]; - error = Get_ValueRecord( gpi, &c2r->Value1, format1, &out[first_pos] ); + error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) ); if ( error ) return error; - return Get_ValueRecord( gpi, &c2r->Value2, format2, &out[in->pos] ); + return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) ); } static FT_Error Lookup_PairPos( GPOS_Instance* gpi, TTO_PairPos* pp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -1695,32 +1601,32 @@ TTO_GPOSHeader* gpos = gpi->gpos; - if ( in->pos >= in->length - 1 ) + if ( buffer->in_pos >= buffer->in_length - 1 ) return TTO_Err_Not_Covered; /* Not enough glyphs in stream */ if ( context_length != 0xFFFF && context_length < 2 ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &pp->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &pp->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; /* second glyph */ - first_pos = in->pos; - (in->pos)++; + first_pos = buffer->in_pos; + (buffer->in_pos)++; - while ( CHECK_Property( gpos->gdef, in->string[in->pos], + while ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos < in->length ) - (in->pos)++; + if ( buffer->in_pos < buffer->in_length ) + (buffer->in_pos)++; else break; } @@ -1728,13 +1634,13 @@ switch ( pp->PosFormat ) { case 1: - error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, in, out, + 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, in, out, first_pos, + error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos, pp->ValueFormat1, pp->ValueFormat2 ); break; @@ -1745,7 +1651,7 @@ /* adjusting the `next' glyph */ if ( pp->ValueFormat2 ) - (in->pos)++; + (buffer->in_pos)++; return error; } @@ -1893,8 +1799,7 @@ static FT_Error Lookup_CursivePos( GPOS_Instance* gpi, TTO_CursivePos* cp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -1916,7 +1821,7 @@ /* Glyphs not having the right GDEF properties will be ignored, i.e., gpi->last won't be reset (contrary to user defined properties). */ - if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; /* We don't handle mark glyphs here. According to Andrei, this isn't @@ -1928,7 +1833,7 @@ return TTO_Err_Not_Covered; } - error = Coverage_Index( &cp->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &cp->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) { gpi->last = 0xFFFF; @@ -2063,7 +1968,7 @@ /* Get_Anchor() returns TTO_Err_Not_Covered if there is no anchor table. */ - error = Get_Anchor( gpi, &eer->EntryAnchor, in->string[in->pos], + error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH( 0 ), &entry_x, &entry_y ); if ( error == TTO_Err_Not_Covered ) goto end; @@ -2072,34 +1977,41 @@ if ( gpi->r2l ) { - out[in->pos].x_advance = entry_x - gpi->anchor_x; - out[in->pos].new_advance = TRUE; + POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x; + POSITION( buffer->in_pos )->new_advance = TRUE; } else { - out[gpi->last].x_advance = gpi->anchor_x - entry_x; - out[gpi->last].new_advance = TRUE; + POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x; + POSITION( gpi->last )->new_advance = TRUE; } - out[in->pos].y_pos = gpi->anchor_y - entry_y + out[gpi->last].y_pos; + if ( flags & 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->string[in->pos], + error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH( 0 ), &exit_x, &exit_y ); if ( error == TTO_Err_Not_Covered ) gpi->last = 0xFFFF; else { - if ( gpi->first == 0xFFFF ) - gpi->first = in->pos; - gpi->last = in->pos; + gpi->last = buffer->in_pos; gpi->anchor_x = exit_x; gpi->anchor_y = exit_y; } if ( error ) return error; - (in->pos)++; + (buffer->in_pos)++; return TT_Err_Ok; } @@ -2312,8 +2224,7 @@ static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi, TTO_MarkBasePos* mbp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -2328,7 +2239,7 @@ TTO_Anchor* mark_anchor; TTO_Anchor* base_anchor; - TTO_GPOS_Data* o; + OTL_Position o; if ( context_length != 0xFFFF && context_length < 1 ) @@ -2337,11 +2248,11 @@ if ( flags & IGNORE_BASE_GLYPHS ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, in->string[in->pos], + if ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &mbp->MarkCoverage, in->string[in->pos], + error = Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH( 0 ), &mark_index ); if ( error ) return error; @@ -2349,11 +2260,11 @@ /* now we search backwards for a non-mark glyph */ i = 1; - j = in->pos - 1; + j = buffer->in_pos - 1; - while ( i <= in->pos ) + while ( i <= buffer->in_pos ) { - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j], + error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), &property ); if ( error ) return error; @@ -2371,10 +2282,10 @@ return TTO_Err_Not_Covered; #endif - if ( i > in->pos ) + if ( i > buffer->in_pos ) return TTO_Err_Not_Covered; - error = Coverage_Index( &mbp->BaseCoverage, in->string[j], + error = Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ), &base_index ); if ( error ) return error; @@ -2398,19 +2309,19 @@ br = &ba->BaseRecord[base_index]; base_anchor = &br->BaseAnchor[class]; - error = Get_Anchor( gpi, mark_anchor, in->string[in->pos], + error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH( 0 ), &x_mark_value, &y_mark_value ); if ( error ) return error; - error = Get_Anchor( gpi, base_anchor, in->string[j], + 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 = &out[in->pos]; + o = POSITION( buffer->in_pos ); o->x_pos = x_base_value - x_mark_value; o->y_pos = y_base_value - y_mark_value; @@ -2418,7 +2329,7 @@ o->y_advance = 0; o->back = i; - (in->pos)++; + (buffer->in_pos)++; return TT_Err_Ok; } @@ -2720,8 +2631,7 @@ static FT_Error Lookup_MarkLigPos( GPOS_Instance* gpi, TTO_MarkLigPos* mlp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -2739,7 +2649,7 @@ TTO_Anchor* mark_anchor; TTO_Anchor* lig_anchor; - TTO_GPOS_Data* o; + OTL_Position o; if ( context_length != 0xFFFF && context_length < 1 ) @@ -2748,7 +2658,7 @@ if ( flags & IGNORE_LIGATURES ) return TTO_Err_Not_Covered; - mark_glyph = in->string[in->pos]; + mark_glyph = IN_CURGLYPH( 0 ); if ( CHECK_Property( gpos->gdef, mark_glyph, flags, &property ) ) return error; @@ -2760,11 +2670,11 @@ /* now we search backwards for a non-mark glyph */ i = 1; - j = in->pos - 1; + j = buffer->in_pos - 1; - while ( i <= in->pos ) + while ( i <= buffer->in_pos ) { - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j], + error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), &property ); if ( error ) return error; @@ -2783,10 +2693,10 @@ return TTO_Err_Not_Covered; #endif - if ( i > in->pos ) + if ( i > buffer->in_pos ) return TTO_Err_Not_Covered; - error = Coverage_Index( &mlp->LigatureCoverage, in->string[j], + error = Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ), &lig_index ); if ( error ) return error; @@ -2814,10 +2724,9 @@ can directly use the component index. If not, we attach the mark glyph to the last component of the ligature. */ - if ( in->ligIDs && in->components && - in->ligIDs[j] == in->ligIDs[in->pos] ) + if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) ) { - comp_index = in->components[in->pos]; + comp_index = IN_COMPONENT( buffer->in_pos ); if ( comp_index >= lat->ComponentCount ) return TTO_Err_Not_Covered; } @@ -2827,18 +2736,18 @@ cr = &lat->ComponentRecord[comp_index]; lig_anchor = &cr->LigatureAnchor[class]; - error = Get_Anchor( gpi, mark_anchor, in->string[in->pos], + error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH( 0 ), &x_mark_value, &y_mark_value ); if ( error ) return error; - error = Get_Anchor( gpi, lig_anchor, in->string[j], + 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 = &out[in->pos]; + o = POSITION( buffer->in_pos ); o->x_pos = x_lig_value - x_mark_value; o->y_pos = y_lig_value - y_mark_value; @@ -2846,7 +2755,7 @@ o->y_advance = 0; o->back = i; - (in->pos)++; + (buffer->in_pos)++; return TT_Err_Ok; } @@ -3061,8 +2970,7 @@ static FT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, TTO_MarkMarkPos* mmp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length ) { @@ -3078,7 +2986,7 @@ TTO_Anchor* mark1_anchor; TTO_Anchor* mark2_anchor; - TTO_GPOS_Data* o; + OTL_Position o; if ( context_length != 0xFFFF && context_length < 1 ) @@ -3087,11 +2995,11 @@ if ( flags & IGNORE_MARKS ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, in->string[in->pos], + if ( CHECK_Property( gpos->gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &mmp->Mark1Coverage, in->string[in->pos], + error = Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH( 0 ), &mark1_index ); if ( error ) return error; @@ -3099,11 +3007,11 @@ /* now we check the preceding glyph whether it is a suitable mark glyph */ - if ( in->pos == 0 ) + if ( buffer->in_pos == 0 ) return TTO_Err_Not_Covered; - j = in->pos - 1; - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j], + j = buffer->in_pos - 1; + error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), &property ); if ( error ) return error; @@ -3119,7 +3027,7 @@ return TTO_Err_Not_Covered; } - error = Coverage_Index( &mmp->Mark2Coverage, in->string[j], + error = Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ), &mark2_index ); if ( error ) return error; @@ -3143,18 +3051,18 @@ m2r = &ma2->Mark2Record[mark2_index]; mark2_anchor = &m2r->Mark2Anchor[class]; - error = Get_Anchor( gpi, mark1_anchor, in->string[in->pos], + error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH( 0 ), &x_mark1_value, &y_mark1_value ); if ( error ) return error; - error = Get_Anchor( gpi, mark2_anchor, in->string[j], + 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 = &out[in->pos]; + o = POSITION( buffer->in_pos ); o->x_pos = x_mark2_value - x_mark1_value; o->y_pos = y_mark2_value - y_mark1_value; @@ -3162,7 +3070,7 @@ o->y_advance = 0; o->back = 1; - (in->pos)++; + (buffer->in_pos)++; return TT_Err_Ok; } @@ -3176,8 +3084,7 @@ FT_UShort GlyphCount, FT_UShort PosCount, TTO_PosLookupRecord* pos, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, int nesting_level ) { FT_Error error; @@ -3190,11 +3097,11 @@ { if ( PosCount && i == pos->SequenceIndex ) { - old_pos = in->pos; + old_pos = buffer->in_pos; /* Do a positioning */ - error = Do_Glyph_Lookup( gpi, pos->LookupListIndex, in, out, + error = Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer, GlyphCount, nesting_level ); if ( error ) @@ -3202,12 +3109,12 @@ pos++; PosCount--; - i += in->pos - old_pos; + i += buffer->in_pos - old_pos; } else { i++; - (in->pos)++; + (buffer->in_pos)++; } } @@ -3928,8 +3835,7 @@ static FT_Error Lookup_ContextPos1( GPOS_Instance* gpi, TTO_ContextPosFormat1* cpf1, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -3937,7 +3843,6 @@ FT_UShort index, property; FT_UShort i, j, k, numpr; FT_Error error; - FT_UShort* s_in; TTO_GPOSHeader* gpos = gpi->gpos; TTO_PosRule* pr; @@ -3946,10 +3851,10 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &cpf1->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &cpf1->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -3961,32 +3866,30 @@ if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount ) continue; - if ( in->pos + pr[k].GlyphCount > in->length ) + if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length ) continue; /* context is too long */ - s_in = &in->string[in->pos]; - for ( i = 1, j = 1; i < pr[k].GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != pr[k].Input[i - 1] ) + if ( IN_CURGLYPH( j ) != pr[k].Input[i - 1] ) break; } if ( i == pr[k].GlyphCount ) return Do_ContextPos( gpi, pr[k].GlyphCount, pr[k].PosCount, pr[k].PosLookupRecord, - in, out, + buffer, nesting_level ); } @@ -3996,8 +3899,7 @@ static FT_Error Lookup_ContextPos2( GPOS_Instance* gpi, TTO_ContextPosFormat2* cpf2, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -4008,7 +3910,6 @@ FT_UShort i, j, k, known_classes; FT_UShort* classes; - FT_UShort* s_in; FT_UShort* cl; TTO_GPOSHeader* gpos = gpi->gpos; @@ -4019,21 +3920,21 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), 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 = Coverage_Index( &cpf2->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &cpf2->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) ) return error; - error = Get_Class( &cpf2->ClassDef, in->string[in->pos], + error = Get_Class( &cpf2->ClassDef, IN_CURGLYPH( 0 ), &classes[0], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End; @@ -4053,22 +3954,21 @@ if ( context_length != 0xFFFF && context_length < pr->GlyphCount ) continue; - if ( in->pos + pr->GlyphCount > in->length ) + if ( buffer->in_pos + pr->GlyphCount > buffer->in_length ) continue; /* context is too long */ - s_in = &in->string[in->pos]; cl = pr->Class; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < pr->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else break; @@ -4078,7 +3978,7 @@ { /* Keeps us from having to do this for each rule */ - error = Get_Class( &cpf2->ClassDef, s_in[j], &classes[i], NULL ); + error = Get_Class( &cpf2->ClassDef, IN_CURGLYPH( j ), &classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End; known_classes = i; @@ -4092,7 +3992,7 @@ { error = Do_ContextPos( gpi, pr->GlyphCount, pr->PosCount, pr->PosLookupRecord, - in, out, + buffer, nesting_level ); goto End; } @@ -4108,15 +4008,13 @@ static FT_Error Lookup_ContextPos3( GPOS_Instance* gpi, TTO_ContextPosFormat3* cpf3, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) { FT_Error error; FT_UShort index, i, j, property; - FT_UShort* s_in; TTO_GPOSHeader* gpos = gpi->gpos; TTO_Coverage* c; @@ -4125,47 +4023,45 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) return TTO_Err_Not_Covered; - if ( in->pos + cpf3->GlyphCount > in->length ) + if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length ) return TTO_Err_Not_Covered; /* context is too long */ - s_in = &in->string[in->pos]; c = cpf3->Coverage; for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &c[i], s_in[j], &index ); + error = Coverage_Index( &c[i], IN_CURGLYPH( j ), &index ); if ( error ) return error; } return Do_ContextPos( gpi, cpf3->GlyphCount, cpf3->PosCount, cpf3->PosLookupRecord, - in, out, + buffer, nesting_level ); } static FT_Error Lookup_ContextPos( GPOS_Instance* gpi, TTO_ContextPos* cp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -4173,15 +4069,15 @@ switch ( cp->PosFormat ) { case 1: - return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, in, out, + return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer, flags, context_length, nesting_level ); case 2: - return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, in, out, + return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer, flags, context_length, nesting_level ); case 3: - return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, in, out, + return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer, flags, context_length, nesting_level ); default: @@ -5210,8 +5106,7 @@ static FT_Error Lookup_ChainContextPos1( GPOS_Instance* gpi, TTO_ChainContextPosFormat1* ccpf1, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -5220,7 +5115,6 @@ FT_UShort i, j, k, num_cpr, curr_pos; FT_UShort bgc, igc, lgc; FT_Error error; - FT_UShort* s_in; TTO_GPOSHeader* gpos = gpi->gpos; TTO_ChainPosRule* cpr; @@ -5230,10 +5124,10 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &ccpf1->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -5252,7 +5146,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) continue; if ( bgc ) @@ -5261,11 +5155,10 @@ we search backwards for matches in the backtrack glyph array */ curr_pos = 0; - s_in = &in->string[curr_pos]; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; @@ -5286,7 +5179,7 @@ Backtrack offsets - 3 2 1 0 Lookahead offsets - 0 1 2 3 */ - if ( s_in[j] != curr_cpr.Backtrack[i] ) + if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) break; } @@ -5294,25 +5187,24 @@ continue; } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != curr_cpr.Input[i - 1] ) + if ( IN_GLYPH( curr_pos + j ) != curr_cpr.Input[i - 1] ) break; } @@ -5323,22 +5215,21 @@ last context glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != curr_cpr.Lookahead[i] ) + if ( IN_GLYPH( curr_pos + j ) != curr_cpr.Lookahead[i] ) break; } @@ -5346,7 +5237,7 @@ return Do_ContextPos( gpi, igc, curr_cpr.PosCount, curr_cpr.PosLookupRecord, - in, out, + buffer, nesting_level ); } @@ -5357,8 +5248,7 @@ static FT_Error Lookup_ChainContextPos2( GPOS_Instance* gpi, TTO_ChainContextPosFormat2* ccpf2, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -5376,8 +5266,6 @@ FT_UShort* input_classes; FT_UShort* lookahead_classes; - FT_UShort* s_in; - FT_UShort* bc; FT_UShort* ic; FT_UShort* lc; @@ -5390,14 +5278,14 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), 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 = Coverage_Index( &ccpf2->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -5413,7 +5301,7 @@ goto End2; known_lookahead_classes = 0; - error = Get_Class( &ccpf2->InputClassDef, in->string[in->pos], + error = Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH( 0 ), &input_classes[0], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -5437,7 +5325,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) continue; if ( bgc ) @@ -5447,12 +5335,11 @@ Note that `known_backtrack_classes' starts at index 0. */ curr_pos = 0; - s_in = &in->string[curr_pos]; bc = cpcr.Backtrack; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -5467,7 +5354,7 @@ { /* Keeps us from having to do this for each rule */ - error = Get_Class( &ccpf2->BacktrackClassDef, s_in[j], + error = Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ), &backtrack_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -5482,20 +5369,19 @@ continue; } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; ic = cpcr.Input; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; @@ -5503,7 +5389,7 @@ if ( i >= known_input_classes ) { - error = Get_Class( &ccpf2->InputClassDef, s_in[j], + error = Get_Class( &ccpf2->InputClassDef, IN_GLYPH( curr_pos + j ), &input_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -5521,17 +5407,16 @@ last context glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; lc = cpcr.Lookahead; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; @@ -5539,7 +5424,7 @@ if ( i >= known_lookahead_classes ) { - error = Get_Class( &ccpf2->LookaheadClassDef, s_in[j], + error = Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( curr_pos + j ), &lookahead_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -5555,7 +5440,7 @@ error = Do_ContextPos( gpi, igc, cpcr.PosCount, cpcr.PosLookupRecord, - in, out, + buffer, nesting_level ); goto End1; } @@ -5578,8 +5463,7 @@ static FT_Error Lookup_ChainContextPos3( GPOS_Instance* gpi, TTO_ChainContextPosFormat3* ccpf3, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -5587,7 +5471,6 @@ FT_UShort index, i, j, curr_pos, property; FT_UShort bgc, igc, lgc; FT_Error error; - FT_UShort* s_in; TTO_GPOSHeader* gpos = gpi->gpos; TTO_Coverage* bc; @@ -5598,7 +5481,7 @@ gdef = gpos->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; bgc = ccpf3->BacktrackGlyphCount; @@ -5610,7 +5493,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) return TTO_Err_Not_Covered; if ( bgc ) @@ -5619,12 +5502,11 @@ we search backwards for matches in the backtrack glyph array */ curr_pos = 0; - s_in = &in->string[curr_pos]; bc = ccpf3->BacktrackCoverage; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; @@ -5635,31 +5517,30 @@ return TTO_Err_Not_Covered; } - error = Coverage_Index( &bc[i], s_in[j], &index ); + error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); if ( error ) return error; } } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; ic = ccpf3->InputCoverage; for ( i = 0, j = 0; i < igc; i++, j++ ) { /* We already called CHECK_Property for s_in[0] */ - while ( j > 0 && CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( j > 0 && CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &ic[i], s_in[j], &index ); + error = Coverage_Index( &ic[i], IN_GLYPH( curr_pos + j ), &index ); if ( error ) return error; } @@ -5668,23 +5549,22 @@ last context glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; lc = ccpf3->LookaheadCoverage; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &lc[i], s_in[j], &index ); + error = Coverage_Index( &lc[i], IN_GLYPH( curr_pos + j ), &index ); if ( error ) return error; } @@ -5692,7 +5572,7 @@ return Do_ContextPos( gpi, igc, ccpf3->PosCount, ccpf3->PosLookupRecord, - in, out, + buffer, nesting_level ); } @@ -5700,8 +5580,7 @@ static FT_Error Lookup_ChainContextPos( GPOS_Instance* gpi, TTO_ChainContextPos* ccp, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -5709,17 +5588,17 @@ switch ( ccp->PosFormat ) { case 1: - return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, in, out, + return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer, flags, context_length, nesting_level ); case 2: - return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, in, out, + return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer, flags, context_length, nesting_level ); case 3: - return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, in, out, + return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer, flags, context_length, nesting_level ); @@ -6025,8 +5904,7 @@ static FT_Error Do_Glyph_Lookup( GPOS_Instance* gpi, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GPOS_Data* out, + OTL_Buffer buffer, FT_UShort context_length, int nesting_level ) { @@ -6051,49 +5929,49 @@ case GPOS_LOOKUP_SINGLE: error = Lookup_SinglePos( gpi, &lo->SubTable[i].st.gpos.single, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_PAIR: error = Lookup_PairPos( gpi, &lo->SubTable[i].st.gpos.pair, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_CURSIVE: error = Lookup_CursivePos( gpi, &lo->SubTable[i].st.gpos.cursive, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_MARKBASE: error = Lookup_MarkBasePos( gpi, &lo->SubTable[i].st.gpos.markbase, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_MARKLIG: error = Lookup_MarkLigPos( gpi, &lo->SubTable[i].st.gpos.marklig, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_MARKMARK: error = Lookup_MarkMarkPos( gpi, &lo->SubTable[i].st.gpos.markmark, - in, out, + buffer, flags, context_length ); break; case GPOS_LOOKUP_CONTEXT: error = Lookup_ContextPos( gpi, &lo->SubTable[i].st.gpos.context, - in, out, + buffer, flags, context_length, nesting_level ); break; @@ -6101,7 +5979,7 @@ case GPOS_LOOKUP_CHAIN: error = Lookup_ChainContextPos( gpi, &lo->SubTable[i].st.gpos.chain, - in, out, + buffer, flags, context_length, nesting_level ); break; @@ -6122,28 +6000,23 @@ static FT_Error Do_String_Lookup( GPOS_Instance* gpi, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GPOS_Data* out ) + OTL_Buffer buffer ) { FT_Error error, retError = TTO_Err_Not_Covered; TTO_GPOSHeader* gpos = gpi->gpos; FT_UShort* properties = gpos->LookupList.Properties; - FT_UShort* p_in = in->properties; int nesting_level = 0; - FT_UShort i; - FT_Pos offset; - gpi->first = 0xFFFF; gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ - in->pos = 0; + buffer->in_pos = 0; - while ( in->pos < in->length ) + while ( buffer->in_pos < buffer->in_length ) { - if ( ~p_in[in->pos] & properties[lookup_index] ) + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) { /* 0xFFFF indicates that we don't have a context length yet. */ @@ -6154,7 +6027,7 @@ It is up to the font designer to provide meaningful lookups and lookup order. */ - error = Do_Glyph_Lookup( gpi, lookup_index, in, out, + error = Do_Glyph_Lookup( gpi, lookup_index, buffer, 0xFFFF, nesting_level ); if ( error && error != TTO_Err_Not_Covered ) return error; @@ -6168,24 +6041,8 @@ error = TTO_Err_Not_Covered; } - /* test whether we have to adjust the offsets for cursive connections */ - - if ( gpi->first != 0xFFFF && gpi->last == 0xFFFF && - gpos->LookupList.Lookup[lookup_index].LookupFlag & RIGHT_TO_LEFT ) - { - offset = out[in->pos].y_pos; - - /* no horizontal offsets (for vertical writing direction) - supported yet */ - - for ( i = gpi->first; i <= in->pos; i++ ) - out[i].y_pos -= offset; - - gpi->first = 0xFFFF; - } - if ( error == TTO_Err_Not_Covered ) - (in->pos)++; + (buffer->in_pos)++; else retError = error; } @@ -6194,6 +6051,30 @@ } + static FT_Error Position_CursiveChain ( OTL_Buffer buffer ) + { + FT_ULong i, j; + OTL_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 TT_Err_Ok; + } + EXPORT_FUNC FT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos, FT_UShort feature_index, @@ -6269,7 +6150,6 @@ return TT_Err_Ok; } - /* If `dvi' is TRUE, glyph contour points for anchor points and device tables are ignored -- you will get device independent values. */ @@ -6277,12 +6157,10 @@ FT_Error TT_GPOS_Apply_String( FT_Face face, TTO_GPOSHeader* gpos, FT_UShort load_flags, - TTO_GSUB_String* in, - TTO_GPOS_Data** out, + OTL_Buffer buffer, FT_Bool dvi, FT_Bool r2l ) { - FT_Memory memory = gpos->memory; FT_Error error, retError = TTO_Err_Not_Covered; GPOS_Instance gpi; @@ -6292,7 +6170,7 @@ if ( !face || !gpos || - !in || in->length == 0 || in->pos >= in->length ) + !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) return TT_Err_Invalid_Argument; properties = gpos->LookupList.Properties; @@ -6303,15 +6181,10 @@ gpi.r2l = r2l; gpi.dvi = dvi; - if ( *out ) - FREE( *out ); - if ( ALLOC_ARRAY( *out, in->length, TTO_GPOS_Data ) ) - return error; - for ( j = 0; j < gpos->LookupList.LookupCount; j++ ) if ( !properties || properties[j] ) { - error = Do_String_Lookup( &gpi, j, in, *out ); + error = Do_String_Lookup( &gpi, j, buffer ); if ( error ) { if ( error != TTO_Err_Not_Covered ) @@ -6321,6 +6194,10 @@ retError = error; } + error = Position_CursiveChain ( buffer ); + if ( error ) + return error; + return retError; } diff --git a/src/ftxgpos.h b/src/ftxgpos.h index 408bcb0ae..bb766c654 100644 --- a/src/ftxgpos.h +++ b/src/ftxgpos.h @@ -758,26 +758,6 @@ extern "C" { typedef union TTO_GPOS_SubTable_ TTO_GPOS_SubTable; - /* This `string object' is much simpler compared to TTO_GSUB_String. - A call to TTO_GPOS_Apply_String() will allocate it. */ - - struct TTO_GPOS_Data_ - { - FT_Pos x_pos; - FT_Pos y_pos; - FT_Pos x_advance; - FT_Pos y_advance; - FT_UShort back; /* number of glyphs to go back - for drawing current glyph */ - FT_Bool new_advance; /* if set, the advance width values are - absolute, i.e., they won't be - added to the original glyph's value - but rather replace them. */ - }; - - typedef struct TTO_GPOS_Data_ TTO_GPOS_Data; - - /* finally, the GPOS API */ /* EXPORT_DEF @@ -844,8 +824,7 @@ extern "C" { FT_Error TT_GPOS_Apply_String( FT_Face face, TTO_GPOSHeader* gpos, FT_UShort load_flags, - TTO_GSUB_String* in, - TTO_GPOS_Data** out, + OTL_Buffer buffer, FT_Bool dvi, FT_Bool r2l ); diff --git a/src/ftxgsub.c b/src/ftxgsub.c index 96aaffa25..0ec246dce 100644 --- a/src/ftxgsub.c +++ b/src/ftxgsub.c @@ -38,17 +38,26 @@ #define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' ) -#define ADD_String( in, num_in, out, num_out, glyph_data, component, ligID ) \ - ( ( error = TT_GSUB_Add_String( (in), (num_in), \ - (out), (num_out), \ - (glyph_data), (component), (ligID) \ - ) ) != TT_Err_Ok ) +#define IN_GLYPH( pos ) buffer->in_string[(pos)].gindex +#define IN_CURGLYPH( pos ) buffer->in_string[(pos) + buffer->in_pos].gindex +#define IN_PROPERTIES( pos ) buffer->in_string[(pos)].properties +#define IN_LIGID( pos ) buffer->in_string[(pos)].ligID + + +#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \ + ( ( error = otl_buffer_add_output_glyphs( (buffer), \ + (num_in), (num_out), \ + (glyph_data), (component), (ligID) \ + ) ) != TT_Err_Ok ) +#define ADD_Glyph( buffer, glyph_index, component, ligID ) \ + ( ( error = otl_buffer_add_output_glyph( (buffer), \ + (glyph_index), (component), (ligID) \ + ) ) != TT_Err_Ok ) static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort context_length, int nesting_level ); @@ -59,203 +68,6 @@ **********************/ - /* The following function copies `num_out' elements from `glyph_data' - to `out', advancing the array pointer in the `in' structure by - `num_in' elements, and in `out' by `num_out' elements. If the - string (resp. the properties) array in `out' is empty or too - small, it allocates resp. reallocates the string (and properties) - array. Finally, it sets the `length' field of `out' equal to - `pos' of the `out' structure. - - If `component' is 0xFFFF, the value `in->component[in->pos]' - will be copied `num_out' times, otherwise `component' itself will - be used to fill `out->component'. - - If `ligID' is 0xFFFF, the value `in->lig_IDs[in->pos]' will be - copied `num_out' times, otherwise `ligID' itself will be used to - fill `out->ligIDs'. - - The properties (if defined) for all replaced glyphs are taken - from the glyph at position `in->pos'. - - The logClusters[] value for the glyph at position in->pos is used - for all replacement glyphs */ - - EXPORT_FUNC - FT_Error TT_GSUB_Add_String( TTO_GSUB_String* in, - FT_UShort num_in, - TTO_GSUB_String* out, - FT_UShort num_out, - FT_UShort* glyph_data, - FT_UShort component, - FT_UShort ligID ) - { - FT_Memory memory = in->memory; - FT_Error error; - FT_UShort i; - FT_UShort p_in; - FT_UShort*p_out; - - - /* sanity check */ - - if ( !in || !out || - in->length == 0 || in->pos >= in->length || - in->length < in->pos + num_in ) - return TT_Err_Invalid_Argument; - - if ( out->pos + num_out >= out->allocated ) - { - FT_ULong size = out->pos + num_out + 256L; - - - /* The following works because all fields in `out' must be - initialized to zero (including the `string' field) for the - first use. */ - - if ( REALLOC_ARRAY( out->string, out->allocated, size, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( out->components, out->allocated, size, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( out->ligIDs, out->allocated, size, FT_UShort ) ) - return error; - if ( in->properties ) - if ( REALLOC_ARRAY( out->properties, out->allocated, size, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( out->logClusters, out->allocated, size, FT_Int ) ) - return error; - - out->allocated = size; - } - - if ( num_out ) - { - MEM_Copy( &out->string[out->pos], glyph_data, - num_out * sizeof ( FT_UShort ) ); - - if ( component == 0xFFFF ) - component = in->components[in->pos]; - - p_out = out->components; - - for ( i = out->pos; i < out->pos + num_out; i++ ) - p_out[i] = component; - - p_out = out->ligIDs; - - if ( ligID == 0xFFFF ) - ligID = in->ligIDs[in->pos]; - - for ( i = out->pos; i < out->pos + num_out; i++ ) - p_out[i] = ligID; - - if ( in->properties ) - { - p_in = in->properties[in->pos]; - p_out = out->properties; - - for ( i = out->pos; i < out->pos + num_out; i++ ) - p_out[i] = p_in; - } - - for ( i = out->pos; i < out->pos + num_out; i++ ) - out->logClusters[i] = in->logClusters[in->pos]; - } - - in->pos += num_in; - out->pos += num_out; - - out->length = out->pos; - - return TT_Err_Ok; - } - - -#if 0 - - /********************** - * Extension Functions - **********************/ - - - static FT_Error GSUB_Create( void* ext, - PFace face ) - { - DEFINE_LOAD_LOCALS( face->stream ); - - TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext; - Long table; - - - /* by convention */ - - if ( !gsub ) - return TT_Err_Ok; - - /* a null offset indicates that there is no GSUB table */ - - gsub->offset = 0; - - /* we store the start offset and the size of the subtable */ - - table = TT_LookUp_Table( face, TTAG_GSUB ); - if ( table < 0 ) - return TT_Err_Ok; /* The table is optional */ - - if ( FILE_Seek( face->dirTables[table].Offset ) || - ACCESS_Frame( 4L ) ) - return error; - - gsub->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ - gsub->Version = GET_ULong(); - - FORGET_Frame(); - - gsub->loaded = FALSE; - - return TT_Err_Ok; - } - - - static FT_Error GSUB_Destroy( void* ext, - PFace face ) - { - TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext; - - - /* by convention */ - - if ( !gsub ) - return TT_Err_Ok; - - if ( gsub->loaded ) - { - Free_LookupList( &gsub->LookupList, GSUB, memory ); - Free_FeatureList( &gsub->FeatureList, memory ); - Free_ScriptList( &gsub->ScriptList, memory ); - } - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_Init_GSUB_Extension( TT_Engine engine ) - { - PEngine_Instance _engine = HANDLE_Engine( engine ); - - - if ( !_engine ) - return TT_Err_Invalid_Engine; - - return TT_Register_Extension( _engine, - GSUB_ID, - sizeof ( TTO_GSUBHeader ), - GSUB_Create, - GSUB_Destroy ); - } -#endif - EXPORT_FUNC FT_Error TT_Load_GSUB_Table( FT_Face face, TTO_GSUBHeader** retptr, @@ -502,39 +314,38 @@ static FT_Error Lookup_SingleSubst( TTO_SingleSubst* ss, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) { - FT_UShort index, value[1], property; + FT_UShort index, value, property; FT_Error error; if ( context_length != 0xFFFF && context_length < 1 ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &ss->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ss->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; switch ( ss->SubstFormat ) { case 1: - value[0] = ( in->string[in->pos] + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; - if ( ADD_String( in, 1, out, 1, value, 0xFFFF, 0xFFFF ) ) + value = ( IN_CURGLYPH( 0 ) + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; + if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) return error; break; case 2: if ( index >= ss->ssf.ssf2.GlyphCount ) return TTO_Err_Invalid_GSUB_SubTable; - value[0] = ss->ssf.ssf2.Substitute[index]; - if ( ADD_String( in, 1, out, 1, value, 0xFFFF, 0xFFFF ) ) + value = ss->ssf.ssf2.Substitute[index]; + if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) return error; break; @@ -546,7 +357,7 @@ { /* we inherit the old glyph class to the substituted glyph */ - error = Add_Glyph_Property( gdef, value[0], property ); + error = Add_Glyph_Property( gdef, value, property ); if ( error && error != TTO_Err_Not_Covered ) return error; } @@ -706,8 +517,7 @@ static FT_Error Lookup_MultipleSubst( TTO_MultipleSubst* ms, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) @@ -720,10 +530,10 @@ if ( context_length != 0xFFFF && context_length < 1 ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &ms->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ms->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -733,7 +543,7 @@ count = ms->Sequence[index].GlyphCount; s = ms->Sequence[index].Substitute; - if ( ADD_String( in, 1, out, count, s, 0xFFFF, 0xFFFF ) ) + if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) return error; if ( gdef && gdef->NewGlyphClasses ) @@ -904,8 +714,7 @@ static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub, TTO_AlternateSubst* as, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) @@ -919,10 +728,10 @@ if ( context_length != 0xFFFF && context_length < 1 ) return TTO_Err_Not_Covered; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &as->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &as->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -931,14 +740,14 @@ /* we use a user-defined callback function to get the alternate index */ if ( gsub->altfunc ) - alt_index = (gsub->altfunc)( out->pos, in->string[in->pos], + alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH( 0 ), aset.GlyphCount, aset.Alternate, gsub->data ); else alt_index = 0; - if ( ADD_String( in, 1, out, 1, &aset.Alternate[alt_index], - 0xFFFF, 0xFFFF ) ) + if ( ADD_Glyph( buffer, aset.Alternate[alt_index], + 0xFFFF, 0xFFFF ) ) return error; if ( gdef && gdef->NewGlyphClasses ) @@ -1184,8 +993,7 @@ static FT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) @@ -1193,19 +1001,18 @@ FT_UShort index, property; FT_Error error; FT_UShort numlig, i, j, is_mark, first_is_mark = FALSE; - FT_UShort* s_in; FT_UShort* c; TTO_Ligature* lig; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; if ( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) first_is_mark = TRUE; - error = Coverage_Index( &ls->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ls->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -1218,10 +1025,9 @@ numlig; numlig--, lig++ ) { - if ( in->pos + lig->ComponentCount > in->length ) + if ( buffer->in_pos + lig->ComponentCount > buffer->in_length ) continue; /* Not enough glyphs in input */ - s_in = &in->string[in->pos]; c = lig->Component; is_mark = first_is_mark; @@ -1231,12 +1037,12 @@ for ( i = 1, j = 1; i < lig->ComponentCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else break; @@ -1245,7 +1051,7 @@ if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) is_mark = FALSE; - if ( s_in[j] != c[i - 1] ) + if ( IN_CURGLYPH( j ) != c[i - 1] ) break; } @@ -1266,25 +1072,25 @@ /* We don't use a new ligature ID if there are no skipped glyphs and the ligature already has an ID. */ - if ( in->ligIDs[in->pos] ) + if ( IN_LIGID( buffer->in_pos ) ) { - if ( ADD_String( in, i, out, 1, &lig->LigGlyph, - 0xFFFF, 0xFFFF ) ) + if ( ADD_String( buffer, i, 1, &lig->LigGlyph, + 0xFFFF, 0xFFFF ) ) return error; } else { - if ( ADD_String( in, i, out, 1, &lig->LigGlyph, - 0xFFFF, in->max_ligID ) ) + FT_UShort ligID = otl_buffer_allocate_ligid( buffer ); + if ( ADD_String( buffer, i, 1, &lig->LigGlyph, + 0xFFFF, ligID ) ) return error; - - (in->max_ligID)++; } } else { - if ( ADD_String( in, 1, out, 1, &lig->LigGlyph, - 0xFFFF, in->max_ligID ) ) + FT_UShort ligID = otl_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 @@ -1296,16 +1102,14 @@ for ( i = 0; i < lig->ComponentCount - 1; i++ ) { - while ( CHECK_Property( gdef, in->string[in->pos], + while ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) - if ( ADD_String( in, 1, out, 1, &in->string[in->pos], - i, in->max_ligID ) ) + if ( ADD_Glyph( buffer, IN_CURGLYPH( 0 ), + i, ligID ) ) return error; - (in->pos)++; + (buffer->in_pos)++; } - - (in->max_ligID)++; } return TT_Err_Ok; @@ -1324,8 +1128,7 @@ FT_UShort GlyphCount, FT_UShort SubstCount, TTO_SubstLookupRecord* subst, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, int nesting_level ) { FT_Error error; @@ -1338,23 +1141,23 @@ { if ( SubstCount && i == subst->SequenceIndex ) { - old_pos = in->pos; + old_pos = buffer->in_pos; /* Do a substitution */ - error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, in, out, + error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer, GlyphCount, nesting_level ); subst++; SubstCount--; - i += in->pos - old_pos; + i += buffer->in_pos - old_pos; if ( error == TTO_Err_Not_Covered ) { /* XXX "can't happen" -- but don't count on it */ - if ( ADD_String( in, 1, out, 1, &in->string[in->pos], - 0xFFFF, 0xFFFF ) ) + if ( ADD_Glyph( buffer, IN_CURGLYPH( 0 ), + 0xFFFF, 0xFFFF ) ) return error; i++; } @@ -1365,8 +1168,8 @@ { /* No substitution for this index */ - if ( ADD_String( in, 1, out, 1, &in->string[in->pos], - 0xFFFF, 0xFFFF ) ) + if ( ADD_Glyph( buffer, IN_CURGLYPH( 0 ), + 0xFFFF, 0xFFFF ) ) return error; i++; } @@ -2090,8 +1893,7 @@ static FT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat1* csf1, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -2099,7 +1901,6 @@ FT_UShort index, property; FT_UShort i, j, k, numsr; FT_Error error; - FT_UShort* s_in; TTO_SubRule* sr; TTO_GDEFHeader* gdef; @@ -2107,10 +1908,10 @@ gdef = gsub->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &csf1->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &csf1->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -2122,32 +1923,30 @@ if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount ) continue; - if ( in->pos + sr[k].GlyphCount > in->length ) + if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length ) continue; /* context is too long */ - s_in = &in->string[in->pos]; - for ( i = 1, j = 1; i < sr[k].GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != sr[k].Input[i - 1] ) + if ( IN_CURGLYPH( j ) != sr[k].Input[i - 1] ) break; } if ( i == sr[k].GlyphCount ) return Do_ContextSubst( gsub, sr[k].GlyphCount, sr[k].SubstCount, sr[k].SubstLookupRecord, - in, out, + buffer, nesting_level ); } @@ -2158,8 +1957,7 @@ static FT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat2* csf2, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -2170,7 +1968,6 @@ FT_UShort i, j, k, known_classes; FT_UShort* classes; - FT_UShort* s_in; FT_UShort* cl; TTO_SubClassSet* scs; @@ -2180,21 +1977,21 @@ gdef = gsub->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), 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 = Coverage_Index( &csf2->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &csf2->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, FT_UShort ) ) return error; - error = Get_Class( &csf2->ClassDef, in->string[in->pos], + error = Get_Class( &csf2->ClassDef, IN_CURGLYPH( 0 ), &classes[0], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End; @@ -2214,22 +2011,21 @@ if ( context_length != 0xFFFF && context_length < sr->GlyphCount ) continue; - if ( in->pos + sr->GlyphCount > in->length ) + if ( buffer->in_pos + sr->GlyphCount > buffer->in_length ) continue; /* context is too long */ - s_in = &in->string[in->pos]; cl = sr->Class; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < sr->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else break; @@ -2239,7 +2035,7 @@ { /* Keeps us from having to do this for each rule */ - error = Get_Class( &csf2->ClassDef, s_in[j], &classes[i], NULL ); + error = Get_Class( &csf2->ClassDef, IN_CURGLYPH( j ), &classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End; known_classes = i; @@ -2253,7 +2049,7 @@ { error = Do_ContextSubst( gsub, sr->GlyphCount, sr->SubstCount, sr->SubstLookupRecord, - in, out, + buffer, nesting_level ); goto End; } @@ -2270,15 +2066,13 @@ static FT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat3* csf3, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) { FT_Error error; FT_UShort index, i, j, property; - FT_UShort* s_in; TTO_Coverage* c; TTO_GDEFHeader* gdef; @@ -2286,47 +2080,45 @@ gdef = gsub->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) return TTO_Err_Not_Covered; - if ( in->pos + csf3->GlyphCount > in->length ) + if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length ) return TTO_Err_Not_Covered; /* context is too long */ - s_in = &in->string[in->pos]; c = csf3->Coverage; for ( i = 1, j = 1; i < csf3->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_CURGLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( in->pos + j < in->length ) + if ( buffer->in_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &c[i], s_in[j], &index ); + error = Coverage_Index( &c[i], IN_CURGLYPH( j ), &index ); if ( error ) return error; } return Do_ContextSubst( gsub, csf3->GlyphCount, csf3->SubstCount, csf3->SubstLookupRecord, - in, out, + buffer, nesting_level ); } static FT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub, TTO_ContextSubst* cs, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -2334,15 +2126,15 @@ switch ( cs->SubstFormat ) { case 1: - return Lookup_ContextSubst1( gsub, &cs->csf.csf1, in, out, + return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level ); case 2: - return Lookup_ContextSubst2( gsub, &cs->csf.csf2, in, out, + return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level ); case 3: - return Lookup_ContextSubst3( gsub, &cs->csf.csf3, in, out, + return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level ); default: @@ -3377,8 +3169,7 @@ static FT_Error Lookup_ChainContextSubst1( TTO_GSUBHeader* gsub, TTO_ChainContextSubstFormat1* ccsf1, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -3387,7 +3178,6 @@ FT_UShort i, j, k, num_csr, curr_pos; FT_UShort bgc, igc, lgc; FT_Error error; - FT_UShort* s_in; TTO_ChainSubRule* csr; TTO_ChainSubRule curr_csr; @@ -3396,10 +3186,10 @@ gdef = gsub->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; - error = Coverage_Index( &ccsf1->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -3418,7 +3208,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) continue; if ( bgc ) @@ -3427,11 +3217,10 @@ we search backwards for matches in the backtrack glyph array */ curr_pos = 0; - s_in = &in->string[curr_pos]; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; @@ -3452,7 +3241,7 @@ Backtrack offsets - 3 2 1 0 Lookahead offsets - 0 1 2 3 */ - if ( s_in[j] != curr_csr.Backtrack[i] ) + if ( IN_GLYPH( j ) != curr_csr.Backtrack[i] ) break; } @@ -3460,25 +3249,24 @@ continue; } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != curr_csr.Input[i - 1] ) + if ( IN_GLYPH( curr_pos + j ) != curr_csr.Input[i - 1] ) break; } @@ -3489,22 +3277,21 @@ last context glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; } - if ( s_in[j] != curr_csr.Lookahead[i] ) + if ( IN_GLYPH( curr_pos + j ) != curr_csr.Lookahead[i] ) break; } @@ -3512,7 +3299,7 @@ return Do_ContextSubst( gsub, igc, curr_csr.SubstCount, curr_csr.SubstLookupRecord, - in, out, + buffer, nesting_level ); } @@ -3523,8 +3310,7 @@ static FT_Error Lookup_ChainContextSubst2( TTO_GSUBHeader* gsub, TTO_ChainContextSubstFormat2* ccsf2, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -3542,8 +3328,6 @@ FT_UShort* input_classes; FT_UShort* lookahead_classes; - FT_UShort* s_in; - FT_UShort* bc; FT_UShort* ic; FT_UShort* lc; @@ -3556,14 +3340,14 @@ gdef = gsub->gdef; memory = gsub->memory; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), 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 = Coverage_Index( &ccsf2->Coverage, in->string[in->pos], &index ); + error = Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH( 0 ), &index ); if ( error ) return error; @@ -3579,7 +3363,7 @@ goto End2; known_lookahead_classes = 0; - error = Get_Class( &ccsf2->InputClassDef, in->string[in->pos], + error = Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH( 0 ), &input_classes[0], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -3603,7 +3387,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) continue; if ( bgc ) @@ -3613,12 +3397,11 @@ Note that `known_backtrack_classes' starts at index 0. */ curr_pos = 0; - s_in = &in->string[curr_pos]; bc = ccsr.Backtrack; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -3633,7 +3416,7 @@ { /* Keeps us from having to do this for each rule */ - error = Get_Class( &ccsf2->BacktrackClassDef, s_in[j], + error = Get_Class( &ccsf2->BacktrackClassDef, IN_GLYPH( j ), &backtrack_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -3648,20 +3431,19 @@ continue; } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; ic = ccsr.Input; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; @@ -3669,7 +3451,7 @@ if ( i >= known_input_classes ) { - error = Get_Class( &ccsf2->InputClassDef, s_in[j], + error = Get_Class( &ccsf2->InputClassDef, IN_GLYPH( curr_pos + j ), &input_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -3687,17 +3469,16 @@ last context glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; lc = ccsr.Lookahead; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) goto End1; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else break; @@ -3705,7 +3486,7 @@ if ( i >= known_lookahead_classes ) { - error = Get_Class( &ccsf2->LookaheadClassDef, s_in[j], + error = Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( curr_pos + j ), &lookahead_classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) goto End1; @@ -3721,7 +3502,7 @@ error = Do_ContextSubst( gsub, igc, ccsr.SubstCount, ccsr.SubstLookupRecord, - in, out, + buffer, nesting_level ); goto End1; } @@ -3744,8 +3525,7 @@ static FT_Error Lookup_ChainContextSubst3( TTO_GSUBHeader* gsub, TTO_ChainContextSubstFormat3* ccsf3, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -3753,7 +3533,6 @@ FT_UShort index, i, j, curr_pos, property; FT_UShort bgc, igc, lgc; FT_Error error; - FT_UShort* s_in; TTO_Coverage* bc; TTO_Coverage* ic; @@ -3763,7 +3542,7 @@ gdef = gsub->gdef; - if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) + if ( CHECK_Property( gdef, IN_CURGLYPH( 0 ), flags, &property ) ) return error; bgc = ccsf3->BacktrackGlyphCount; @@ -3775,7 +3554,7 @@ /* check whether context is too long; it is a first guess only */ - if ( bgc > in->pos || in->pos + igc + lgc > in->length ) + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) return TTO_Err_Not_Covered; if ( bgc ) @@ -3784,12 +3563,11 @@ we search backwards for matches in the backtrack glyph array */ curr_pos = 0; - s_in = &in->string[curr_pos]; bc = ccsf3->BacktrackCoverage; - for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- ) + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; @@ -3800,31 +3578,30 @@ return TTO_Err_Not_Covered; } - error = Coverage_Index( &bc[i], s_in[j], &index ); + error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); if ( error ) return error; } } - curr_pos = in->pos; - s_in = &in->string[curr_pos]; + curr_pos = buffer->in_pos; ic = ccsf3->InputCoverage; for ( i = 0, j = 0; i < igc; i++, j++ ) { - /* We already called CHECK_Property for s_in[0] */ - while ( j > 0 && CHECK_Property( gdef, s_in[j], flags, &property ) ) + /* We already called CHECK_Property for IN_GLYPH( curr_pos ) */ + while ( j > 0 && CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &ic[i], s_in[j], &index ); + error = Coverage_Index( &ic[i], IN_GLYPH( curr_pos + j ), &index ); if ( error ) return error; } @@ -3833,23 +3610,22 @@ glyph */ curr_pos += j; - s_in = &in->string[curr_pos]; lc = ccsf3->LookaheadCoverage; for ( i = 0, j = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) + while ( CHECK_Property( gdef, IN_GLYPH( curr_pos + j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; - if ( curr_pos + j < in->length ) + if ( curr_pos + j < buffer->in_length ) j++; else return TTO_Err_Not_Covered; } - error = Coverage_Index( &lc[i], s_in[j], &index ); + error = Coverage_Index( &lc[i], IN_GLYPH( curr_pos + j ), &index ); if ( error ) return error; } @@ -3857,7 +3633,7 @@ return Do_ContextSubst( gsub, igc, ccsf3->SubstCount, ccsf3->SubstLookupRecord, - in, out, + buffer, nesting_level ); } @@ -3865,8 +3641,7 @@ static FT_Error Lookup_ChainContextSubst( TTO_GSUBHeader* gsub, TTO_ChainContextSubst* ccs, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ) @@ -3874,17 +3649,17 @@ switch ( ccs->SubstFormat ) { case 1: - return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, in, out, + return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level ); case 2: - return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, in, out, + return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level ); case 3: - return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, in, out, + return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level ); @@ -4196,8 +3971,7 @@ static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GSUB_String* out, + OTL_Buffer buffer, FT_UShort context_length, int nesting_level ) { @@ -4220,39 +3994,39 @@ { case GSUB_LOOKUP_SINGLE: error = Lookup_SingleSubst( &lo->SubTable[i].st.gsub.single, - in, out, + buffer, flags, context_length, gsub->gdef ); break; case GSUB_LOOKUP_MULTIPLE: error = Lookup_MultipleSubst( &lo->SubTable[i].st.gsub.multiple, - in, out, + buffer, flags, context_length, gsub->gdef ); break; case GSUB_LOOKUP_ALTERNATE: error = Lookup_AlternateSubst( gsub, &lo->SubTable[i].st.gsub.alternate, - in, out, + buffer, flags, context_length, gsub->gdef ); break; case GSUB_LOOKUP_LIGATURE: error = Lookup_LigatureSubst( &lo->SubTable[i].st.gsub.ligature, - in, out, + buffer, flags, context_length, gsub->gdef ); break; case GSUB_LOOKUP_CONTEXT: error = Lookup_ContextSubst( gsub, &lo->SubTable[i].st.gsub.context, - in, out, + buffer, flags, context_length, nesting_level ); break; case GSUB_LOOKUP_CHAIN: error = Lookup_ChainContextSubst( gsub, &lo->SubTable[i].st.gsub.chain, - in, out, + buffer, flags, context_length, nesting_level ); break; @@ -4268,29 +4042,25 @@ return TTO_Err_Not_Covered; } - /* apply one lookup to the input string object */ static FT_Error Do_String_Lookup( TTO_GSUBHeader* gsub, FT_UShort lookup_index, - TTO_GSUB_String* in, - TTO_GSUB_String* out ) + OTL_Buffer buffer ) { FT_Error error, retError = TTO_Err_Not_Covered; FT_UShort* properties = gsub->LookupList.Properties; - FT_UShort* p_in = in->properties; - FT_UShort* s_in = in->string; int nesting_level = 0; - while ( in->pos < in->length ) + while ( buffer->in_pos < buffer->in_length ) { - if ( ~p_in[in->pos] & properties[lookup_index] ) + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) { /* 0xFFFF indicates that we don't have a context length yet */ - error = Do_Glyph_Lookup( gsub, lookup_index, in, out, + error = Do_Glyph_Lookup( gsub, lookup_index, buffer, 0xFFFF, nesting_level ); if ( error ) { @@ -4304,7 +4074,7 @@ error = TTO_Err_Not_Covered; if ( error == TTO_Err_Not_Covered ) - if ( ADD_String( in, 1, out, 1, &s_in[in->pos], 0xFFFF, 0xFFFF ) ) + if ( ADD_Glyph( buffer, IN_CURGLYPH( 0 ), 0xFFFF, 0xFFFF ) ) return error; } @@ -4375,149 +4145,25 @@ } - EXPORT_FUNC - FT_Error TT_GSUB_String_New( FT_Memory memory, - TTO_GSUB_String **result ) - { - FT_Error error; - - TTO_GSUB_String *str; - - if ( ALLOC( str, sizeof( *str ) ) ) - return error; - - str->memory = memory; - - str->length = 0; - str->allocated = 0; - str->pos = 0; - str->string = NULL; - str->properties = NULL; - str->components = NULL; - str->max_ligID = 0; - str->ligIDs = 0; - str->logClusters = 0; - - *result = str; - - return TT_Err_Ok; - } - - EXPORT_DEF - FT_Error TT_GSUB_String_Set_Length( TTO_GSUB_String *str, - FT_ULong new_length) - { - FT_Memory memory = str->memory; - FT_Error error; - - if ( new_length > str->allocated ) - { - if ( REALLOC_ARRAY( str->string, str->allocated, new_length, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( str->properties, str->allocated, new_length, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( str->components, str->allocated, new_length, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( str->ligIDs, str->allocated, new_length, FT_UShort ) ) - return error; - if ( REALLOC_ARRAY( str->logClusters, str->allocated, new_length, FT_Int ) ) - return error; - - str->allocated = new_length; - str->length = new_length; - } - - return TT_Err_Ok; - } - - EXPORT_FUNC - FT_Error TT_GSUB_String_Done( TTO_GSUB_String *str ) - { - FT_Memory memory = str->memory; - - FREE( str->string ); - FREE( str->properties ); - FREE( str->components ); - FREE( str->ligIDs ); - FREE( str->logClusters ); - - FREE( str ); - - return TT_Err_Ok; - } - EXPORT_FUNC FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub, - TTO_GSUB_String* in, - TTO_GSUB_String* out ) + OTL_Buffer buffer ) { FT_Error error, retError = TTO_Err_Not_Covered; - FT_Memory memory = in->memory; FT_UShort j; - TTO_GSUB_String tmp1; - TTO_GSUB_String* ptmp1; - TTO_GSUB_String tmp2; - TTO_GSUB_String* ptmp2; - TTO_GSUB_String* t; - FT_UShort* properties; - if ( !gsub || - !in || !out || in->length == 0 || in->pos >= in->length ) + !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) return TT_Err_Invalid_Argument; properties = gsub->LookupList.Properties; - tmp1.memory = memory; - tmp1.length = in->length; - tmp1.allocated = in->length; - tmp1.pos = in->pos; - tmp1.max_ligID = 1; - tmp1.string = NULL; - tmp1.properties = NULL; - tmp1.components = NULL; - tmp1.ligIDs = NULL; - tmp1.logClusters = NULL; - - tmp2.memory = memory; - tmp2.allocated = 0; - tmp2.pos = 0; - tmp2.string = NULL; - tmp2.properties = NULL; - tmp2.components = NULL; - tmp2.ligIDs = NULL; - tmp2.logClusters = NULL; - - ptmp1 = &tmp1; - ptmp2 = &tmp2; - - if ( ALLOC_ARRAY( tmp1.string, tmp1.length, FT_UShort ) ) - return error; - MEM_Copy( tmp1.string, in->string, in->length * sizeof ( FT_UShort ) ); - - /* make sure that we always have a `properties', `components', and - `ligIDs' array in the string object */ - - if ( ALLOC_ARRAY( tmp1.components, tmp1.length, FT_UShort ) ) - goto End; - if ( ALLOC_ARRAY( tmp1.ligIDs, tmp1.length, FT_UShort ) ) - goto End; - if ( ALLOC_ARRAY( tmp1.properties, tmp1.length, FT_UShort ) ) - goto End; - if ( in->properties ) - MEM_Copy( tmp1.properties, in->properties, - in->length * sizeof( FT_UShort ) ); - if ( ALLOC_ARRAY( tmp1.logClusters, tmp1.length, FT_Int ) ) - goto End; - MEM_Copy( tmp1.logClusters, in->logClusters, - in->length * sizeof( FT_Int ) ); - for ( j = 0; j < gsub->LookupList.LookupCount; j++ ) if ( properties[j] ) { - error = Do_String_Lookup( gsub, j, ptmp1, ptmp2 ); + error = Do_String_Lookup( gsub, j, buffer ); if ( error ) { if ( error != TTO_Err_Not_Covered ) @@ -4526,56 +4172,15 @@ else retError = error; - - /* flipping `in' and `out', preparing the next loop */ - - ptmp1->pos = in->pos; - ptmp2->length = ptmp2->pos; - ptmp2->pos = in->pos; - ptmp2->max_ligID = ptmp1->max_ligID; - - t = ptmp2; - ptmp2 = ptmp1; - ptmp1 = t; + error = otl_buffer_swap( buffer ); + if ( error ) + goto End; } + + error = retError; End: - FREE( ptmp2->string ); - FREE( ptmp2->properties ); - FREE( ptmp2->components ); - FREE( ptmp2->ligIDs ); - FREE( ptmp2->logClusters ); - - if ( error && error != TTO_Err_Not_Covered ) - { - FREE( ptmp1->string ); - FREE( ptmp1->components ); - FREE( ptmp1->ligIDs ); - FREE( ptmp1->properties ); - FREE( ptmp1->logClusters ); - - return error; - } - else - { - out->length = ptmp1->length; - out->pos = 0; - out->allocated = ptmp1->allocated; - out->string = ptmp1->string; - out->components = ptmp1->components; - out->ligIDs = ptmp1->ligIDs; - out->logClusters = ptmp1->logClusters; - - if ( in->properties ) - out->properties = ptmp1->properties; - else - { - FREE( ptmp1->properties ); - out->properties = NULL; - } - - return retError; - } + return error; } diff --git a/src/ftxgsub.h b/src/ftxgsub.h index 8951e4413..51dda1c13 100644 --- a/src/ftxgsub.h +++ b/src/ftxgsub.h @@ -504,23 +504,6 @@ extern "C" { TT_Add_String() will also handle allocation; you should use free() in case you want to destroy the arrays in the object. */ - struct TTO_GSUB_String_ - { - FT_Memory memory; - - FT_ULong length; - FT_ULong pos; - FT_ULong allocated; - FT_UShort* string; - FT_UShort* properties; - FT_UShort* components; - FT_UShort max_ligID; - FT_UShort* ligIDs; - FT_Int* logClusters; - }; - - typedef struct TTO_GSUB_String_ TTO_GSUB_String; - /* finally, the GSUB API */ @@ -577,31 +560,10 @@ extern "C" { TTO_AltFunction altfunc, void* data ); - EXPORT_DEF - FT_Error TT_GSUB_String_New( FT_Memory memory, - TTO_GSUB_String **result ); - - EXPORT_DEF - FT_Error TT_GSUB_String_Set_Length( TTO_GSUB_String *str, - FT_ULong new_length); - - EXPORT_DEF - FT_Error TT_GSUB_String_Done( TTO_GSUB_String *str ); - - EXPORT_DEF FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub, - TTO_GSUB_String* in, - TTO_GSUB_String* out ); + OTL_Buffer buffer ); - EXPORT_DEF - FT_Error TT_GSUB_Add_String( TTO_GSUB_String* in, - FT_UShort num_in, - TTO_GSUB_String* out, - FT_UShort num_out, - FT_UShort* glyph_data, - FT_UShort component, - FT_UShort ligID ); #ifdef __cplusplus } diff --git a/src/ftxopen.h b/src/ftxopen.h index 6788dec5f..482bcb5d2 100644 --- a/src/ftxopen.h +++ b/src/ftxopen.h @@ -280,6 +280,7 @@ extern "C" { typedef struct TTO_Device_ TTO_Device; +#include "otlbuffer.h" #include "ftxgdef.h" #include "ftxgsub.h" #include "ftxgpos.h" diff --git a/src/otlbuffer.c b/src/otlbuffer.c new file mode 100644 index 000000000..b35a63fb4 --- /dev/null +++ b/src/otlbuffer.c @@ -0,0 +1,213 @@ +/* otlbuffer.c: Buffer of glyphs for substitution/positioning + * + * Copyright 2004 Red Hat Software + * + * Portions Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + */ +#include + +#include FT_INTERNAL_MEMORY_H + + static FT_Error + otl_buffer_ensure( OTL_Buffer buffer, + FT_ULong size ) + { + FT_Memory memory = buffer->memory; + FT_ULong new_allocated = buffer->allocated; + + if (size > new_allocated) + { + FT_Error error; + + while (size > new_allocated) + new_allocated += (new_allocated >> 1) + 8; + + if ( FT_REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) ) + return error; + if ( FT_REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) ) + return error; + if ( FT_REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, OTL_PositionRec ) ) + return error; + + buffer->allocated = new_allocated; + } + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_new( FT_Memory memory, + OTL_Buffer *buffer ) + { + FT_Error error; + + if ( FT_ALLOC( *buffer, sizeof( OTL_BufferRec ) ) ) + return error; + + (*buffer)->memory = memory; + (*buffer)->in_length = 0; + (*buffer)->out_length = 0; + (*buffer)->allocated = 0; + (*buffer)->in_pos = 0; + (*buffer)->out_pos = 0; + + (*buffer)->in_string = NULL; + (*buffer)->out_string = NULL; + (*buffer)->positions = NULL; + (*buffer)->max_ligID = 0; + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_swap( OTL_Buffer buffer ) + { + OTL_GlyphItem tmp_string; + + tmp_string = buffer->in_string; + buffer->in_string = buffer->out_string; + buffer->out_string = tmp_string; + + buffer->in_length = buffer->out_length; + buffer->out_length = 0; + + buffer->in_pos = 0; + buffer->out_pos = 0; + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_free( OTL_Buffer buffer ) + { + FT_Memory memory = buffer->memory; + + FT_FREE( buffer->in_string ); + FT_FREE( buffer->out_string ); + FT_FREE( buffer ); + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_clear( OTL_Buffer buffer ) + { + buffer->in_length = 0; + buffer->out_length = 0; + buffer->in_pos = 0; + buffer->out_pos = 0; + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_add_glyph( OTL_Buffer buffer, + FT_UInt glyph_index, + FT_UInt properties, + FT_UInt cluster ) + { + FT_Error error; + OTL_GlyphItem glyph; + + error = otl_buffer_ensure( buffer, buffer->in_length + 1 ); + if ( error != FT_Err_Ok ) + return error; + + glyph = &buffer->in_string[buffer->in_length]; + glyph->gindex = glyph_index; + glyph->properties = properties; + glyph->cluster = cluster; + glyph->component = 0; + glyph->ligID = 0; + + buffer->in_length++; + + return FT_Err_Ok; + } + + /* The following function copies `num_out' elements from `glyph_data' + to `buffer->out_string', advancing the in array pointer in the structure + by `num_in' elements, and the out array pointer by `num_out' elements. + Finally, it sets the `length' field of `out' equal to + `pos' of the `out' structure. + + If `component' is 0xFFFF, the component value from buffer->in_pos + will copied `num_out' times, otherwise `component' itself will + be used to fill the `component' fields. + + If `ligID' is 0xFFFF, the ligID value from buffer->in_pos + will copied `num_out' times, otherwise `ligID' itself will + be used to fill the `ligID' fields. + + The properties for all replacement glyphs are taken + from the glyph at position `buffer->in_pos'. + + The cluster value for the glyph at position buffer->in_pos is used + for all replacement glyphs */ + FT_Error + otl_buffer_add_output_glyphs( OTL_Buffer buffer, + FT_UShort num_in, + FT_UShort num_out, + FT_UShort *glyph_data, + FT_UShort component, + FT_UShort ligID ) + { + FT_Error error; + FT_UShort i; + FT_UInt properties; + FT_UInt cluster; + + error = otl_buffer_ensure( buffer, buffer->out_pos + num_out ); + if ( error != FT_Err_Ok ) + return error; + + properties = buffer->in_string[buffer->in_pos].properties; + cluster = buffer->in_string[buffer->in_pos].cluster; + if ( component == 0xFFFF ) + component = buffer->in_string[buffer->in_pos].component; + if ( ligID == 0xFFFF ) + ligID = buffer->in_string[buffer->in_pos].ligID; + + for ( i = 0; i < num_out; i++ ) + { + OTL_GlyphItem item = &buffer->out_string[buffer->out_pos + i]; + + item->gindex = glyph_data[i]; + item->properties = properties; + item->cluster = cluster; + item->component = component; + item->ligID = ligID; + } + + buffer->in_pos += num_in; + buffer->out_pos += num_out; + + buffer->out_length = buffer->out_pos; + + return FT_Err_Ok; + } + + FT_Error + otl_buffer_add_output_glyph( OTL_Buffer buffer, + FT_UInt glyph_index, + FT_UShort component, + FT_UShort ligID ) + { + FT_UShort glyph_data = glyph_index; + + return otl_buffer_add_output_glyphs ( buffer, 1, 1, + &glyph_data, component, ligID ); + } + + FT_UShort + otl_buffer_allocate_ligid( OTL_Buffer buffer ) + { + return buffer->max_ligID++; + } diff --git a/src/otlbuffer.h b/src/otlbuffer.h new file mode 100644 index 000000000..426b4473c --- /dev/null +++ b/src/otlbuffer.h @@ -0,0 +1,97 @@ +/* otlbuffer.h: Buffer of glyphs for substitution/positioning + * + * Copyrigh 2004 Red Hat Software + * + * Portions Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + */ +#include +#include FT_FREETYPE_H + +#include + +G_BEGIN_DECLS + + typedef struct OTL_GlyphItemRec_ { + FT_UInt gindex; + FT_UInt properties; + FT_UInt cluster; + FT_UShort component; + FT_UShort ligID; + } OTL_GlyphItemRec, *OTL_GlyphItem; + + typedef struct OTL_PositionRec_ { + FT_Pos x_pos; + FT_Pos y_pos; + FT_Pos x_advance; + FT_Pos y_advance; + FT_UShort back; /* number of glyphs to go back + for drawing current glyph */ + FT_Bool new_advance; /* if set, the advance width values are + absolute, i.e., they won't be + added to the original glyph's value + but rather replace them. */ + FT_Short cursive_chain; /* character to which this connects, + may be positive or negative; used + only internally */ + } OTL_PositionRec, *OTL_Position; + + + typedef struct OTL_BufferRec_{ + FT_Memory memory; + FT_ULong allocated; + + FT_ULong in_length; + FT_ULong out_length; + FT_ULong in_pos; + FT_ULong out_pos; + + OTL_GlyphItem in_string; + OTL_GlyphItem out_string; + OTL_Position positions; + FT_UShort max_ligID; + } OTL_BufferRec, *OTL_Buffer; + + FT_Error + otl_buffer_new( FT_Memory memory, + OTL_Buffer *buffer ); + + FT_Error + otl_buffer_swap( OTL_Buffer buffer ); + + FT_Error + otl_buffer_free( OTL_Buffer buffer ); + + FT_Error + otl_buffer_clear( OTL_Buffer buffer ); + + FT_Error + otl_buffer_add_glyph( OTL_Buffer buffer, + FT_UInt glyph_index, + FT_UInt properties, + FT_UInt cluster ); + + FT_Error + otl_buffer_add_output_glyphs( OTL_Buffer buffer, + FT_UShort num_in, + FT_UShort num_out, + FT_UShort *glyph_data, + FT_UShort component, + FT_UShort ligID ); + + FT_Error + otl_buffer_add_output_glyph ( OTL_Buffer buffer, + FT_UInt glyph_index, + FT_UShort component, + FT_UShort ligID ); + + FT_UShort + otl_buffer_allocate_ligid( OTL_Buffer buffer ); + +G_END_DECLS diff --git a/src/ottest.c b/src/ottest.c index b70f91189..e9a81c9f1 100644 --- a/src/ottest.c +++ b/src/ottest.c @@ -145,6 +145,7 @@ add_features (TTO_GSUB gsub) maybe_add_feature (gsub, script_index, FT_MAKE_TAG ('l', 'i', 'g', 'a'), L); } +#if 0 void dump_string (TTO_GSUB_String *str) { @@ -203,6 +204,7 @@ try_string (FT_Library library, if ((error = TT_GSUB_String_Done (out_str))) croak ("TT_GSUB_String_New", error); } +#endif int main (int argc, char **argv) diff --git a/src/pango-ot-buffer.c b/src/pango-ot-buffer.c new file mode 100644 index 000000000..9b5486668 --- /dev/null +++ b/src/pango-ot-buffer.c @@ -0,0 +1,265 @@ +/* Pango + * pango-ot-buffer.c: Buffer of glyphs for shaping/positioning + * + * Copyright (C) 2004 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "pango-ot-private.h" + +#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6)) +#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d)) + +PangoOTBuffer * +pango_ot_buffer_new (PangoFcFont *font) +{ + /* We lock the font here immediately for the silly reason + * of getting the FT_Memory; otherwise we'd have to + * add a new operation to PangoFcFontmap; callers will + * probably already have the font locked, however, + * so there is little performance penalty. + */ + PangoOTBuffer *buffer = g_new (PangoOTBuffer, 1); + FT_Face face = pango_fc_font_lock_face (font); + + if (otl_buffer_new (face->memory, &buffer->buffer) != FT_Err_Ok) + g_error ("Allocation of OTLBuffer failed"); + + buffer->font = g_object_ref (font); + buffer->applied_gpos = FALSE; + buffer->rtl = FALSE; + + pango_fc_font_unlock_face (font); + + return buffer; +} + +void +pango_ot_buffer_destroy (PangoOTBuffer *buffer) +{ + otl_buffer_free (buffer->buffer); + g_object_unref (buffer->font); + g_free (buffer); +} + +void +pango_ot_buffer_clear (PangoOTBuffer *buffer) +{ + otl_buffer_clear (buffer->buffer); + buffer->applied_gpos = FALSE; +} + +void +pango_ot_buffer_add_glyph (PangoOTBuffer *buffer, + guint glyph_index, + guint properties, + guint cluster) +{ + otl_buffer_add_glyph (buffer->buffer, + glyph_index, properties, cluster); + +} + +void +pango_ot_buffer_set_rtl (PangoOTBuffer *buffer, + gboolean rtl) +{ + rtl = rtl != FALSE; + buffer->rtl = rtl; +} + +void +pango_ot_buffer_get_glyphs (PangoOTBuffer *buffer, + PangoOTGlyph **glyphs, + int *n_glyphs) +{ + if (glyphs) + *glyphs = (PangoOTGlyph *)buffer->buffer->in_string; + + if (n_glyphs) + *n_glyphs = buffer->buffer->in_length; +} + +static void +swap_range (PangoGlyphString *glyphs, int start, int end) +{ + int i, j; + + for (i = start, j = end - 1; i < j; i++, j--) + { + PangoGlyphInfo glyph_info; + gint log_cluster; + + glyph_info = glyphs->glyphs[i]; + glyphs->glyphs[i] = glyphs->glyphs[j]; + glyphs->glyphs[j] = glyph_info; + + log_cluster = glyphs->log_clusters[i]; + glyphs->log_clusters[i] = glyphs->log_clusters[j]; + glyphs->log_clusters[j] = log_cluster; + } +} + +static void +apply_gpos_ltr (PangoGlyphString *glyphs, + OTL_Position positions) +{ + int i; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + FT_Pos x_pos = positions[i].x_pos; + FT_Pos y_pos = positions[i].y_pos; + int back = i; + int j; + + while (positions[back].back != 0) + { + back -= positions[back].back; + x_pos += positions[back].x_pos; + y_pos += positions[back].y_pos; + } + + for (j = back; j < i; j++) + glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width; + + glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos); + glyphs->glyphs[i].geometry.y_offset += PANGO_UNITS_26_6(y_pos); + + if (positions[i].new_advance) + glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(positions[i].x_advance); + else + glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(positions[i].x_advance); + } +} + +static void +apply_gpos_rtl (PangoGlyphString *glyphs, + OTL_Position positions) +{ + int i; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + int i_rev = glyphs->num_glyphs - i - 1; + int back_rev = i_rev; + int back; + FT_Pos x_pos = positions[i_rev].x_pos; + FT_Pos y_pos = positions[i_rev].y_pos; + int j; + + while (positions[back_rev].back != 0) + { + back_rev -= positions[back_rev].back; + x_pos += positions[back_rev].x_pos; + y_pos += positions[back_rev].y_pos; + } + + back = glyphs->num_glyphs - back_rev - 1; + + for (j = i; j < back; j++) + glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[j].geometry.width; + + glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos); + glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos); + + if (positions[i_rev].new_advance) + glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(positions[i_rev].x_advance); + else + glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(positions[i_rev].x_advance); + } +} + +void +pango_ot_buffer_output (PangoOTBuffer *buffer, + PangoGlyphString *glyphs) +{ + FT_Face face; + PangoOTInfo *info; + TTO_GDEF gdef = NULL; + int i; + int last_cluster; + + face = pango_fc_font_lock_face (buffer->font); + g_assert (face); + + /* Copy glyphs into output glyph string */ + pango_glyph_string_set_size (glyphs, buffer->buffer->in_length); + + last_cluster = -1; + for (i = 0; i < buffer->buffer->in_length; i++) + { + OTL_GlyphItem item = &buffer->buffer->in_string[i]; + + glyphs->glyphs[i].glyph = item->gindex; + + glyphs->log_clusters[i] = item->cluster; + if (glyphs->log_clusters[i] != last_cluster) + glyphs->glyphs[i].attr.is_cluster_start = 1; + else + glyphs->glyphs[i].attr.is_cluster_start = 0; + + last_cluster = glyphs->log_clusters[i]; + } + + info = pango_ot_info_get (face); + gdef = pango_ot_info_get_gdef (info); + + /* Apply default positioning */ + for (i = 0; i < glyphs->num_glyphs; i++) + { + if (glyphs->glyphs[i].glyph) + { + PangoRectangle logical_rect; + + FT_UShort property; + + if (gdef && + TT_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == FT_Err_Ok && + (property == TTO_MARK || (property & IGNORE_SPECIAL_MARKS) != 0)) + { + glyphs->glyphs[i].geometry.width = 0; + } + else + { + pango_font_get_glyph_extents ((PangoFont *)buffer->font, glyphs->glyphs[i].glyph, NULL, &logical_rect); + glyphs->glyphs[i].geometry.width = logical_rect.width; + } + } + else + glyphs->glyphs[i].geometry.width = 0; + + glyphs->glyphs[i].geometry.x_offset = 0; + glyphs->glyphs[i].geometry.y_offset = 0; + } + + if (buffer->rtl) + { + /* Swap all glyphs */ + swap_range (glyphs, 0, glyphs->num_glyphs); + } + + if (buffer->applied_gpos) + { + if (buffer->rtl) + apply_gpos_rtl (glyphs, buffer->buffer->positions); + else + apply_gpos_ltr (glyphs, buffer->buffer->positions); + } + + pango_fc_font_unlock_face (buffer->font); +} diff --git a/src/pango-ot-info.c b/src/pango-ot-info.c index 578c95d1a..a6baa7fd4 100644 --- a/src/pango-ot-info.c +++ b/src/pango-ot-info.c @@ -162,17 +162,31 @@ compare_glyph_info (gconstpointer a, /* Make a guess at the appropriate class for a glyph given * a character code that maps to the glyph */ -static FT_UShort -get_glyph_class (gunichar charcode) +static gboolean +get_glyph_class (gunichar charcode, + FT_UShort *class) { + /* For characters mapped into the Arabic Presentation forms, using properties + * derived as we apply GSUB substitutions will be more reliable + */ + if ((charcode >= 0xFB50 && charcode <= 0xFDFF) || /* Arabic Presentation Forms-A */ + (charcode >= 0xFE70 && charcode <= 0XFEFF)) /* Arabic Presentation Forms-B */ + return FALSE; + switch (g_unichar_type (charcode)) { case G_UNICODE_COMBINING_MARK: case G_UNICODE_ENCLOSING_MARK: case G_UNICODE_NON_SPACING_MARK: - return 3; /* Mark glyph (non-spacing combining glyph) */ + *class = 3; /* Mark glyph (non-spacing combining glyph) */ + return TRUE; + case G_UNICODE_UNASSIGNED: + case G_UNICODE_PRIVATE_USE: + return FALSE; /* Unknown, don't assign a class; classes get + * propagated during GSUB application */ default: - return 1; /* Base glyph (single character, spacing glyph) */ + *class = 1; /* Base glyph (single character, spacing glyph) */ + return TRUE; } } @@ -225,9 +239,8 @@ synthesize_class_def (PangoOTInfo *info) if (glyph <= 65535) { glyph_info.glyph = glyph; - glyph_info.class = get_glyph_class (charcode); - - g_array_append_val (glyph_infos, glyph_info); + if (get_glyph_class (charcode, &glyph_info.class)) + g_array_append_val (glyph_infos, glyph_info); } charcode = FT_Get_Next_Char (info->face, charcode, &glyph); diff --git a/src/pango-ot-private.h b/src/pango-ot-private.h index 5c27f3a55..9d8f5d0ed 100644 --- a/src/pango-ot-private.h +++ b/src/pango-ot-private.h @@ -80,6 +80,14 @@ struct _PangoOTRulesetClass GObjectClass parent_class; }; +struct _PangoOTBuffer +{ + OTL_Buffer buffer; + PangoFcFont *font; + gboolean rtl; + gboolean applied_gpos; +}; + GType pango_ot_info_get_type (void); TTO_GDEF pango_ot_info_get_gdef (PangoOTInfo *info); diff --git a/src/pango-ot-ruleset.c b/src/pango-ot-ruleset.c index bf297f114..47af334b8 100644 --- a/src/pango-ot-ruleset.c +++ b/src/pango-ot-ruleset.c @@ -24,9 +24,6 @@ #include FT_INTERNAL_MEMORY_H /* For FT_Free() */ -#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6)) -#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d)) - typedef struct _PangoOTRule PangoOTRule; struct _PangoOTRule @@ -139,34 +136,15 @@ pango_ot_ruleset_add_feature (PangoOTRuleset *ruleset, g_array_append_val (ruleset->rules, tmp_rule); } -/** - * pango_ot_ruleset_shape: - * @ruleset: a #PangoOTRuleset. - * @glyphs: a pointer to a #PangoGlyphString. - * @properties: an array containing one #gulong bitfield for each glyph, - * which gives the glyph's properties: If a certain bit is set for a glyph, - * the feature which has the same bit set in its property value is applied. - * - * Shapes a string of glyphs with the given properties according to @ruleset. - **/ void -pango_ot_ruleset_shape (PangoOTRuleset *ruleset, - PangoGlyphString *glyphs, - gulong *properties) +pango_ot_ruleset_substitute (PangoOTRuleset *ruleset, + PangoOTBuffer *buffer) { int i; - int last_cluster; - int result; TTO_GSUB gsub = NULL; - TTO_GPOS gpos = NULL; - TTO_GSUB_String *in_string = NULL; - TTO_GSUB_String *out_string = NULL; - TTO_GSUB_String *result_string = NULL; - gboolean need_gsub = FALSE; - gboolean need_gpos = FALSE; g_return_if_fail (PANGO_OT_IS_RULESET (ruleset)); @@ -176,26 +154,17 @@ pango_ot_ruleset_shape (PangoOTRuleset *ruleset, if (rule->table_type == PANGO_OT_TABLE_GSUB) need_gsub = TRUE; - else - need_gpos = TRUE; } if (need_gsub) { + gsub = pango_ot_info_get_gsub (ruleset->info); if (gsub) TT_GSUB_Clear_Features (gsub); } - if (need_gpos) - { - gpos = pango_ot_info_get_gpos (ruleset->info); - - if (gpos) - TT_GPOS_Clear_Features (gpos); - } - for (i = 0; i < ruleset->rules->len; i++) { PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i); @@ -205,98 +174,59 @@ pango_ot_ruleset_shape (PangoOTRuleset *ruleset, if (gsub) TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit); } - else + } + + if (!gsub) + return; + + TT_GSUB_Apply_String (gsub, buffer->buffer); +} + +void +pango_ot_ruleset_position (PangoOTRuleset *ruleset, + PangoOTBuffer *buffer) +{ + int i; + + TTO_GPOS gpos = NULL; + + gboolean need_gpos = FALSE; + + g_return_if_fail (PANGO_OT_IS_RULESET (ruleset)); + + for (i = 0; i < ruleset->rules->len; i++) + { + PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i); + + if (rule->table_type == PANGO_OT_TABLE_GPOS) + need_gpos = TRUE; + } + + if (need_gpos) + gpos = pango_ot_info_get_gpos (ruleset->info); + + if (gpos) + { + TT_GPOS_Clear_Features (gpos); + + for (i = 0; i < ruleset->rules->len; i++) { - if (gpos) + PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i); + + if (rule->table_type == PANGO_OT_TABLE_GPOS) TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit); } } - if (!gsub && !gpos) - return; - - result = TT_GSUB_String_New (ruleset->info->face->memory, &in_string); - g_assert (result == FT_Err_Ok); - - result = TT_GSUB_String_Set_Length (in_string, glyphs->num_glyphs); - g_assert (result == FT_Err_Ok); - - for (i = 0; i < glyphs->num_glyphs; i++) - { - in_string->string[i] = glyphs->glyphs[i].glyph; - in_string->properties[i] = properties[i]; - in_string->logClusters[i] = glyphs->log_clusters[i]; - } - in_string->max_ligID = i; - - if (gsub) - { - result = TT_GSUB_String_New (ruleset->info->face->memory, - &out_string); - g_assert (result == FT_Err_Ok); - result_string = out_string; - - TT_GSUB_Apply_String (gsub, in_string, out_string); - } - else - result_string = in_string; - + /* Apply GPOS rules */ if (gpos) { - TTO_GPOS_Data *outgpos = NULL; - - if (!TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, result_string, &outgpos, - FALSE /* enable device-dependant values */, - FALSE /* Even though this might be r2l text, RTL is handled elsewhere */)) + if (TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, buffer->buffer, + FALSE /* enable device-dependant values */, + buffer->rtl) == FT_Err_Ok) { - for (i = 0; i < result_string->length; i++) - { - FT_Pos x_pos = outgpos[i].x_pos; - FT_Pos y_pos = outgpos[i].y_pos; - int back = i; - int j; - - while (outgpos[back].back != 0) - { - back -= outgpos[back].back; - x_pos += outgpos[back].x_pos; - y_pos += outgpos[back].y_pos; - } - - for (j = back; j < i; j++) - glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width; - - glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos); - glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos); - - if (outgpos[i].new_advance) - glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(outgpos[i].x_advance); - else - glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(outgpos[i].x_advance); - } - - FT_Free(gpos->memory, (void *)outgpos); + buffer->applied_gpos = TRUE; } } - - pango_glyph_string_set_size (glyphs, result_string->length); - - last_cluster = -1; - for (i = 0; i < result_string->length; i++) - { - glyphs->glyphs[i].glyph = result_string->string[i]; - - glyphs->log_clusters[i] = result_string->logClusters[i]; - if (glyphs->log_clusters[i] != last_cluster) - glyphs->glyphs[i].attr.is_cluster_start = 1; - else - glyphs->glyphs[i].attr.is_cluster_start = 0; - - last_cluster = glyphs->log_clusters[i]; - } - - if (in_string) - TT_GSUB_String_Done (in_string); - if (out_string) - TT_GSUB_String_Done (out_string); } +