Merge harfbuzz-ng

This commit is contained in:
Behdad Esfahbod 2009-11-02 14:35:51 -05:00
commit ce48f03946
21 changed files with 3159 additions and 177 deletions

1
src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
main

View File

@ -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 \

11
src/Makefile.ng Normal file
View File

@ -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

View File

@ -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), \

View File

@ -28,6 +28,9 @@
#ifndef HARFBUZZ_GLOBAL_H
#define HARFBUZZ_GLOBAL_H
/* XXX */
#include "hb-ot-layout.h"
#include <ft2build.h>
#include FT_FREETYPE_H

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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 );

View File

@ -34,6 +34,9 @@
#include <stdlib.h>
/* 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) \

View File

@ -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;

View File

@ -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"

54
src/hb-common.h Normal file
View File

@ -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 <stdint.h>
# 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

565
src/hb-ot-layout.cc Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
struct _hb_ot_layout_t {
const GDEF *gdef;
const GSUB *gsub;
const /*XXX*/GSUBGPOS *gpos;
struct {
unsigned char *klasses;
unsigned int len;
} new_gdef;
/* TODO add max-nesting-level here? */
};
hb_ot_layout_t *
hb_ot_layout_create (void)
{
hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
layout->gdef = &NullGDEF;
layout->gsub = &NullGSUB;
layout->gpos = &/*XXX*/NullGSUBGPOS;
return layout;
}
hb_ot_layout_t *
hb_ot_layout_create_for_data (const char *font_data,
int face_index)
{
hb_ot_layout_t *layout;
if (HB_UNLIKELY (font_data == NULL))
return hb_ot_layout_create ();
layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data);
const OpenTypeFontFace &face = font.get_face (face_index);
layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table_by_tag (GDEF::Tag)));
layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table_by_tag (GSUB::Tag)));
layout->gpos = &/*XXX*/GSUBGPOS::get_for_data (font.get_table_data (face.get_table_by_tag (/*XXX*/GSUBGPOS::GPOSTag)));
return layout;
}
void
hb_ot_layout_destroy (hb_ot_layout_t *layout)
{
free (layout);
}
/*
* GDEF
*/
hb_bool_t
hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout)
{
return layout->gdef->has_glyph_classes ();
}
HB_OT_LAYOUT_INTERNAL hb_bool_t
_hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout)
{
return layout->new_gdef.len > 0;
}
HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t
_hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout,
hb_codepoint_t glyph)
{
hb_ot_layout_class_t klass;
/* TODO old harfbuzz doesn't always parse mark attachments as it says it was
* introduced without a version bump, so it may not be safe */
klass = layout->gdef->get_mark_attachment_type (glyph);
if (klass)
return klass << 8;
klass = layout->gdef->get_glyph_class (glyph);
if (!klass && glyph < layout->new_gdef.len)
klass = layout->new_gdef.klasses[glyph];
switch (klass) {
default:
case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
case GDEF::MarkGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
}
}
HB_OT_LAYOUT_INTERNAL hb_bool_t
_hb_ot_layout_check_glyph_properties (hb_ot_layout_t *layout,
HB_GlyphItem gitem,
hb_ot_layout_lookup_flags_t lookup_flags,
hb_ot_layout_glyph_properties_t *property)
{
hb_ot_layout_glyph_class_t basic_glyph_class;
hb_ot_layout_glyph_properties_t desired_attachment_class;
if (gitem->gproperties == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
{
gitem->gproperties = *property = _hb_ot_layout_get_glyph_properties (layout, gitem->gindex);
if (gitem->gproperties == HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
return false;
}
*property = gitem->gproperties;
/* If the glyph was found in the MarkAttachmentClass table,
* then that class value is the high byte of the result,
* otherwise the low byte contains the basic type of the glyph
* as defined by the GlyphClassDef table.
*/
if (*property & LookupFlag::MarkAttachmentType)
basic_glyph_class = HB_OT_LAYOUT_GLYPH_CLASS_MARK;
else
basic_glyph_class = (hb_ot_layout_glyph_class_t) *property;
/* Not covered, if, for example, basic_glyph_class
* is HB_GDEF_LIGATURE and lookup_flags includes LookupFlags::IgnoreLigatures
*/
if (lookup_flags & basic_glyph_class)
return false;
/* The high byte of lookup_flags has the meaning
* "ignore marks of attachment type different than
* the attachment type specified."
*/
desired_attachment_class = lookup_flags & LookupFlag::MarkAttachmentType;
if (desired_attachment_class)
{
if (basic_glyph_class == HB_OT_LAYOUT_GLYPH_CLASS_MARK &&
*property != desired_attachment_class )
return false;
}
return true;
}
hb_ot_layout_glyph_class_t
hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
hb_codepoint_t glyph)
{
hb_ot_layout_glyph_properties_t properties;
hb_ot_layout_class_t klass;
properties = _hb_ot_layout_get_glyph_properties (layout, glyph);
if (properties & 0xFF00)
return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
return (hb_ot_layout_glyph_class_t) properties;
}
void
hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout,
hb_codepoint_t glyph,
hb_ot_layout_glyph_class_t klass)
{
/* TODO optimize this, similar to old harfbuzz code for example */
hb_ot_layout_class_t gdef_klass;
int len = layout->new_gdef.len;
if (glyph >= len) {
int new_len;
unsigned char *new_klasses;
new_len = len == 0 ? 120 : 2 * len;
if (new_len > 65535)
new_len = 65535;
new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
if (G_UNLIKELY (!new_klasses))
return;
memset (new_klasses + len, 0, new_len - len);
layout->new_gdef.klasses = new_klasses;
layout->new_gdef.len = new_len;
}
switch (klass) {
default:
case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break;
case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break;
case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break;
case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break;
case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break;
}
layout->new_gdef.klasses[glyph] = gdef_klass;
return;
}
void
hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
uint16_t num_total_glyphs,
hb_codepoint_t *glyphs,
unsigned char *klasses,
uint16_t count)
{
int i;
if (G_UNLIKELY (!count || !glyphs || !klasses))
return;
if (layout->new_gdef.len == 0) {
layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
layout->new_gdef.len = count;
}
for (i = 0; i < count; i++)
hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
}
/*
* GSUB/GPOS
*/
static const GSUBGPOS&
get_gsubgpos_table (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type)
{
switch (table_type) {
case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub);
case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos);
default: return NullGSUBGPOS;
}
}
unsigned int
hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
return g.get_script_count ();
}
hb_tag_t
hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
return g.get_script_tag (script_index);
}
hb_bool_t
hb_ot_layout_table_find_script (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
hb_tag_t script_tag,
unsigned int *script_index)
{
ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
if (g.find_script_index (script_tag, script_index))
return TRUE;
/* try finding 'DFLT' */
if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
return FALSE;
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
return FALSE;
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
return FALSE;
}
unsigned int
hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
return g.get_feature_count ();
}
hb_tag_t
hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int feature_index)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
return g.get_feature_tag (feature_index);
}
hb_bool_t
hb_ot_layout_table_find_feature (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
hb_tag_t feature_tag,
unsigned int *feature_index)
{
ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
if (g.find_feature_index (feature_tag, feature_index))
return TRUE;
if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
return FALSE;
}
unsigned int
hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
return g.get_lookup_count ();
}
unsigned int
hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index)
{
const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
return s.get_lang_sys_count ();
}
hb_tag_t
hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index)
{
const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
return s.get_lang_sys_tag (language_index);
}
hb_bool_t
hb_ot_layout_script_find_language (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
hb_tag_t language_tag,
unsigned int *language_index)
{
ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
if (s.find_lang_sys_index (language_tag, language_index))
return TRUE;
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
return FALSE;
if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
return FALSE;
}
hb_bool_t
hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index)
{
const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
if (feature_index) *feature_index = l.get_required_feature_index ();
return l.has_required_feature ();
}
unsigned int
hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index)
{
const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
return l.get_feature_count ();
}
unsigned int
hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index,
unsigned int num_feature)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
return l.get_feature_index (num_feature);
}
hb_tag_t
hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index,
unsigned int num_feature)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int feature_index = l.get_feature_index (num_feature);
return g.get_feature_tag (feature_index);
}
hb_bool_t
hb_ot_layout_language_find_feature (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int script_index,
unsigned int language_index,
hb_tag_t feature_tag,
unsigned int *feature_index)
{
ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int i;
for (i = 0; i < l.get_feature_count (); i++) {
unsigned int f_index = l.get_feature_index (i);
if (feature_tag == g.get_feature_tag (f_index)) {
if (feature_index) *feature_index = f_index;
return TRUE;
}
}
if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
return FALSE;
}
unsigned int
hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int feature_index)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
const Feature &f = g.get_feature (feature_index);
return f.get_lookup_count ();
}
unsigned int
hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout,
hb_ot_layout_table_type_t table_type,
unsigned int feature_index,
unsigned int num_lookup)
{
const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
const Feature &f = g.get_feature (feature_index);
return f.get_lookup_index (num_lookup);
}
/*
* GSUB
*/
hb_bool_t
hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout,
hb_buffer_t *buffer,
unsigned int lookup_index,
hb_ot_layout_feature_mask_t mask)
{
const GSUB &gsub = *(layout->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index);
unsigned int lookup_type = l.get_type ();
unsigned int nesting_level_left = HB_OT_LAYOUT_MAX_NESTING_LEVEL;
unsigned int context_length = NO_CONTEXT;
bool handled, ret = false;
if (!l.is_reverse ()) {
/* in/out forward substitution */
_hb_buffer_clear_output (buffer);
buffer->in_pos = 0;
while (buffer->in_pos < buffer->in_length) {
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
l.substitute (layout, buffer, context_length, nesting_level_left))
ret = true;
else
_hb_buffer_copy_output_glyph (buffer);
}
_hb_buffer_swap (buffer);
} else {
/* in-place backward substitution */
buffer->in_pos = buffer->in_length - 1;
do {
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
l.substitute (layout, buffer, context_length, nesting_level_left))
ret = true;
else
buffer->in_pos--;
} while (buffer->in_pos);
}
return ret;
}

