ref: 8cd8907311da7ee6c09e22d9b8e26124d365db2a
parent: 948ee807e1d1d3270dc4d3a9c09615c11024b9c3
author: David Turner <[email protected]>
date: Sat May 4 14:02:59 EDT 2002
* src/truetype/ttgload.c (TT_Load_Glyph): finally fixing the last bug that prevented FreeType 2.x and FreeType 1.x to produce bit-by-bit identical monochrome glyph bitmaps with native TrueType hinting. The culprit was a single-bit flag that wasn't set correctly by the TrueType glyph loader !! * src/otlayout/otlayout.h, src/otlayout/otlbase.c, src/otlayout/otlbase.h, src/otlayout/otlconf.h, src/otlayout/otlgdef.c, src/otlayout/otlgdef.h, src/otlayout/otlgpos.c, src/otlayout/otlgpos.h, src/otlayout/otlgsub.c, src/otlayout/otlgsub.h, src/otlayout/otljstf.c, src/otlayout/otljstf.h, src/otlayout/otltable.c, src/otlayout/otltable.h, src/otlayout/otltags.h: adding OpenType Layout source files. Module is still incomplete
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2002-05-04 David Turner <[email protected]>
+
+ * src/truetype/ttgload.c (TT_Load_Glyph): finally fixing the last
+ bug that prevented FreeType 2.x and FreeType 1.x to produce
+ bit-by-bit identical monochrome glyph bitmaps with native TrueType
+ hinting. The culprit was a single-bit flag that wasn't set
+ correctly by the TrueType glyph loader !!
+
+ * src/otlayout/otlayout.h,
+ src/otlayout/otlbase.c,
+ src/otlayout/otlbase.h,
+ src/otlayout/otlconf.h,
+ src/otlayout/otlgdef.c,
+ src/otlayout/otlgdef.h,
+ src/otlayout/otlgpos.c,
+ src/otlayout/otlgpos.h,
+ src/otlayout/otlgsub.c,
+ src/otlayout/otlgsub.h,
+ src/otlayout/otljstf.c,
+ src/otlayout/otljstf.h,
+ src/otlayout/otltable.c,
+ src/otlayout/otltable.h,
+ src/otlayout/otltags.h:
+
+ adding OpenType Layout source files. Module is still incomplete
+
+
2002-05-02 Werner Lemberg <[email protected]>
* src/sfnt/ttcmap0.c (tt_cmap4_char_index): Fix serious typo
--- /dev/null
+++ b/src/otlayout/otlayout.h
@@ -1,0 +1,168 @@
+#ifndef __OT_LAYOUT_H__
+#define __OT_LAYOUT_H__
+
+
+#include "otlconf.h"
+
+OTL_BEGIN_HEADER
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** BASE DATA TYPES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef unsigned char OTL_Byte;
+ typedef const OTL_Byte* OTL_Bytes;
+
+ typedef int OTL_Error;
+
+ typedef void* OTL_Pointer;
+
+ typedef int OTL_Int;
+ typedef unsigned int OTL_UInt;
+
+ typedef short OTL_Int16;
+ typedef unsigned short OTL_UInt16;
+
+#if OTL_SIZEOF_INT == 4
+
+ typedef int OTL_Int32;
+ typedef unsigned int OTL_UInt32;
+
+#elif OTL_SIZEOF_LONG == 4
+
+ typedef long OTL_Int32;
+ typedef unsigned long OTL_UInt32;
+
+#else
+# error "no 32-bits type found"
+#endif
+
+ typedef OTL_UInt32 OTL_Tag;
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ERROR CODES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef enum
+ {
+ OTL_Err_Ok = 0,
+ OTL_Err_InvalidArgument,
+ OTL_Err_InvalidFormat,
+ OTL_Err_InvalidOffset,
+
+ } OTL_Error;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ENUMERATIONS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#define OTL_MAKE_TAG(c1,c2,c3,c4) \
+ ( ( (OTL_UInt32)(c1) << 24 ) | \
+ (OTL_UInt32)(c2) << 16 ) | \
+ (OTL_UInt32)(c3) << 8 ) | \
+ (OTL_UInt32)(c4) )
+
+ typedef enum OTL_ScriptTag_
+ {
+ OTL_SCRIPT_NONE = 0,
+
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n) OTL_SCRIPT_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+ OTL_SCRIPT_MAX
+
+ } OTL_ScriptTag;
+
+
+ typedef enum OTL_LangTag_
+ {
+ OTL_LANG_DEFAULT = 0,
+
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n) OTL_LANG_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+ OTL_LANG_MAX
+
+ } OTL_LangTag;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** MEMORY READS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#define OTL_PEEK_USHORT(p) ( ((OTL_UInt)((p)[0]) << 8) | \
+ ((OTL_UInt)((p)[1]) ) )
+
+#define OTL_PEEK_ULONG(p) ( ((OTL_UInt32)((p)[0]) << 24) | \
+ ((OTL_UInt32)((p)[1]) << 16) | \
+ ((OTL_UInt32)((p)[2]) << 8) | \
+ ((OTL_UInt32)((p)[3]) ) )
+
+#define OTL_PEEK_SHORT(p) ((OTL_Int16)OTL_PEEK_USHORT(p))
+
+#define OTL_PEEK_LONG(p) ((OTL_Int32)OTL_PEEK_ULONG(p))
+
+#define OTL_NEXT_USHORT(p) ( (p) += 2, OTL_PEEK_USHORT((p)-2) )
+#define OTL_NEXT_ULONG(p) ( (p) += 4, OTL_PEEK_ULONG((p)-4) )
+
+#define OTL_NEXT_SHORT(p) ((OTL_Int16)OTL_NEXT_USHORT(p))
+#define OTL_NEXT_LONG(p) ((OTL_Int32)OTL_NEXT_ULONG(p))
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** VALIDATION *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef struct OTL_ValidatorRec_* OTL_Validator;
+
+ typedef struct OTL_ValidatorRec_
+ {
+ OTL_Bytes limit;
+ OTL_Bytes base;
+ OTL_Error error;
+ OTL_jmp_buf jump_buffer;
+
+ } OTL_ValidatorRec;
+
+ typedef void (*OTL_ValidateFunc)( OTL_Bytes table,
+ OTL_Valid valid );
+
+ OTL_API( void )
+ otl_validator_error( OTL_Validator validator,
+ OTL_Error error );
+
+#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_CHECK(_count) OTL_BEGIN_STMNT \
+ if ( p + (_count) > valid->limit ) \
+ OTL_INVALID_TOO_SHORT; \
+ OTL_END_STMNT
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OPENTYPE_LAYOUT_H__ */
--- /dev/null
+++ b/src/otlayout/otlbase.c
@@ -1,0 +1,181 @@
+#include "otlbase.h"
+#include "otlcommn.h"
+
+ static void
+ otl_base_coord_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 4 );
+
+ format = OTL_NEXT_USHORT( p );
+ p += 2;
+
+ switch ( format )
+ {
+ case 1:
+ break;
+
+ case 2:
+ OTL_CHECK( 4 );
+ break;
+
+ case 3:
+ OTL_CHECK( 2 );
+ otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static void
+ otl_base_tag_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK(2);
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*4 );
+ }
+
+
+
+ static void
+ otl_base_values_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 4 );
+
+ p += 2; /* skip default index */
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+
+ for ( ; count > 0; count-- )
+ otl_base_coord_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_base_minmax_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt min_coord, max_coord, count;
+
+ OTL_CHECK(6);
+ min_coord = OTL_NEXT_USHORT( p );
+ max_coord = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( min_coord )
+ otl_base_coord_validate( table + min_coord, valid );
+
+ if ( max_coord )
+ otl_base_coord_validate( table + max_coord, valid );
+
+ OTL_CHECK( count*8 );
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ min_coord = OTL_NEXT_USHORT( p );
+ max_coord = OTL_NEXT_USHORT( p );
+
+ if ( min_coord )
+ otl_base_coord_validate( table + min_coord, valid );
+
+ if ( max_coord )
+ otl_base_coord_validate( table + max_coord, valid );
+ }
+ }
+
+
+ static void
+ otl_base_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt values, default_minmax;
+
+ OTL_CHECK(6);
+
+ values = OTL_NEXT_USHORT( p );
+ default_minmax = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( values )
+ otl_base_values_validate( table + values, valid );
+
+ if ( default_minmax )
+ otl_base_minmax_validate( table + default_minmax, valid );
+
+ OTL_CHECK( count*6 );
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ otl_base_minmax_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ static void
+ otl_base_script_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK(2);
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK(count*6);
+
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore script tag */
+ otl_base_script_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+ }
+
+ static void
+ otl_axis_table_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt tags;
+
+ OTL_CHECK(4);
+
+ tags = OTL_NEXT_USHORT( p );
+ if ( tags )
+ otl_base_tag_list_validate ( table + tags );
+
+ otl_base_script_list_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_base_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ OTL_CHECK(6);
+
+ if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+ otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+ }
\ No newline at end of file
--- /dev/null
+++ b/src/otlayout/otlbase.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_BASE_H__
+#define __OTL_BASE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_base_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_BASE_H__ */
--- a/src/otlayout/otlcommn.c
+++ b/src/otlayout/otlcommn.c
@@ -38,12 +38,12 @@
if ( table + 4 > valid->limit )
OTL_INVALID_TOO_SHORT;
- format = OTL_NEXT_UShort( p );
+ format = OTL_NEXT_USHORT( p );
switch ( format )
{
case 1:
{
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
if ( p + count * 2 >= valid->limit )
@@ -55,7 +55,7 @@
case 2:
{
- OTL_UInt n, num_ranges = OTL_NEXT_UShort( p );
+ OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p );
OTL_UInt start, end, start_cover, total = 0, last = 0;
@@ -64,9 +64,9 @@
for ( n = 0; n < num_ranges; n++ )
{
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
- start_cover = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ start_cover = OTL_NEXT_USHORT( p );
if ( start > end || start_cover != total )
OTL_INVALID_DATA;
@@ -90,8 +90,8 @@
otl_coverage_get_count( OTL_Bytes table )
{
OTL_Bytes p = table;
- OTL_UInt format = OTL_NEXT_UShort( p );
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt format = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
OTL_UInt result = 0;
@@ -107,8 +107,8 @@
for ( ; count > 0; count-- )
{
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
p += 2; /* skip start_index */
result += end - start + 1;
@@ -129,8 +129,8 @@
OTL_UInt glyph_index )
{
OTL_Bytes p = table;
- OTL_UInt format = OTL_NEXT_UShort( p );
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt format = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
switch ( format )
@@ -145,7 +145,7 @@
{
mid = ( min + max ) >> 1;
p = table + 2 * mid;
- gindex = OTL_PEEK_UShort( p );
+ gindex = OTL_PEEK_USHORT( p );
if ( glyph_index == gindex )
return (OTL_Int)mid;
@@ -169,8 +169,8 @@
{
mid = ( min + max ) >> 1;
p = table + 6 * mid;
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
if ( glyph_index < start )
max = mid;
@@ -177,7 +177,7 @@
else if ( glyph_index > end )
min = mid + 1;
else
- return (OTL_Int)( glyph_index + OTL_NEXT_UShort( p ) - start );
+ return (OTL_Int)( glyph_index + OTL_NEXT_USHORT( p ) - start );
}
}
break;
@@ -209,18 +209,18 @@
if ( p + 4 > valid->limit )
OTL_INVALID_TOO_SHORT;
- format = OTL_NEXT_UShort( p );
+ format = OTL_NEXT_USHORT( p );
switch ( format )
{
case 1:
{
- OTL_UInt count, start = OTL_NEXT_UShort( p );
+ OTL_UInt count, start = OTL_NEXT_USHORT( p );
if ( p + 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
- count = OTL_NEXT_UShort( p );
+ count = OTL_NEXT_USHORT( p );
if ( p + count * 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -231,7 +231,7 @@
case 2:
{
- OTL_UInt n, num_ranges = OTL_NEXT_UShort( p );
+ OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p );
OTL_UInt start, end, value, last = 0;
@@ -240,9 +240,9 @@
for ( n = 0; n < num_ranges; n++ )
{
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
- value = OTL_NEXT_UShort( p ); /* ignored */
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ value = OTL_NEXT_USHORT( p ); /* ignored */
if ( start > end || ( n > 0 && start <= last ) )
OTL_INVALID_DATA;
@@ -263,7 +263,7 @@
OTL_UInt glyph_index )
{
OTL_Bytes p = table;
- OTL_UInt format = OTL_NEXT_UShort( p );
+ OTL_UInt format = OTL_NEXT_USHORT( p );
switch ( format )
@@ -270,8 +270,8 @@
{
case 1:
{
- OTL_UInt start = OTL_NEXT_UShort( p );
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt start = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
OTL_UInt idx = (OTL_UInt)( glyph_index - start );
@@ -278,7 +278,7 @@
if ( idx < count )
{
p += 2 * idx;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
}
break;
@@ -285,7 +285,7 @@
case 2:
{
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
OTL_UInt min = 0, max = count, mid, gindex;
@@ -294,8 +294,8 @@
{
mid = ( min + max ) >> 1;
p = table + 6 * mid;
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
if ( glyph_index < start )
max = mid;
@@ -302,7 +302,7 @@
else if ( glyph_index > end )
min = mid + 1;
else
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
}
break;
@@ -334,9 +334,9 @@
if ( p + 8 > valid->limit )
OTL_INVALID_TOO_SHORT;
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
- format = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ format = OTL_NEXT_USHORT( p );
if ( format < 1 || format > 3 || end < start )
OTL_INVALID_DATA;
@@ -354,7 +354,7 @@
OTL_Bytes p = table;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -364,7 +364,7 @@
OTL_Bytes p = table + 2;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -377,9 +377,9 @@
OTL_UInt start, end, format, idx, value;
- start = OTL_NEXT_UShort( p );
- end = OTL_NEXT_UShort( p );
- format = OTL_NEXT_UShort( p );
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ format = OTL_NEXT_USHORT( p );
if ( size >= start && size <= end )
{
@@ -391,7 +391,7 @@
case 1:
idx = (OTL_UInt)( ( size - start ) * 2 );
p += idx / 16;
- value = OTL_PEEK_UShort( p );
+ value = OTL_PEEK_USHORT( p );
shift = idx & 15;
result = (OTL_Short)( value << shift ) >> ( 14 - shift );
@@ -400,7 +400,7 @@
case 2:
idx = (OTL_UInt)( ( size - start ) * 4 );
p += idx / 16;
- value = OTL_PEEK_UShort( p );
+ value = OTL_PEEK_USHORT( p );
shift = idx & 15;
result = (OTL_Short)( value << shift ) >> ( 12 - shift );
@@ -409,7 +409,7 @@
case 3:
idx = (OTL_UInt)( ( size - start ) * 8 );
p += idx / 16;
- value = OTL_PEEK_UShort( p );
+ value = OTL_PEEK_USHORT( p );
shift = idx & 15;
result = (OTL_Short)( value << shift ) >> ( 8 - shift );
@@ -444,7 +444,7 @@
OTL_INVALID_TOO_SHORT;
p += 4;
- num_tables = OTL_NEXT_UShort( p );
+ num_tables = OTL_NEXT_USHORT( p );
if ( p + num_tables * 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -451,7 +451,7 @@
for ( ; num_tables > 0; num_tables-- )
{
- offset = OTL_NEXT_UShort( p );
+ offset = OTL_NEXT_USHORT( p );
if ( table + offset >= valid->limit )
OTL_INVALID_OFFSET;
@@ -467,7 +467,7 @@
OTL_Bytes p = table + 4;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -480,11 +480,11 @@
p = table + 4;
- count = OTL_NEXT_UShort( p );
+ count = OTL_NEXT_USHORT( p );
if ( idx < count )
{
p += idx * 2;
- result = table + OTL_PEEK_UShort( p );
+ result = table + OTL_PEEK_USHORT( p );
}
return result;
@@ -510,7 +510,7 @@
if ( p + 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
- num_lookups = OTL_NEXT_UShort( p );
+ num_lookups = OTL_NEXT_USHORT( p );
if ( p + num_lookups * 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -517,7 +517,7 @@
for ( ; num_lookups > 0; num_lookups-- )
{
- offset = OTL_NEXT_UShort( p );
+ offset = OTL_NEXT_USHORT( p );
otl_lookup_validate( table + offset, valid );
}
@@ -530,7 +530,7 @@
OTL_Bytes p = table;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -543,11 +543,11 @@
p = table;
- count = OTL_NEXT_UShort( p );
+ count = OTL_NEXT_USHORT( p );
if ( idx < count )
{
p += idx * 2;
- result = table + OTL_PEEK_UShort( p );
+ result = table + OTL_PEEK_USHORT( p );
}
return result;
@@ -576,7 +576,7 @@
OTL_Pointer func_data )
{
OTL_Bytes p = table;
- OTL_UInt count = OTL_NEXT_UShort( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
for ( ; count > 0; count-- )
@@ -603,8 +603,8 @@
if ( p + 4 > valid->limit )
OTL_INVALID_TOO_SHORT;
- feat_params = OTL_NEXT_UShort( p ); /* ignored */
- num_lookups = OTL_NEXT_UShort( p );
+ feat_params = OTL_NEXT_USHORT( p ); /* ignored */
+ num_lookups = OTL_NEXT_USHORT( p );
if ( p + num_lookups * 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -619,7 +619,7 @@
OTL_Bytes p = table + 4;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -634,13 +634,13 @@
p = table + 4;
- num_features = OTL_NEXT_UShort( p );
+ num_features = OTL_NEXT_USHORT( p );
p += start * 2;
for ( ; count > 0 && start < num_features; count--, start++ )
{
- lookups[0] = OTL_NEXT_UShort(p);
+ lookups[0] = OTL_NEXT_USHORT(p);
lookups++;
result++;
}
@@ -668,7 +668,7 @@
if ( table + 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
- num_features = OTL_NEXT_UShort( p );
+ num_features = OTL_NEXT_USHORT( p );
if ( p + num_features * 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -676,7 +676,7 @@
for ( ; num_features > 0; num_features-- )
{
p += 4; /* skip tag */
- offset = OTL_NEXT_UShort( p );
+ offset = OTL_NEXT_USHORT( p );
otl_feature_table_validate( table + offset, valid );
}
@@ -689,7 +689,7 @@
OTL_Bytes p = table;
- return OTL_PEEK_UShort( p );
+ return OTL_PEEK_USHORT( p );
}
@@ -702,12 +702,12 @@
p = table;
- count = OTL_NEXT_UShort( p );
+ count = OTL_NEXT_USHORT( p );
if ( idx < count )
{
p += idx * 2;
- result = table + OTL_PEEK_UShort( p );
+ result = table + OTL_PEEK_USHORT( p );
}
return result;
@@ -724,10 +724,10 @@
p = table;
- count = OTL_NEXT_UShort( p );
+ count = OTL_NEXT_USHORT( p );
for ( ; count > 0; count-- )
- func( table + OTL_NEXT_UShort( p ), func_data );
+ func( table + OTL_NEXT_USHORT( p ), func_data );
}
@@ -753,9 +753,9 @@
if ( table + 6 >= valid->limit )
OTL_INVALID_TOO_SHORT;
- lookup_order = OTL_NEXT_UShort( p );
- req_feature = OTL_NEXT_UShort( p );
- num_features = OTL_NEXT_UShort( p );
+ lookup_order = OTL_NEXT_USHORT( p );
+ req_feature = OTL_NEXT_USHORT( p );
+ num_features = OTL_NEXT_USHORT( p );
/* XXX: check req_feature if not 0xFFFFU */
@@ -769,10 +769,19 @@
OTL_LOCALDEF( OTL_UInt )
otl_lang_get_count( OTL_Bytes table )
{
- OTL_Bytes p = table + 4;
+ OTL_Bytes p = table + 4;
+ return OTL_PEEK_USHORT( p );
+ }
- return OTL_PEEK_UShort( p );
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lang_get_req_feature( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 2;
+
+
+ return OTL_PEEK_USHORT( p );
}
@@ -783,7 +792,7 @@
OTL_UInt *features )
{
OTL_Bytes p = table + 4;
- OTL_UInt num_features = OTL_NEXT_UShort( p );
+ OTL_UInt num_features = OTL_NEXT_USHORT( p );
OTL_UInt result = 0;
@@ -791,7 +800,7 @@
for ( ; count > 0 && start < num_features; start++, count-- )
{
- features[0] = OTL_NEXT_UShort( p );
+ features[0] = OTL_NEXT_USHORT( p );
features++;
result++;
}
@@ -800,16 +809,8 @@
}
- OTL_LOCALDEF( OTL_UInt )
- otl_lang_get_req_feature( OTL_Bytes table )
- {
- OTL_Bytes p = table + 2;
- return OTL_PEEK_UShort( p );
- }
-
-
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -820,8 +821,8 @@
OTL_LOCALDEF( void )
- otl_script_table_validate( OTL_Bytes table,
- OTL_Validator valid )
+ otl_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
{
OTL_UInt default_lang;
OTL_Bytes p = table;
@@ -830,8 +831,8 @@
if ( table + 4 > valid->limit )
OTL_INVALID_TOO_SHORT;
- default_lang = OTL_NEXT_UShort( p );
- num_langs = OTL_NEXT_UShort( p );
+ default_lang = OTL_NEXT_USHORT( p );
+ num_langs = OTL_NEXT_USHORT( p );
if ( default_lang != 0 )
{
@@ -848,7 +849,7 @@
p += 4; /* skip tag */
- offset = OTL_NEXT_UShort( p );
+ offset = OTL_NEXT_USHORT( p );
otl_lang_validate( table + offset, valid );
}
@@ -866,7 +867,7 @@
if ( list + 2 > valid->limit )
OTL_INVALID_TOO_SHORT;
- num_scripts = OTL_NEXT_UShort( p );
+ num_scripts = OTL_NEXT_USHORT( p );
if ( p + num_scripts * 6 > valid->limit )
OTL_INVALID_TOO_SHORT;
@@ -877,11 +878,63 @@
p += 4; /* skip tag */
- offset = OTL_NEXT_UShort( p );
+ offset = OTL_NEXT_USHORT( p );
otl_script_table_validate( list + offset, valid );
}
}
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ otl_lookup_table_validate( OTL_Bytes table,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt lookup_type, lookup_flag, count;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_flag = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( lookup_type == 0 || lookup_type >= type_count )
+ OTL_INVALID_DATA;
+
+ validate = type_funcs[ lookup_type - 1 ];
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_lookup_list_validate( OTL_Bytes table,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_lookup_table_validate( table + OTL_NEXT_USHORT( p ),
+ type_count, type_funcs, valid );
+ }
/* END */
--- a/src/otlayout/otlcommn.h
+++ b/src/otlayout/otlcommn.h
@@ -208,6 +208,65 @@
OTL_ForeachFunc func,
OTL_Pointer func_data );
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LANGUAGE SYSTEM *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_lang_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_req_feature( OTL_Bytes table );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_count( OTL_Bytes table );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_features( OTL_Bytes table,
+ OTL_UInt start,
+ OTL_UInt count,
+ OTL_UInt *features );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SCRIPTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_script_list_validate( OTL_Bytes list,
+ OTL_Validator valid );
+
+ OTL_LOCAL( OTL_Bytes )
+ otl_script_list_get_script( OTL_Bytes table );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_lookup_list_validate( OTL_Bytes list,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid );
+
/* */
OTL_END_HEADER
--- /dev/null
+++ b/src/otlayout/otlconf.h
@@ -1,0 +1,73 @@
+#ifndef __OT_LAYOUT_CONFIG_H__
+#define __OT_LAYOUT_CONFIG_H__
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** CONFIGURATION MACROS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifdef __cplusplus
+# define OTL_BEGIN_HEADER extern "C" {
+#else
+# define OTL_BEGIN_HEADER /* nothing */
+#endif
+
+#ifdef __cplusplus
+# define OTL_END_HEADER }
+#else
+# define OTL_END_HEADER /* nothing */
+#endif
+
+#ifndef OTL_API
+# ifdef __cplusplus
+# define OTL_API( x ) extern "C"
+# else
+# define OTL_API( x ) extern x
+# endif
+#endif
+
+#ifndef OTL_APIDEF
+# define OTL_APIDEF( x ) x
+#endif
+
+#ifndef OTL_LOCAL
+# define OTL_LOCAL( x ) extern x
+#endif
+
+#ifndef OTL_LOCALDEF
+# define OTL_LOCALDEF( x ) x
+#endif
+
+#define OTL_BEGIN_STMNT do {
+#define OTL_END_STMNT } while (0)
+#define OTL_DUMMY_STMNT do { } while (0)
+
+#define OTL_UNUSED( x ) (x)=(x)
+#define OTL_UNUSED_CONST(x) (void)(x)
+
+
+#include <limits.h>
+#if UINT_MAX == 0xFFFFU
+# define OTL_SIZEOF_INT 2
+#elif UINT_MAX == 0xFFFFFFFFU
+# define OTL_SIZEOF_INT 4
+#elif UINT_MAX > 0xFFFFFFFFU && UINT_MAX == 0xFFFFFFFFFFFFFFFFU
+# define OTL_SIZEOF_INT 8
+#else
+# error "unsupported number of bytes in 'int' type!"
+#endif
+
+#if ULONG_MAX == 0xFFFFFFFFU
+# define OTL_SIZEOF_LONG 4
+#elif ULONG_MAX > 0xFFFFFFFFU && ULONG_MAX == 0xFFFFFFFFFFFFFFFFU
+# define OTL_SIZEOF_LONG 8
+#else
+# error "unsupported number of bytes in 'long' type!"
+#endif
+
+/* */
+
+#endif /* __OT_LAYOUT_CONFIG_H__ */
--- /dev/null
+++ b/src/otlayout/otlgdef.c
@@ -1,0 +1,175 @@
+#include "otlgdef.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ATTACHMENTS LIST *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_attach_point_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ count = OTL_NEXT_USHORT( p );
+ if ( table + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+ }
+
+
+ static void
+ otl_attach_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage;
+ OTL_UInt count;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ coverage = table + OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( coverage, valid );
+ if ( count != otl_coverage_get_count( coverage ) )
+ OTL_INVALID_DATA;
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_attach_point_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** LIGATURE CARETS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_caret_value_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ case 2:
+ break;
+
+ case 3:
+ {
+ OTL_Bytes device;
+
+ p += 2;
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static void
+ otl_ligature_glyph_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ count = OTL_NEXT_USHORT( p );
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_caret_value_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ static void
+ otl_ligature_caret_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage;
+ OTL_UInt count;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ coverage = table + OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( coverage, valid );
+ if ( count != otl_coverage_get_count( coverage ) )
+ OTL_INVALID_DATA;
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_ligature_glyph_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GDEF TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ OTL_APIDEF( void )
+ otl_gdef_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ if ( p + 12 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* check format */
+ if ( OTL_NEXT_ULONG( p ) != 0x00010000UL )
+ OTL_INVALID_FORMAT;
+
+ /* validate class definition table */
+ otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate attachment point list */
+ otl_attach_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate ligature caret list */
+ otl_ligature_caret_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate mark attach class */
+ otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
--- /dev/null
+++ b/src/otlayout/otlgdef.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GDEF_H__
+#define __OTL_GDEF_H__
+
+#include "otltable.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_API( void )
+ otl_gdef_validate( OTL_Bytes table,
+ OTL_Valid valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GDEF_H__ */
--- /dev/null
+++ b/src/otlayout/otlgpos.c
@@ -1,0 +1,980 @@
+#include "otlgpos.h"
+#include "otlcommn.h"
+
+ /* forward declaration */
+ static OTL_ValidateFunc otl_gpos_validate_funcs[];
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** VALUE RECORDS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static OTL_UInt
+ otl_value_length( OTL_UInt format )
+ {
+ FT_UInt count;
+
+ count = (( format & 0xAA ) >> 1) + ( format & 0x55 );
+ count = (( count & 0xCC ) >> 2) + ( count & 0x33 );
+ count = (( count & 0xF0 ) >> 4) + ( count & 0x0F );
+
+ return count;
+ }
+
+
+ static void
+ otl_value_validate( OTL_Bytes table,
+ OTL_Bytes pos_table,
+ OTL_UInt format,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, device;
+
+ if ( format >= 0x100U )
+ OTL_INVALID_DATA;
+
+ for ( count = 4; count > 0; count-- )
+ {
+ if ( format & 1 )
+ {
+ OTL_CHECK( 2 );
+ p += 2;
+ }
+
+ format >>= 1;
+ }
+
+ for ( count = 4; count > 0; count-- )
+ {
+ if ( format & 1 )
+ {
+ OTL_CHECK( 2 );
+ device = OTL_NEXT_USHORT( p );
+ if ( device )
+ otl_device_table_validate( pos_table + device, valid );
+ }
+ format >>= 1;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ANCHORS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_anchor_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 6 );
+ format = OTL_NEXT_USHORT( p );
+ p += 4;
+
+ switch ( format )
+ {
+ case 1:
+ break;
+
+ case 2:
+ OTL_CHECK( 2 ); /* anchor point */
+ break;
+
+ case 3:
+ {
+ OTL_UInt x_device, y_device;
+
+ OTL_CHECK( 4 );
+ x_device = OTL_NEXT_USHORT( p );
+ y_device = OTL_NEXT_USHORT( p );
+
+ if ( x_device )
+ otl_device_table_validate( table + x_device, valid );
+
+ if ( y_device )
+ otl_device_table_validate( table + y_device, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** MARK ARRAY *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_mark_array_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count * 4 );
+ for ( ; count > 0; count-- )
+ {
+ p += 2; /* ignore class index */
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 1 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup1_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ FT_UInt coverage, value_format;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ value_format = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+ otl_value_validate( p, table, value_format, valid );
+ }
+ break;
+
+ case 2:
+ {
+ FT_UInt coverage, value_format, count, len;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ value_format = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+ len = otl_value_length( value_format );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count * len );
+ for ( ; count > 0; count-- )
+ {
+ otl_value_validate( p, table, value_format, valid );
+ p += len;
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 2 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static otl_gpos_pairset_validate( OTL_Bytes table,
+ OTL_Bytes pos_table,
+ OTL_UInt format1,
+ OTL_UInt format2,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt len1, len2, count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ len1 = otl_value_length( format1 );
+ len2 = otl_value_length( format2 );
+
+ OTL_CHECK( count * (len1+len2+2) );
+ for ( ; count > 0; count-- )
+ {
+ p += 2; /* ignore glyph id */
+ otl_value_validate( p, pos_table, format1, valid );
+ p += len1;
+
+ otl_value_validate( p, pos_table, format2, valid );
+ p += len2;
+ }
+ }
+
+ static void
+ otl_gpos_lookup2_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, value1, value2, count;
+
+ OTL_CHECK( 8 );
+ coverage = OTL_NEXT_USHORT( p );
+ value1 = OTL_NEXT_USHORT( p );
+ value2 = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ {
+ otl_gpos_pairset_validate( table + OTL_NEXT_USHORT( p ),
+ table, value1, value2, valid );
+ }
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, value1, value2, class1, class2, count1, count2;
+ OTL_UInt len1, len2;
+
+ OTL_CHECK( 14 );
+ coverage = OTL_NEXT_USHORT( p );
+ value1 = OTL_NEXT_USHORT( p );
+ value2 = OTL_NEXT_USHORT( p );
+ class1 = OTL_NEXT_USHORT( p );
+ class2 = OTL_NEXT_USHORT( p );
+ count1 = OTL_NEXT_USHORT( p );
+ count2 = OTL_NEXT_USHORT( p );
+
+ len1 = otl_value_length( value1 );
+ len2 = otl_value_length( value2 );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count1*count2*(len1+len2) );
+ for ( ; count1 > 0; count1-- )
+ {
+ for ( ; count2 > 0; count2-- )
+ {
+ otl_value_validate( p, table, value1, valid );
+ p += len1;
+
+ otl_value_validate( p, table, value2, valid );
+ p += len2;
+ }
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 3 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup3_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count, anchor1, anchor2;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*4 );
+ for ( ; count > 0; count-- )
+ {
+ anchor1 = OTL_NEXT_USHORT( p );
+ anchor2 = OTL_NEXT_USHORT( p );
+
+ if ( anchor1 )
+ otl_anchor_validate( table + anchor1, valid );
+
+ if ( anchor2 )
+ otl_anchor_validate( table + anchor2, valid );
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 4 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_base_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; count2 > 0; count2-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ static void
+ otl_gpos_lookup4_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt mark_coverage, base_coverage, class_count;
+ OTL_UInt mark_array, base_array;
+
+ OTL_CHECK( 10 );
+ mark_coverage = OTL_NEXT_USHORT( p );
+ base_coverage = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ mark_array = OTL_NEXT_USHORT( p );
+ base_array = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + mark_coverage, valid );
+ otl_coverage_validate( table + base_coverage, valid );
+
+ otl_mark_array_validate( table + mark_array, valid );
+ otl_base_array_validate( table, class_count, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 5 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_liga_attach_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; class_count > 0; class_count-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_liga_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_liga_attach_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup5_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt mark_coverage, lig_coverage, class_count;
+ OTL_UInt mar_array, lig_array;
+
+ OTL_CHECK( 10 );
+ mark_coverage = OTL_NEXT_USHORT( p );
+ liga_coverage = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ mark_array = OTL_NEXT_USHORT( p );
+ liga_array = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + mark_coverage, valid );
+ otl_coverage_validate( table + liga_coverage, valid );
+
+ otl_mark_array_validate( table + mark_array, valid );
+ otl_liga_array_validate( table + liga_array, class_count, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_mark2_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; class_count > 0; class_count-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup6_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage1, coverage2, class_count, array1, array2;
+
+ OTL_CHECK( 10 );
+ coverage1 = OTL_NEXT_USHORT( p );
+ coverage2 = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ array1 = OTL_NEXT_USHORT( p );
+ array2 = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage1, valid );
+ otl_coverage_validate( table + coverage2, valid );
+
+ otl_mark_array_validate( table + array1, valid );
+ otl_mark2_array_validate( table + array2, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 7 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_pos_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+ /* XXX: check glyph indices and pos lookups */
+ }
+
+
+ static void
+ otl_pos_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+ }
+
+
+
+ static void
+ otl_pos_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+ /* XXX: check glyph indices and pos lookups */
+ }
+
+
+ static void
+ otl_pos_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup7_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, class_def, count;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ class_def = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate ( table + coverage, valid );
+ otl_class_definition_validate( table + class_def, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( glyph_count*2 + pos_count*4 );
+ for ( ; glyph_count > 0; glyph_count )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ /* XXX: check pos lookups */
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 8 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_chain_pos_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, pos_count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( back_count*2 + 2 );
+ p += back_count*2;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( input_count*2 );
+ p += (input_count-1)*2;
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( ahead_count*2 + 2 );
+ p += ahead_count*2;
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+
+
+ static void
+ otl_chain_pos_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+
+ static void
+ otl_chain_pos_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, pos_count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( back_count*2 + 2 );
+ p += back_count*2;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( input_count*2 );
+ p += (input_count-1)*2;
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( ahead_count*2 + 2 );
+ p += ahead_count*2;
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+
+
+ static void
+ otl_chain_pos_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup8_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+ valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, back_class, input_class, ahead_class, count;
+
+ OTL_CHECK( 10 );
+ coverage = OTL_NEXT_USHORT( p );
+ back_class = OTL_NEXT_USHORT( p );
+ input_class = OTL_NEXT_USHORT( p );
+ ahead_class = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ otl_class_definition_validate( table + back_class, valid );
+ otl_class_definition_validate( table + input_class, valid );
+ otl_class_definition_validate( table + ahead_class, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_class_set_validate( table + OTL_NEXT_USHORT( p ),
+ valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt back_count, input_count, ahead_count, pos_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ for ( count = back_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ input_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*input_count+2 );
+ for ( count = input_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ ahead_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*ahead_count+2 );
+ for ( count = ahead_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 9 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup9_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt lookup_type, lookup_offset;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_offset = OTL_NEXT_ULONG( p );
+
+ if ( lookup_type == 0 || lookup_type >= 9 )
+ OTL_INVALID_DATA;
+
+ validate = otl_gpos_validate_funcs[ lookup_type-1 ];
+ validate( table + lookup_offset, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ static OTL_ValidateFunc otl_gpos_validate_funcs[ 9 ] =
+ {
+ otl_gpos_lookup1_validate,
+ otl_gpos_lookup2_validate,
+ otl_gpos_lookup3_validate,
+ otl_gpos_lookup4_validate,
+ otl_gpos_lookup5_validate,
+ otl_gpos_lookup6_validate,
+ otl_gpos_lookup7_validate,
+ otl_gpos_lookup8_validate,
+ otl_gpos_lookup9_validate,
+ };
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_gpos_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt scripts, features, lookups;
+
+ OTL_CHECK( 10 );
+
+ if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ scripts = OTL_NEXT_USHORT( p );
+ features = OTL_NEXT_USHORT( p );
+ lookups = OTL_NEXT_USHORT( p );
+
+ otl_script_list_validate ( table + scripts, valid );
+ otl_feature_list_validate( table + features, valid );
+
+ otl_lookup_list_validate( table + lookups, 9, otl_gpos_validate_funcs,
+ valid );
+ }
+
\ No newline at end of file
--- /dev/null
+++ b/src/otlayout/otlgpos.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GPOS_H__
+#define __OTL_GPOS_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_gpos_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GPOS_H__ */
--- /dev/null
+++ b/src/otlayout/otlgsub.c
@@ -1,0 +1,654 @@
+#include "otlgsub.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 1 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gsub_lookup1_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 2 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_seq_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ /* check glyph indices */
+ }
+
+
+ static void
+ otl_gsub_lookup2_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, seq_count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ seq_count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( seq_count*2 );
+ for ( ; seq_count > 0; seq_count-- )
+ otl_seq_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 3 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_alternate_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ /* XXX: check glyph indices */
+ }
+
+
+ static void
+ otl_gsub_lookup3_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 4 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_ligature_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_UInt glyph_id, count;
+
+ OTL_CHECK( 4 );
+ glyph_id = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*(count-1) );
+ /* XXX: check glyph indices */
+ }
+
+
+ static void
+ otl_ligature_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup4_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 5 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_sub_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, subst_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_sub_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_sub_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_UInt glyph_count, subst_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_sub_class_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup5_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_rule_set_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, class_def, count;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ class_def = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate ( table + coverage, valid );
+ otl_class_definition_validate( table + class_def, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_class_rule_set_validate( table + coveragen valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt glyph_count, subst_count, count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*glyph_count + 4*subst_count );
+ for ( count = glyph_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_chain_sub_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ p += 2*back_count;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*input_count );
+ p += 2*(input_count-1);
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 2*ahead_count + 2 );
+ p += 2*ahead_count;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 4*count );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_chain_sub_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_chain_sub_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ p += 2*back_count;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*input_count );
+ p += 2*(input_count-1);
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 2*ahead_count + 2 );
+ p += 2*ahead_count;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 4*count );
+
+ /* XXX: check class indices and subst lookups */
+ }
+
+
+
+ static void
+ otl_chain_sub_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup6_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_set_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, back_class, input_class, ahead_class, count;
+
+ OTL_CHECK( 10 );
+ coverage = OTL_NEXT_USHORT( p );
+ back_class = OTL_NEXT_USHORT( p );
+ input_class = OTL_NEXT_USHORT( p );
+ ahead_class = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ otl_class_definition_validate( table + back_class, valid );
+ otl_class_definition_validate( table + input_class, valid );
+ otl_class_definition_validate( table + ahead_class, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_class_set( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ for ( count = back_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ input_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*input_count+2 );
+ for ( count = input_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ ahead_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*ahead_count+2 );
+ for ( count = ahead_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ subst_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( subst_count*4 );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gsub_lookup7_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt lookup_type, lookup_offset;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_offset = OTL_NEXT_ULONG( p );
+
+ if ( lookup_type == 0 || lookup_type >= 7 )
+ OTL_INVALID_DATA;
+
+ validate = otl_gsub_validate_funcs[ lookup_type-1 ];
+ validate( table + lookup_offset, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static const OTL_ValidateFunc otl_gsub_validate_funcs[ 7 ] =
+ {
+ otl_gsub_lookup1_validate,
+ otl_gsub_lookup2_validate,
+ otl_gsub_lookup3_validate,
+ otl_gsub_lookup4_validate,
+ otl_gsub_lookup5_validate,
+ otl_gsub_lookup6_validate
+ };
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_gsub_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt scripts, features, lookups;
+
+ OTL_CHECK( 10 );
+
+ if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ scripts = OTL_NEXT_USHORT( p );
+ features = OTL_NEXT_USHORT( p );
+ lookups = OTL_NEXT_USHORT( p );
+
+ otl_script_list_validate ( table + scripts, valid );
+ otl_feature_list_validate( table + features, valid );
+
+ otl_lookup_list_validate( table + lookups, 7, otl_gsub_validate_funcs,
+ valid );
+ }
--- /dev/null
+++ b/src/otlayout/otlgsub.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GSUB_H__
+#define __OTL_GSUB_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_gsub_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GSUB_H__ */
--- /dev/null
+++ b/src/otlayout/otljstf.c
@@ -1,0 +1,189 @@
+#include "otljstf.h"
+#include "otlcommn.h"
+#include "otlgpos.h"
+
+ static void
+ otl_jstf_extender_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ }
+
+
+ static void
+ otl_jstf_gsub_mods_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*2 );
+
+ /* XXX: check GSUB lookup indices */
+ }
+
+
+ static void
+ otl_jstf_gpos_mods_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*2 );
+
+ /* XXX: check GPOS lookup indices */
+ }
+
+
+ static void
+ otl_jstf_max_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_gpos_subtable_check( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_jstf_priority_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt offset;
+
+ OTL_CHECK( 20 );
+
+ /* shrinkage GSUB enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ /* shrinkage GPOS enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ /* shrinkage JSTF max */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_max_validate( table + val, valid );
+
+ /* extension GSUB enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ /* extension GPOS enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ /* extension JSTF max */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_max_validate( table + val, valid );
+ }
+
+ static void
+ otl_jstf_lang_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_jstf_priority_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_jstf_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, extender, default_lang;
+
+ OTL_CHECK( 6 );
+ extender = OTL_NEXT_USHORT( p );
+ default_lang = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( extender )
+ otl_jstf_extender_validate( table + extender, valid );
+
+ if ( default_lang )
+ otl_jstf_lang_validate( table + default_lang, valid );
+
+ OTL_CHECK( 6*count );
+
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ otl_jstf_lang_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_jstf_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 4 );
+
+ if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*6 );
+
+ for ( ; count > 0; count++ )
+ {
+ p += 4; /* ignore tag */
+ otl_jstf_script_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
\ No newline at end of file
--- /dev/null
+++ b/src/otlayout/otljstf.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_JSTF_H__
+#define __OTL_JSTF_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_jstf_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_JSTF_H__ */
\ No newline at end of file
--- /dev/null
+++ b/src/otlayout/otltable.h
@@ -1,0 +1,60 @@
+#ifndef __OTL_TABLE_H__
+#define __OTL_TABLE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ typedef struct OTL_TableRec_* OTL_Table;
+
+ typedef enum
+ {
+ OTL_TABLE_TYPE_GDEF = 1,
+ OTL_TABLE_TYPE_GSUB,
+ OTL_TABLE_TYPE_GPOS,
+ OTL_TABLE_TYPE_BASE,
+ OTL_TABLE_TYPE_JSTF
+
+ } OTL_TableType;
+
+
+ /* this may become a private structure later */
+ typedef struct OTL_TableRec_
+ {
+ OTL_TableType type;
+ OTL_Bytes base;
+ OTL_Bytes limit;
+
+ OTL_Tag script_tag;
+ OTL_Tag lang_tag;
+
+ OTL_UInt lookup_count;
+ OTL_Byte* lookup_flags;
+
+ OTL_UInt feature_count;
+ OTL_Tag feature_tags;
+ OTL_Byte* feature_flags;
+
+ } OTL_TableRec;
+
+
+ OTL_API( OTL_Error )
+ otl_table_validate( OTL_Bytes table,
+ OTL_Size size,
+ OTL_TableType type,
+ OTL_Size *abyte_size );
+
+ OTL_API( void )
+ otl_table_init( OTL_Table table,
+ OTL_TableType type,
+ OTL_Bytes base,
+ OTL_Size size );
+
+ OTL_API( void )
+ otl_table_set_script( OTL_Table table,
+ OTL_ScriptTag script,
+ OTL_LangTag language );
+
+OTL_END_HEADER
+
+#endif /* __OTL_TABLE_H__ */
--- /dev/null
+++ b/src/otlayout/otltags.h
@@ -1,0 +1,86 @@
+/* this file may be included several times by other parts of */
+/* the OpenType Layout library.. don't add #ifdef .. #endif */
+/* delimiters to it... */
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** SCRIPT TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_SCRIPT_TAG
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+OTL_SCRIPT_TAG( 'a','r','a','b', "Arabic", ARABIC )
+OTL_SCRIPT_TAG( 'a','r','m','n', "Armenian", ARMENIAN )
+OTL_SCRIPT_TAG( 'b','e','n','g', "Bengali", BENGALI )
+OTL_SCRIPT_TAG( 'b','o','p','o', "Bopomofo", BOPOMOFO )
+OTL_SCRIPT_TAG( 'b','r','a','i', "Braille", BRAILLE )
+OTL_SCRIPT_TAG( 'c','a','n','s', "Canadian Syllabic", CANADIAN )
+OTL_SCRIPT_TAG( 'c','h','e','r', "Cherokee", CHEROKEE )
+OTL_SCRIPT_TAG( 'h','a','n','i', "CJK Ideographic", CJK )
+OTL_SCRIPT_TAG( 'c','y','r','l', "Cyrillic", CYRILLIC )
+OTL_SCRIPT_TAG( 'd','e','v','a', "Devanagari", DEVANAGARI )
+OTL_SCRIPT_TAG( 'e','t','h','i', "Ethiopic", ETHIOPIC )
+OTL_SCRIPT_TAG( 'g','e','o','r', "Georgian", GEORGIAN )
+OTL_SCRIPT_TAG( 'g','r','e','k', "Greek", GREEK )
+OTL_SCRIPT_TAG( 'g','u','j','r', "Gujarati", GUJARATI )
+OTL_SCRIPT_TAG( 'g','u','r','u', "Gurmukhi", GURMUKHI )
+OTL_SCRIPT_TAG( 'j','a','m','o', "Hangul Jamo", JAMO )
+OTL_SCRIPT_TAG( 'h','a','n','g', "Hangul", HANGUL )
+OTL_SCRIPT_TAG( 'h','e','b','r', "Hebrew", HEBREW )
+OTL_SCRIPT_TAG( 'h','i','r','a', "Hiragana", HIRAGANA )
+OTL_SCRIPT_TAG( 'k','n','d','a', "Kannada", KANNADA )
+OTL_SCRIPT_TAG( 'k','a','n','a', "Katakana", KATAKANA )
+OTL_SCRIPT_TAG( 'k','h','m','r', "Khmer", KHMER )
+OTL_SCRIPT_TAG( 'l','a','o',' ', "Lao", LAO )
+OTL_SCRIPT_TAG( 'l','a','t','n', "Latin", LATIN )
+OTL_SCRIPT_TAG( 'm','l','y','m', "Malayalam", MALAYALAM )
+OTL_SCRIPT_TAG( 'm','o','n','g', "Mongolian", MONGOLIAN )
+OTL_SCRIPT_TAG( 'm','y','m','r', "Myanmar", MYANMAR )
+OTL_SCRIPT_TAG( 'o','g','a','m', "Ogham", OGHAM )
+OTL_SCRIPT_TAG( 'o','r','y','a', "Oriya", ORIYA )
+OTL_SCRIPT_TAG( 'r','u','n','r', "Runic", RUNIC )
+OTL_SCRIPT_TAG( 's','i','n','h', "Sinhala", SINHALA )
+OTL_SCRIPT_TAG( 's','y','r','c', "Syriac", SYRIAC )
+OTL_SCRIPT_TAG( 't','a','m','l', "Tamil", TAMIL )
+OTL_SCRIPT_TAG( 't','e','l','u', "Telugu", TELUGU )
+OTL_SCRIPT_TAG( 't','h','a','a', "Thaana", THAANA )
+OTL_SCRIPT_TAG( 't','h','a','i', "Thai", THAI )
+OTL_SCRIPT_TAG( 't','i','b','t', "Tibetan", TIBETAN )
+OTL_SCRIPT_TAG( 'y','i',' ',' ', "Yi", YI )
+
+#undef OTL_SCRIPT_TAG
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** LANGUAGE TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_LANG_TAG
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+#undef OTL_LANG_TAG
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** FEATURE TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_FEATURE_TAG
+#define OTL_FEATURE_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+#undef OTL_FEATURE_TAG
+
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -1543,9 +1543,6 @@
/* clear all outline flags, except the `owner' one */
glyph->outline.flags = 0;
- if ( size && size->root.metrics.y_ppem < 24 )
- glyph->outline.flags |= ft_outline_high_precision;
-
/* let's initialize the rest of our loader now */
loader.load_flags = load_flags;
@@ -1580,6 +1577,14 @@
TT_Done_Context( loader.exec );
#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* Don't forget to set the 'high precision' bit flag !! */
+ /* This is _critical_ to get correct output for monochrome */
+ /* TrueType glyphs at all sizes using the bytecode interpreter */
+ /* */
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->outline.flags |= ft_outline_high_precision;
+
Exit:
return error;