X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..249c4c5ea9376c24572daf9c2effa7484a282f14:/icuSources/layout/KernTable.cpp diff --git a/icuSources/layout/KernTable.cpp b/icuSources/layout/KernTable.cpp index fc6a6f7d..70005324 100644 --- a/icuSources/layout/KernTable.cpp +++ b/icuSources/layout/KernTable.cpp @@ -1,7 +1,7 @@ /* * @(#)KernTable.cpp 1.1 04/10/13 * - * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 2004-2014 - All Rights Reserved * */ @@ -10,18 +10,23 @@ #include "LEGlyphStorage.h" #include "LESwaps.h" +#include "OpenTypeUtilities.h" #include -#define DEBUG 0 +#define KERNTABLE_DEBUG 0 U_NAMESPACE_BEGIN struct PairInfo { - le_uint32 key; // sigh, MSVC compiler gags on union here + le_uint16 left; // left glyph of kern pair + le_uint16 right; // right glyph of kern pair le_int16 value; // fword, kern value in funits }; #define KERN_PAIRINFO_SIZE 6 +LE_CORRECT_SIZE(PairInfo, KERN_PAIRINFO_SIZE) + +#define SWAP_KEY(p) (((le_uint32) SWAPW((p)->left) << 16) | SWAPW((p)->right)) struct Subtable_0 { le_uint16 nPairs; @@ -30,6 +35,7 @@ struct Subtable_0 { le_uint16 rangeShift; }; #define KERN_SUBTABLE_0_HEADER_SIZE 8 +LE_CORRECT_SIZE(Subtable_0, KERN_SUBTABLE_0_HEADER_SIZE) // Kern table version 0 only struct SubtableHeader { @@ -38,6 +44,7 @@ struct SubtableHeader { le_uint16 coverage; }; #define KERN_SUBTABLE_HEADER_SIZE 6 +LE_CORRECT_SIZE(SubtableHeader, KERN_SUBTABLE_HEADER_SIZE) // Version 0 only, version 1 has different layout struct KernTableHeader { @@ -45,6 +52,7 @@ struct KernTableHeader { le_uint16 nTables; }; #define KERN_TABLE_HEADER_SIZE 4 +LE_CORRECT_SIZE(KernTableHeader, KERN_TABLE_HEADER_SIZE) #define COVERAGE_HORIZONTAL 0x1 #define COVERAGE_MINIMUM 0x2 @@ -66,21 +74,21 @@ struct KernTableHeader { * TODO: support multiple subtables * TODO: respect header flags */ -KernTable::KernTable(const LEFontInstance* font, const void* tableData) - : pairs(0), font(font) +KernTable::KernTable(const LETableReference& base, LEErrorCode &success) + : pairs(), fTable(base) { - const KernTableHeader* header = (const KernTableHeader*)tableData; - if (header == 0) { -#if DEBUG + if(LE_FAILURE(success) || fTable.isEmpty()) { +#if KERNTABLE_DEBUG fprintf(stderr, "no kern data\n"); #endif return; } + LEReferenceTo header(fTable, success); -#if DEBUG +#if KERNTABLE_DEBUG // dump first 32 bytes of header for (int i = 0; i < 64; ++i) { - fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff); + fprintf(stderr, "%0.2x ", ((const char*)header.getAlias())[i]&0xff); if (((i+1)&0xf) == 0) { fprintf(stderr, "\n"); } else if (((i+1)&0x7) == 0) { @@ -89,72 +97,107 @@ KernTable::KernTable(const LEFontInstance* font, const void* tableData) } #endif - if (header->version == 0 && SWAPW(header->nTables) > 0) { - const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE); - if (subhead->version == 0) { + if(LE_FAILURE(success)) return; + + if (!header.isEmpty() && header->version == 0 && SWAPW(header->nTables) > 0) { + LEReferenceTo subhead(header, success, KERN_TABLE_HEADER_SIZE); + + if (LE_SUCCESS(success) && !subhead.isEmpty() && subhead->version == 0) { coverage = SWAPW(subhead->coverage); + if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning - const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE); - nPairs = SWAPW(table->nPairs); - searchRange = SWAPW(table->searchRange); - entrySelector = SWAPW(table->entrySelector); - rangeShift = SWAPW(table->rangeShift); - pairs = (const PairInfo*)((char*)table + KERN_SUBTABLE_0_HEADER_SIZE); - -#if DEBUG - fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs); - fprintf(stderr, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift); - - { - // dump part of the pair list - char ids[256]; - for (int i = 256; --i >= 0;) { - LEGlyphID id = font->mapCharToGlyph(i); - if (id < 256) { - ids[id] = (char)i; - } - } - - const PairInfo* p = pairs; - for (i = 0; i < nPairs; ++i, p = (const PairInfo*)((char*)p+KERN_PAIRINFO_SIZE)) { - le_uint32 k = SWAPL(p->key); - le_uint16 left = (k >> 16) & 0xffff; - le_uint16 right = k & 0xffff; - if (left < 256 && right < 256) { - char c = ids[left]; - if (c > 0x20 && c < 0x7f) { - fprintf(stderr, "%c/", c & 0xff); - } else { - fprintf(stderr, "%0.2x/", c & 0xff); - } - c = ids[right]; - if (c > 0x20 && c < 0x7f) { - fprintf(stderr, "%c ", c & 0xff); - } else { - fprintf(stderr, "%0.2x ", c & 0xff); - } - } - } - } + LEReferenceTo table(subhead, success, KERN_SUBTABLE_HEADER_SIZE); + + if(table.isEmpty() || LE_FAILURE(success)) return; + + nPairs = SWAPW(table->nPairs); + +#if 0 // some old fonts have bad values here... + searchRange = SWAPW(table->searchRange); + entrySelector = SWAPW(table->entrySelector); + rangeShift = SWAPW(table->rangeShift); +#else + entrySelector = OpenTypeUtilities::highBit(nPairs); + searchRange = (1 << entrySelector) * KERN_PAIRINFO_SIZE; + rangeShift = (nPairs * KERN_PAIRINFO_SIZE) - searchRange; +#endif + + if(LE_SUCCESS(success) && nPairs>0) { + // pairs is an instance member, and table is on the stack. + // set 'pairs' based on table.getAlias(). This will range check it. + + pairs = LEReferenceToArrayOf(fTable, // based on overall table + success, + (const PairInfo*)table.getAlias(), // subtable 0 + .. + KERN_SUBTABLE_0_HEADER_SIZE, // .. offset of header size + nPairs); // count + } + +#if 0 + fprintf(stderr, "coverage: %0.4x nPairs: %d pairs %p\n", coverage, nPairs, pairs.getAlias()); + fprintf(stderr, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift); + fprintf(stderr, "[[ ignored font table entries: range %d selector %d shift %d ]]\n", SWAPW(table->searchRange), SWAPW(table->entrySelector), SWAPW(table->rangeShift)); +#endif +#if KERNTABLE_DEBUG + fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs); + fprintf(stderr, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift); + + if(LE_SUCCESS(success) { + // dump part of the pair list + char ids[256]; + + for (int i = 256; --i >= 0;) { + LEGlyphID id = font->mapCharToGlyph(i); + + if (id < 256) { + ids[id] = (char)i; + } + } + + for (i = 0; i < nPairs; ++i) { + const PairInfo& p = pairs[i, success]; + + le_uint16 left = p->left; + le_uint16 right = p->right; + + + if (left < 256 && right < 256) { + char c = ids[left]; + + if (c > 0x20 && c < 0x7f) { + fprintf(stderr, "%c/", c & 0xff); + } else { + printf(stderr, "%0.2x/", c & 0xff); + } + + c = ids[right]; + if (c > 0x20 && c < 0x7f) { + fprintf(stderr, "%c ", c & 0xff); + } else { + fprintf(stderr, "%0.2x ", c & 0xff); + } + } + } + } #endif } } } } - + /* * Process the glyph positions. The positions array has two floats for each - * glyph, plus a trailing pair to mark the end of the last glyph. +g * glyph, plus a trailing pair to mark the end of the last glyph. */ -void KernTable::process(LEGlyphStorage& storage) +void KernTable::process(LEGlyphStorage& storage, LEErrorCode &success) { - if (pairs) { - LEErrorCode success = LE_NO_ERROR; + if (LE_SUCCESS(success) && !pairs.isEmpty()) { le_uint32 key = storage[0]; // no need to mask off high bits float adjust = 0; - for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) { + + for (int i = 1, e = storage.getGlyphCount(); LE_SUCCESS(success)&& i < e; ++i) { key = key << 16 | (storage[i] & 0xffff); // argh, to do a binary search, we need to have the pair list in sorted order @@ -162,41 +205,50 @@ void KernTable::process(LEGlyphStorage& storage) // so either I have to swap the element each time I examine it, or I have to swap // all the elements ahead of time and store them in the font - const PairInfo* p = pairs; - const PairInfo* tp = (const PairInfo*)((char*)p + rangeShift); - if (key > SWAPL(tp->key)) { - p = tp; + const PairInfo *p = pairs.getAlias(0, success); + + LEReferenceTo tpRef(pairs, success, rangeShift); // ((char*)pairs) + rangeShift + const PairInfo *tp = tpRef.getAlias(); + if(LE_FAILURE(success)) return; // get out. + + if (key > SWAP_KEY(tp)) { + p = tp; } -#if DEBUG +#if KERNTABLE_DEBUG fprintf(stderr, "binary search for %0.8x\n", key); #endif le_uint32 probe = searchRange; - while (probe > KERN_PAIRINFO_SIZE) { + + while (probe > KERN_PAIRINFO_SIZE && LE_SUCCESS(success)) { probe >>= 1; - tp = (const PairInfo*)((char*)p + probe); - le_uint32 tkey = SWAPL(tp->key); -#if DEBUG + tpRef = LEReferenceTo(pairs, success, p, probe); // (char*)p + probe + tp = tpRef.getAlias(); + le_uint32 tkey = SWAP_KEY(tp); + if(LE_FAILURE(success)) break; +#if KERNTABLE_DEBUG fprintf(stdout, " %.3d (%0.8x)\n", ((char*)tp - (char*)pairs)/KERN_PAIRINFO_SIZE, tkey); #endif - if (tkey <= key) { - if (tkey == key) { - le_int16 value = SWAPW(tp->value); -#if DEBUG - fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n", - storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value)); - fflush(stdout); + if (tkey <= key && LE_SUCCESS(success)) { + if (tkey == key) { + le_int16 value = SWAPW(tp->value); +#if KERNTABLE_DEBUG + fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n", + storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value)); + fflush(stdout); #endif - adjust += font->xUnitsToPoints(value); - break; - } - p = tp; + adjust += fTable.getFont()->xUnitsToPoints(value); + break; + } + + p = tp; } } storage.adjustPosition(i, adjust, 0, success); } + storage.adjustPosition(storage.getGlyphCount(), adjust, 0, success); } }