diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 000000000..ba2906d06 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +main diff --git a/src/Makefile.am b/src/Makefile.am index 5c0b18ef8..40644c1a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,17 +2,20 @@ INCLUDES = \ -I $(srcdir) \ - $(FREETYPE_CFLAGS) + $(FREETYPE_CFLAGS) \ + $(GLIB_CFLAGS) +CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align noinst_LTLIBRARIES = libharfbuzz-1.la MAINSOURCES = \ - harfbuzz.c + $(INCLUDEDSOURCES) \ + hb-ot-layout.cc +# harfbuzz.c # included from harfbuzz.c INCLUDEDSOURCES = \ harfbuzz-buffer.c \ - harfbuzz-gdef.c \ harfbuzz-gpos.c \ harfbuzz-gsub.c \ harfbuzz-impl.c \ @@ -23,7 +26,6 @@ PUBLICHEADERS = \ harfbuzz.h \ harfbuzz-global.h \ harfbuzz-buffer.h \ - harfbuzz-gdef.h \ harfbuzz-gpos.h \ harfbuzz-gsub.h \ harfbuzz-open.h @@ -31,7 +33,6 @@ PUBLICHEADERS = \ PRIVATEHEADERS = \ harfbuzz-impl.h \ harfbuzz-buffer-private.h \ - harfbuzz-gdef-private.h \ harfbuzz-gpos-private.h \ harfbuzz-gsub-private.h \ harfbuzz-open-private.h \ @@ -45,7 +46,7 @@ libharfbuzz_1_la_SOURCES = \ libharfbuzz_1_la_LIBADD = \ $(FREETYPE_LIBS) -noinst_PROGRAMS = harfbuzz-dump +noinst_PROGRAMS = harfbuzz-dump main harfbuzz_dump_SOURCES = \ harfbuzz-dump.c \ @@ -56,6 +57,9 @@ harfbuzz_dump_LDADD = \ $(libharfbuzz_1_la_LIBADD) \ libharfbuzz-1.la +main_LDADD = \ + $(GLIB_LIBS) + EXTRA_DIST = \ README \ COPYING \ diff --git a/src/Makefile.ng b/src/Makefile.ng new file mode 100644 index 000000000..816269b47 --- /dev/null +++ b/src/Makefile.ng @@ -0,0 +1,11 @@ +all: main + +CPPFLAGS = -Wall -Wextra `pkg-config --cflags glib-2.0` +LDFLAGS = `pkg-config --libs glib-2.0` +CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align + +main: main.cc *.h + $(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -f main main.o diff --git a/src/harfbuzz-buffer-private.h b/src/harfbuzz-buffer-private.h index 5065f2e03..02ae33636 100644 --- a/src/harfbuzz-buffer-private.h +++ b/src/harfbuzz-buffer-private.h @@ -83,9 +83,9 @@ _hb_buffer_allocate_ligid( HB_Buffer buffer ); #define OUT_GLYPH( pos ) (buffer->out_string[(pos)].gindex) #define OUT_ITEM( pos ) (&buffer->out_string[(pos)]) -#define CHECK_Property( gdef, index, flags, property ) \ - ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags), \ - (property) ) ) != HB_Err_Ok ) +#define CHECK_Property( layout, index, flags, property ) \ + (error = _hb_ot_layout_check_glyph_properties((layout), (index), (flags), (property)) \ + ? HB_Err_Ok : HB_Err_Not_Covered) #define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \ ( ( error = _hb_buffer_add_output_glyphs( (buffer), \ diff --git a/src/harfbuzz-global.h b/src/harfbuzz-global.h index dab20b54b..7b8a0f27c 100644 --- a/src/harfbuzz-global.h +++ b/src/harfbuzz-global.h @@ -28,6 +28,9 @@ #ifndef HARFBUZZ_GLOBAL_H #define HARFBUZZ_GLOBAL_H +/* XXX */ +#include "hb-ot-layout.h" + #include #include FT_FREETYPE_H diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c index c78dcba46..560a29117 100644 --- a/src/harfbuzz-gpos.c +++ b/src/harfbuzz-gpos.c @@ -75,7 +75,7 @@ static HB_Error default_mmfunc( HB_Font font, HB_Error HB_Load_GPOS_Table( HB_Font font, HB_GPOSHeader** retptr, - HB_GDEFHeader* gdef ) + hb_ot_layout_t *layout ) { HB_UInt cur_offset, new_offset, base_offset; @@ -85,7 +85,7 @@ HB_Error HB_Load_GPOS_Table( HB_Font font, HB_Error error; - if ( !retptr ) + if ( !retptr || !layout ) return ERR(HB_Err_Invalid_Argument); if ( GOTO_Table( TTAG_GPOS ) ) @@ -143,20 +143,12 @@ HB_Error HB_Load_GPOS_Table( HB_Font font, stream, HB_Type_GPOS ) ) != HB_Err_Ok ) goto Fail2; - gpos->gdef = gdef; /* can be NULL */ - - if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream, - gpos->LookupList.Lookup, - gpos->LookupList.LookupCount ) ) ) - goto Fail1; + gpos->layout = layout; /* can be NULL */ *retptr = gpos; return HB_Err_Ok; -Fail1: - _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS ); - Fail2: _HB_OPEN_Free_FeatureList( &gpos->FeatureList ); @@ -1005,7 +997,7 @@ static HB_Error Lookup_SinglePos( GPOS_Instance* gpi, if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index ); @@ -1568,7 +1560,7 @@ static HB_Error Lookup_PairPos( GPOS_Instance* gpi, if ( context_length != 0xFFFF && context_length < 2 ) return HB_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index ); @@ -1580,7 +1572,7 @@ static HB_Error Lookup_PairPos( GPOS_Instance* gpi, first_pos = buffer->in_pos; (buffer->in_pos)++; - while ( CHECK_Property( gpos->gdef, IN_CURITEM(), + while ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) @@ -1794,13 +1786,13 @@ static HB_Error Lookup_CursivePos( GPOS_Instance* gpi, /* 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_CURITEM(), flags, &property ) ) + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; /* We don't handle mark glyphs here. According to Andrei, this isn't possible, but who knows... */ - if ( property == HB_GDEF_MARK ) + if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK ) { gpi->last = 0xFFFF; return HB_Err_Not_Covered; @@ -2216,7 +2208,7 @@ static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi, if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS ) return HB_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; @@ -2232,12 +2224,11 @@ static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi, while ( i <= buffer->in_pos ) { - error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; + property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j)); + if ( !property ) + return HB_Err_Not_Covered; - if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) break; i++; @@ -2246,7 +2237,7 @@ static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi, /* The following assertion is too strong -- at least for mangal.ttf. */ #if 0 - if ( property != HB_GDEF_BASE_GLYPH ) + if ( property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH ) return HB_Err_Not_Covered; #endif @@ -2628,7 +2619,7 @@ static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi, mark_glyph = IN_CURGLYPH(); - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index ); @@ -2642,12 +2633,11 @@ static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi, while ( i <= buffer->in_pos ) { - error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; + property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j)); + if ( !property ) + return HB_Err_Not_Covered; - if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) break; i++; @@ -2657,7 +2647,7 @@ static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi, /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is too strong, thus it is commented out. */ #if 0 - if ( property != HB_GDEF_LIGATURE ) + if ( property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ) return HB_Err_Not_Covered; #endif @@ -2951,7 +2941,7 @@ static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS ) return HB_Err_Not_Covered; - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), + if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) ) return error; @@ -2970,12 +2960,11 @@ static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, j = buffer->in_pos - 1; while ( i <= buffer->in_pos ) { - error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; + property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j)); + if ( !property ) + return HB_Err_Not_Covered; - if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) return HB_Err_Not_Covered; if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) @@ -3780,12 +3769,12 @@ static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi, HB_GPOSHeader* gpos = gpi->gpos; HB_PosRule* pr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index ); @@ -3805,7 +3794,7 @@ static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi, for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3849,12 +3838,12 @@ static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi, HB_PosClassSet* pcs; HB_PosClassRule* pr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; /* Note: The coverage table in format 2 doesn't give an index into @@ -3900,7 +3889,7 @@ static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi, for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End; @@ -3954,12 +3943,12 @@ static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi, HB_GPOSHeader* gpos = gpi->gpos; HB_Coverage* c; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) @@ -3972,7 +3961,7 @@ static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi, for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -4990,12 +4979,12 @@ static HB_Error Lookup_ChainContextPos1( HB_ChainPosRule* cpr; HB_ChainPosRule curr_cpr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index ); @@ -5027,7 +5016,7 @@ static HB_Error Lookup_ChainContextPos1( for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -5056,7 +5045,7 @@ static HB_Error Lookup_ChainContextPos1( for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -5075,7 +5064,7 @@ static HB_Error Lookup_ChainContextPos1( for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -5130,12 +5119,12 @@ static HB_Error Lookup_ChainContextPos2( HB_ChainPosClassSet* cpcs; HB_ChainPosClassRule cpcr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; /* Note: The coverage table in format 2 doesn't give an index into @@ -5198,7 +5187,7 @@ static HB_Error Lookup_ChainContextPos2( for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -5230,7 +5219,7 @@ static HB_Error Lookup_ChainContextPos2( for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -5260,7 +5249,7 @@ static HB_Error Lookup_ChainContextPos2( for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -5324,12 +5313,12 @@ static HB_Error Lookup_ChainContextPos3( HB_Coverage* bc; HB_Coverage* ic; HB_Coverage* lc; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gpos->gdef; + layout = gpos->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; bgc = ccpf3->BacktrackGlyphCount; @@ -5353,7 +5342,7 @@ static HB_Error Lookup_ChainContextPos3( for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -5374,7 +5363,7 @@ static HB_Error Lookup_ChainContextPos3( for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) { /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ - while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( j > buffer->in_pos && CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -5396,7 +5385,7 @@ static HB_Error Lookup_ChainContextPos3( for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; diff --git a/src/harfbuzz-gpos.h b/src/harfbuzz-gpos.h index 8638cf149..b1aa13508 100644 --- a/src/harfbuzz-gpos.h +++ b/src/harfbuzz-gpos.h @@ -26,7 +26,7 @@ #ifndef HARFBUZZ_GPOS_H #define HARFBUZZ_GPOS_H -#include "harfbuzz-gdef.h" +#include "harfbuzz-open.h" #include "harfbuzz-buffer.h" HB_BEGIN_HEADER @@ -86,7 +86,7 @@ struct HB_GPOSHeader_ HB_FeatureList FeatureList; HB_LookupList LookupList; - HB_GDEFHeader* gdef; + hb_ot_layout_t *layout; /* the next field is used for a callback function to get the glyph outline. */ @@ -107,7 +107,7 @@ typedef HB_GPOSHeader* HB_GPOS; HB_Error HB_Load_GPOS_Table( HB_Font font, HB_GPOSHeader** gpos, - HB_GDEFHeader* gdef ); + hb_ot_layout_t *layout ); HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos ); diff --git a/src/harfbuzz-gsub.c b/src/harfbuzz-gsub.c index c05f20db5..38879a857 100644 --- a/src/harfbuzz-gsub.c +++ b/src/harfbuzz-gsub.c @@ -47,7 +47,7 @@ static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, HB_Error HB_Load_GSUB_Table( HB_Font font, HB_GSUBHeader** retptr, - HB_GDEFHeader* gdef ) + hb_ot_layout_t *layout ) { HB_Stream stream = font->stream; HB_Error error; @@ -55,7 +55,7 @@ HB_Error HB_Load_GSUB_Table( HB_Font font, HB_GSUBHeader* gsub; - if ( !retptr ) + if ( !retptr || !layout ) return ERR(HB_Err_Invalid_Argument); if ( GOTO_Table( TTAG_GSUB ) ) @@ -111,20 +111,12 @@ HB_Error HB_Load_GSUB_Table( HB_Font font, stream, HB_Type_GSUB ) ) != HB_Err_Ok ) goto Fail2; - gsub->gdef = gdef; /* can be NULL */ - - if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream, - gsub->LookupList.Lookup, - gsub->LookupList.LookupCount ) ) ) - goto Fail1; + gsub->layout = layout; /* can be NULL */ *retptr = gsub; return HB_Err_Ok; -Fail1: - _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB ); - Fail2: _HB_OPEN_Free_FeatureList( &gsub->FeatureList ); @@ -271,14 +263,14 @@ static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub, HB_UShort index, value, property; HB_Error error; HB_SingleSubst* ss = &st->single; - HB_GDEFHeader* gdef = gsub->gdef; + hb_ot_layout_t* layout = gsub->layout; HB_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index ); @@ -305,13 +297,11 @@ static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub, return ERR(HB_Err_Invalid_SubTable); } - if ( gdef && gdef->NewGlyphClasses ) + if ( _hb_ot_layout_has_new_glyph_classes (layout) ) { /* we inherit the old glyph class to the substituted glyph */ - error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); - if ( error && error != HB_Err_Not_Covered ) - return error; + hb_ot_layout_set_glyph_class (layout, value, property); } return HB_Err_Ok; @@ -477,14 +467,14 @@ static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub, HB_UShort index, property, n, count; HB_UShort*s; HB_MultipleSubst* ms = &st->multiple; - HB_GDEFHeader* gdef = gsub->gdef; + hb_ot_layout_t* layout = gsub->layout; HB_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index ); @@ -500,19 +490,15 @@ static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub, if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) return error; - if ( gdef && gdef->NewGlyphClasses ) + if ( _hb_ot_layout_has_new_glyph_classes (layout) ) { /* this is a guess only ... */ - if ( property == HB_GDEF_LIGATURE ) - property = HB_GDEF_BASE_GLYPH; + if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ) + property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; for ( n = 0; n < count; n++ ) - { - error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property ); - if ( error && error != HB_Err_Not_Covered ) - return error; - } + hb_ot_layout_set_glyph_class (layout, s[n], property); } return HB_Err_Ok; @@ -674,7 +660,7 @@ static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub, HB_Error error; HB_UShort index, value, alt_index, property; HB_AlternateSubst* as = &st->alternate; - HB_GDEFHeader* gdef = gsub->gdef; + hb_ot_layout_t* layout = gsub->layout; HB_AlternateSet aset; HB_UNUSED(nesting_level); @@ -682,7 +668,7 @@ static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub, if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index ); @@ -704,14 +690,9 @@ static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub, if ( REPLACE_Glyph( buffer, value, nesting_level ) ) return error; - if ( gdef && gdef->NewGlyphClasses ) - { + if ( _hb_ot_layout_has_new_glyph_classes (layout) ) /* we inherit the old glyph class to the substituted glyph */ - - error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); - if ( error && error != HB_Err_Not_Covered ) - return error; - } + hb_ot_layout_set_glyph_class (layout, value, property); return HB_Err_Ok; } @@ -953,16 +934,16 @@ static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, HB_UShort numlig, i, j, is_mark, first_is_mark = FALSE; HB_UShort* c; HB_LigatureSubst* ls = &st->ligature; - HB_GDEFHeader* gdef = gsub->gdef; + hb_ot_layout_t* layout = gsub->layout; HB_Ligature* lig; HB_UNUSED(nesting_level); - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; - if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) first_is_mark = TRUE; error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index ); @@ -990,7 +971,7 @@ static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -1000,22 +981,16 @@ static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, j++; } - if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) is_mark = FALSE; if ( IN_GLYPH( j ) != c[i - 1] ) goto next_ligature; } - if ( gdef && gdef->NewGlyphClasses ) - { + if ( _hb_ot_layout_has_new_glyph_classes (layout) ) /* this is just a guess ... */ - - error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph, - is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE ); - if ( error && error != HB_Err_Not_Covered ) - return error; - } + hb_ot_layout_set_glyph_class (layout, lig->LigGlyph, is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE); if ( j == buffer->in_pos + i ) /* No input glyphs skipped */ { @@ -1051,7 +1026,7 @@ static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, for ( i = 0; i < lig->ComponentCount - 1; i++ ) { - while ( CHECK_Property( gdef, IN_CURITEM(), + while ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) ) return error; @@ -1813,12 +1788,12 @@ static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub, HB_Error error; HB_SubRule* sr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index ); @@ -1838,7 +1813,7 @@ static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -1880,12 +1855,12 @@ static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub, HB_SubClassSet* scs; HB_SubClassRule* sr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; /* Note: The coverage table in format 2 doesn't give an index into @@ -1931,7 +1906,7 @@ static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End; @@ -1984,12 +1959,12 @@ static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub, HB_UShort index, i, j, property; HB_Coverage* c; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) @@ -2002,7 +1977,7 @@ static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3004,12 +2979,12 @@ static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, HB_ChainSubRule* csr; HB_ChainSubRule curr_csr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index ); @@ -3041,7 +3016,7 @@ static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3070,7 +3045,7 @@ static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3089,7 +3064,7 @@ static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3142,12 +3117,12 @@ static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, HB_ChainSubClassSet* cscs; HB_ChainSubClassRule ccsr; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; /* Note: The coverage table in format 2 doesn't give an index into @@ -3210,7 +3185,7 @@ static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -3242,7 +3217,7 @@ static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -3272,7 +3247,7 @@ static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) goto End1; @@ -3334,12 +3309,12 @@ static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, HB_Coverage* bc; HB_Coverage* ic; HB_Coverage* lc; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; bgc = ccsf3->BacktrackGlyphCount; @@ -3363,7 +3338,7 @@ static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3384,7 +3359,7 @@ static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) { /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */ - while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( j > buffer->in_pos && CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3406,7 +3381,7 @@ static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, for ( i = 0; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3653,14 +3628,14 @@ static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub, HB_ReverseChainContextSubst* rccs = &st->reverse; HB_Coverage* bc; HB_Coverage* lc; - HB_GDEFHeader* gdef; + hb_ot_layout_t* layout; if ( nesting_level != 1 || context_length != 0xFFFF ) return HB_Err_Not_Covered; - gdef = gsub->gdef; + layout = gsub->layout; - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) ) return error; bgc = rccs->BacktrackGlyphCount; @@ -3680,7 +3655,7 @@ static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; @@ -3706,7 +3681,7 @@ static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub, for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ ) { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) ) { if ( error && error != HB_Err_Not_Covered ) return error; diff --git a/src/harfbuzz-gsub.h b/src/harfbuzz-gsub.h index 3d6cfa18c..b1e78ce93 100644 --- a/src/harfbuzz-gsub.h +++ b/src/harfbuzz-gsub.h @@ -68,7 +68,7 @@ struct HB_GSUBHeader_ HB_FeatureList FeatureList; HB_LookupList LookupList; - HB_GDEFHeader* gdef; + hb_ot_layout_t *layout; /* the next two fields are used for an alternate substitution callback function to select the proper alternate glyph. */ @@ -83,7 +83,7 @@ typedef HB_GSUBHeader* HB_GSUB; HB_Error HB_Load_GSUB_Table( HB_Font font, HB_GSUBHeader** gsub, - HB_GDEFHeader* gdef ); + hb_ot_layout_t *layout ); HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub ); diff --git a/src/harfbuzz-impl.h b/src/harfbuzz-impl.h index f886e676b..29101f878 100644 --- a/src/harfbuzz-impl.h +++ b/src/harfbuzz-impl.h @@ -34,6 +34,9 @@ #include +/* XXX */ +#include "hb-ot-layout-private.h" + HB_BEGIN_HEADER #ifndef HB_INTERNAL @@ -66,8 +69,12 @@ HB_BEGIN_HEADER # define HB_UNUSED(arg) ((arg) = (arg)) #endif -#define HB_LIKELY(cond) (cond) -#define HB_UNLIKELY(cond) (cond) +#ifndef HB_LIKELY +# define HB_LIKELY(cond) (cond) +#endif +#ifndef HB_UNLIKELY +# define HB_UNLIKELY(cond) (cond) +#endif #define ALLOC(_ptr,_size) \ diff --git a/src/harfbuzz-open.c b/src/harfbuzz-open.c index e187916e5..68b27d4b6 100644 --- a/src/harfbuzz-open.c +++ b/src/harfbuzz-open.c @@ -124,15 +124,6 @@ static HB_Error Load_Script( HB_ScriptTable* s, count = s->LangSysCount = GET_UShort(); - /* safety check; otherwise the official handling of TrueType Open - fonts won't work */ - - if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) - { - error = HB_Err_Not_Covered; - goto Fail2; - } - FORGET_Frame(); s->LangSysRecord = NULL; diff --git a/src/harfbuzz.h b/src/harfbuzz.h index 10d4f74d6..d23b6bc26 100644 --- a/src/harfbuzz.h +++ b/src/harfbuzz.h @@ -28,7 +28,6 @@ #include "harfbuzz-global.h" #include "harfbuzz-buffer.h" -#include "harfbuzz-gdef.h" #include "harfbuzz-gsub.h" #include "harfbuzz-gpos.h" #include "harfbuzz-open.h" diff --git a/src/hb-common.h b/src/hb-common.h new file mode 100644 index 000000000..d404353ce --- /dev/null +++ b/src/hb-common.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_COMMON_H +#define HB_COMMON_H + +#include + +# ifdef __cplusplus +# define HB_BEGIN_DECLS() extern "C" { extern int hb_dummy_prototype (int) +# define HB_END_DECLS() } extern "C" int hb_dummy_prototype (int) +# else /* !__cplusplus */ +# define HB_BEGIN_DECLS() extern int hb_dummy_prototype (int) +# define HB_END_DECLS() extern int hb_dummy_prototype (int) +# endif /* !__cplusplus */ + +typedef int hb_bool_t; + +typedef uint32_t hb_tag_t; +#define HB_TAG(a,b,c,d) ((hb_tag_t)(((uint8_t)a<<24)|((uint8_t)b<<16)|((uint8_t)c<<8)|(uint8_t)d)) +#define HB_TAG_STR(s) (HB_TAG(((const char *) s)[0], \ + ((const char *) s)[1], \ + ((const char *) s)[2], \ + ((const char *) s)[3])) + +typedef uint32_t hb_codepoint_t; + +/* XXX */ +typedef struct HB_BufferRec_ hb_buffer_t; + +#endif /* HB_COMMON_H */ diff --git a/src/hb-ot-layout-gdef-private.h b/src/hb-ot-layout-gdef-private.h new file mode 100644 index 000000000..5418d8b1a --- /dev/null +++ b/src/hb-ot-layout-gdef-private.h @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_GDEF_PRIVATE_H +#define HB_OT_LAYOUT_GDEF_PRIVATE_H + +#include "hb-ot-layout-private.h" + +#include "hb-ot-layout-open-private.h" + + +#define DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP(Type, name) \ + inline const Type& name (hb_codepoint_t glyph) { \ + const Coverage &c = get_coverage (); \ + hb_ot_layout_coverage_t c_index = c.get_coverage (glyph); \ + return (*this)[c_index]; \ + } + + +struct GlyphClassDef : ClassDef { + static const unsigned int BaseGlyph = 0x0001u; + static const unsigned int LigatureGlyph = 0x0002u; + static const unsigned int MarkGlyph = 0x0003u; + static const unsigned int ComponentGlyph = 0x0004u; +}; + +/* + * Attachment List Table + */ + +struct AttachPoint { + + friend struct AttachList; + + private: + /* countour point indices, in increasing numerical order */ + DEFINE_ARRAY_TYPE (USHORT, pointIndex, pointCount); + + private: + USHORT pointCount; /* Number of attachment points on + * this glyph */ + USHORT pointIndex[]; /* Array of contour point indices--in + * increasing numerical order */ +}; +DEFINE_NULL_ASSERT_SIZE (AttachPoint, 2); + +struct AttachList { + + friend struct GDEF; + + private: + /* const AttachPoint& get_attach_points (hb_codepoint_t glyph); */ + DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (AttachPoint, get_attach_points); + + private: + /* AttachPoint tables, in Coverage Index order */ + DEFINE_OFFSET_ARRAY_TYPE (AttachPoint, attachPoint, glyphCount); + DEFINE_GET_ACCESSOR (Coverage, coverage, coverage); + + private: + Offset coverage; /* Offset to Coverage table -- from + * beginning of AttachList table */ + USHORT glyphCount; /* Number of glyphs with attachment + * points */ + Offset attachPoint[]; /* Array of offsets to AttachPoint + * tables--from beginning of AttachList + * table--in Coverage Index order */ +}; +DEFINE_NULL_ASSERT_SIZE (AttachList, 4); + +/* + * Ligature Caret Table + */ + +struct CaretValueFormat1 { + + friend struct CaretValue; + + private: + inline int get_caret_value (int ppem) const { + return /* TODO garbage */ coordinate / ppem; + } + + private: + USHORT caretValueFormat; /* Format identifier--format = 1 */ + SHORT coordinate; /* X or Y value, in design units */ +}; +ASSERT_SIZE (CaretValueFormat1, 4); + +struct CaretValueFormat2 { + + friend struct CaretValue; + + private: + inline int get_caret_value (int ppem) const { + return /* TODO garbage */ 0 / ppem; + } + + private: + USHORT caretValueFormat; /* Format identifier--format = 2 */ + USHORT caretValuePoint; /* Contour point index on glyph */ +}; +ASSERT_SIZE (CaretValueFormat2, 4); + +struct CaretValueFormat3 { + + friend struct CaretValue; + + private: + inline const Device& get_device (void) const { + if (HB_UNLIKELY (!deviceTable)) return NullDevice; + return *(const Device*)((const char*)this + deviceTable); + } + + inline int get_caret_value (int ppem) const { + return /* TODO garbage */ (coordinate + get_device().get_delta (ppem)) / ppem; + } + + private: + USHORT caretValueFormat; /* Format identifier--format = 3 */ + SHORT coordinate; /* X or Y value, in design units */ + Offset deviceTable; /* Offset to Device table for X or Y + * value--from beginning of CaretValue + * table */ +}; +ASSERT_SIZE (CaretValueFormat3, 6); + +struct CaretValue { + DEFINE_NON_INSTANTIABLE(CaretValue); + + unsigned int get_size (void) const { + switch (u.caretValueFormat) { + case 1: return sizeof (u.format1); + case 2: return sizeof (u.format2); + case 3: return sizeof (u.format3); + default:return sizeof (u.caretValueFormat); + } + } + + /* XXX we need access to a load-contour-point vfunc here */ + int get_caret_value (int ppem) const { + switch (u.caretValueFormat) { + case 1: return u.format1.get_caret_value(ppem); + case 2: return u.format2.get_caret_value(ppem); + case 3: return u.format3.get_caret_value(ppem); + default:return 0; + } + } + + private: + union { + USHORT caretValueFormat; /* Format identifier */ + CaretValueFormat1 format1; + CaretValueFormat2 format2; + CaretValueFormat3 format3; + /* FIXME old HarfBuzz code has a format 4 here! */ + } u; +}; +DEFINE_NULL (CaretValue, 2); + +struct LigGlyph { + + friend struct LigCaretList; + + private: + /* Caret value tables, in increasing coordinate order */ + DEFINE_OFFSET_ARRAY_TYPE (CaretValue, caretValue, caretCount); + /* TODO */ + + private: + USHORT caretCount; /* Number of CaretValues for this + * ligature (components - 1) */ + Offset caretValue[]; /* Array of offsets to CaretValue + * tables--from beginning of LigGlyph + * table--in increasing coordinate + * order */ +}; +DEFINE_NULL_ASSERT_SIZE (LigGlyph, 2); + +struct LigCaretList { + + friend struct GDEF; + + private: + /* const LigGlyph& get_lig_glyph (hb_codepoint_t glyph); */ + DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (LigGlyph, get_lig_glyph); + + private: + /* AttachPoint tables, in Coverage Index order */ + DEFINE_OFFSET_ARRAY_TYPE (LigGlyph, ligGlyph, ligGlyphCount); + DEFINE_GET_ACCESSOR (Coverage, coverage, coverage); + + private: + Offset coverage; /* Offset to Coverage table--from + * beginning of LigCaretList table */ + USHORT ligGlyphCount; /* Number of ligature glyphs */ + Offset ligGlyph[]; /* Array of offsets to LigGlyph + * tables--from beginning of + * LigCaretList table--in Coverage + * Index order */ +}; +DEFINE_NULL_ASSERT_SIZE (LigCaretList, 4); + +/* + * GDEF + */ + +struct GDEF { + static const hb_tag_t Tag = HB_TAG ('G','D','E','F'); + + static const hb_ot_layout_class_t UnclassifiedGlyph = 0; + static const hb_ot_layout_class_t BaseGlyph = 1; + static const hb_ot_layout_class_t LigatureGlyph = 2; + static const hb_ot_layout_class_t MarkGlyph = 3; + static const hb_ot_layout_class_t ComponentGlyph = 4; + + STATIC_DEFINE_GET_FOR_DATA (GDEF); + /* XXX check version here? */ + + DEFINE_GET_HAS_ACCESSOR (ClassDef, glyph_classes, glyphClassDef); + DEFINE_GET_HAS_ACCESSOR (AttachList, attach_list, attachList); + DEFINE_GET_HAS_ACCESSOR (LigCaretList, lig_caret_list, ligCaretList); + DEFINE_GET_HAS_ACCESSOR (ClassDef, mark_attachment_types, markAttachClassDef); + + inline hb_ot_layout_class_t get_glyph_class (hb_codepoint_t glyph) const { + return get_glyph_classes ().get_class (glyph); + } + + inline hb_ot_layout_class_t get_mark_attachment_type (hb_codepoint_t glyph) const { + return get_mark_attachment_types ().get_class (glyph); + } + + /* TODO get_attach and get_lig_caret */ + + private: + Fixed version; /* Version of the GDEF table--initially + * 0x00010000 */ + Offset glyphClassDef; /* Offset to class definition table + * for glyph type--from beginning of + * GDEF header (may be Null) */ + Offset attachList; /* Offset to list of glyphs with + * attachment points--from beginning + * of GDEF header (may be Null) */ + Offset ligCaretList; /* Offset to list of positioning points + * for ligature carets--from beginning + * of GDEF header (may be Null) */ + Offset markAttachClassDef; /* Offset to class definition table for + * mark attachment type--from beginning + * of GDEF header (may be Null) */ +}; +DEFINE_NULL_ASSERT_SIZE (GDEF, 12); + +#endif /* HB_OT_LAYOUT_GDEF_PRIVATE_H */ diff --git a/src/hb-ot-layout-gsub-private.h b/src/hb-ot-layout-gsub-private.h new file mode 100644 index 000000000..c8d5405b3 --- /dev/null +++ b/src/hb-ot-layout-gsub-private.h @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H +#define HB_OT_LAYOUT_GSUB_PRIVATE_H + +#include "hb-ot-layout-private.h" + +#include "hb-ot-layout-open-private.h" +#include "hb-ot-layout-gdef-private.h" + + +struct SingleSubstFormat1 { + + friend struct SingleSubst; + + private: + inline bool substitute (hb_ot_layout_t *layout, + hb_buffer_t *buffer, + unsigned int context_length, + unsigned int nesting_level_left) const { +// if (get_coverage (IN_CURGLYPH())) +// return ; + } + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + SHORT deltaGlyphID; /* Add to original GlyphID to get + * substitute GlyphID */ +}; +ASSERT_SIZE (SingleSubstFormat1, 6); + +struct SingleSubstFormat2 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 2 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT glyphCount; /* Number of GlyphIDs in the Substitute + * array */ + GlyphID substitute[]; /* Array of substitute + * GlyphIDs--ordered by Coverage Index */ +}; +ASSERT_SIZE (SingleSubstFormat2, 6); + +struct MultipleSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT sequenceCount; /* Number of Sequence table offsets in + * the Sequence array */ + Offset sequence[]; /* Array of offsets to Sequence + * tables--from beginning of + * Substitution table--ordered by + * Coverage Index */ +}; +ASSERT_SIZE (MultipleSubstFormat1, 6); + +struct Sequence { + /* TODO */ + + private: + USHORT glyphCount; /* Number of GlyphIDs in the Substitute + * array. This should always be + * greater than 0. */ + GlyphID substitute[]; /* String of GlyphIDs to substitute */ +}; +DEFINE_NULL_ASSERT_SIZE (Sequence, 2); + +struct AlternateSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT alternateSetCount; /* Number of AlternateSet tables */ + Offset alternateSet[]; /* Array of offsets to AlternateSet + * tables--from beginning of + * Substitution table--ordered by + * Coverage Index */ +}; +ASSERT_SIZE (AlternateSubstFormat1, 6); + +struct AlternateSet { + /* TODO */ + + private: + USHORT glyphCount; /* Number of GlyphIDs in the Alternate + * array */ + GlyphID alternate[]; /* Array of alternate GlyphIDs--in + * arbitrary order */ +}; +DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2); + +struct LigatureSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT ligSetCount; /* Number of LigatureSet tables */ + Offset ligatureSet[]; /* Array of offsets to LigatureSet + * tables--from beginning of + * Substitution table--ordered by + * Coverage Index */ +}; +ASSERT_SIZE (LigatureSubstFormat1, 6); + +struct LigatureSet { + /* TODO */ + + private: + USHORT ligatureCount; /* Number of Ligature tables */ + Offset ligature[]; /* Array of offsets to Ligature + * tables--from beginning of + * LigatureSet table--ordered by + * preference */ +}; +DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2); + +struct Ligature { + /* TODO */ + + private: + GlyphID ligGlyph; /* GlyphID of ligature to substitute */ + USHORT compCount; /* Number of components in the ligature */ + GlyphID component[]; /* Array of component GlyphIDs--start + * with the second component--ordered + * in writing direction */ +}; +DEFINE_NULL_ASSERT_SIZE (Ligature, 4); + +struct SubstLookupRecord { + /* TODO */ + + private: + USHORT sequenceIndex; /* Index into current glyph + * sequence--first glyph = 0 */ + USHORT lookupListIndex; /* Lookup to apply to that + * position--zero--based */ +}; +DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4); + +struct ContextSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT subRuleSetCount; /* Number of SubRuleSet tables--must + * equal GlyphCount in Coverage table */ + Offset subRuleSet[]; /* Array of offsets to SubRuleSet + * tables--from beginning of + * Substitution table--ordered by + * Coverage Index */ +}; +ASSERT_SIZE (ContextSubstFormat1, 6); + +struct SubRuleSet { + /* TODO */ + + private: + USHORT subRuleCount; /* Number of SubRule tables */ + Offset subRule[]; /* Array of offsets to SubRule + * tables--from beginning of SubRuleSet + * table--ordered by preference */ +}; +DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2); + +struct SubRule { + /* TODO */ + + private: + USHORT glyphCount; /* Total number of glyphs in input + * glyph sequence--includes the first + * glyph */ + USHORT substCount; /* Number of SubstLookupRecords */ + GlyphID input[]; /* Array of input GlyphIDs--start with + * second glyph */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order */ +}; +DEFINE_NULL_ASSERT_SIZE (SubRule, 4); + +struct ContextSubstFormat2 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 2 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Offset classDef; /* Offset to glyph ClassDef table--from + * beginning of Substitution table */ + USHORT subClassSetCnt; /* Number of SubClassSet tables */ + Offset subClassSet[]; /* Array of offsets to SubClassSet + * tables--from beginning of + * Substitution table--ordered by + * class--may be NULL */ +}; +ASSERT_SIZE (ContextSubstFormat2, 8); + +struct SubClassSet { + /* TODO */ + + private: + USHORT subClassRuleCnt; /* Number of SubClassRule tables */ + Offset subClassRule[]; /* Array of offsets to SubClassRule + * tables--from beginning of + * SubClassSet--ordered by preference */ +}; +DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2); + +struct SubClassRule { + /* TODO */ + + private: + USHORT glyphCount; /* Total number of classes + * specified for the context in the + * rule--includes the first class */ + USHORT substCount; /* Number of SubstLookupRecords */ + USHORT klass[]; /* Array of classes--beginning with the + * second class--to be matched to the + * input glyph class sequence */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order */ +}; +DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4); + +struct ContextSubstFormat3 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 3 */ + USHORT glyphCount; /* Number of glyphs in the input glyph + * sequence */ + USHORT substCount; /* Number of SubstLookupRecords */ + Offset coverage[]; /* Array of offsets to Coverage + * table--from beginning of + * Substitution table--in glyph + * sequence order */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order */ +}; +ASSERT_SIZE (ContextSubstFormat3, 6); + +struct ChainContextSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + USHORT chainSubRuleSetCount; /* Number of ChainSubRuleSet + * tables--must equal GlyphCount in + * Coverage table */ + Offset chainSubRuleSet[]; /* Array of offsets to ChainSubRuleSet + * tables--from beginning of + * Substitution table--ordered by + * Coverage Index */ +}; +ASSERT_SIZE (ChainContextSubstFormat1, 6); + +struct ChainSubRuleSet { + /* TODO */ + + private: + USHORT chainSubRuleCount; /* Number of ChainSubRule tables */ + Offset chainSubRule[]; /* Array of offsets to ChainSubRule + * tables--from beginning of + * ChainSubRuleSet table--ordered + * by preference */ +}; +DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2); + +struct ChainSubRule { + /* TODO */ + + private: + USHORT backtrackGlyphCount; /* Total number of glyphs in the + * backtrack sequence (number of + * glyphs to be matched before the + * first glyph) */ + GlyphID backtrack[]; /* Array of backtracking GlyphID's + * (to be matched before the input + * sequence) */ + USHORT inputGlyphCount; /* Total number of glyphs in the input + * sequence (includes the first glyph) */ + GlyphID input[]; /* Array of input GlyphIDs (start with + * second glyph) */ + USHORT lookaheadGlyphCount; /* Total number of glyphs in the look + * ahead sequence (number of glyphs to + * be matched after the input sequence) */ + GlyphID lookAhead[]; /* Array of lookahead GlyphID's (to be + * matched after the input sequence) */ + USHORT substCount; /* Number of SubstLookupRecords */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order) */ +}; +DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8); + +struct ChainContextSubstFormat2 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 2 */ + Offset coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Offset backtrackClassDef; /* Offset to glyph ClassDef table + * containing backtrack sequence + * data--from beginning of Substitution + * table */ + Offset inputClassDef; /* Offset to glyph ClassDef + * table containing input sequence + * data--from beginning of Substitution + * table */ + Offset lookaheadClassDef; /* Offset to glyph ClassDef table + * containing lookahead sequence + * data--from beginning of Substitution + * table */ + USHORT chainSubClassSetCnt; /* Number of ChainSubClassSet tables */ + Offset chainSubClassSet[]; /* Array of offsets to ChainSubClassSet + * tables--from beginning of + * Substitution table--ordered by input + * class--may be NULL */ +}; +ASSERT_SIZE (ChainContextSubstFormat2, 12); + +struct ChainSubClassSet { + /* TODO */ + + private: + USHORT chainSubClassRuleCnt; /* Number of ChainSubClassRule tables */ + Offset chainSubClassRule[]; /* Array of offsets + * to ChainSubClassRule + * tables--from beginning of + * ChainSubClassSet--ordered by + * preference */ +}; +DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2); + +struct ChainSubClassRule { + /* TODO */ + + private: + USHORT backtrackGlyphCount; /* Total number of glyphs in the + * backtrack sequence (number of + * glyphs to be matched before the + * first glyph) */ + USHORT backtrack[]; /* Array of backtracking classes(to be + * matched before the input sequence) */ + USHORT inputGlyphCount; /* Total number of classes in the input + * sequence (includes the first class) */ + USHORT input[]; /* Array of input classes(start with + * second class; to be matched with + * the input glyph sequence) */ + USHORT lookaheadGlyphCount; /* Total number of classes in the + * look ahead sequence (number of + * classes to be matched after the + * input sequence) */ + USHORT lookAhead[]; /* Array of lookahead classes(to be + * matched after the input sequence) */ + USHORT substCount; /* Number of SubstLookupRecords */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order) */ +}; +DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8); + +struct ChainContextSubstFormat3 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 3 */ + USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking + * sequence */ + Offset backtrackCoverage[]; /* Array of offsets to coverage tables + * in backtracking sequence, in glyph + * sequence order */ + USHORT inputGlyphCount; /* Number of glyphs in input sequence */ + Offset inputCoverage[]; /* Array of offsets to coverage + * tables in input sequence, in glyph + * sequence order */ + USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead + * sequence */ + Offset lookaheadCoverage[]; /* Array of offsets to coverage tables + * in lookahead sequence, in glyph + * sequence order */ + USHORT substCount; /* Number of SubstLookupRecords */ + SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in + * design order */ +}; +ASSERT_SIZE (ChainContextSubstFormat3, 10); + +struct ExtensionSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier. Set to 1. */ + USHORT extensionLookupType; /* Lookup type of subtable referenced + * by ExtensionOffset (i.e. the + * extension subtable). */ + ULONG extensionOffset; /* Offset to the extension subtable, + * of lookup type subtable. */ +}; +ASSERT_SIZE (ExtensionSubstFormat1, 8); + +struct ReverseChainSingleSubstFormat1 { + /* TODO */ + + private: + USHORT substFormat; /* Format identifier--format = 1 */ + Offset coverage; /* Offset to Coverage table -- from + * beginning of Substitution table */ + USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking + * sequence */ + Offset backtrackCoverage[]; /* Array of offsets to coverage tables + * in backtracking sequence, in glyph + * sequence order */ + USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead + * sequence */ + Offset lookaheadCoverage[]; /* Array of offsets to coverage tables + * in lookahead sequence, in glyph + * sequence order */ + USHORT glyphCount; /* Number of GlyphIDs in the Substitute + * array */ + GlyphID substitute[]; /* Array of substitute + * GlyphIDs--ordered by Coverage Index */ +}; +ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10); + +/* + * SubstLookup + */ + +struct SubstLookupSubTable { + DEFINE_NON_INSTANTIABLE(SubstLookupSubTable); + + friend struct SubstLookup; + + unsigned int get_size (unsigned int lookup_type) const { + switch (lookup_type) { +// case 1: return u.format1.get_size (); +// case 2: return u.format2.get_size (); + /* + case Single: + case Multiple: + case Alternate: + case Ligature: + case Context: + case ChainingContext: + case Extension: + case ReverseChainingContextSingle: + */ + default:return sizeof (LookupSubTable); + } + } + + inline bool substitute (hb_ot_layout_t *layout, + hb_buffer_t *buffer, + unsigned int context_length, + unsigned int nesting_level_left, + unsigned int lookup_type) const { + } + + private: + union { + USHORT substFormat; + CoverageFormat1 format1; + CoverageFormat2 format2; + } u; +}; + +struct SubstLookup : Lookup { + + DEFINE_NON_INSTANTIABLE(SubstLookup); + + static const unsigned int Single = 1; + static const unsigned int Multiple = 2; + static const unsigned int Alternate = 3; + static const unsigned int Ligature = 4; + static const unsigned int Context = 5; + static const unsigned int ChainingContext = 6; + static const unsigned int Extension = 7; + static const unsigned int ReverseChainingContextSingle = 8; + + inline const SubstLookupSubTable& get_subtable (unsigned int i) const { + return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i)); + } + + /* Like get_type(), but looks through extension lookups. + * Never returns SubstLookup::Extension */ + inline unsigned int get_effective_type (void) const { + unsigned int type = get_type (); + + if (HB_UNLIKELY (type == Extension)) { + /* Return lookup type of first extension subtable. + * The spec says all of them should have the same type. + * XXX check for that somehow */ +//XXX type = get_subtable(0).v.extension.get_type (); + } + + return type; + } + + inline bool is_reverse (void) const { + switch (get_effective_type ()) { + case ReverseChainingContextSingle: return true; + default: return false; + } + } + + inline bool substitute (hb_ot_layout_t *layout, + hb_buffer_t *buffer, + unsigned int context_length, + unsigned int nesting_level_left) const { + unsigned int lookup_type = get_type (); + + if (HB_UNLIKELY (nesting_level_left == 0)) + return false; + nesting_level_left--; + + for (unsigned int i = 0; i < get_subtable_count (); i++) + if (get_subtable (i).substitute (layout, buffer, + context_length, nesting_level_left, + lookup_type)) + return true; + + return false; + } +}; +DEFINE_NULL_ALIAS (SubstLookup, Lookup); + +/* + * GSUB + */ + +struct GSUB : GSUBGPOS { + static const hb_tag_t Tag = HB_TAG ('G','S','U','B'); + + STATIC_DEFINE_GET_FOR_DATA (GSUB); + /* XXX check version here? */ + + inline const SubstLookup& get_lookup (unsigned int i) const { + return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i)); + } + + +}; +DEFINE_NULL_ALIAS (GSUB, GSUBGPOS); + + +#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */ diff --git a/src/hb-ot-layout-open-private.h b/src/hb-ot-layout-open-private.h new file mode 100644 index 000000000..d5ca8105b --- /dev/null +++ b/src/hb-ot-layout-open-private.h @@ -0,0 +1,993 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_OPEN_PRIVATE_H +#define HB_OT_LAYOUT_OPEN_PRIVATE_H + +#ifndef HB_OT_LAYOUT_CC +#error "This file should only be included from hb-ot-layout.c" +#endif + +#include "hb-ot-layout-private.h" + + +#define NO_INDEX ((unsigned int) 0xFFFF) +#define NO_CONTEXT ((unsigned int) -1) + +/* + * Int types + */ + +/* XXX define these as structs of chars on machines that do not allow + * unaligned access */ +#define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN) \ + inline NAME& operator = (TYPE i) { v = BIG_ENDIAN(i); return *this; } \ + inline operator TYPE(void) const { return BIG_ENDIAN(v); } \ + inline bool operator== (NAME o) const { return v == o.v; } \ + private: TYPE v; \ + public: +#define DEFINE_INT_TYPE0(NAME, type) DEFINE_INT_TYPE1 (NAME, type, hb_be_##type) +#define DEFINE_INT_TYPE(NAME, u, w) DEFINE_INT_TYPE0 (NAME, u##int##w##_t) +#define DEFINE_INT_TYPE_STRUCT(NAME, u, w) \ + struct NAME { \ + DEFINE_INT_TYPE(NAME, u, w) \ + } + +/* + * Array types + */ + +/* get_len() is a method returning the number of items in an array-like object */ +#define DEFINE_LEN(Type, array, num) \ + inline unsigned int get_len(void) const { return num; } \ + +/* get_size() is a method returning the size in bytes of an array-like object */ +#define DEFINE_SIZE(Type, array, num) \ + inline unsigned int get_size(void) const { return sizeof (*this) + sizeof (Type) * num; } + +#define DEFINE_LEN_AND_SIZE(Type, array, num) \ + DEFINE_LEN(Type, array, num) \ + DEFINE_SIZE(Type, array, num) + +/* An array type is one that contains a variable number of objects + * as its last item. An array object is extended with len() and size() + * methods, as well as overloaded [] operator. */ +#define DEFINE_ARRAY_TYPE(Type, array, num) \ + DEFINE_INDEX_OPERATOR(Type, array, num) \ + DEFINE_LEN_AND_SIZE(Type, array, num) +#define DEFINE_INDEX_OPERATOR(Type, array, num) \ + inline const Type& operator[] (unsigned int i) const { \ + if (HB_UNLIKELY (i >= num)) return Null##Type; \ + return array[i]; \ + } + +/* An offset array type is like an array type, but it contains a table + * of offsets to the objects, relative to the beginning of the current + * object. */ +#define DEFINE_OFFSET_ARRAY_TYPE(Type, array, num) \ + DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \ + DEFINE_LEN_AND_SIZE(Offset, array, num) +#define DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \ + inline const Type& operator[] (unsigned int i) const { \ + if (HB_UNLIKELY (i >= num)) return Null##Type; \ + if (HB_UNLIKELY (!array[i])) return Null##Type; \ + return *(const Type *)((const char*)this + array[i]); \ + } + +/* A record array type is like an array type, but it contains a table + * of records to the objects. Each record has a tag, and an offset + * relative to the beginning of the current object. */ +#define DEFINE_RECORD_ARRAY_TYPE(Type, array, num) \ + DEFINE_RECORD_ACCESSOR(Type, array, num) \ + DEFINE_LEN_AND_SIZE(Record, array, num) +#define DEFINE_RECORD_ACCESSOR(Type, array, num) \ + inline const Type& operator[] (unsigned int i) const { \ + if (HB_UNLIKELY (i >= num)) return Null##Type; \ + if (HB_UNLIKELY (!array[i].offset)) return Null##Type; \ + return *(const Type *)((const char*)this + array[i].offset); \ + } \ + inline const Tag& get_tag (unsigned int i) const { \ + if (HB_UNLIKELY (i >= num)) return NullTag; \ + return array[i].tag; \ + } + + +#define DEFINE_ARRAY_INTERFACE(Type, name) \ + inline const Type& get_##name (unsigned int i) const { \ + return (*this)[i]; \ + } \ + inline unsigned int get_##name##_count (void) const { \ + return this->get_len (); \ + } +#define DEFINE_INDEX_ARRAY_INTERFACE(name) \ + inline unsigned int get_##name##_index (unsigned int i) const { \ + if (HB_UNLIKELY (i >= get_len ())) return NO_INDEX; \ + return (*this)[i]; \ + } \ + inline unsigned int get_##name##_count (void) const { \ + return get_len (); \ + } + + +/* + * List types + */ + +#define DEFINE_LIST_ARRAY(Type, name) \ + inline const Type##List& get_##name##_list (void) const { \ + if (HB_UNLIKELY (!name##List)) return Null##Type##List; \ + return *(const Type##List *)((const char*)this + name##List); \ + } + +#define DEFINE_LIST_INTERFACE(Type, name) \ + inline const Type& get_##name (unsigned int i) const { \ + return get_##name##_list ()[i]; \ + } \ + inline unsigned int get_##name##_count (void) const { \ + return get_##name##_list ().get_len (); \ + } + +/* + * Tag types + */ + +#define DEFINE_TAG_ARRAY_INTERFACE(Type, name) \ + DEFINE_ARRAY_INTERFACE (Type, name); \ + inline const Tag& get_##name##_tag (unsigned int i) const { \ + return (*this)[i].tag; \ + } +#define DEFINE_TAG_LIST_INTERFACE(Type, name) \ + DEFINE_LIST_INTERFACE (Type, name); \ + inline const Tag& get_##name##_tag (unsigned int i) const { \ + return get_##name##_list ().get_tag (i); \ + } + +#define DEFINE_TAG_FIND_INTERFACE(Type, name) \ + inline bool find_##name##_index (hb_tag_t tag, unsigned int *name##_index) const { \ + const Tag t = tag; \ + for (unsigned int i = 0; i < get_##name##_count (); i++) { \ + if (t == get_##name##_tag (i)) { \ + if (name##_index) *name##_index = i; \ + return true; \ + } \ + } \ + if (name##_index) *name##_index = NO_INDEX; \ + return false; \ + } \ + inline const Type& get_##name##_by_tag (hb_tag_t tag) const { \ + unsigned int i; \ + if (find_##name##_index (tag, &i)) \ + return get_##name (i); \ + else \ + return Null##Type; \ + } + +/* + * Class features + */ + +/* makes class uninstantiable. should be used for union classes that don't + * contain any complete type */ +#define DEFINE_NON_INSTANTIABLE(Type) \ + protected: inline Type() {} /* cannot be instantiated */ \ + public: + +// TODO use a global nul-array for most Null's +/* defines Null##Type as a safe nil instance of Type */ +#define DEFINE_NULL_DATA(Type, size, data) \ + static const unsigned char Null##Type##Data[size] = data; \ + DEFINE_NULL_ALIAS (Type, Type) +#define DEFINE_NULL(Type, size) \ + DEFINE_NULL_DATA(Type, size, "") +#define DEFINE_NULL_ASSERT_SIZE(Type, size) \ + DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, "") +#define DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, data) \ + ASSERT_SIZE (Type, size); \ + DEFINE_NULL_DATA (Type, size, data) +#define DEFINE_NULL_ALIAS(NewType, OldType) \ + /* XXX static */ const NewType &Null##NewType = *(NewType *)Null##OldType##Data + +/* get_for_data() is a static class method returning a reference to an + * instance of Type located at the input data location. It's just a + * fancy, NULL-safe, cast! */ +#define STATIC_DEFINE_GET_FOR_DATA(Type) \ + static inline const Type& get_for_data (const char *data) { \ + extern const Type &Null##Type; \ + if (HB_UNLIKELY (data == NULL)) return Null##Type; \ + return *(const Type*)data; \ + } \ + static inline Type& get_for_data (char *data) { \ + return *(Type*)data; \ + } + + +#define DEFINE_GET_ACCESSOR(Type, name, Name) \ + inline const Type& get_##name (void) const { \ + if (HB_UNLIKELY (!Name)) return Null##Type; \ + return *(const Type*)((const char*)this + Name); \ + } +#define DEFINE_GET_HAS_ACCESSOR(Type, name, Name) \ + DEFINE_GET_ACCESSOR (Type, name, Name); \ + inline bool has_##name (void) const { \ + return Name != 0; \ + } + + + + +/* + * + * The OpenType Font File + * + */ + + + +/* + * Data Types + */ + + +/* "The following data types are used in the OpenType font file. + * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ + + +DEFINE_INT_TYPE_STRUCT (BYTE, u, 8); /* 8-bit unsigned integer. */ +DEFINE_NULL_ASSERT_SIZE (BYTE, 1); +DEFINE_INT_TYPE_STRUCT (CHAR, , 8); /* 8-bit signed integer. */ +DEFINE_NULL_ASSERT_SIZE (CHAR, 1); +DEFINE_INT_TYPE_STRUCT (USHORT, u, 16); /* 16-bit unsigned integer. */ +DEFINE_NULL_ASSERT_SIZE (USHORT, 2); +DEFINE_INT_TYPE_STRUCT (SHORT, , 16); /* 16-bit signed integer. */ +DEFINE_NULL_ASSERT_SIZE (SHORT, 2); +DEFINE_INT_TYPE_STRUCT (ULONG, u, 32); /* 32-bit unsigned integer. */ +DEFINE_NULL_ASSERT_SIZE (ULONG, 4); +DEFINE_INT_TYPE_STRUCT (LONG, , 32); /* 32-bit signed integer. */ +DEFINE_NULL_ASSERT_SIZE (LONG, 4); + +/* Date represented in number of seconds since 12:00 midnight, January 1, + * 1904. The value is represented as a signed 64-bit integer. */ +DEFINE_INT_TYPE_STRUCT (LONGDATETIME, , 64); + +/* 32-bit signed fixed-point number (16.16) */ +struct Fixed { + inline Fixed& operator = (int32_t v) { i = (int16_t) (v >> 16); f = (uint16_t) v; return *this; } \ + inline operator int32_t(void) const { return (((int32_t) i) << 16) + (uint16_t) f; } \ + inline bool operator== (Fixed o) const { return i == o.i && f == o.f; } \ + + inline operator double(void) const { return (uint32_t) this / 65536.; } + inline int16_t int_part (void) const { return i; } + inline uint16_t frac_part (void) const { return f; } + + private: + SHORT i; + USHORT f; +}; +DEFINE_NULL_ASSERT_SIZE (Fixed, 4); + +/* Smallest measurable distance in the em space. */ +struct FUNIT; + +/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ +struct FWORD : SHORT { +}; +DEFINE_NULL_ASSERT_SIZE (FWORD, 2); + +/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ +struct UFWORD : USHORT { +}; +DEFINE_NULL_ASSERT_SIZE (UFWORD, 2); + +/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ +struct F2DOT14 : SHORT { + inline operator double() const { return (uint32_t) this / 16384.; } +}; +DEFINE_NULL_ASSERT_SIZE (F2DOT14, 2); + +/* Array of four uint8s (length = 32 bits) used to identify a script, language + * system, feature, or baseline */ +struct Tag { + inline Tag (void) { v[0] = v[1] = v[2] = v[3] = 0; } + inline Tag (uint32_t v) { (ULONG&)(*this) = v; } + inline Tag (const char *c) { v[0] = c[0]; v[1] = c[1]; v[2] = c[2]; v[3] = c[3]; } + inline bool operator== (Tag o) const { return v[0]==o.v[0]&&v[1]==o.v[1]&&v[2]==o.v[2]&&v[3]==o.v[3]; } + inline bool operator== (const char *c) const { return v[0]==c[0]&&v[1]==c[1]&&v[2]==c[2]&&v[3]==c[3]; } + inline bool operator== (uint32_t i) const { return i == (uint32_t) *this; } + inline operator uint32_t(void) const { return (v[0]<<24)+(v[1]<<16) +(v[2]<<8)+v[3]; } + /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ + inline operator const char* (void) const { return (const char *)this; } + inline operator char* (void) { return (char *)this; } + + private: + char v[4]; +}; +ASSERT_SIZE (Tag, 4); +DEFINE_NULL_DATA (Tag, 5, " "); + +/* Glyph index number, same as uint16 (length = 16 bits) */ +DEFINE_INT_TYPE_STRUCT (GlyphID, u, 16); +DEFINE_NULL_ASSERT_SIZE (GlyphID, 2); + +/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */ +DEFINE_INT_TYPE_STRUCT (Offset, u, 16); +DEFINE_NULL_ASSERT_SIZE (Offset, 2); + +/* CheckSum */ +struct CheckSum : ULONG { + static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) { + uint32_t Sum = 0L; + ULONG *EndPtr = Table+((Length+3) & ~3) / sizeof(ULONG); + + while (Table < EndPtr) + Sum += *Table++; + return Sum; + } +}; +DEFINE_NULL_ASSERT_SIZE (CheckSum, 4); + + +/* + * Version Numbers + */ + +struct USHORT_Version : USHORT { +}; +DEFINE_NULL_ASSERT_SIZE (USHORT_Version, 2); + +struct Fixed_Version : Fixed { + inline int16_t major (void) const { return this->int_part(); } + inline int16_t minor (void) const { return this->frac_part(); } +}; +DEFINE_NULL_ASSERT_SIZE (Fixed_Version, 4); + + +/* + * Organization of an OpenType Font + */ + +struct OpenTypeFontFile; +struct OffsetTable; +struct TTCHeader; + +typedef struct TableDirectory { + + friend struct OpenTypeFontFile; + friend struct OffsetTable; + + inline bool is_null (void) const { return length == 0; } + inline const Tag& get_tag (void) const { return tag; } + inline unsigned long get_checksum (void) const { return checkSum; } + inline unsigned long get_offset (void) const { return offset; } + inline unsigned long get_length (void) const { return length; } + + private: + Tag tag; /* 4-byte identifier. */ + CheckSum checkSum; /* CheckSum for this table. */ + ULONG offset; /* Offset from beginning of TrueType font + * file. */ + ULONG length; /* Length of this table. */ +} OpenTypeTable; +DEFINE_NULL_ASSERT_SIZE (TableDirectory, 16); +DEFINE_NULL_ALIAS (OpenTypeTable, TableDirectory); + +typedef struct OffsetTable { + + friend struct OpenTypeFontFile; + friend struct TTCHeader; + + DEFINE_TAG_ARRAY_INTERFACE (OpenTypeTable, table); /* get_table_count(), get_table(i), get_table_tag(i) */ + DEFINE_TAG_FIND_INTERFACE (OpenTypeTable, table); /* find_table_index(tag), get_table_by_tag(tag) */ + + private: + /* OpenTypeTables, in no particular order */ + DEFINE_ARRAY_TYPE (TableDirectory, tableDir, numTables); + + private: + Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ + USHORT numTables; /* Number of tables. */ + USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */ + USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */ + USHORT rangeShift; /* NumTables x 16-searchRange. */ + TableDirectory tableDir[]; /* TableDirectory entries. numTables items */ +} OpenTypeFontFace; +DEFINE_NULL_ASSERT_SIZE (OffsetTable, 12); +DEFINE_NULL_ALIAS (OpenTypeFontFace, OffsetTable); + +/* + * TrueType Collections + */ + +struct TTCHeader { + + friend struct OpenTypeFontFile; + + private: + /* OpenTypeFontFaces, in no particular order */ + DEFINE_OFFSET_ARRAY_TYPE (OffsetTable, offsetTable, numFonts); + /* XXX check version here? */ + + private: + Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ + ULONG version; /* Version of the TTC Header (1.0 or 2.0), + * 0x00010000 or 0x00020000 */ + ULONG numFonts; /* Number of fonts in TTC */ + ULONG offsetTable[]; /* Array of offsets to the OffsetTable for each font + * from the beginning of the file */ +}; +DEFINE_NULL_ASSERT_SIZE (TTCHeader, 12); + + +/* + * OpenType Font File + */ + +struct OpenTypeFontFile { + DEFINE_NON_INSTANTIABLE(OpenTypeFontFile); + static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); + static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); + static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); + + STATIC_DEFINE_GET_FOR_DATA (OpenTypeFontFile); + + DEFINE_ARRAY_INTERFACE (OpenTypeFontFace, face); /* get_face_count(), get_face(i) */ + + inline const Tag& get_tag (void) const { return tag; } + + /* This is how you get a table */ + inline const char* get_table_data (const OpenTypeTable& table) const { + return (*this)[table]; + } + inline char* get_table_data (const OpenTypeTable& table) { + return (*this)[table]; + } + + private: + inline const char* operator[] (const OpenTypeTable& table) const { + if (G_UNLIKELY (table.offset == 0)) return NULL; + return ((const char*)this) + table.offset; + } + inline char* operator[] (const OpenTypeTable& table) { + if (G_UNLIKELY (table.offset == 0)) return NULL; + return ((char*)this) + table.offset; + } + + /* Array interface sans get_size() */ + unsigned int get_len (void) const { + switch (tag) { + default: return 0; + case TrueTypeTag: case CFFTag: return 1; + case TTCTag: return ((const TTCHeader&)*this).get_len(); + } + } + const OpenTypeFontFace& operator[] (unsigned int i) const { + if (HB_UNLIKELY (i >= get_len ())) return NullOpenTypeFontFace; + switch (tag) { + default: case TrueTypeTag: case CFFTag: return (const OffsetTable&)*this; + case TTCTag: return ((const TTCHeader&)*this)[i]; + } + } + + private: + Tag tag; /* 4-byte identifier. */ +}; +DEFINE_NULL_ASSERT_SIZE (OpenTypeFontFile, 4); + + + +/* + * + * OpenType Layout Common Table Formats + * + */ + +/* + * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList + */ + +typedef struct Record { + Tag tag; /* 4-byte Tag identifier */ + Offset offset; /* Offset from beginning of object holding + * the Record */ +} ScriptRecord, LangSysRecord, FeatureRecord; +DEFINE_NULL_ASSERT_SIZE (Record, 6); + +struct LangSys { + + DEFINE_INDEX_ARRAY_INTERFACE (feature); + + inline const bool has_required_feature (void) const { + return reqFeatureIndex != 0xffff; + } + /* Returns NO_INDEX if none */ + inline int get_required_feature_index (void) const { + if (reqFeatureIndex == 0xffff) + return NO_INDEX; + return reqFeatureIndex;; + } + + private: + /* Feature indices, in no particular order */ + DEFINE_ARRAY_TYPE (USHORT, featureIndex, featureCount); + + private: + Offset lookupOrder; /* = Null (reserved for an offset to a + * reordering table) */ + USHORT reqFeatureIndex;/* Index of a feature required for this + * language system--if no required features + * = 0xFFFF */ + USHORT featureCount; /* Number of FeatureIndex values for this + * language system--excludes the required + * feature */ + USHORT featureIndex[]; /* Array of indices into the FeatureList--in + * arbitrary order. featureCount entires long */ +}; +DEFINE_NULL_ASSERT_SIZE_DATA (LangSys, 6, "\0\0\xFF\xFF"); + +struct Script { + + /* DEFINE_ARRAY_INTERFACE (LangSys, lang_sys) but handling defaultLangSys */ + + inline const LangSys& get_lang_sys (unsigned int i) const { + if (i == NO_INDEX) return get_default_lang_sys (); + return (*this)[i]; + } + inline unsigned int get_lang_sys_count (void) const { + return this->get_len (); + } + + inline const Tag& get_lang_sys_tag (unsigned int i) const { + return get_tag (i); + } + + // LONGTERMTODO bsearch + DEFINE_TAG_FIND_INTERFACE (LangSys, lang_sys); /* find_lang_sys_index (), get_lang_sys_by_tag (tag) */ + + inline const bool has_default_lang_sys (void) const { + return defaultLangSys != 0; + } + inline const LangSys& get_default_lang_sys (void) const { + if (HB_UNLIKELY (!defaultLangSys)) + return NullLangSys; + return *(LangSys*)((const char*)this + defaultLangSys); + } + + private: + /* LangSys', in sorted alphabetical tag order */ + DEFINE_RECORD_ARRAY_TYPE (LangSys, langSysRecord, langSysCount); + + private: + Offset defaultLangSys; /* Offset to DefaultLangSys table--from + * beginning of Script table--may be Null */ + USHORT langSysCount; /* Number of LangSysRecords for this script-- + * excluding the DefaultLangSys */ + LangSysRecord langSysRecord[];/* Array of LangSysRecords--listed + * alphabetically by LangSysTag */ +}; +DEFINE_NULL_ASSERT_SIZE (Script, 4); + +struct ScriptList { + + friend struct GSUBGPOS; + +private: + /* Scripts, in sorted alphabetical tag order */ + DEFINE_RECORD_ARRAY_TYPE (Script, scriptRecord, scriptCount); + +private: + USHORT scriptCount; /* Number of ScriptRecords */ + ScriptRecord scriptRecord[]; /* Array of ScriptRecords--listed alphabetically + * by ScriptTag */ +}; +DEFINE_NULL_ASSERT_SIZE (ScriptList, 2); + +struct Feature { + + DEFINE_INDEX_ARRAY_INTERFACE (lookup); /* get_lookup_count(), get_lookup_index(i) */ + + private: + /* LookupList indices, in no particular order */ + DEFINE_ARRAY_TYPE (USHORT, lookupIndex, lookupCount); + + /* TODO: implement get_feature_parameters() */ + /* TODO: implement FeatureSize and other special features? */ + + private: + Offset featureParams; /* Offset to Feature Parameters table (if one + * has been defined for the feature), relative + * to the beginning of the Feature Table; = Null + * if not required */ + USHORT lookupCount; /* Number of LookupList indices for this + * feature */ + USHORT lookupIndex[]; /* Array of LookupList indices for this + * feature--zero-based (first lookup is + * LookupListIndex = 0) */ +}; +DEFINE_NULL_ASSERT_SIZE (Feature, 4); + +struct FeatureList { + + friend struct GSUBGPOS; + + private: + /* Feature indices, in sorted alphabetical tag order */ + DEFINE_RECORD_ARRAY_TYPE (Feature, featureRecord, featureCount); + + private: + USHORT featureCount; /* Number of FeatureRecords in this table */ + FeatureRecord featureRecord[];/* Array of FeatureRecords--zero-based (first + * feature has FeatureIndex = 0)--listed + * alphabetically by FeatureTag */ +}; +DEFINE_NULL_ASSERT_SIZE (FeatureList, 2); + +struct LookupFlag : USHORT { + static const unsigned int RightToLeft = 0x0001u; + static const unsigned int IgnoreBaseGlyphs = 0x0002u; + static const unsigned int IgnoreLigatures = 0x0004u; + static const unsigned int IgnoreMarks = 0x0008u; + static const unsigned int Reserved = 0x00F0u; + static const unsigned int MarkAttachmentType = 0xFF00u; +}; +DEFINE_NULL_ASSERT_SIZE (LookupFlag, 2); + +struct LookupSubTable { + DEFINE_NON_INSTANTIABLE(LookupSubTable); + + private: + USHORT format; /* Subtable format. Different for GSUB and GPOS */ +}; +DEFINE_NULL_ASSERT_SIZE (LookupSubTable, 2); + + +struct Lookup { + DEFINE_NON_INSTANTIABLE(Lookup); + + DEFINE_ARRAY_INTERFACE (LookupSubTable, subtable); /* get_subtable_count(), get_subtable(i) */ + + inline bool is_right_to_left (void) const { return lookupFlag & LookupFlag::RightToLeft; } + inline bool ignore_base_glyphs(void) const { return lookupFlag & LookupFlag::IgnoreBaseGlyphs; } + inline bool ignore_ligatures (void) const { return lookupFlag & LookupFlag::IgnoreLigatures; } + inline bool ignore_marks (void) const { return lookupFlag & LookupFlag::IgnoreMarks; } + inline bool get_mark_attachment_type (void) const { return lookupFlag & LookupFlag::MarkAttachmentType; } + + inline unsigned int get_type (void) const { return lookupType; } + inline unsigned int get_flag (void) const { return lookupFlag; } + + private: + /* SubTables, in the desired order */ + DEFINE_OFFSET_ARRAY_TYPE (LookupSubTable, subTableOffset, subTableCount); + + protected: + USHORT lookupType; /* Different enumerations for GSUB and GPOS */ + USHORT lookupFlag; /* Lookup qualifiers */ + USHORT subTableCount; /* Number of SubTables for this lookup */ + Offset subTableOffset[];/* Array of offsets to SubTables-from + * beginning of Lookup table */ +}; +DEFINE_NULL_ASSERT_SIZE (Lookup, 6); + +struct LookupList { + + friend struct GSUBGPOS; + + private: + /* Lookup indices, in sorted alphabetical tag order */ + DEFINE_OFFSET_ARRAY_TYPE (Lookup, lookupOffset, lookupCount); + + private: + USHORT lookupCount; /* Number of lookups in this table */ + Offset lookupOffset[]; /* Array of offsets to Lookup tables--from + * beginning of LookupList--zero based (first + * lookup is Lookup index = 0) */ +}; +DEFINE_NULL_ASSERT_SIZE (LookupList, 2); + +/* + * Coverage Table + */ + +struct CoverageFormat1 { + + friend struct Coverage; + + private: + /* GlyphIDs, in sorted numerical order */ + DEFINE_ARRAY_TYPE (GlyphID, glyphArray, glyphCount); + + inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const { + GlyphID gid; + if (HB_UNLIKELY (glyph_id > 65535)) + return -1; + gid = glyph_id; + // TODO: bsearch + for (unsigned int i = 0; i < glyphCount; i++) + if (gid == glyphArray[i]) + return i; + return -1; + } + + private: + USHORT coverageFormat; /* Format identifier--format = 1 */ + USHORT glyphCount; /* Number of glyphs in the GlyphArray */ + GlyphID glyphArray[]; /* Array of GlyphIDs--in numerical order */ +}; +ASSERT_SIZE (CoverageFormat1, 4); + +struct CoverageRangeRecord { + + friend struct CoverageFormat2; + + private: + inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const { + if (glyph_id >= start && glyph_id <= end) + return startCoverageIndex + (glyph_id - start); + return -1; + } + + private: + GlyphID start; /* First GlyphID in the range */ + GlyphID end; /* Last GlyphID in the range */ + USHORT startCoverageIndex; /* Coverage Index of first GlyphID in + * range */ +}; +DEFINE_NULL_ASSERT_SIZE_DATA (CoverageRangeRecord, 6, "\001"); + +struct CoverageFormat2 { + + friend struct Coverage; + + private: + /* CoverageRangeRecords, in sorted numerical start order */ + DEFINE_ARRAY_TYPE (CoverageRangeRecord, rangeRecord, rangeCount); + + inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const { + // TODO: bsearch + for (unsigned int i = 0; i < rangeCount; i++) { + int coverage = rangeRecord[i].get_coverage (glyph_id); + if (coverage >= 0) + return coverage; + } + return -1; + } + + private: + USHORT coverageFormat; /* Format identifier--format = 2 */ + USHORT rangeCount; /* Number of CoverageRangeRecords */ + CoverageRangeRecord rangeRecord[]; /* Array of glyph ranges--ordered by + * Start GlyphID. rangeCount entries + * long */ +}; +ASSERT_SIZE (CoverageFormat2, 4); + +struct Coverage { + DEFINE_NON_INSTANTIABLE(Coverage); + + unsigned int get_size (void) const { + switch (u.coverageFormat) { + case 1: return u.format1.get_size (); + case 2: return u.format2.get_size (); + default:return sizeof (u.coverageFormat); + } + } + + hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const { + switch (u.coverageFormat) { + case 1: return u.format1.get_coverage(glyph_id); + case 2: return u.format2.get_coverage(glyph_id); + default:return -1; + } + } + + private: + union { + USHORT coverageFormat; /* Format identifier */ + CoverageFormat1 format1; + CoverageFormat2 format2; + } u; +}; +DEFINE_NULL (Coverage, 2); + +/* + * Class Definition Table + */ + +struct ClassDefFormat1 { + + friend struct ClassDef; + + private: + /* GlyphIDs, in sorted numerical order */ + DEFINE_ARRAY_TYPE (USHORT, classValueArray, glyphCount); + + inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const { + if (glyph_id >= startGlyph && glyph_id - startGlyph < glyphCount) + return classValueArray[glyph_id - startGlyph]; + return 0; + } + + private: + USHORT classFormat; /* Format identifier--format = 1 */ + GlyphID startGlyph; /* First GlyphID of the classValueArray */ + USHORT glyphCount; /* Size of the classValueArray */ + USHORT classValueArray[]; /* Array of Class Values--one per GlyphID */ +}; +ASSERT_SIZE (ClassDefFormat1, 6); + +struct ClassRangeRecord { + + friend struct ClassDefFormat2; + + private: + inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const { + if (glyph_id >= start && glyph_id <= end) + return classValue; + return 0; + } + + private: + GlyphID start; /* First GlyphID in the range */ + GlyphID end; /* Last GlyphID in the range */ + USHORT classValue; /* Applied to all glyphs in the range */ +}; +DEFINE_NULL_ASSERT_SIZE_DATA (ClassRangeRecord, 6, "\001"); + +struct ClassDefFormat2 { + + friend struct ClassDef; + + private: + /* ClassRangeRecords, in sorted numerical start order */ + DEFINE_ARRAY_TYPE (ClassRangeRecord, rangeRecord, rangeCount); + + inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const { + // TODO: bsearch + for (unsigned int i = 0; i < rangeCount; i++) { + int classValue = rangeRecord[i].get_class (glyph_id); + if (classValue > 0) + return classValue; + } + return 0; + } + + private: + USHORT classFormat; /* Format identifier--format = 2 */ + USHORT rangeCount; /* Number of Number of ClassRangeRecords */ + ClassRangeRecord rangeRecord[]; /* Array of glyph ranges--ordered by + * Start GlyphID */ +}; +ASSERT_SIZE (ClassDefFormat2, 4); + +struct ClassDef { + DEFINE_NON_INSTANTIABLE(ClassDef); + + unsigned int get_size (void) const { + switch (u.classFormat) { + case 1: return u.format1.get_size (); + case 2: return u.format2.get_size (); + default:return sizeof (u.classFormat); + } + } + + hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const { + switch (u.classFormat) { + case 1: return u.format1.get_class(glyph_id); + case 2: return u.format2.get_class(glyph_id); + default:return 0; + } + } + + private: + union { + USHORT classFormat; /* Format identifier */ + ClassDefFormat1 format1; + ClassDefFormat2 format2; + } u; +}; +DEFINE_NULL (ClassDef, 2); + +/* + * Device Tables + */ + +struct Device { + DEFINE_NON_INSTANTIABLE(Device); + + unsigned int get_size (void) const { + int count = endSize - startSize + 1; + if (count < 0) count = 0; + switch (deltaFormat) { + case 1: return sizeof (Device) + sizeof (USHORT) * ((count+7)/8); + case 2: return sizeof (Device) + sizeof (USHORT) * ((count+3)/4); + case 3: return sizeof (Device) + sizeof (USHORT) * ((count+1)/2); + default:return sizeof (Device); + } + } + + int get_delta (int ppem_size) const { + if (ppem_size >= startSize && ppem_size <= endSize && + deltaFormat >= 1 && deltaFormat <= 3) { + int s = ppem_size - startSize; + int f = deltaFormat; + + uint16_t byte = deltaValue[s >> (4 - f)]; + uint16_t bits = byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)); + uint16_t mask = 0xFFFF >> (16 - (1 << f)); + + int delta = bits & mask; + + if (delta >= ((mask + 1) >> 1)) + delta -= mask + 1; + + return delta; + } + return 0; + } + + private: + USHORT startSize; /* Smallest size to correct--in ppem */ + USHORT endSize; /* Largest size to correct--in ppem */ + USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 */ + USHORT deltaValue[]; /* Array of compressed data */ +}; +DEFINE_NULL_ASSERT_SIZE (Device, 6); + +/* + * GSUB/GPOS Common + */ + +struct GSUBGPOS { + static const hb_tag_t GSUBTag = HB_TAG ('G','S','U','B'); + static const hb_tag_t GPOSTag = HB_TAG ('G','P','O','S'); + + STATIC_DEFINE_GET_FOR_DATA (GSUBGPOS); + /* XXX check version here? */ + + DEFINE_TAG_LIST_INTERFACE (Script, script ); /* get_script_count (), get_script (i), get_script_tag (i) */ + DEFINE_TAG_LIST_INTERFACE (Feature, feature); /* get_feature_count(), get_feature(i), get_feature_tag(i) */ + DEFINE_LIST_INTERFACE (Lookup, lookup ); /* get_lookup_count (), get_lookup (i) */ + + // LONGTERMTODO bsearch + DEFINE_TAG_FIND_INTERFACE (Script, script ); /* find_script_index (), get_script_by_tag (tag) */ + DEFINE_TAG_FIND_INTERFACE (Feature, feature); /* find_feature_index(), get_feature_by_tag(tag) */ + + private: + DEFINE_LIST_ARRAY(Script, script); + DEFINE_LIST_ARRAY(Feature, feature); + DEFINE_LIST_ARRAY(Lookup, lookup); + + private: + Fixed_Version version; /* Version of the GSUB/GPOS table--initially set + * to 0x00010000 */ + Offset scriptList; /* Offset to ScriptList table--from beginning of + * GSUB/GPOS table */ + Offset featureList; /* Offset to FeatureList table--from beginning of + * GSUB/GPOS table */ + Offset lookupList; /* Offset to LookupList table--from beginning of + * GSUB/GPOS table */ +}; +DEFINE_NULL_ASSERT_SIZE (GSUBGPOS, 10); + +#endif /* HB_OT_LAYOUT_OPEN_PRIVATE_H */ diff --git a/src/hb-ot-layout-private.h b/src/hb-ot-layout-private.h new file mode 100644 index 000000000..a1be8aaf2 --- /dev/null +++ b/src/hb-ot-layout-private.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_PRIVATE_H +#define HB_OT_LAYOUT_PRIVATE_H + +#include "hb-private.h" +#include "hb-ot-layout.h" + +/* XXX */ +#include "harfbuzz-buffer.h" + + +typedef uint16_t hb_ot_layout_class_t; +typedef uint16_t hb_ot_layout_glyph_properties_t; +typedef uint16_t hb_ot_layout_lookup_flags_t; +typedef int hb_ot_layout_coverage_t; /* -1 is not covered, >= 0 otherwise */ + +/* XXX #define HB_OT_LAYOUT_INTERNAL static */ +#define HB_OT_LAYOUT_INTERNAL + +HB_BEGIN_DECLS(); + +/* + * GDEF + */ + +HB_OT_LAYOUT_INTERNAL hb_bool_t +_hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout); + +HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t +_hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout, + hb_codepoint_t glyph); + +HB_OT_LAYOUT_INTERNAL hb_bool_t +_hb_ot_layout_check_glyph_properties (hb_ot_layout_t *layout, + HB_GlyphItem gitem, + hb_ot_layout_lookup_flags_t lookup_flags, + hb_ot_layout_glyph_properties_t *property); + +HB_END_DECLS(); + +#endif /* HB_OT_LAYOUT_PRIVATE_H */ diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc new file mode 100644 index 000000000..01923db48 --- /dev/null +++ b/src/hb-ot-layout.cc @@ -0,0 +1,565 @@ +/* + * Copyright (C) 1998-2004 David Turner and Werner Lemberg + * Copyright (C) 2006 Behdad Esfahbod + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#define HB_OT_LAYOUT_CC + +#include "hb-ot-layout.h" +#include "hb-ot-layout-private.h" + +#include "hb-ot-layout-open-private.h" +#include "hb-ot-layout-gdef-private.h" +#include "hb-ot-layout-gsub-private.h" + +/* XXX */ +#include "harfbuzz-buffer-private.h" + +#include +#include + + +struct _hb_ot_layout_t { + const GDEF *gdef; + const GSUB *gsub; + const /*XXX*/GSUBGPOS *gpos; + + struct { + unsigned char *klasses; + unsigned int len; + } new_gdef; + + /* TODO add max-nesting-level here? */ +}; + +hb_ot_layout_t * +hb_ot_layout_create (void) +{ + hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); + + layout->gdef = &NullGDEF; + layout->gsub = &NullGSUB; + layout->gpos = &/*XXX*/NullGSUBGPOS; + + return layout; +} + +hb_ot_layout_t * +hb_ot_layout_create_for_data (const char *font_data, + int face_index) +{ + hb_ot_layout_t *layout; + + if (HB_UNLIKELY (font_data == NULL)) + return hb_ot_layout_create (); + + layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); + + const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data); + const OpenTypeFontFace &face = font.get_face (face_index); + + layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table_by_tag (GDEF::Tag))); + layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table_by_tag (GSUB::Tag))); + layout->gpos = &/*XXX*/GSUBGPOS::get_for_data (font.get_table_data (face.get_table_by_tag (/*XXX*/GSUBGPOS::GPOSTag))); + + return layout; +} + +void +hb_ot_layout_destroy (hb_ot_layout_t *layout) +{ + free (layout); +} + +/* + * GDEF + */ + +hb_bool_t +hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout) +{ + return layout->gdef->has_glyph_classes (); +} + +HB_OT_LAYOUT_INTERNAL hb_bool_t +_hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout) +{ + return layout->new_gdef.len > 0; +} + +HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t +_hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout, + hb_codepoint_t glyph) +{ + hb_ot_layout_class_t klass; + + /* TODO old harfbuzz doesn't always parse mark attachments as it says it was + * introduced without a version bump, so it may not be safe */ + klass = layout->gdef->get_mark_attachment_type (glyph); + if (klass) + return klass << 8; + + klass = layout->gdef->get_glyph_class (glyph); + + if (!klass && glyph < layout->new_gdef.len) + klass = layout->new_gdef.klasses[glyph]; + + switch (klass) { + default: + case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; + case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; + case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE; + case GDEF::MarkGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_MARK; + case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT; + } +} + +HB_OT_LAYOUT_INTERNAL hb_bool_t +_hb_ot_layout_check_glyph_properties (hb_ot_layout_t *layout, + HB_GlyphItem gitem, + hb_ot_layout_lookup_flags_t lookup_flags, + hb_ot_layout_glyph_properties_t *property) +{ + hb_ot_layout_glyph_class_t basic_glyph_class; + hb_ot_layout_glyph_properties_t desired_attachment_class; + + if (gitem->gproperties == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN) + { + gitem->gproperties = *property = _hb_ot_layout_get_glyph_properties (layout, gitem->gindex); + if (gitem->gproperties == HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED) + return false; + } + + *property = gitem->gproperties; + + /* If the glyph was found in the MarkAttachmentClass table, + * then that class value is the high byte of the result, + * otherwise the low byte contains the basic type of the glyph + * as defined by the GlyphClassDef table. + */ + if (*property & LookupFlag::MarkAttachmentType) + basic_glyph_class = HB_OT_LAYOUT_GLYPH_CLASS_MARK; + else + basic_glyph_class = (hb_ot_layout_glyph_class_t) *property; + + /* Not covered, if, for example, basic_glyph_class + * is HB_GDEF_LIGATURE and lookup_flags includes LookupFlags::IgnoreLigatures + */ + if (lookup_flags & basic_glyph_class) + return false; + + /* The high byte of lookup_flags has the meaning + * "ignore marks of attachment type different than + * the attachment type specified." + */ + desired_attachment_class = lookup_flags & LookupFlag::MarkAttachmentType; + if (desired_attachment_class) + { + if (basic_glyph_class == HB_OT_LAYOUT_GLYPH_CLASS_MARK && + *property != desired_attachment_class ) + return false; + } + + return true; +} + + +hb_ot_layout_glyph_class_t +hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout, + hb_codepoint_t glyph) +{ + hb_ot_layout_glyph_properties_t properties; + hb_ot_layout_class_t klass; + + properties = _hb_ot_layout_get_glyph_properties (layout, glyph); + + if (properties & 0xFF00) + return HB_OT_LAYOUT_GLYPH_CLASS_MARK; + + return (hb_ot_layout_glyph_class_t) properties; +} + +void +hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout, + hb_codepoint_t glyph, + hb_ot_layout_glyph_class_t klass) +{ + /* TODO optimize this, similar to old harfbuzz code for example */ + + hb_ot_layout_class_t gdef_klass; + int len = layout->new_gdef.len; + + if (glyph >= len) { + int new_len; + unsigned char *new_klasses; + + new_len = len == 0 ? 120 : 2 * len; + if (new_len > 65535) + new_len = 65535; + new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char)); + + if (G_UNLIKELY (!new_klasses)) + return; + + memset (new_klasses + len, 0, new_len - len); + + layout->new_gdef.klasses = new_klasses; + layout->new_gdef.len = new_len; + } + + switch (klass) { + default: + case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break; + case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break; + case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break; + case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break; + case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break; + } + + layout->new_gdef.klasses[glyph] = gdef_klass; + return; +} + +void +hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout, + uint16_t num_total_glyphs, + hb_codepoint_t *glyphs, + unsigned char *klasses, + uint16_t count) +{ + int i; + + if (G_UNLIKELY (!count || !glyphs || !klasses)) + return; + + if (layout->new_gdef.len == 0) { + layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char)); + layout->new_gdef.len = count; + } + + for (i = 0; i < count; i++) + hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]); +} + +/* + * GSUB/GPOS + */ + +static const GSUBGPOS& +get_gsubgpos_table (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type) +{ + switch (table_type) { + case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub); + case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos); + default: return NullGSUBGPOS; + } +} + + +unsigned int +hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + return g.get_script_count (); +} + +hb_tag_t +hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + return g.get_script_tag (script_index); +} + +hb_bool_t +hb_ot_layout_table_find_script (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + hb_tag_t script_tag, + unsigned int *script_index) +{ + ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + if (g.find_script_index (script_tag, script_index)) + return TRUE; + + /* try finding 'DFLT' */ + if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index)) + return FALSE; + + /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ + if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index)) + return FALSE; + + if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; + return FALSE; +} + +unsigned int +hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + return g.get_feature_count (); +} + +hb_tag_t +hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + return g.get_feature_tag (feature_index); +} + +hb_bool_t +hb_ot_layout_table_find_feature (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + hb_tag_t feature_tag, + unsigned int *feature_index) +{ + ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + if (g.find_feature_index (feature_tag, feature_index)) + return TRUE; + + if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; + return FALSE; +} + +unsigned int +hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + + return g.get_lookup_count (); +} + + +unsigned int +hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index) +{ + const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index); + + return s.get_lang_sys_count (); +} + +hb_tag_t +hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index) +{ + const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index); + + return s.get_lang_sys_tag (language_index); +} + +hb_bool_t +hb_ot_layout_script_find_language (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + hb_tag_t language_tag, + unsigned int *language_index) +{ + ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); + const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index); + + if (s.find_lang_sys_index (language_tag, language_index)) + return TRUE; + + /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ + if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index)) + return FALSE; + + if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; + return FALSE; +} + +hb_bool_t +hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int *feature_index) +{ + const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index); + + if (feature_index) *feature_index = l.get_required_feature_index (); + + return l.has_required_feature (); +} + +unsigned int +hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index) +{ + const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index); + + return l.get_feature_count (); +} + +unsigned int +hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int num_feature) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); + + return l.get_feature_index (num_feature); +} + +hb_tag_t +hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int num_feature) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); + unsigned int feature_index = l.get_feature_index (num_feature); + + return g.get_feature_tag (feature_index); +} + + +hb_bool_t +hb_ot_layout_language_find_feature (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + hb_tag_t feature_tag, + unsigned int *feature_index) +{ + ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); + unsigned int i; + + for (i = 0; i < l.get_feature_count (); i++) { + unsigned int f_index = l.get_feature_index (i); + + if (feature_tag == g.get_feature_tag (f_index)) { + if (feature_index) *feature_index = f_index; + return TRUE; + } + } + + if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; + return FALSE; +} + +unsigned int +hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + const Feature &f = g.get_feature (feature_index); + + return f.get_lookup_count (); +} + +unsigned int +hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index, + unsigned int num_lookup) +{ + const GSUBGPOS &g = get_gsubgpos_table (layout, table_type); + const Feature &f = g.get_feature (feature_index); + + return f.get_lookup_index (num_lookup); +} + +/* + * GSUB + */ + +hb_bool_t +hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout, + hb_buffer_t *buffer, + unsigned int lookup_index, + hb_ot_layout_feature_mask_t mask) +{ + const GSUB &gsub = *(layout->gsub); + const SubstLookup &l = gsub.get_lookup (lookup_index); + unsigned int lookup_type = l.get_type (); + unsigned int nesting_level_left = HB_OT_LAYOUT_MAX_NESTING_LEVEL; + unsigned int context_length = NO_CONTEXT; + bool handled, ret = false; + + if (!l.is_reverse ()) { + + /* in/out forward substitution */ + _hb_buffer_clear_output (buffer); + buffer->in_pos = 0; + while (buffer->in_pos < buffer->in_length) { + + if ((~IN_PROPERTIES (buffer->in_pos) & mask) && + l.substitute (layout, buffer, context_length, nesting_level_left)) + ret = true; + else + _hb_buffer_copy_output_glyph (buffer); + + } + _hb_buffer_swap (buffer); + + } else { + + /* in-place backward substitution */ + buffer->in_pos = buffer->in_length - 1; + do { + + if ((~IN_PROPERTIES (buffer->in_pos) & mask) && + l.substitute (layout, buffer, context_length, nesting_level_left)) + ret = true; + else + buffer->in_pos--; + + } while (buffer->in_pos); + + } + + return ret; +} diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h new file mode 100644 index 000000000..c29485c02 --- /dev/null +++ b/src/hb-ot-layout.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_H +#define HB_OT_LAYOUT_H + +#include "hb-common.h" + +HB_BEGIN_DECLS(); + +/* + * hb_ot_layout_t + */ + +typedef struct _hb_ot_layout_t hb_ot_layout_t; + +hb_ot_layout_t * +hb_ot_layout_create (void); + +hb_ot_layout_t * +hb_ot_layout_create_for_data (const char *font_data, + int face_index); + +void +hb_ot_layout_destroy (hb_ot_layout_t *layout); + +/* TODO sanitizing API/constructor (make_wrieable_func_t) */ +/* TODO get_table_func_t constructor */ + +/* + * GDEF + */ + +typedef enum { + HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0000, + HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002, + HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004, + HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008, + HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010 +} hb_ot_layout_glyph_class_t; + +hb_bool_t +hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout); + +hb_ot_layout_glyph_class_t +hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout, + hb_codepoint_t glyph); + +void +hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout, + hb_codepoint_t glyph, + hb_ot_layout_glyph_class_t klass); + +void +hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout, + uint16_t num_total_glyphs, + hb_codepoint_t *glyphs, + unsigned char *klasses, + uint16_t count); + +/* + * GSUB/GPOS + */ + +typedef enum { + HB_OT_LAYOUT_TABLE_TYPE_GSUB, + HB_OT_LAYOUT_TABLE_TYPE_GPOS, + HB_OT_LAYOUT_TABLE_TYPE_NONE +} hb_ot_layout_table_type_t; + +typedef uint16_t hb_ot_layout_feature_mask_t; + +#define HB_OT_LAYOUT_MAX_NESTING_LEVEL 100 + +#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF) +#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF) +#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF) +#define HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T') +#define HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't') + +unsigned int +hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type); + +hb_tag_t +hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index); + +hb_bool_t +hb_ot_layout_table_find_script (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + hb_tag_t script_tag, + unsigned int *script_index); + +unsigned int +hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type); + +hb_tag_t +hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index); + +hb_bool_t +hb_ot_layout_table_find_script (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + hb_tag_t feature_tag, + unsigned int *feature_index); + +unsigned int +hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type); + +unsigned int +hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index); + +hb_tag_t +hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index); + +hb_bool_t +hb_ot_layout_script_find_language (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + hb_tag_t language_tag, + unsigned int *language_index); + +hb_bool_t +hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int *feature_index); + +unsigned int +hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index); + +unsigned int +hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int num_feature); + +hb_tag_t +hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + unsigned int num_feature); + +hb_bool_t +hb_ot_layout_language_find_feature (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int script_index, + unsigned int language_index, + hb_tag_t feature_tag, + unsigned int *feature_index); + +unsigned int +hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index); + +unsigned int +hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout, + hb_ot_layout_table_type_t table_type, + unsigned int feature_index, + unsigned int num_lookup); + +/* + * GSUB + */ + +hb_bool_t +hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout, + hb_buffer_t *buffer, + unsigned int lookup_index, + hb_ot_layout_feature_mask_t mask); + + + + + + + + + + + +/* +#define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF) + +*/ + +HB_END_DECLS(); + +#endif /* HB_OT_LAYOUT_H */ diff --git a/src/hb-private.h b/src/hb-private.h new file mode 100644 index 000000000..3dca04907 --- /dev/null +++ b/src/hb-private.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_PRIVATE_H +#define HB_PRIVATE_H + +#include + +/* Macros to convert to/from BigEndian */ +#define hb_be_uint8_t +#define hb_be_int8_t +#define hb_be_uint16_t GUINT16_TO_BE +#define hb_be_int16_t GINT16_TO_BE +#define hb_be_uint32_t GUINT32_TO_BE +#define hb_be_int32_t GINT32_TO_BE +#define hb_be_uint64_t GUINT64_TO_BE +#define hb_be_int64_t GINT64_TO_BE + +#define HB_LIKELY G_LIKEYLY +#define HB_UNLIKELY G_UNLIKELY +#define HB_UNUSED(arg) ((arg) = (arg)) + + +#include + +#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] +#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond)) +#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond)) + +#define ASSERT_SIZE(_type, _size) ASSERT_STATIC (sizeof (_type) == (_size)) + +/* + * buffer + */ + +/* XXX */ +#define HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN 0xFFFF + +#endif /* HB_PRIVATE_H */ diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 000000000..ffd13b4aa --- /dev/null +++ b/src/main.cc @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2007,2008 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#define HB_OT_LAYOUT_CC +#include "hb-ot-layout-open-private.h" +#include "hb-ot-layout-gdef-private.h" +#include "hb-ot-layout-gsub-private.h" + +#include +#include + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); + exit (1); + } + + GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL); + const char *font_data = g_mapped_file_get_contents (mf); + int len = g_mapped_file_get_length (mf); + + printf ("Opened font file %s: %d bytes long\n", argv[1], len); + + const OpenTypeFontFile &ot = OpenTypeFontFile::get_for_data (font_data); + + switch (ot.get_tag()) { + case OpenTypeFontFile::TrueTypeTag: + printf ("OpenType font with TrueType outlines\n"); + break; + case OpenTypeFontFile::CFFTag: + printf ("OpenType font with CFF (Type1) outlines\n"); + break; + case OpenTypeFontFile::TTCTag: + printf ("TrueType Collection of OpenType fonts\n"); + break; + default: + printf ("Unknown font format\n"); + break; + } + + int num_fonts = ot.get_face_count (); + printf ("%d font(s) found in file\n", num_fonts); + for (int n_font = 0; n_font < num_fonts; n_font++) { + const OpenTypeFontFace &font = ot.get_face (n_font); + printf ("Font %d of %d:\n", n_font, num_fonts); + + int num_tables = font.get_table_count (); + printf (" %d table(s) found in font\n", num_tables); + for (int n_table = 0; n_table < num_tables; n_table++) { + const OpenTypeTable &table = font.get_table (n_table); + printf (" Table %2d of %2d: %.4s (0x%08lx+0x%08lx)\n", n_table, num_tables, + (const char *)table.get_tag(), table.get_offset(), table.get_length()); + + switch (table.get_tag ()) { + + case GSUBGPOS::GSUBTag: + case GSUBGPOS::GPOSTag: + { + + const GSUBGPOS &g = GSUBGPOS::get_for_data (ot.get_table_data (table)); + + int num_scripts = g.get_script_count (); + printf (" %d script(s) found in table\n", num_scripts); + for (int n_script = 0; n_script < num_scripts; n_script++) { + const Script &script = g.get_script (n_script); + printf (" Script %2d of %2d: %.4s\n", n_script, num_scripts, + (const char *)g.get_script_tag(n_script)); + + if (!script.has_default_lang_sys()) + printf (" No default language system\n"); + int num_langsys = script.get_lang_sys_count (); + printf (" %d language system(s) found in script\n", num_langsys); + for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) { + const LangSys &langsys = n_langsys == -1 + ? script.get_default_lang_sys () + : script.get_lang_sys (n_langsys); + printf (n_langsys == -1 + ? " Default Language System\n" + : " Language System %2d of %2d: %.4s\n", n_langsys, num_langsys, + (const char *)script.get_lang_sys_tag (n_langsys)); + if (langsys.get_required_feature_index () == NO_INDEX) + printf (" No required feature\n"); + + int num_features = langsys.get_feature_count (); + printf (" %d feature(s) found in language system\n", num_features); + for (int n_feature = 0; n_feature < num_features; n_feature++) { + unsigned int feature_index = langsys.get_feature_index (n_feature); + printf (" Feature index %2d of %2d: %d\n", n_feature, num_features, + langsys.get_feature_index (n_feature)); + } + } + } + + int num_features = g.get_feature_count (); + printf (" %d feature(s) found in table\n", num_features); + for (int n_feature = 0; n_feature < num_features; n_feature++) { + const Feature &feature = g.get_feature (n_feature); + printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features, + (const char *)g.get_feature_tag(n_feature), + feature.get_lookup_count()); + + int num_lookups = feature.get_lookup_count (); + printf (" %d lookup(s) found in feature\n", num_lookups); + for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) { + unsigned int lookup_index = feature.get_lookup_index (n_lookup); + printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups, + feature.get_lookup_index (n_lookup)); + } + } + + int num_lookups = g.get_lookup_count (); + printf (" %d lookup(s) found in table\n", num_lookups); + for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) { + const Lookup &lookup = g.get_lookup (n_lookup); + printf (" Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups, + lookup.get_type(), lookup.get_flag()); + } + + } + break; + + case GDEF::Tag: + { + + const GDEF &gdef = GDEF::get_for_data (ot.get_table_data (table)); + + printf (" Has %sglyph classes\n", + gdef.has_glyph_classes () ? "" : "no "); + printf (" Has %smark attachment types\n", + gdef.has_mark_attachment_types () ? "" : "no "); + printf (" Has %sattach list\n", + gdef.has_attach_list () ? "" : "no "); + printf (" Has %slig caret list\n", + gdef.has_lig_caret_list () ? "" : "no "); + + for (int glyph = 0; glyph < 1; glyph++) + printf (" glyph %d has class %d and mark attachment type %d\n", + glyph, + gdef.get_glyph_class (glyph), + gdef.get_mark_attachment_type (glyph)); + + } + break; + } + } + } + + return 0; +}