X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fotfopen.c;h=8aa062dd8996fa405e5c56366e3493ec409399f4;hb=e82129639d46b119f5d4935132cce722e7039384;hp=f6a08329ac361ee56adb581cac845207abe56806;hpb=59b34045097e5e57ecb1d6293c015c80d8553d56;p=m17n%2Flibotf.git diff --git a/src/otfopen.c b/src/otfopen.c index f6a0832..8aa062d 100644 --- a/src/otfopen.c +++ b/src/otfopen.c @@ -1,6 +1,6 @@ /* otfopen.c -- OpenType font reader. -Copyright (C) 2003, 2004 +Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H15PRO167 @@ -27,7 +27,9 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite #include #include "otf.h" -#include "otferror.h" +#include "internal.h" + +#include FT_TRUETYPE_TABLES_H /*** Table of contents (almost parallel to otf.h): @@ -55,6 +57,15 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite (5) API miscellaneous */ + +int debug_flag = -1; + +static void +set_debug_flag () +{ + debug_flag = getenv ("LIBOTF_DEBUG") != NULL; +} + /* (0) Stream handler @@ -80,8 +91,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite typedef struct { - FILE *fp; - char *name; + const char *name; long pos; long bufsize; long allocated; @@ -90,8 +100,8 @@ typedef struct typedef long OTF_StreamState; -OTF_Stream * -make_stream () +static OTF_Stream * +make_stream (const char *name) { OTF_Stream *stream; char *errfmt = "stream creation%s"; @@ -100,17 +110,16 @@ make_stream () stream = calloc (1, sizeof (OTF_Stream)); if (! stream) OTF_ERROR (OTF_ERROR_MEMORY, ""); + stream->name = name; return stream; } -int -setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, - char *name) +static int +setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes) { char *errfmt = "stream setup for %s"; int errret = -1; - stream->name = name; stream->pos = 0; if (stream->allocated < nbytes) { @@ -131,11 +140,41 @@ setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, return 0; } +static OTF_Stream * +make_stream_from_ft_face (FT_Face face, const char *name) +{ + char *errfmt = "FT_Face stream creation for %s"; + void *errret = NULL; + FT_ULong nbytes = 0; + unsigned char *buf; + OTF_Stream *stream; + FT_ULong tag = FT_MAKE_TAG (name[0], name[1], name[2], name[3]); -void + if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &nbytes)) + return NULL; + buf = malloc (nbytes); + if (! buf) + OTF_ERROR (OTF_ERROR_MEMORY, name); + if (FT_Load_Sfnt_Table (face, tag, 0, buf, &nbytes)) + { + free (buf); + OTF_ERROR (OTF_ERROR_FT_FACE, name); + } + stream = make_stream (name); + if (! stream) + return NULL; + stream->pos = 0; + stream->buf = buf; + stream->allocated = nbytes; + stream->bufsize = nbytes; + return stream; +} + +static void free_stream (OTF_Stream *stream) { - free (stream->buf); + if (stream->buf) + free (stream->buf); free (stream); } @@ -170,6 +209,15 @@ free_stream (OTF_Stream *stream) (stream)->pos += 2; \ } while (0) +#define READ_UINT24(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 3); \ + (var) = (((stream)->buf[(stream)->pos ] << 16) \ + | ((stream)->buf[(stream)->pos + 1] << 8) \ + | (stream)->buf[(stream)->pos + 2]); \ + (stream)->pos += 3; \ + } while (0) + #define READ_ULONG(stream, var) \ do { \ STREAM_CHECK_SIZE ((stream), 4); \ @@ -239,15 +287,36 @@ struct OTF_MemoryRecord typedef struct OTF_MemoryRecord OTF_MemoryRecord; -typedef struct +enum OTF_ReaderFlag + { + OTF_READ_FULL, + OTF_READ_SCRIPTS, + OTF_READ_FEATURES, + OTF_READ_MAX + }; + +struct _OTF_TableInfo; +typedef struct _OTF_TableInfo OTF_TableInfo; + +struct _OTF_TableInfo { /* Points to one of OTF->head, OTF->name, etc. */ void **address; /* Function to read one of OTF tables. */ - void *(*reader) (OTF *otf, OTF_Stream *stream); + void *(*reader) (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag); /* Stream given to . */ OTF_Stream *stream; -} OTF_TableInfo; +}; + +struct _OTF_ApplicationData +{ + char *id; + void *data; + void (*freer) (void *data); + struct _OTF_ApplicationData *next; +}; + +typedef struct _OTF_ApplicationData OTF_ApplicationData; struct OTF_InternalData { @@ -259,8 +328,10 @@ struct OTF_InternalData /* Records of allocated memories. */ OTF_MemoryRecord *memory_record; -}; + /* Root of application data chain. */ + OTF_ApplicationData *app_data; +}; static OTF_MemoryRecord * allocate_memory_record (OTF *otf) @@ -317,8 +388,9 @@ allocate_memory_record (OTF *otf) /*** (1-2) "head" table */ static void * -read_head_table (OTF *otf, OTF_Stream *stream) +read_head_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = "head%s"; void *errret = NULL; OTF_head *head; @@ -331,6 +403,7 @@ read_head_table (OTF *otf, OTF_Stream *stream) READ_USHORT (stream, head->flags); READ_USHORT (stream, head->unitsPerEm); + *table->address = head; return head; } @@ -340,13 +413,14 @@ read_head_table (OTF *otf, OTF_Stream *stream) static int read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec) { - char *errfmt = "nameID (%d)"; + char errfmt[256]; int errret = -1; OTF_StreamState state; int ucs = 0; int ascii = 0; int i; + sprintf (errfmt, "nameID (%d)%%s", rec->nameID); if (rec->platformID == 0) ucs = (rec->encodingID <= 3) ? 2 : 4; else if (rec->platformID == 1 && rec->encodingID == 0) @@ -356,7 +430,7 @@ read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec) : rec->encodingID == 10 ? 4 : 0); - OTF_MALLOC (rec->name, rec->length + 1, (void *) rec->nameID); + OTF_MALLOC (rec->name, rec->length + 1, ""); SAVE_STREAM (stream, state); SEEK_STREAM (stream, stream->pos + rec->offset); READ_BYTES (stream, rec->name, rec->length); @@ -408,8 +482,9 @@ read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec) } static void * -read_name_table (OTF *otf, OTF_Stream *stream) +read_name_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = "name%s"; void *errret = NULL; OTF_name *name; @@ -445,15 +520,96 @@ read_name_table (OTF *otf, OTF_Stream *stream) name->name[nameID] = (char *) rec->name; } + *table->address = name; return name; } /*** (1-4) "cmap" table */ +static OTF_EncodingSubtable14 * +read_cmap_uvs_table (OTF *otf, OTF_Stream *stream, OTF_Offset offset) +{ + OTF_EncodingSubtable14 *sub14; + char *errfmt = "cmap-uvs%s"; + void *errret = NULL; + unsigned nRecords; + unsigned i,j; + + OTF_MALLOC (sub14, 1, " (EncodingSubtable14)"); + READ_ULONG (stream, nRecords); + sub14->nRecords = nRecords; + OTF_MALLOC (sub14->Records, nRecords, "(EncodingSubtable14-Records)"); + for (i = 0; i < sub14->nRecords; i++) + { + unsigned varSelector=0, defaultUVSOffset, nonDefaultUVSOffset; + + READ_UINT24 (stream, varSelector); + sub14->Records[i].varSelector = varSelector; + READ_ULONG (stream, defaultUVSOffset); + sub14->Records[i].defaultUVSOffset = defaultUVSOffset; + READ_ULONG (stream, nonDefaultUVSOffset); + sub14->Records[i].nonDefaultUVSOffset = nonDefaultUVSOffset; + } + for (i = 0; i < sub14->nRecords; i++) + { + OTF_VariationSelectorRecord *record = &sub14->Records[i]; + unsigned defaultUVSOffset = record->defaultUVSOffset; + unsigned nonDefaultUVSOffset = record->nonDefaultUVSOffset; + + if (defaultUVSOffset) + { + unsigned numUnicodeValueRanges; + + SEEK_STREAM (stream, offset+defaultUVSOffset); + READ_ULONG (stream, numUnicodeValueRanges); + record->numUnicodeValueRanges = numUnicodeValueRanges; + OTF_MALLOC (record->unicodeValueRanges, + numUnicodeValueRanges, + "(EncodingSubtable14-Records-unicodeValueRanges)"); + for (j = 0; j < numUnicodeValueRanges; j++) + { + OTF_UnicodeValueRange *unicodeValueRange + = &record->unicodeValueRanges[j]; + unsigned startUnicodeValue; + char additionalCount; + + READ_UINT24 (stream, startUnicodeValue); + unicodeValueRange->startUnicodeValue=startUnicodeValue; + READ_BYTES (stream, &additionalCount, 1); + unicodeValueRange->additionalCount + = (unsigned short) additionalCount; + } + } + if (nonDefaultUVSOffset) + { + unsigned numUVSMappings; + + SEEK_STREAM (stream, offset+nonDefaultUVSOffset); + READ_ULONG (stream, numUVSMappings); + record->numUVSMappings = numUVSMappings; + OTF_MALLOC (record->uvsMappings, numUVSMappings, + "(EncodingSubtable14-Records-uvsMappings)"); + for (j = 0; j < numUVSMappings; j++) + { + OTF_UVSMapping *uvsMapping = &record->uvsMappings[j]; + unsigned unicodeValue; + unsigned short glyphID; + + READ_UINT24 (stream, unicodeValue); + uvsMapping->unicodeValue = unicodeValue; + READ_USHORT (stream, glyphID); + uvsMapping->glyphID = glyphID; + } + } + } + return sub14; +} + static void * -read_cmap_table (OTF *otf, OTF_Stream *stream) +read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = "cmap%s"; void *errret = NULL; OTF_cmap *cmap; @@ -488,6 +644,8 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) unicode_full_index = i; } } + cmap->table_index = unicode_full_index; + for (i = 0; i < cmap->numTables; i++) { unsigned format; @@ -495,15 +653,23 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) SEEK_STREAM (stream, cmap->EncodingRecord[i].offset); READ_USHORT (stream, format); cmap->EncodingRecord[i].subtable.format = format; - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); - if (format == 8 || format == 10 || format == 12) + if (format == 14) { READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); - READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); + cmap->EncodingRecord[i].subtable.language = 0; } else { - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); + if (format == 8 || format == 10 || format == 12) + { + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); + } + else + { + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); + } } switch (format) { @@ -518,7 +684,36 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) break; case 2: - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)"); + { + OTF_EncodingSubtable2 *sub2; + int j, max_key; + + OTF_MALLOC (sub2, 1, " (EncodingSubtable2)"); + cmap->EncodingRecord[i].subtable.f.f2 = sub2; + for (j = 0, max_key = 0; j < 256; j++) + { + READ_USHORT (stream, sub2->subHeaderKeys[j]); + if (max_key < sub2->subHeaderKeys[j]) + max_key = sub2->subHeaderKeys[j]; + } + max_key += 8; + sub2->subHeaderCount = max_key / 8; + OTF_MALLOC (sub2->subHeaders, max_key / 8, " (subHeaders)"); + for (j = 0; j < sub2->subHeaderCount; j++) + { + READ_USHORT (stream, sub2->subHeaders[j].firstCode); + READ_USHORT (stream, sub2->subHeaders[j].entryCount); + READ_SHORT (stream, sub2->subHeaders[j].idDelta); + READ_USHORT (stream, sub2->subHeaders[j].idRangeOffset); + /* Make it offset from sub2->glyphIndexArray. */ + sub2->subHeaders[j].idRangeOffset -= max_key - (j * 8 + 6); + } + sub2->glyphIndexCount = (cmap->EncodingRecord[i].subtable.length + - 262 - max_key); + OTF_MALLOC (sub2->glyphIndexArray, sub2->glyphIndexCount, + " (glyphIndexArray)"); + READ_BYTES (stream, sub2->glyphIndexArray, sub2->glyphIndexCount); + } break; case 4: @@ -547,7 +742,7 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) { unsigned off; unsigned rest = 2 * (segCount - j); - + READ_USHORT (stream, off); if (off == 0) sub4->segments[j].idRangeOffset = 0xFFFF; @@ -624,13 +819,21 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) OTF_MALLOC (sub12->Groups, sub12->nGroups, " (Groups)"); for (j = 0; j < sub12->nGroups; j++) { - READ_ULONG (stream, sub12->Groups[i].startCharCode); - READ_ULONG (stream, sub12->Groups[i].endCharCode); - READ_ULONG (stream, sub12->Groups[i].startGlyphID); + READ_ULONG (stream, sub12->Groups[j].startCharCode); + READ_ULONG (stream, sub12->Groups[j].endCharCode); + READ_ULONG (stream, sub12->Groups[j].startGlyphID); } } break; + case 14: + { + cmap->EncodingRecord[i].subtable.f.f14 + = read_cmap_uvs_table (otf, stream, + cmap->EncodingRecord[i].offset); + break; + } + default: OTF_ERROR (OTF_ERROR_TABLE, " (invalid Subtable format)"); } @@ -651,13 +854,13 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) for (i = 0; i < segCount; i++) { - OTF_cmapSegument *seg = sub4->segments + i; + OTF_cmapSegment *seg = sub4->segments + i; int c; if (seg->idRangeOffset == 0xFFFF) for (c = seg->startCount; c <= seg->endCount; c++) { - glyph_id = c + seg->idDelta; + glyph_id = (c + seg->idDelta) % 0x10000; cmap->unicode_table[c] = glyph_id; if (glyph_id > max_glyph_id) max_glyph_id = glyph_id; @@ -683,6 +886,7 @@ read_cmap_table (OTF *otf, OTF_Stream *stream) cmap->max_glyph_id = max_glyph_id; } + *table->address = cmap; return cmap; } @@ -876,41 +1080,48 @@ read_device_table (OTF *otf, OTF_Stream *stream, long offset, READ_UINT16 (stream, table->EndSize); READ_UINT16 (stream, table->DeltaFormat); num = table->EndSize - table->StartSize + 1; - OTF_MALLOC (table->DeltaValue, num, ""); + if (num > 0 && table->DeltaFormat >= 1 && table->DeltaFormat <= 3) + { + OTF_MALLOC (table->DeltaValue, num, ""); - if (table->DeltaFormat == 1) - for (i = 0; i < num; i++) - { - if ((i % 8) == 0) - READ_UINT16 (stream, val); - intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; - table->DeltaValue[i] = intval.int2; - } - else if (table->DeltaFormat == 2) - for (i = 0; i < num; i++) - { - if ((i % 4) == 0) - READ_UINT16 (stream, val); - intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; - table->DeltaValue[i] = intval.int4; - } - else if (table->DeltaFormat == 3) - for (i = 0; i < num; i++) - { - if ((i % 2) == 0) + if (table->DeltaFormat == 1) + for (i = 0; i < num; i++) { - READ_UINT16 (stream, val); - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; + if ((i % 8) == 0) + READ_UINT16 (stream, val); + intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; + table->DeltaValue[i] = intval.int2; } - else + else if (table->DeltaFormat == 2) + for (i = 0; i < num; i++) { - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; + if ((i % 4) == 0) + READ_UINT16 (stream, val); + intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; + table->DeltaValue[i] = intval.int4; } - } + else /* (table->DeltaFormat == 3) */ + for (i = 0; i < num; i++) + { + if ((i % 2) == 0) + { + READ_UINT16 (stream, val); + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + else + { + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + } + } else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + { + /* Invalid DeltaFormat but several fonts has such values (bug of + fontforge?). So accept it with NULL delta values. */ + table->DeltaValue = NULL; + } return 0; } @@ -1016,31 +1227,38 @@ read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header) } static void * -read_gdef_table (OTF *otf, OTF_Stream *stream) +read_gdef_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = "GDEF%s"; void *errret = NULL; OTF_GDEF *gdef; OTF_CALLOC (gdef, 1, ""); - read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); - if (gdef->header.GlyphClassDef) - { - gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; - read_class_def_without_offset (otf, stream, &gdef->glyph_class_def); - } - if (gdef->header.AttachList) - read_attach_list (otf, stream, gdef->header.AttachList, - &gdef->attach_list); - if (gdef->header.LigCaretList) - read_lig_caret_list (otf, stream, gdef->header.LigCaretList, - &gdef->lig_caret_list); - if (gdef->header.MarkAttachClassDef) + if (stream->buf) { - gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; - read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def); + read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); + if (gdef->header.GlyphClassDef) + { + gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; + read_class_def_without_offset (otf, stream, + &gdef->glyph_class_def); + } + if (gdef->header.AttachList) + read_attach_list (otf, stream, gdef->header.AttachList, + &gdef->attach_list); + if (gdef->header.LigCaretList) + read_lig_caret_list (otf, stream, gdef->header.LigCaretList, + &gdef->lig_caret_list); + if (gdef->header.MarkAttachClassDef) + { + gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; + read_class_def_without_offset (otf, stream, + &gdef->mark_attach_class_def); + } } + *table->address = gdef; return gdef; } @@ -1121,6 +1339,7 @@ read_feature_list (OTF *otf, OTF_Stream *stream, long offset, int errret = -1; int i, j; + SEEK_STREAM (stream, offset); READ_UINT16 (stream, list->FeatureCount); OTF_CALLOC (list->Feature, list->FeatureCount, ""); for (i = 0; i < list->FeatureCount; i++) @@ -1351,7 +1570,7 @@ read_class_set_list (OTF *otf, OTF_Stream *stream, long offset, READ_UINT16 (stream, count); if (! count) OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*set, count, ""); + OTF_CALLOC (*set, count, ""); for (i = 0; i < count; i++) /* Offset can be zero. */ READ_OFFSET (stream, (*set)[i].offset); @@ -1622,25 +1841,46 @@ read_chain_context3 (OTF *otf, OTF_Stream *stream, long offset, } static void * -read_gsub_gpos_table (OTF *otf, OTF_Stream *stream, int gsubp) +read_gsub_gpos_table (OTF *otf, OTF_TableInfo *table, int gsubp, + enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = gsubp ? "GSUB%s" : "GPOS%s"; void *errret = NULL; - OTF_GSUB_GPOS *gsub_gpos; - - OTF_CALLOC (gsub_gpos, 1, ""); - READ_FIXED (stream, gsub_gpos->Version); - READ_OFFSET (stream, gsub_gpos->ScriptList.offset); - READ_OFFSET (stream, gsub_gpos->FeatureList.offset); - READ_OFFSET (stream, gsub_gpos->LookupList.offset); - - if (read_script_list (otf, stream, gsub_gpos->ScriptList.offset, - &gsub_gpos->ScriptList) < 0 - || read_feature_list (otf, stream, gsub_gpos->FeatureList.offset, - &gsub_gpos->FeatureList) < 0 - || read_lookup_list (otf, stream, gsub_gpos->LookupList.offset, - &gsub_gpos->LookupList, gsubp) < 0) + OTF_GSUB_GPOS *gsub_gpos = *table->address; + + if (gsub_gpos) + SEEK_STREAM (stream, 10); + else + { + SEEK_STREAM (stream, 0); + OTF_CALLOC (gsub_gpos, 1, ""); + READ_FIXED (stream, gsub_gpos->Version); + READ_OFFSET (stream, gsub_gpos->ScriptList.offset); + READ_OFFSET (stream, gsub_gpos->FeatureList.offset); + READ_OFFSET (stream, gsub_gpos->LookupList.offset); + *table->address = gsub_gpos; + } + + if (! gsub_gpos->ScriptList.Script + && read_script_list (otf, stream, gsub_gpos->ScriptList.offset, + &gsub_gpos->ScriptList) < 0) return NULL; + if (flag != OTF_READ_SCRIPTS) + { + if (! gsub_gpos->FeatureList.Feature + && read_feature_list (otf, stream, gsub_gpos->FeatureList.offset, + &gsub_gpos->FeatureList) < 0) + return NULL; + if (flag != OTF_READ_FEATURES) + { + if (! gsub_gpos->LookupList.Lookup + && read_lookup_list (otf, stream, gsub_gpos->LookupList.offset, + &gsub_gpos->LookupList, gsubp) < 0) + return NULL; + } + } + return gsub_gpos; } @@ -1778,7 +2018,7 @@ read_reverse_chain1 (OTF *otf, OTF_Stream *stream, long offset, count = read_glyph_ids (otf, stream, &reverse_chain->Substitute, 0, -1); if (count <= 0) return -1; - reverse_chain->GlyphCount = count; + reverse_chain->GlyphCount = count; return 0; } @@ -1942,9 +2182,9 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, } static void * -read_gsub_table (OTF *otf, OTF_Stream *stream) +read_gsub_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { - return read_gsub_gpos_table (otf, stream, 1); + return read_gsub_gpos_table (otf, table, 1, flag); } @@ -1967,7 +2207,7 @@ read_value_record (OTF *otf, OTF_Stream *stream, long offset, if (bit & OTF_XPlacement) READ_INT16 (stream, value_record->XPlacement); - if (bit & OTF_XPlacement) + if (bit & OTF_YPlacement) READ_INT16 (stream, value_record->YPlacement); if (bit & OTF_XAdvance) READ_INT16 (stream, value_record->XAdvance); @@ -2213,9 +2453,16 @@ read_ligature_attach (OTF *otf, OTF_Stream *stream, long offset, } for (i = 0; i < attach->ComponentCount; i++) for (j = 0; j < ClassCount; j++) - if (read_anchor (otf, stream, offset + attach->offset, - &attach->ComponentRecord[i].LigatureAnchor[j]) < 0) - return -1; + { + if (attach->ComponentRecord[i].LigatureAnchor[j].offset) + { + if (read_anchor (otf, stream, offset + attach->offset, + &attach->ComponentRecord[i].LigatureAnchor[j]) < 0) + return -1; + } + else + attach->ComponentRecord[i].LigatureAnchor[j].AnchorFormat = 0; + } return 0; } @@ -2463,9 +2710,9 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, } static void * -read_gpos_table (OTF *otf, OTF_Stream *stream) +read_gpos_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { - return read_gsub_gpos_table (otf, stream, 0); + return read_gsub_gpos_table (otf, table, 0, flag); } @@ -2498,7 +2745,7 @@ read_jstf_table (OTF_Stream *stream, long offset) /*** (1-11) Structure for OTF */ -int +static int read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table) { int errret = -1; @@ -2521,9 +2768,9 @@ read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) table->tag = tag; table->name[0] = tag >> 24; table->name[1] = (tag >> 16) & 0xFF; - table->name[0] = (tag >> 8) & 0xFF; - table->name[0] = tag >> 8; - table->name[0] = '\0'; + table->name[2] = (tag >> 8) & 0xFF; + table->name[3] = tag & 0xFF; + table->name[4] = '\0'; READ_ULONG (stream, table->checkSum); READ_ULONG (stream, table->offset); READ_ULONG (stream, table->length); @@ -2531,12 +2778,10 @@ read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) } static int -read_header_part (OTF *otf, FILE *fp) +read_header_part (OTF *otf, FILE *fp, FT_Face face) { char *errfmt = "otf header%s"; int errret = -1; - OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag; - OTF_Stream *stream; int i; OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; @@ -2553,69 +2798,108 @@ read_header_part (OTF *otf, FILE *fp) internal_data->table_info[OTF_TABLE_TYPE_GPOS].address = (void *) &otf->gpos; internal_data->table_info[OTF_TABLE_TYPE_GPOS].reader = read_gpos_table; - head_tag = OTF_tag ("head"); - name_tag = OTF_tag ("name"); - cmap_tag = OTF_tag ("cmap"); - gdef_tag = OTF_tag ("GDEF"); - gsub_tag = OTF_tag ("GSUB"); - gpos_tag = OTF_tag ("GPOS"); + if (fp) + { + OTF_Tag head_tag = OTF_tag ("head"); + OTF_Tag name_tag = OTF_tag ("name"); + OTF_Tag cmap_tag = OTF_tag ("cmap"); + OTF_Tag gdef_tag = OTF_tag ("GDEF"); + OTF_Tag gsub_tag = OTF_tag ("GSUB"); + OTF_Tag gpos_tag = OTF_tag ("GPOS"); + OTF_Stream *stream = make_stream ("Offset Table"); + unsigned char ttctag[4]; - stream = make_stream (); - if (! stream) - return -1; + if (! stream) + return -1; + internal_data->header_stream = stream; - internal_data->header_stream = stream; + /* Size of Offset Table is 12 bytes. Size of TTC header + (including only the an offset of the first font) is 16. */ + if (setup_stream (stream, fp, 0, 16) < 0) + return -1; + READ_BYTES (stream, ttctag, 4); + if (memcmp (ttctag, "ttcf", 4) == 0) + { + /* This is a TrueType Collection file. We extract the first font. */ + unsigned version, numfonts, offset; + READ_ULONG (stream, version); + READ_ULONG (stream, numfonts); + READ_ULONG (stream, offset); /* Offset of the first font. */ + if (setup_stream (stream, fp, offset, 12) < 0) + return -1; + } + else + SEEK_STREAM (stream, 0L); + if (read_offset_table (otf, stream, &otf->offset_table) < 0) + return -1; + /* Size of each Table Directory is 16 bytes. */ + if (setup_stream (stream, fp, stream->pos, + 16 * otf->offset_table.numTables) < 0) + return -1; - /* Size of Offset Table is 12 bytes. */ - if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0) - return -1; - if (read_offset_table (otf, stream, &otf->offset_table) < 0) - return -1; + OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, + " (OffsetTable)"); + for (i = 0; i < otf->offset_table.numTables; i++) + { + OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); + OTF_TableInfo *table_info = NULL; - /* Size of each Table Directory is 16 bytes. */ - if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables, - "Table Directory") < 0) - return -1; + if (! tag) + return -1; + if (tag == head_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; + else if (tag == name_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; + else if (tag == cmap_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; + else if (tag == gdef_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; + else if (tag == gsub_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; + else if (tag == gpos_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; + + if (table_info) + { + table_info->stream = make_stream (otf->table_dirs[i].name); + if (setup_stream (table_info->stream, fp, + otf->table_dirs[i].offset, + otf->table_dirs[i].length) < 0) + return -1; + } + } - OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, " (OffsetTable)"); - for (i = 0; i < otf->offset_table.numTables; i++) + internal_data->header_stream = NULL; + free_stream (stream); + } + else { - OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); - OTF_TableInfo *table_info = NULL; + OTF_Stream *stream; - if (! tag) - return -1; - if (tag == head_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; - else if (tag == name_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; - else if (tag == cmap_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; - else if (tag == gdef_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; - else if (tag == gsub_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; - else if (tag == gpos_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; - - if (table_info) - { - table_info->stream = make_stream (); - if (setup_stream (table_info->stream, fp, - otf->table_dirs[i].offset, - otf->table_dirs[i].length, - otf->table_dirs[i].name) < 0) - return -1; - } + internal_data->header_stream = NULL; + if ((stream = make_stream_from_ft_face (face, "head"))) + internal_data->table_info[OTF_TABLE_TYPE_HEAD].stream = stream; + if ((stream = make_stream_from_ft_face (face, "name"))) + internal_data->table_info[OTF_TABLE_TYPE_NAME].stream = stream; + if ((stream = make_stream_from_ft_face (face, "cmap"))) + internal_data->table_info[OTF_TABLE_TYPE_CMAP].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GDEF"))) + internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GSUB"))) + internal_data->table_info[OTF_TABLE_TYPE_GSUB].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GPOS"))) + internal_data->table_info[OTF_TABLE_TYPE_GPOS].stream = stream; } - internal_data->header_stream = NULL; - free_stream (stream); + if (! internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream) + /* We can simulate the GDEF table. */ + internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream + = make_stream ("GDEF"); return 0; } static OTF_TableInfo * -get_table_info (OTF *otf, char *name) +get_table_info (OTF *otf, const char *name) { char *errfmt = "OTF Table Read%s"; OTF_TableInfo *errret = NULL; @@ -2662,7 +2946,7 @@ get_table_info (OTF *otf, char *name) freeing memory previously allocated. */ OTF * -OTF_open (char *otf_name) +OTF_open (const char *otf_name) { FILE *fp; char *errfmt = "opening otf (%s)"; @@ -2672,11 +2956,14 @@ OTF_open (char *otf_name) int len = strlen (otf_name); const char *ext = otf_name + (len - 4); + if (debug_flag < 0) + set_debug_flag (); + if (len < 4 || ext[0] != '.' - || (ext[1] != 'O' && ext[1] != 'T' && ext[1] != 'o' && ext[1] != 't') - || (ext[2] != 'T' && ext[2] != 't') - || (ext[3] != 'F' && ext[3] != 'f')) + || (strncasecmp (ext + 1, "otf", 3) + && strncasecmp (ext + 1, "ttf", 3) + && strncasecmp (ext + 1, "ttc", 3))) OTF_ERROR (OTF_ERROR_FILE, otf_name); fp = fopen (otf_name, "r"); if (! fp) @@ -2703,7 +2990,7 @@ OTF_open (char *otf_name) otf->internal_data->memory_record except for what allocated by the functions allocate_memory_record and make_stream. */ - if (read_header_part (otf, fp) < 0) + if (read_header_part (otf, fp, NULL) < 0) { OTF_close (otf); fclose (fp); @@ -2714,6 +3001,40 @@ OTF_open (char *otf_name) return otf; } +OTF * +OTF_open_ft_face (FT_Face face) +{ + char *errfmt = "opening otf from Freetype (%s)"; + void *errret = NULL; + OTF *otf; + OTF_InternalData *internal_data; + + if (debug_flag < 0) + set_debug_flag (); + + if (! FT_IS_SFNT (face)) + OTF_ERROR (OTF_ERROR_FILE, (char *) face->family_name); + otf = calloc (1, sizeof (OTF)); + if (! otf) + OTF_ERROR (OTF_ERROR_MEMORY, "body allocation"); + otf->filename = NULL; + + internal_data = calloc (1, sizeof (OTF_InternalData)); + if (! internal_data) + OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData"); + otf->internal_data = internal_data; + if (! allocate_memory_record (otf)) + OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData)"); + + if (read_header_part (otf, NULL, face) < 0) + { + OTF_close (otf); + return NULL; + } + + return otf; +} + /*** (2-2) OTF_close() */ void @@ -2725,6 +3046,7 @@ OTF_close (OTF *otf) if (internal_data) { OTF_MemoryRecord *memrec = internal_data->memory_record; + OTF_ApplicationData *app_data = internal_data->app_data; if (internal_data->header_stream) free_stream (internal_data->header_stream); @@ -2733,6 +3055,10 @@ OTF_close (OTF *otf) if (internal_data->table_info[i].stream) free_stream (internal_data->table_info[i].stream); + for (; app_data; app_data = app_data->next) + if (app_data->data && app_data->freer) + app_data->freer (app_data->data); + while (memrec) { OTF_MemoryRecord *next = memrec->next; @@ -2742,6 +3068,7 @@ OTF_close (OTF *otf) free (memrec); memrec = next; } + free (internal_data); } if (otf->filename) @@ -2752,17 +3079,21 @@ OTF_close (OTF *otf) /*** (2-3) OTF_get_table() */ int -OTF_get_table (OTF *otf, char *name) +OTF_get_table (OTF *otf, const char *name) { OTF_TableInfo *table_info = get_table_info (otf, name); + void *address; if (! table_info) return -1; + if (! table_info->stream) + /* Already fully loaded. */ + return 0; - *table_info->address = (*table_info->reader) (otf, table_info->stream); + address = (*table_info->reader) (otf, table_info, OTF_READ_FULL); free_stream (table_info->stream); table_info->stream = NULL; - if (! *table_info->address) + if (! address) { table_info->reader = NULL; return -1; @@ -2773,24 +3104,158 @@ OTF_get_table (OTF *otf, char *name) /*** (2-4) OTF_check_table() */ int -OTF_check_table (OTF *otf, char *name) +OTF_check_table (OTF *otf, const char *name) { return (get_table_info (otf, name) ? 0 : -1); } +/*** (2-5) OTF_get_scripts() */ +int +OTF_get_scripts (OTF *otf, int gsubp) +{ + OTF_TableInfo *table_info + = (otf->internal_data->table_info + + (gsubp ? OTF_TABLE_TYPE_GSUB : OTF_TABLE_TYPE_GPOS)); + void *address; + + if (! table_info->reader) + return -1; + if (! table_info->stream) + /* Already fully loaded. */ + return 0; + + address = (*table_info->reader) (otf, table_info, OTF_READ_SCRIPTS); + if (! address) + { + table_info->reader = NULL; + return -1; + } + return 0; +} + +/*** (2-6) OTF_get_features() */ + +int +OTF_get_features (OTF *otf, int gsubp) +{ + OTF_TableInfo *table_info + = (otf->internal_data->table_info + + (gsubp ? OTF_TABLE_TYPE_GSUB : OTF_TABLE_TYPE_GPOS)); + void *address; + + if (! table_info->reader) + return -1; + if (! table_info->stream) + { + if (*table_info->address) + /* Already fully loaded. */ + return 0; + return -1; + } + + address = (*table_info->reader) (otf, table_info, OTF_READ_FEATURES); + if (! address) + { + table_info->reader = NULL; + return -1; + } + return 0; +} + +/*** (2-7) OTF_check_features */ + +int +OTF_check_features (OTF *otf, int gsubp, + OTF_Tag script, OTF_Tag language, const OTF_Tag *features, + int n_features) +{ + OTF_ScriptList *script_list; + OTF_Script *Script = NULL; + OTF_LangSys *LangSys = NULL; + OTF_FeatureList *feature_list; + int i, j; + + if (OTF_get_features (otf, gsubp) < 0) + { + if (gsubp ? ! otf->gsub : ! otf->gpos) + return 0; + for (i = 0; i < n_features; i++) + { + OTF_Tag feature = features[i]; + + if (feature == 0) + continue; + if ((((unsigned) feature) & 0x80000000) == 0) + return -1; + } + } + if (gsubp) + { + script_list = &otf->gsub->ScriptList; + feature_list = &otf->gsub->FeatureList; + } + else + { + script_list = &otf->gpos->ScriptList; + feature_list = &otf->gpos->FeatureList; + } + for (i = 0; i < script_list->ScriptCount && ! Script; i++) + if (script_list->Script[i].ScriptTag == script) + Script = script_list->Script + i; + if (! Script) + return 0; + if (language) + { + for (i = 0; i < Script->LangSysCount && ! LangSys; i++) + if (Script->LangSysRecord[i].LangSysTag == language) + LangSys = Script->LangSys + i; + if (! LangSys) + return 0; + } + else + LangSys = &Script->DefaultLangSys; + for (j = 0; j < n_features; j++) + { + OTF_Tag feature = features[j]; + int negate = 0; + + if (feature == 0) + continue; + if (((unsigned) feature) & 0x80000000) + { + feature = (OTF_Tag) (((unsigned) feature) & 0x7FFFFFFF); + negate = 1; + } + for (i = 0; i < LangSys->FeatureCount; i++) + if (feature_list->Feature[LangSys->FeatureIndex[i]].FeatureTag + == feature) + { + if (negate) + return 0; + break; + } + if (i == LangSys->FeatureCount) + return 0; + } + return 1; +} /*** (5) API miscellaneous ***/ OTF_Tag -OTF_tag (char *name) +OTF_tag (const char *name) { - unsigned char *p = (unsigned char *) name; + const unsigned char *p = (unsigned char *) name; if (! name) return (OTF_Tag) 0; - return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); + return (OTF_Tag) ((p[0] << 24) + | (! p[1] ? 0 + : ((p[1] << 16) + | (! p[2] ? 0 + : (p[2] << 8) | p[3])))); } void @@ -2802,3 +3267,44 @@ OTF_tag_name (OTF_Tag tag, char *name) name[3] = (char) (tag & 0xFF); name[4] = '\0'; } + +int +OTF_put_data (OTF *otf, char *id, void *data, void (*freer) (void *data)) +{ + char *errfmt = "appdata %s"; + int errret = -1; + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; + OTF_ApplicationData *app_data = internal_data->app_data; + int len = strlen (id) + 1; + + for (; app_data; app_data = app_data->next) + if (memcmp (app_data->id, id, len) == 0) + { + if (app_data->data && app_data->freer) + app_data->freer (app_data->data); + break; + } + if (! app_data) + { + OTF_MALLOC (app_data, sizeof (OTF_ApplicationData), id); + app_data->next = internal_data->app_data; + internal_data->app_data = app_data; + OTF_MALLOC (app_data->id, len, id); + memcpy (app_data->id, id, len); + } + app_data->data = data; + app_data->freer = freer; + return 0; +} + +void * +OTF_get_data (OTF *otf, char *id) +{ + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; + OTF_ApplicationData *app_data = internal_data->app_data; + + for (; app_data; app_data = app_data->next) + if (strcmp (app_data->id, id) == 0) + return app_data->data; + return NULL; +}