229
src/hb-ot-layout.h Normal file
View File

@ -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 */

62
src/hb-private.h Normal file
View File

@ -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 <glib.h>
/* 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 <assert.h>
#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 */

174
src/main.cc Normal file
View File

@ -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 <stdlib.h>
#include <stdio.h>
int
main (int argc, char **argv)
{
if (argc != 2) {
fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
exit (1);
}
GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL);
const char *font_data = g_mapped_file_get_contents (mf);
int len = g_mapped_file_get_length (mf);
printf ("Opened font file %s: %d bytes long\n", argv[1], len);
const OpenTypeFontFile &ot = OpenTypeFontFile::get_for_data (font_data);
switch (ot.get_tag()) {
case OpenTypeFontFile::TrueTypeTag:
printf ("OpenType font with TrueType outlines\n");
break;
case OpenTypeFontFile::CFFTag:
printf ("OpenType font with CFF (Type1) outlines\n");
break;
case OpenTypeFontFile::TTCTag:
printf ("TrueType Collection of OpenType fonts\n");
break;
default:
printf ("Unknown font format\n");
break;
}
int num_fonts = ot.get_face_count ();
printf ("%d font(s) found in file\n", num_fonts);
for (int n_font = 0; n_font < num_fonts; n_font++) {
const OpenTypeFontFace &font = ot.get_face (n_font);
printf ("Font %d of %d:\n", n_font, num_fonts);
int num_tables = font.get_table_count ();
printf (" %d table(s) found in font\n", num_tables);
for (int n_table = 0; n_table < num_tables; n_table++) {
const OpenTypeTable &table = font.get_table (n_table);
printf (" Table %2d of %2d: %.4s (0x%08lx+0x%08lx)\n", n_table, num_tables,
(const char *)table.get_tag(), table.get_offset(), table.get_length());
switch (table.get_tag ()) {
case GSUBGPOS::GSUBTag:
case GSUBGPOS::GPOSTag:
{
const GSUBGPOS &g = GSUBGPOS::get_for_data (ot.get_table_data (table));
int num_scripts = g.get_script_count ();
printf (" %d script(s) found in table\n", num_scripts);
for (int n_script = 0; n_script < num_scripts; n_script++) {
const Script &script = g.get_script (n_script);
printf (" Script %2d of %2d: %.4s\n", n_script, num_scripts,
(const char *)g.get_script_tag(n_script));
if (!script.has_default_lang_sys())
printf (" No default language system\n");
int num_langsys = script.get_lang_sys_count ();
printf (" %d language system(s) found in script\n", num_langsys);
for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) {
const LangSys &langsys = n_langsys == -1
? script.get_default_lang_sys ()
: script.get_lang_sys (n_langsys);
printf (n_langsys == -1
? " Default Language System\n"
: " Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
(const char *)script.get_lang_sys_tag (n_langsys));
if (langsys.get_required_feature_index () == NO_INDEX)
printf (" No required feature\n");
int num_features = langsys.get_feature_count ();
printf (" %d feature(s) found in language system\n", num_features);
for (int n_feature = 0; n_feature < num_features; n_feature++) {
unsigned int feature_index = langsys.get_feature_index (n_feature);
printf (" Feature index %2d of %2d: %d\n", n_feature, num_features,
langsys.get_feature_index (n_feature));
}
}
}
int num_features = g.get_feature_count ();
printf (" %d feature(s) found in table\n", num_features);
for (int n_feature = 0; n_feature < num_features; n_feature++) {
const Feature &feature = g.get_feature (n_feature);
printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
(const char *)g.get_feature_tag(n_feature),
feature.get_lookup_count());
int num_lookups = feature.get_lookup_count ();
printf (" %d lookup(s) found in feature\n", num_lookups);
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
unsigned int lookup_index = feature.get_lookup_index (n_lookup);
printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
feature.get_lookup_index (n_lookup));
}
}
int num_lookups = g.get_lookup_count ();
printf (" %d lookup(s) found in table\n", num_lookups);
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
const Lookup &lookup = g.get_lookup (n_lookup);
printf (" Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups,
lookup.get_type(), lookup.get_flag());
}
}
break;
case GDEF::Tag:
{
const GDEF &gdef = GDEF::get_for_data (ot.get_table_data (table));
printf (" Has %sglyph classes\n",
gdef.has_glyph_classes () ? "" : "no ");
printf (" Has %smark attachment types\n",
gdef.has_mark_attachment_types () ? "" : "no ");
printf (" Has %sattach list\n",
gdef.has_attach_list () ? "" : "no ");
printf (" Has %slig caret list\n",
gdef.has_lig_caret_list () ? "" : "no ");
for (int glyph = 0; glyph < 1; glyph++)
printf (" glyph %d has class %d and mark attachment type %d\n",
glyph,
gdef.get_glyph_class (glyph),
gdef.get_mark_attachment_type (glyph));
}
break;
}
}
}
return 0;
}