diff --git a/ChangeLog b/ChangeLog index 2994a3e1d..bc1283172 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2002-11-07 David Turner + + * src/otlayout/otlayout.h, src/otlyaout/otlconf.h, + src/otlayout/otlgsub.c, src/otlayout/otlgsub.h, src/otlayout/otlparse.c, + src/otlayout/otlparse.h, src/otlayout/otlutils.h: + + updating the OpenType Layout code, adding support fot the first + GSUB lookups. Nothing that really compiles for now though + 2002-11-05 David Turner * include/freetype/config/ftoption.h, src/gzip/ftgzip.c: added diff --git a/src/otlayout/otlayout.h b/src/otlayout/otlayout.h index 2802f3946..2cd67f568 100644 --- a/src/otlayout/otlayout.h +++ b/src/otlayout/otlayout.h @@ -24,9 +24,13 @@ OTL_BEGIN_HEADER typedef int OTL_Int; typedef unsigned int OTL_UInt; + typedef long OTL_Long; + typedef unsigned long OTL_ULong; + typedef short OTL_Int16; typedef unsigned short OTL_UInt16; + #if OTL_SIZEOF_INT == 4 typedef int OTL_Int32; @@ -58,9 +62,38 @@ OTL_BEGIN_HEADER OTL_Err_InvalidFormat, OTL_Err_InvalidOffset, + OTL_Err_Max + } OTL_Error; + /************************************************************************/ + /************************************************************************/ + /***** *****/ + /***** MEMORY MANAGEMENT *****/ + /***** *****/ + /************************************************************************/ + /************************************************************************/ + + typedef OTL_Pointer (*OTL_AllocFunc)( OTL_ULong size, + OTL_Pointer data ); + + typedef OTL_Pointer (*OTL_ReallocFunc)( OTL_Pointer block, + OTL_ULong size, + OTL_Pointer data ); + + typedef void (*OTL_FreeFunc)( OTL_Pointer block, + OTL_Pointer data ); + + typedef struct OTL_MemoryRec_ + { + OTL_Pointer mem_data; + OTL_AllocFunc mem_alloc; + OTL_ReallocFunc mem_realloc; + OTL_FreeFunc mem_free; + + } OTL_MemoryRec, *OTL_Memory; + /************************************************************************/ /************************************************************************/ /***** *****/ @@ -69,11 +102,15 @@ OTL_BEGIN_HEADER /************************************************************************/ /************************************************************************/ +/* re-define OTL_MAKE_TAG to something different if you're not */ +/* using an ASCII-based character set (Vaxes anyone ?) */ +#ifndef OTL_MAKE_TAG #define OTL_MAKE_TAG(c1,c2,c3,c4) \ ( ( (OTL_UInt32)(c1) << 24 ) | \ (OTL_UInt32)(c2) << 16 ) | \ (OTL_UInt32)(c3) << 8 ) | \ (OTL_UInt32)(c4) ) +#endif typedef enum OTL_ScriptTag_ { @@ -153,8 +190,8 @@ OTL_BEGIN_HEADER #define OTL_INVALID(e) otl_validator_error( valid, e ) -#define OTL_INVALID_TOO_SHORT OTL_INVALID( OTL_Err_InvalidOffset ); -#define OTL_INVALID_DATA OTL_INVALID( OTL_Err_InvalidFormat ); +#define OTL_INVALID_TOO_SHORT OTL_INVALID( OTL_Err_InvalidOffset ) +#define OTL_INVALID_DATA OTL_INVALID( OTL_Err_InvalidFormat ) #define OTL_CHECK(_count) OTL_BEGIN_STMNT \ if ( p + (_count) > valid->limit ) \ diff --git a/src/otlayout/otlconf.h b/src/otlayout/otlconf.h index 155b0db80..3ef17a079 100644 --- a/src/otlayout/otlconf.h +++ b/src/otlayout/otlconf.h @@ -43,10 +43,10 @@ #define OTL_BEGIN_STMNT do { #define OTL_END_STMNT } while (0) -#define OTL_DUMMY_STMNT do { } while (0) +#define OTL_DUMMY_STMNT OTL_BEGIN_STMNT OTL_END_STMNT #define OTL_UNUSED( x ) (x)=(x) -#define OTL_UNUSED_CONST(x) (void)(x) +#define OTL_UNUSED_CONST(x) (void)(x) #include @@ -68,6 +68,11 @@ # error "unsupported number of bytes in 'long' type!" #endif +#include +#define OTL_jmp_buf jmp_buf +#define otl_setjmp setjmp +#define otl_longjmp longjmp + /* */ #endif /* __OT_LAYOUT_CONFIG_H__ */ diff --git a/src/otlayout/otlgsub.c b/src/otlayout/otlgsub.c index 41e603da1..817760a7c 100644 --- a/src/otlayout/otlgsub.c +++ b/src/otlayout/otlgsub.c @@ -9,6 +9,28 @@ /************************************************************************/ /************************************************************************/ + /* + * 1: Single Substitution - Table format(s) + * + * This table is used to substiture individual glyph indices + * with another one. There are only two sub-formats: + * + * Name Offset Size Description + * ------------------------------------------ + * format 0 2 sub-table format (1) + * offset 2 2 offset to coverage table + * delta 4 2 16-bit delta to apply on all + * covered glyph indices + * + * Name Offset Size Description + * ------------------------------------------ + * format 0 2 sub-table format (2) + * offset 2 2 offset to coverage table + * count 4 2 coverage table count + * substs[] 6 2*count substituted glyph indices, + * + */ + static void otl_gsub_lookup1_validate( OTL_Bytes table, OTL_Validator valid ) @@ -42,6 +64,10 @@ otl_coverage_validate( table + coverage, valid ); OTL_CHECK( 2*count ); + + /* NB: we don't check that there are at most 'count' */ + /* elements in the coverage table. This is delayed */ + /* to the lookup function... */ } break; @@ -51,6 +77,63 @@ } + static OTL_Bool + otl_gsub_lookup1_apply( OTL_Bytes table, + OTL_Parser parser ) + { + OTL_Bytes p = table; + OTL_Bytes coverage; + OTL_UInt format, gindex, property; + OTL_Int index; + OTL_Bool subst = 0; + + if ( parser->context_len != 0xFFFF && parser->context_len < 1 ) + goto Exit; + + gindex = otl_parser_get_gindex( parser ); + + if ( !otl_parser_check_property( parser, gindex, &property ) ) + goto Exit; + + format = OTL_NEXT_USHORT(p); + coverage = table + OTL_NEXT_USHORT(p); + index = otl_coverage_lookup( coverage, gindex ); + + if ( index >= 0 ) + { + switch ( format ) + { + case 1: + { + OTL_Int delta = OTL_NEXT_SHORT(p); + + gindex = ( gindex + delta ) & 0xFFFF; + otl_parser_replace_1( parser, gindex ); + subst = 1; + } + break; + + case 2: + { + OTL_UInt count = OTL_NEXT_USHORT(p); + + if ( (OTL_UInt) index < count ) + { + p += index*2; + otl_parser_replace_1( parser, OTL_PEEK_USHORT(p) ); + subst = 1; + } + } + break; + + default: + ; + } + } + Exit: + return subst; + } + /************************************************************************/ /************************************************************************/ /***** *****/ @@ -59,6 +142,26 @@ /************************************************************************/ /************************************************************************/ + /* + * 2: Multiple Substitution - Table format(s) + * + * Replaces a single glyph with one or more glyphs. + * + * Name Offset Size Description + * ----------------------------------------------------------- + * format 0 2 sub-table format (1) + * offset 2 2 offset to coverage table + * count 4 2 coverage table count + * sequencess[] 6 2*count offsets to sequence items + * + * each sequence item has the following format: + * + * Name Offset Size Description + * ----------------------------------------------------------- + * count 0 2 number of replacement glyphs + * gindices[] 2 2*count string of glyph indices + */ + static void otl_seq_validate( OTL_Bytes table, OTL_Validator valid ) @@ -69,6 +172,9 @@ OTL_CHECK( 2 ); count = OTL_NEXT_USHORT( p ); + /* XXX: according to the spec, 'count' should be > 0 */ + /* we can deal with these cases pretty well however */ + OTL_CHECK( 2*count ); /* check glyph indices */ } @@ -106,6 +212,45 @@ } } + + static OTL_Bool + otl_gsub_lookup2_apply( OTL_Bytes table, + OTL_Parser parser ) + { + OTL_Bytes p = table; + OTL_Bytes coverage, sequence; + OTL_UInt format, gindex, index, property; + OTL_Int index; + OTL_Bool subst = 0; + + if ( context_len != 0xFFFF && context_len < 1 ) + goto Exit; + + gindex = otl_parser_get_gindex( parser ); + + if ( !otl_parser_check_property( parser, gindex, &property ) ) + goto Exit; + + p += 2; /* skip format */ + coverage = table + OTL_NEXT_USHORT(p); + seq_count = OTL_NEXT_USHORT(p); + index = otl_coverage_lookup( coverage, gindex ); + + if ( (OTL_UInt) index >= seq_count ) + goto Exit; + + p += index*2; + sequence = table + OTL_PEEK_USHORT(p); + p = sequence; + count = OTL_NEXT_USHORT(p); + + otl_parser_replace_n( parser, count, p ); + subst = 1; + + Exit: + return subst; + } + /************************************************************************/ /************************************************************************/ /***** *****/ @@ -114,6 +259,28 @@ /************************************************************************/ /************************************************************************/ + /* + * 3: Alternate Substitution - Table format(s) + * + * Replaces a single glyph by another one taken liberally + * in a list of alternatives + * + * Name Offset Size Description + * ----------------------------------------------------------- + * format 0 2 sub-table format (1) + * offset 2 2 offset to coverage table + * count 4 2 coverage table count + * alternates[] 6 2*count offsets to alternate items + * + * each alternate item has the following format: + * + * Name Offset Size Description + * ----------------------------------------------------------- + * count 0 2 number of replacement glyphs + * gindices[] 2 2*count string of glyph indices, each one + * is a valid alternative + */ + static void otl_alternate_set_validate( OTL_Bytes table, OTL_Validator valid ) @@ -162,6 +329,52 @@ } + static OTL_Bool + otl_gsub_lookup3_apply( OTL_Bytes table, + OTL_Parser parser ) + { + OTL_Bytes p = table; + OTL_Bytes coverage, alternates; + OTL_UInt format, gindex, index, property; + OTL_Int index; + OTL_Bool subst = 0; + + OTL_GSUB_Alternate alternate = parser->alternate; + + if ( context_len != 0xFFFF && context_len < 1 ) + goto Exit; + + if ( alternate == NULL ) + goto Exit; + + gindex = otl_parser_get_gindex( parser ); + + if ( !otl_parser_check_property( parser, gindex, &property ) ) + goto Exit; + + p += 2; /* skip format */ + coverage = table + OTL_NEXT_USHORT(p); + seq_count = OTL_NEXT_USHORT(p); + index = otl_coverage_lookup( coverage, gindex ); + + if ( (OTL_UInt) index >= seq_count ) + goto Exit; + + p += index*2; + alternates = table + OTL_PEEK_USHORT(p); + p = alternates; + count = OTL_NEXT_USHORT(p); + + gindex = alternate->handler_func( + gindex, count, p, alternate->handler_data ); + + otl_parser_replace_1( parser, gindex ); + subst = 1; + + Exit: + return subst; + } + /************************************************************************/ /************************************************************************/ /***** *****/ diff --git a/src/otlayout/otlgsub.h b/src/otlayout/otlgsub.h index af57b1681..db5edecf1 100644 --- a/src/otlayout/otlgsub.h +++ b/src/otlayout/otlgsub.h @@ -5,6 +5,18 @@ OTL_BEGIN_HEADER + typedef OTL_UInt (*OTL_GSUB_AlternateFunc)( OTL_UInt gindex, + OTL_UInt count, + OTL_Bytes alternates, + OTL_Pointer data ); + + typedef struct OTL_GSUB_AlternateRec_ + { + OTL_GSUB_AlternateFunc handler_func; + OTL_Pointer handler_data; + + } OTL_GSUB_AlternateRec, *OTL_GSUB_Alternate; + OTL_LOCAL( void ) otl_gsub_validate( OTL_Bytes table, OTL_Validator valid ); diff --git a/src/otlayout/otlparse.c b/src/otlayout/otlparse.c new file mode 100644 index 000000000..705c0c60f --- /dev/null +++ b/src/otlayout/otlparse.c @@ -0,0 +1,142 @@ +#include "otlparse.h" +#include "otlutils.h" + + static void + otl_string_ensure( OTL_String string, + OTL_UInt count, + OTL_Parser parser ) + { + count += string->length; + + if ( count > string->capacity ) + { + OTL_UInt old_count = string->capacity; + OTL_UInt new_count = old_count; + OTL_Memory memory = parser->memory; + + while ( new_count < count ) + new_count += (new_count >> 1) + 16; + + if ( OTL_MEM_RENEW_ARRAY( string->glyphs, old_count, new_count ) ) + otl_parser_error( parser, OTL_Parse_Err_Memory ); + + string->capacity = new_count; + } + } + +#define OTL_STRING_ENSURE(str,count,parser) \ + OTL_BEGIN_STMNT \ + if ( (str)->length + (count) > (str)>capacity ) \ + otl_string_ensure( str, count, parser ); \ + OTL_END_STMNT + + + OTL_LOCALDEF( OTL_UInt ) + otl_parser_get_gindex( OTL_Parser parser ) + { + OTL_String in = parser->str_in; + + if ( in->cursor >= in->num_glyphs ) + otl_parser_error( parser, OTL_Err_Parser_Internal ); + + return in->str[ in->cursor ].gindex; + } + + + OTL_LOCALDEF( void ) + otl_parser_error( OTL_Parser parser, + OTL_ParseError error; ) + { + parser->error = error; + otl_longjmp( parser->jump_buffer, 1 ); + } + +#define OTL_PARSER_UNCOVERED(x) otl_parser_error( x, OTL_Parse_Err_UncoveredGlyph ); + + OTL_LOCAL( void ) + otl_parser_check_property( OTL_Parser parser, + OTL_UInt gindex, + OTL_UInt flags, + OTL_UInt *aproperty ); + + OTL_LOCALDEF( void ) + otl_parser_replace_1( OTL_Parser parser, + OTL_UInt gindex ) + { + OTL_String in = parser->str_in; + OTL_String out = parser->str_out; + OTL_StringGlyph glyph, in_glyph; + + /* sanity check */ + if ( in == NULL || + out == NULL || + in->length == 0 || + in->cursor >= in->length ) + { + /* report as internal error, since these should */ + /* never happen !! */ + otl_parser_error( parser, OTL_Err_Parse_Internal ); + } + + OTL_STRING_ENSURE( out, 1, parser ); + glyph = out->glyphs + out->length; + in_glyph = in->glyphs + in->cursor; + + glyph->gindex = gindex; + glyph->property = in_glyph->property; + glyph->lig_component = in_glyph->lig_component; + glyph->lig_id = in_glyph->lig_id; + + out->length += 1; + out->cursor = out->length; + in->cursor += 1; + } + + OTL_LOCALDEF( void ) + otl_parser_replace_n( OTL_Parser parser, + OTL_UInt count, + OTL_Bytes indices ) + { + OTL_UInt lig_component, lig_id, property; + OTL_String in = parser->str_in; + OTL_String out = parser->str_out; + OTL_StringGlyph glyph, in_glyph; + OTL_Bytes p = indices; + + /* sanity check */ + if ( in == NULL || + out == NULL || + in->length == 0 || + in->cursor >= in->length ) + { + /* report as internal error, since these should */ + /* never happen !! */ + otl_parser_error( parser, OTL_Err_Parse_Internal ); + } + + OTL_STRING_ENSURE( out, count, parser ); + glyph = out->glyphs + out->length; + in_glyph = in->glyphs + in->cursor; + + glyph->gindex = gindex; + + lig_component = in_glyph->lig_component; + lig_id = in_glyph->lid_id; + property = in_glyph->property; + + for ( ; count > 0; count-- ) + { + glyph->gindex = OTL_NEXT_USHORT(p); + glyph->property = property; + glyph->lig_component = lig_component; + glyph->lig_id = lig_id; + + out->length ++; + } + + out->cursor = out->length; + in->cursor += 1; + } + + + diff --git a/src/otlayout/otlparse.h b/src/otlayout/otlparse.h new file mode 100644 index 000000000..92f34bfdc --- /dev/null +++ b/src/otlayout/otlparse.h @@ -0,0 +1,99 @@ +#ifndef __OTL_PARSER_H__ +#define __OTL_PARSER_H__ + +#include "otlayout.h" +#include "otlgdef.h" +#include "otlgsub.h" +#include "otlgpos.h" + +OTL_BEGIN_HEADER + + typedef struct OTL_ParserRec_* OTL_Parser; + + typedef struct OTL_StringRec_* OTL_String; + + typedef struct OTL_StringGlyphRec_ + { + OTL_UInt gindex; + OTL_UInt properties; + OTL_UInt lig_component; + OTL_UInt lig_id; + + } OTL_StringGlyphRec, *OTL_StringGlyph; + + typedef struct OTL_StringRec_ + { + OTL_StringGlyph glyphs; + OTL_UInt cursor; + OTL_UInt length; + OTL_UInt capacity; + + } OTL_StringRec; + + typedef struct OTL_ParserRec_ + { + OTL_Bytes tab_gdef; + OTL_Bytes tab_gsub; + OTL_Bytes tab_gpos; + OTL_Bytes tab_base; + OTL_Bytes tab_jstf; + + OTL_Alternate alternate; /* external alternate handler */ + + OTL_UInt context_len; + OTL_UInt markup_flags; + + OTL_jmp_buf jump_buffer; + OTL_Memory memory; + OTL_Error error; + + OTL_StringRec strings[2]; + OTL_String str_in; + OTL_String str_out; + + } OTL_ParserRec; + + typedef enum + { + OTL_Err_Parser_Ok = 0, + OTL_Err_Parser_InvalidData, + OTL_Err_Parser_UncoveredGlyph + + } OTL_ParseError; + + OTL_LOCAL( OTL_UInt ) + otl_parser_get_gindex( OTL_Parser parser ); + + + OTL_LOCAL( void ) + otl_parser_error( OTL_Parser parser, OTL_ParserError error ); + +#define OTL_PARSER_UNCOVERED(x) \ + otl_parser_error( x, OTL_Err_Parser_UncoveredGlyph ) + + OTL_LOCAL( void ) + otl_parser_check_property( OTL_Parser parser, + OTL_UInt gindex, + OTL_UInt flags, + OTL_UInt *aproperty ); + + /* copy current input glyph to output */ + OTL_LOCAL( void ) + otl_parser_copy_1( OTL_Parser parser ); + + /* copy current input glyph to output, replacing its index */ + OTL_LOCAL( void ) + otl_parser_replace_1( OTL_Parser parser, + OTL_UInt gindex ); + + /* copy current input glyph to output, replacing it by several indices */ + /* read directly from the table */ + OTL_LOCAL( void ) + otl_parser_replace_n( OTL_Parser parser, + OTL_UInt count, + OTL_Bytes indices ); + +OTL_END_HEADER + +#endif /* __OTL_PARSER_H__ */ + diff --git a/src/otlayout/otlutils.h b/src/otlayout/otlutils.h new file mode 100644 index 000000000..de50f66f0 --- /dev/null +++ b/src/otlayout/otlutils.h @@ -0,0 +1,33 @@ +#ifndef __OTLAYOUT_UTILS_H__ +#define __OTLAYOUT_UTILS_H__ + +#include "otlayout.h" + +OTL_BEGIN_HEADER + + OTL_LOCAL( OTL_Error ) + otl_mem_alloc( OTL_Pointer* pblock, + OTL_ULong size, + OTL_Memory memory ); + + OTL_LOCAL( void ) + otl_mem_free( OTL_Pointer* pblock, + OTL_Memory memory ); + + OTL_LOCAL( OTL_Error ) + otl_mem_realloc( OTL_Pointer *pblock, + OTL_ULong cur_size, + OTL_ULong new_size, + OTL_Memory memory ); + +#define OTL_MEM_ALLOC(p,s) otl_mem_alloc( (void**)&(p), (s), memory ) +#define OTL_MEM_FREE(p) otl_mem_free( (void**)&(p), memory ) +#define OTL_MEM_REALLOC(p,c,n) otl_mem_realloc( (void**)&(p), (c), (s), memory ) + +#define OTL_MEM_NEW(p) OTL_MEM_ALLOC(p,sizeof(*(p))) +#define OTL_MEM_NEW_ARRAY(p,c) OTL_MEM_ALLOC(p,(c)*sizeof(*(p))) +#define OTL_MEM_RENEW_ARRAY(p,c,n) OTL_MEM_REALLOC(p,(c)*sizeof(*(p)),(n)*sizeof(*(p))) + +OTL_END_HEADER + +#endif /* __OTLAYOUT_UTILS_H__ */