diff --git a/icu4c/source/layout/ContextualGlyphInsertion.h b/icu4c/source/layout/ContextualGlyphInsertion.h index ead88425dd..526273257b 100644 --- a/icu4c/source/layout/ContextualGlyphInsertion.h +++ b/icu4c/source/layout/ContextualGlyphInsertion.h @@ -1,6 +1,6 @@ -/* +/** * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and Others 1998-2013 - All Rights Reserved * */ @@ -24,6 +24,11 @@ struct ContextualGlyphInsertionHeader : MorphStateTableHeader { }; +struct ContextualGlyphInsertionHeader2 : MorphStateTableHeader2 +{ + le_uint32 insertionTableOffset; +}; + enum ContextualGlyphInsertionFlags { cgiSetMark = 0x8000, @@ -36,11 +41,17 @@ enum ContextualGlyphInsertionFlags cgiMarkedInsertCountMask = 0x001F }; -struct LigatureSubstitutionStateEntry : StateEntry +struct ContextualGlyphInsertionStateEntry : StateEntry { ByteOffset currentInsertionListOffset; ByteOffset markedInsertionListOffset; }; +struct ContextualGlyphInsertionStateEntry2 : StateEntry2 +{ + le_uint16 currentInsertionListIndex; + le_uint16 markedInsertionListIndex; +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/ContextualGlyphInsertionProc2.cpp b/icu4c/source/layout/ContextualGlyphInsertionProc2.cpp new file mode 100644 index 0000000000..ee912ae4a8 --- /dev/null +++ b/icu4c/source/layout/ContextualGlyphInsertionProc2.cpp @@ -0,0 +1,143 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) + +ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + contextualGlyphHeader = (const ContextualGlyphInsertionHeader2 *) morphSubtableHeader; + le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); + insertionTable = ((le_uint16 *) ((char *)&stateTableHeader->stHeader + insertionTableOffset)); + entryTable = (const ContextualGlyphInsertionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() +{ +} + +void ContextualGlyphInsertionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const ContextualGlyphInsertionStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); + le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); + int i = 0; + + if (markIndex > 0) { + le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; + if (!(flags & cgiMarkedIsKashidaLike)) { + // extra glyph(s) will be added directly before/after the specified marked glyph + if (!(flags & cgiMarkInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + for (i = 0; i < count; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + insertGlyphs[i] = glyphStorage[markGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + insertGlyphs[0] = glyphStorage[markGlyph]; + for (i = 1; i < count + 1; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + glyphStorage.applyInsertions(); + } + } else { + // inserted as a split-vowel-like insertion + // extra glyph(s) will be inserted some distance away from the marked glyph + if (!(flags & cgiMarkInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + for (i = 0; i < count; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + insertGlyphs[i] = glyphStorage[markGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + insertGlyphs[0] = glyphStorage[markGlyph]; + for (i = 1; i < count + 1; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + glyphStorage.applyInsertions(); + } + } + } + + if (currIndex > 0) { + le_int16 count = flags & cgiCurrentInsertCountMask; + if (!(flags & cgiCurrentIsKashidaLike)) { + // extra glyph(s) will be added directly before/after the specified current glyph + if (!(flags & cgiCurrentInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + for (i = 0; i < count; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + insertGlyphs[i] = glyphStorage[currGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + insertGlyphs[0] = glyphStorage[currGlyph]; + for (i = 1; i < count + 1; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + glyphStorage.applyInsertions(); + } + } else { + // inserted as a split-vowel-like insertion + // extra glyph(s) will be inserted some distance away from the current glyph + if (!(flags & cgiCurrentInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + for (i = 0; i < count; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + insertGlyphs[i] = glyphStorage[currGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + insertGlyphs[0] = glyphStorage[currGlyph]; + for (i = 1; i < count + 1; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + glyphStorage.applyInsertions(); + } + } + } + + if (flags & cgiSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgiDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +void ContextualGlyphInsertionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/ContextualGlyphInsertionProc2.h b/icu4c/source/layout/ContextualGlyphInsertionProc2.h new file mode 100644 index 0000000000..f0096d30d2 --- /dev/null +++ b/icu4c/source/layout/ContextualGlyphInsertionProc2.h @@ -0,0 +1,64 @@ +/* + * + * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "ContextualGlyphInsertion.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphInsertionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~ContextualGlyphInsertionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphInsertionProcessor2(); + +protected: + le_int32 markGlyph; + const le_uint16* insertionTable; + const ContextualGlyphInsertionStateEntry2 *entryTable; + const ContextualGlyphInsertionHeader2 *contextualGlyphHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/ContextualGlyphSubstProc2.cpp b/icu4c/source/layout/ContextualGlyphSubstProc2.cpp new file mode 100644 index 0000000000..d15b346969 --- /dev/null +++ b/icu4c/source/layout/ContextualGlyphSubstProc2.cpp @@ -0,0 +1,134 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" +#include + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor2) + +ContextualGlyphSubstitutionProcessor2::ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + contextualGlyphHeader = (const ContextualGlyphHeader2 *) morphSubtableHeader; + le_uint32 perGlyphTableOffset = SWAPL(contextualGlyphHeader->perGlyphTableOffset); + perGlyphTable = ((le_uint32 *) ((char *)&stateTableHeader->stHeader + perGlyphTableOffset)); + entryTable = (const ContextualGlyphStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +ContextualGlyphSubstitutionProcessor2::~ContextualGlyphSubstitutionProcessor2() +{ +} + +void ContextualGlyphSubstitutionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const ContextualGlyphStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + le_int16 markIndex = SWAPW(entry->markIndex); + le_int16 currIndex = SWAPW(entry->currIndex); + + if (markIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable[markIndex]); + LEGlyphID mGlyph = glyphStorage[markGlyph]; + TTGlyphID newGlyph = lookup(offset, mGlyph); + glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); + } + + if (currIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable[currIndex]); + LEGlyphID thisGlyph = glyphStorage[currGlyph]; + TTGlyphID newGlyph = lookup(offset, thisGlyph); + glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + + if (flags & cgsSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgsDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyphID gid) +{ + LookupTable *lookupTable = ((LookupTable *) ((char *)perGlyphTable + offset)); + le_int16 format = SWAPW(lookupTable->format); + TTGlyphID newGlyph = 0xFFFF; + + switch (format) { + case ltfSimpleArray: { +#ifdef TEST_FORMAT + // Disabled pending for design review + SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) lookupTable; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + newGlyph = SWAPW(lookupTable0->valueArray[glyphCode]); +#endif + break; + } + case ltfSegmentSingle: { +#ifdef TEST_FORMAT + // Disabled pending for design review + SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) lookupTable; + const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfSegmentArray: { + printf("Context Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: { +#ifdef TEST_FORMAT + // Disabled pending for design review + SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) lookupTable; + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfTrimmedArray: { + TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) lookupTable; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + newGlyph = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + } + } + default: + break; + } + return newGlyph; +} + +void ContextualGlyphSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/ContextualGlyphSubstProc2.h b/icu4c/source/layout/ContextualGlyphSubstProc2.h new file mode 100644 index 0000000000..aaf986f7e5 --- /dev/null +++ b/icu4c/source/layout/ContextualGlyphSubstProc2.h @@ -0,0 +1,67 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~ContextualGlyphSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphSubstitutionProcessor2(); + TTGlyphID lookup(le_uint32 offset, LEGlyphID gid); + +protected: + const le_uint32* perGlyphTable; + const ContextualGlyphStateEntry2 *entryTable; + + le_int16 perGlyphTableFormat; + le_int32 markGlyph; + + const ContextualGlyphHeader2 *contextualGlyphHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/ContextualGlyphSubstitution.h b/icu4c/source/layout/ContextualGlyphSubstitution.h index 72c23559db..4ecc8ade8a 100644 --- a/icu4c/source/layout/ContextualGlyphSubstitution.h +++ b/icu4c/source/layout/ContextualGlyphSubstitution.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -24,6 +24,11 @@ struct ContextualGlyphSubstitutionHeader : MorphStateTableHeader ByteOffset substitutionTableOffset; }; +struct ContextualGlyphHeader2 : MorphStateTableHeader2 +{ + le_uint32 perGlyphTableOffset; // no more substitution tables +}; + enum ContextualGlyphSubstitutionFlags { cgsSetMark = 0x8000, @@ -37,5 +42,11 @@ struct ContextualGlyphSubstitutionStateEntry : StateEntry WordOffset currOffset; }; +struct ContextualGlyphStateEntry2 : StateEntry2 +{ + le_uint16 markIndex; + le_uint16 currIndex; +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/GXLayoutEngine2.cpp b/icu4c/source/layout/GXLayoutEngine2.cpp new file mode 100644 index 0000000000..1356fc4f6c --- /dev/null +++ b/icu4c/source/layout/GXLayoutEngine2.cpp @@ -0,0 +1,66 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutEngine.h" +#include "GXLayoutEngine2.h" +#include "LEGlyphStorage.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine2) + +GXLayoutEngine2::GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMorphTable(morphTable) +{ + // nothing else to do? +} + +GXLayoutEngine2::~GXLayoutEngine2() +{ + reset(); +} + +// apply 'morx' table +le_int32 GXLayoutEngine2::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return 0; + } + + if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); + + if (LE_FAILURE(success)) { + return 0; + } + + fMorphTable->process(glyphStorage, fTypoFlags); + return count; +} + +// apply positional tables +void GXLayoutEngine2::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/, + LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return; + } + + if (chars == NULL || offset < 0 || count < 0) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return; + } + + // FIXME: no positional processing yet... +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/GXLayoutEngine2.h b/icu4c/source/layout/GXLayoutEngine2.h new file mode 100644 index 0000000000..14104b79b1 --- /dev/null +++ b/icu4c/source/layout/GXLayoutEngine2.h @@ -0,0 +1,125 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __GXLAYOUTENGINE2_H +#define __GXLAYOUTENGINE2_H + +#include "LETypes.h" +#include "LayoutEngine.h" + +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEFontInstance; +class LEGlyphStorage; + +/** + * This class implements layout for QuickDraw GX or Apple Advanced Typograyph (AAT) + * fonts. A font is a GX or AAT font if it contains a 'mort' table. See Apple's + * TrueType Reference Manual (http://fonts.apple.com/TTRefMan/index.html) for details. + * Information about 'mort' tables is in the chapter titled "Font Files." + * + * @internal + */ +class GXLayoutEngine2 : public LayoutEngine +{ +public: + /** + * This is the main constructor. It constructs an instance of GXLayoutEngine for + * a particular font, script and language. It takes the 'mort' table as a parameter since + * LayoutEngine::layoutEngineFactory has to read the 'mort' table to know that it has a + * GX font. + * + * Note: GX and AAT fonts don't contain any script and language specific tables, so + * the script and language are ignored. + * + * @param fontInstance - the font + * @param scriptCode - the script + * @param langaugeCode - the language + * @param morphTable - the 'mort' table + * @param success - set to an error code if the operation fails + * + * @see LayoutEngine::layoutEngineFactory + * @see ScriptAndLangaugeTags.h for script and language codes + * + * @internal + */ + GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success); + + /** + * The destructor, virtual for correct polymorphic invocation. + * + * @internal + */ + virtual ~GXLayoutEngine2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + + /** + * The address of the 'mort' table + * + * @internal + */ + const MorphTableHeader2 *fMorphTable; + + /** + * This method does GX layout using the font's 'mort' table. It converts the + * input character codes to glyph indices using mapCharsToGlyphs, and then + * applies the 'mort' table. + * + * Input parameters: + * @param chars - the input character context + * @param offset - the index of the first character to process + * @param count - the number of characters to process + * @param max - the number of characters in the input context + * @param rightToLeft - TRUE if the text is in a right to left directional run + * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @return the number of glyphs in the glyph index array + * + * @internal + */ + virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + + /** + * This method adjusts the glyph positions using the font's + * 'kern', 'trak', 'bsln', 'opbd' and 'just' tables. + * + * Input parameters: + * @param glyphStorage - the object holding the glyph storage. The positions will be updated as needed. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @internal + */ + virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/layout/IndicRearrangement.h b/icu4c/source/layout/IndicRearrangement.h index 48b1d08ada..3af3692a4a 100644 --- a/icu4c/source/layout/IndicRearrangement.h +++ b/icu4c/source/layout/IndicRearrangement.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and Others 1998-2013 - All Rights Reserved * */ @@ -24,6 +24,10 @@ struct IndicRearrangementSubtableHeader : MorphStateTableHeader { }; +struct IndicRearrangementSubtableHeader2 : MorphStateTableHeader2 +{ +}; + enum IndicRearrangementFlags { irfMarkFirst = 0x8000, @@ -60,6 +64,10 @@ struct IndicRearrangementStateEntry : StateEntry { }; +struct IndicRearrangementStateEntry2 : StateEntry2 +{ +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/IndicRearrangementProcessor2.cpp b/icu4c/source/layout/IndicRearrangementProcessor2.cpp new file mode 100644 index 0000000000..b7849e3a65 --- /dev/null +++ b/icu4c/source/layout/IndicRearrangementProcessor2.cpp @@ -0,0 +1,398 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2) + +IndicRearrangementProcessor2::IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader2 *) morphSubtableHeader; + entryTable = (const IndicRearrangementStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +IndicRearrangementProcessor2::~IndicRearrangementProcessor2() +{ +} + +void IndicRearrangementProcessor2::beginStateTable() +{ + firstGlyph = 0; + lastGlyph = 0; +} + +le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const IndicRearrangementStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); // index to the new state + IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags); + + if (flags & irfMarkFirst) { + firstGlyph = currGlyph; + } + + if (flags & irfMarkLast) { + lastGlyph = currGlyph; + } + + doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask)); + + if (!(flags & irfDontAdvance)) { + currGlyph += dir; + } + + return newState; // index to new state +} + +void IndicRearrangementProcessor2::endStateTable() +{ +} + +void IndicRearrangementProcessor2::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const +{ + LEGlyphID a, b, c, d; + le_int32 ia, ib, ic, id, ix, x; + LEErrorCode success = LE_NO_ERROR; + + switch(verb) + { + case irvNoAction: + break; + + case irvxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + x = firstGlyph + 1; + + while (x <= lastGlyph) { + glyphStorage[x - 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 1, ix, success); + x += 1; + } + + glyphStorage[lastGlyph] = a; + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDx: + d = glyphStorage[lastGlyph]; + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 1; + + while (x >= firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage.setCharIndex(firstGlyph, id, success); + break; + + case irvDxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + break; + + case irvDCx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + break; + + case irvCDxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvCDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDCxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + default: + break; + } + +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/IndicRearrangementProcessor2.h b/icu4c/source/layout/IndicRearrangementProcessor2.h new file mode 100644 index 0000000000..45d4f92c45 --- /dev/null +++ b/icu4c/source/layout/IndicRearrangementProcessor2.h @@ -0,0 +1,63 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __INDICREARRANGEMENTPROCESSOR2_H +#define __INDICREARRANGEMENTPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangement.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class IndicRearrangementProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; + + IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~IndicRearrangementProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + le_int32 firstGlyph; + le_int32 lastGlyph; + + const IndicRearrangementStateEntry2 *entryTable; + const IndicRearrangementSubtableHeader2 *indicRearrangementSubtableHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/LETypes.h b/icu4c/source/layout/LETypes.h index 56c8d21f39..0d0b1ca04c 100644 --- a/icu4c/source/layout/LETypes.h +++ b/icu4c/source/layout/LETypes.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2012 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -454,7 +454,7 @@ enum LEFeatureTags { LE_CALT_FEATURE_TAG = 0x63616C74UL, /**< 'calt' */ LE_CASE_FEATURE_TAG = 0x63617365UL, /**< 'case' */ LE_CCMP_FEATURE_TAG = 0x63636D70UL, /**< 'ccmp' */ - LE_CJCT_FEATURE_TAG = 0x636A6374UL, /**< 'cjct' */ + LE_CJCT_FEATURE_TAG = 0x636A6374UL, /**< 'cjct' */ LE_CLIG_FEATURE_TAG = 0x636C6967UL, /**< 'clig' */ LE_CPSP_FEATURE_TAG = 0x63707370UL, /**< 'cpsp' */ LE_CSWH_FEATURE_TAG = 0x63737768UL, /**< 'cswh' */ @@ -518,7 +518,7 @@ enum LEFeatureTags { LE_RAND_FEATURE_TAG = 0x72616E64UL, /**< 'rand' */ LE_RLIG_FEATURE_TAG = 0x726C6967UL, /**< 'rlig' */ LE_RPHF_FEATURE_TAG = 0x72706866UL, /**< 'rphf' */ - LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ + LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ LE_RTBD_FEATURE_TAG = 0x72746264UL, /**< 'rtbd' */ LE_RTLA_FEATURE_TAG = 0x72746C61UL, /**< 'rtla' */ LE_RUBY_FEATURE_TAG = 0x72756279UL, /**< 'ruby' */ @@ -569,6 +569,64 @@ enum LEFeatureTags { LE_ZERO_FEATURE_TAG = 0x7A65726FUL /**< 'zero' */ }; +/** + * @internal + */ +enum LEFeatureENUMs { + LE_Kerning_FEATURE_ENUM = 0, /**< Requests Kerning. Formerly LayoutEngine::kTypoFlagKern */ + LE_Ligatures_FEATURE_ENUM = 1, /**< Requests Ligatures. Formerly LayoutEngine::kTypoFlagLiga */ + LE_CLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_DLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_HLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_LIGA_FEATURE_ENUM, /**< Feature specific enum */ + LE_RLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_SMCP_FEATURE_ENUM, /**< Feature specific enum */ + LE_FRAC_FEATURE_ENUM, /**< Feature specific enum */ + LE_AFRC_FEATURE_ENUM, /**< Feature specific enum */ + LE_ZERO_FEATURE_ENUM, /**< Feature specific enum */ + LE_SWSH_FEATURE_ENUM, /**< Feature specific enum */ + LE_CSWH_FEATURE_ENUM, /**< Feature specific enum */ + LE_SALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_NALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_RUBY_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS01_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS02_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS03_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS04_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS05_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS06_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS07_FEATURE_ENUM, /**< Feature specific enum */ + + LE_CHAR_FILTER_FEATURE_ENUM = 31, /**< Apply CharSubstitutionFilter */ + LE_FEATURE_ENUM_MAX = LE_CHAR_FILTER_FEATURE_ENUM +}; + +#define LE_Kerning_FEATURE_FLAG (1 << LE_Kerning_FEATURE_ENUM) +#define LE_Ligatures_FEATURE_FLAG (1 << LE_Ligatures_FEATURE_ENUM) +#define LE_CLIG_FEATURE_FLAG (1 << LE_CLIG_FEATURE_ENUM) +#define LE_DLIG_FEATURE_FLAG (1 << LE_DLIG_FEATURE_ENUM) +#define LE_HLIG_FEATURE_FLAG (1 << LE_HLIG_FEATURE_ENUM) +#define LE_LIGA_FEATURE_FLAG (1 << LE_LIGA_FEATURE_ENUM) +#define LE_RLIG_FEATURE_FLAG (1 << LE_RLIG_FEATURE_ENUM) +#define LE_SMCP_FEATURE_FLAG (1 << LE_SMCP_FEATURE_ENUM) +#define LE_FRAC_FEATURE_FLAG (1 << LE_FRAC_FEATURE_ENUM) +#define LE_AFRC_FEATURE_FLAG (1 << LE_AFRC_FEATURE_ENUM) +#define LE_ZERO_FEATURE_FLAG (1 << LE_ZERO_FEATURE_ENUM) +#define LE_SWSH_FEATURE_FLAG (1 << LE_SWSH_FEATURE_ENUM) +#define LE_CSWH_FEATURE_FLAG (1 << LE_CSWH_FEATURE_ENUM) +#define LE_SALT_FEATURE_FLAG (1 << LE_SALT_FEATURE_ENUM) +#define LE_NALT_FEATURE_FLAG (1 << LE_NALT_FEATURE_ENUM) +#define LE_RUBY_FEATURE_FLAG (1 << LE_RUBY_FEATURE_ENUM) +#define LE_SS01_FEATURE_FLAG (1 << LE_SS01_FEATURE_ENUM) +#define LE_SS02_FEATURE_FLAG (1 << LE_SS02_FEATURE_ENUM) +#define LE_SS03_FEATURE_FLAG (1 << LE_SS03_FEATURE_ENUM) +#define LE_SS04_FEATURE_FLAG (1 << LE_SS04_FEATURE_ENUM) +#define LE_SS05_FEATURE_FLAG (1 << LE_SS05_FEATURE_ENUM) +#define LE_SS06_FEATURE_FLAG (1 << LE_SS06_FEATURE_ENUM) +#define LE_SS07_FEATURE_FLAG (1 << LE_SS07_FEATURE_ENUM) + +#define LE_CHAR_FILTER_FEATURE_FLAG (1 << LE_CHAR_FILTER_FEATURE_ENUM) + /** * Error codes returned by the LayoutEngine. * diff --git a/icu4c/source/layout/LayoutEngine.cpp b/icu4c/source/layout/LayoutEngine.cpp index c815c83c85..62088a5b2b 100644 --- a/icu4c/source/layout/LayoutEngine.cpp +++ b/icu4c/source/layout/LayoutEngine.cpp @@ -1,10 +1,11 @@ /* - * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved */ #include "LETypes.h" #include "LEScripts.h" #include "LELanguages.h" +#include "LESwaps.h" #include "LayoutEngine.h" #include "ArabicLayoutEngine.h" @@ -16,6 +17,8 @@ #include "ThaiLayoutEngine.h" #include "TibetanLayoutEngine.h" #include "GXLayoutEngine.h" +#include "GXLayoutEngine2.h" + #include "ScriptAndLanguageTags.h" #include "CharSubstitutionFilter.h" @@ -35,8 +38,9 @@ U_NAMESPACE_BEGIN /* Leave this copyright notice here! It needs to go somewhere in this library. */ static const char copyright[] = U_COPYRIGHT_STRING; -const le_int32 LayoutEngine::kTypoFlagKern = 0x1; -const le_int32 LayoutEngine::kTypoFlagLiga = 0x2; +/* TODO: remove these? */ +const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; +const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; const LEUnicode32 DefaultCharMapper::controlChars[] = { 0x0009, 0x000A, 0x000D, @@ -134,9 +138,9 @@ static const FeatureMap canonFeatureMap[] = static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); -LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, - le_int32 scriptCode, - le_int32 languageCode, +LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, + le_int32 scriptCode, + le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), @@ -144,7 +148,7 @@ LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, { if (LE_FAILURE(success)) { return; - } + } fGlyphStorage = new LEGlyphStorage(); if (fGlyphStorage == NULL) { @@ -208,7 +212,7 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off if (canonGSUBTable->coversScript(scriptTag)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); - if (substitutionFilter == NULL) { + if (substitutionFilter == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } @@ -398,7 +402,7 @@ void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter for (p = 0; p < glyphCount; p += 1) { float next, xAdvance; - + glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; @@ -440,7 +444,7 @@ void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, for (p = 0; p < charCount; p += 1, c += direction) { float next, xAdvance; - + glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; @@ -495,7 +499,7 @@ le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_ if (fGlyphStorage->getGlyphCount() > 0) { fGlyphStorage->reset(); } - + glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); positionGlyphs(*fGlyphStorage, x, y, success); adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); @@ -507,17 +511,18 @@ void LayoutEngine::reset() { fGlyphStorage->reset(); } - + LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) { // 3 -> kerning and ligatures return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success); } - + LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) { static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; + static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; if (LE_FAILURE(success)) { return NULL; @@ -597,46 +602,63 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan break; } } else { - const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - - if (morphTable != NULL) { - result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success); - } else { - switch (scriptCode) { - case bengScriptCode: - case devaScriptCode: - case gujrScriptCode: - case kndaScriptCode: - case mlymScriptCode: - case oryaScriptCode: - case guruScriptCode: - case tamlScriptCode: - case teluScriptCode: - case sinhScriptCode: - { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + MorphTableHeader2 *table = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); + if (table != NULL) { + le_uint32 version = SWAPL(table->version); + switch (version) { + case 0x10000: { // mort e.g.:Skia Regular + const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); + if (mortTable != NULL) { + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + } + break; + } + case 0x20000: { // morx + result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, table, typoFlags, success); + break; + } } + } else { + const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); + if (mortTable != NULL) { // mort + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + } else { + switch (scriptCode) { + case bengScriptCode: + case devaScriptCode: + case gujrScriptCode: + case kndaScriptCode: + case mlymScriptCode: + case oryaScriptCode: + case guruScriptCode: + case tamlScriptCode: + case teluScriptCode: + case sinhScriptCode: + { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } - case arabScriptCode: - //case hebrScriptCode: - result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + case arabScriptCode: + //case hebrScriptCode: + result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; - //case hebrScriptCode: - // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); + //case hebrScriptCode: + // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - case thaiScriptCode: - result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + case thaiScriptCode: + result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; - case hangScriptCode: - result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + case hangScriptCode: + result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; - default: - result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + default: + result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } } } } diff --git a/icu4c/source/layout/LayoutEngine.h b/icu4c/source/layout/LayoutEngine.h index b76f5748b7..b9734cda08 100644 --- a/icu4c/source/layout/LayoutEngine.h +++ b/icu4c/source/layout/LayoutEngine.h @@ -1,5 +1,5 @@ /* - * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved */ #ifndef __LAYOUTENGINE_H @@ -64,10 +64,10 @@ class LEGlyphStorage; class U_LAYOUT_API LayoutEngine : public UObject { public: #ifndef U_HIDE_INTERNAL_API - /** @internal Flag to request kerning. */ + /** @internal Flag to request kerning. Use LE_Kerning_FEATURE_FLAG instead. */ static const le_int32 kTypoFlagKern; - /** @internal Flag to request ligatures. */ - static const le_int32 kTypoFlagLiga; + /** @internal Flag to request ligatures. Use LE_Ligatures_FEATURE_FLAG instead. */ + static const le_int32 kTypoFlagLiga; #endif /* U_HIDE_INTERNAL_API */ protected: diff --git a/icu4c/source/layout/LigatureSubstProc2.cpp b/icu4c/source/layout/LigatureSubstProc2.cpp new file mode 100644 index 0000000000..78ea3fdeb6 --- /dev/null +++ b/icu4c/source/layout/LigatureSubstProc2.cpp @@ -0,0 +1,116 @@ +/* + * + * (C) Copyright IBM Corp and Others. 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +#define ExtendedComplement(m) ((le_int32) (~((le_uint32) (m)))) +#define SignBit(m) ((ExtendedComplement(m) >> 1) & (le_int32)(m)) +#define SignExtend(v,m) (((v) & SignBit(m))? ((v) | ExtendedComplement(m)): (v)) + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor2) + +LigatureSubstitutionProcessor2::LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + ligatureSubstitutionHeader = (const LigatureSubstitutionHeader2 *) morphSubtableHeader; + ligActionOffset = SWAPL(ligatureSubstitutionHeader->ligActionOffset); + componentOffset = SWAPL(ligatureSubstitutionHeader->componentOffset); + ligatureOffset = SWAPL(ligatureSubstitutionHeader->ligatureOffset); + + entryTable = (const LigatureSubstitutionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +LigatureSubstitutionProcessor2::~LigatureSubstitutionProcessor2() +{ +} + +void LigatureSubstitutionProcessor2::beginStateTable() +{ + m = -1; +} + +le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const LigatureSubstitutionStateEntry2 *entry = &entryTable[index]; + le_uint16 nextStateIndex = SWAPW(entry->nextStateIndex); + le_uint16 flags = SWAPW(entry->entryFlags); + le_uint16 ligActionIndex = SWAPW(entry->ligActionIndex); + + if (flags & lsfSetComponent) { + if (++m >= nComponents) { + m = 0; + } + componentStack[m] = currGlyph; + } + + ByteOffset actionOffset = flags & lsfPerformAction; + + if (actionOffset != 0) { + const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + ligActionOffset) + ligActionIndex; + const TTGlyphID *ligatureTable = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + ligatureOffset); + LigatureActionEntry action; + le_int32 offset, i = 0; + le_int32 stack[nComponents]; + le_int16 mm = -1; + + const le_uint16 *componentTable = (const le_uint16 *)((char *) &ligatureSubstitutionHeader->stHeader + componentOffset); + + do { + le_uint32 componentGlyph = componentStack[m--]; // pop off + + action = SWAPL(*ap++); + + if (m < 0) { + m = nComponents - 1; + } + + offset = action & lafComponentOffsetMask; + if (offset != 0) { + + i += SWAPW(componentTable[LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask))]); + + if (action & (lafLast | lafStore)) { + TTGlyphID ligatureGlyph = SWAPW(ligatureTable[i]); + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); + stack[++mm] = componentGlyph; + i = 0; + } else { + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); + } + } + } while (!(action & lafLast)); + + while (mm >= 0) { + if (++m >= nComponents) { + m = 0; + } + + componentStack[m] = stack[mm--]; + } + } + + if (!(flags & lsfDontAdvance)) { + currGlyph += dir; + } + + return nextStateIndex; +} + +void LigatureSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/LigatureSubstProc2.h b/icu4c/source/layout/LigatureSubstProc2.h new file mode 100644 index 0000000000..8ef5f6f220 --- /dev/null +++ b/icu4c/source/layout/LigatureSubstProc2.h @@ -0,0 +1,71 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __LIGATURESUBSTITUTIONPROCESSOR2_H +#define __LIGATURESUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +#define nComponents 16 + +class LigatureSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~LigatureSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + LigatureSubstitutionProcessor2(); + +protected: + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; + + const LigatureSubstitutionStateEntry2 *entryTable; + + le_int32 componentStack[nComponents]; + le_int16 m; + + const LigatureSubstitutionHeader2 *ligatureSubstitutionHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/LigatureSubstitution.h b/icu4c/source/layout/LigatureSubstitution.h index 2963b7c144..fed2c2192f 100644 --- a/icu4c/source/layout/LigatureSubstitution.h +++ b/icu4c/source/layout/LigatureSubstitution.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and Others 1998-2013 - All Rights Reserved * */ @@ -27,17 +27,32 @@ struct LigatureSubstitutionHeader : MorphStateTableHeader ByteOffset ligatureTableOffset; }; +struct LigatureSubstitutionHeader2 : MorphStateTableHeader2 +{ + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; +}; + enum LigatureSubstitutionFlags { lsfSetComponent = 0x8000, lsfDontAdvance = 0x4000, - lsfActionOffsetMask = 0x3FFF + lsfActionOffsetMask = 0x3FFF, // N/A in morx + lsfPerformAction = 0x2000 }; struct LigatureSubstitutionStateEntry : StateEntry { }; +struct LigatureSubstitutionStateEntry2 +{ + le_uint16 nextStateIndex; + le_uint16 entryFlags; + le_uint16 ligActionIndex; +}; + typedef le_uint32 LigatureActionEntry; enum LigatureActionFlags diff --git a/icu4c/source/layout/LookupProcessor.cpp b/icu4c/source/layout/LookupProcessor.cpp index 4f9d97c58d..03986bafbf 100644 --- a/icu4c/source/layout/LookupProcessor.cpp +++ b/icu4c/source/layout/LookupProcessor.cpp @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2012 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -99,6 +99,10 @@ le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIt } const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex); + if (lookupTable == NULL) { + success = LE_INTERNAL_ERROR; + return 0; + } le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); GlyphIterator tempIterator(*glyphIterator, lookupFlags); le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success); diff --git a/icu4c/source/layout/Makefile.in b/icu4c/source/layout/Makefile.in index d63a244942..77be2be947 100644 --- a/icu4c/source/layout/Makefile.in +++ b/icu4c/source/layout/Makefile.in @@ -1,6 +1,6 @@ #****************************************************************************** # -# Copyright (C) 1999-2011, International Business Machines +# Copyright (C) 1999-2013, International Business Machines # Corporation and others. All Rights Reserved. # #****************************************************************************** @@ -130,7 +130,21 @@ TibetanLayoutEngine.o \ TibetanReordering.o \ HangulLayoutEngine.o \ KernTable.o \ -loengine.o +loengine.o \ +ContextualGlyphInsertionProc2.o \ +ContextualGlyphSubstProc2.o \ +GXLayoutEngine2.o \ +IndicRearrangementProcessor2.o \ +LigatureSubstProc2.o \ +MorphTables2.o \ +NonContextualGlyphSubstProc2.o \ +SegmentArrayProcessor2.o \ +SegmentSingleProcessor2.o \ +SimpleArrayProcessor2.o \ +SingleTableProcessor2.o \ +StateTableProcessor2.o \ +SubtableProcessor2.o \ +TrimmedArrayProcessor2.o ## Header files to install HEADERS= $(srcdir)/LayoutEngine.h $(srcdir)/LE*.h $(srcdir)/loengine.h @@ -237,4 +251,3 @@ ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),) -include $(DEPS) endif endif - diff --git a/icu4c/source/layout/MorphStateTables.h b/icu4c/source/layout/MorphStateTables.h index a2e0b00b7f..f51e0396d2 100644 --- a/icu4c/source/layout/MorphStateTables.h +++ b/icu4c/source/layout/MorphStateTables.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -24,5 +24,10 @@ struct MorphStateTableHeader : MorphSubtableHeader StateTableHeader stHeader; }; +struct MorphStateTableHeader2 : MorphSubtableHeader2 +{ + StateTableHeader2 stHeader; +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/MorphTables.h b/icu4c/source/layout/MorphTables.h index 8d198cf41f..550bd98148 100644 --- a/icu4c/source/layout/MorphTables.h +++ b/icu4c/source/layout/MorphTables.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -51,6 +51,7 @@ struct MorphTableHeader }; typedef le_int16 SubtableCoverage; +typedef le_uint32 SubtableCoverage2; enum SubtableCoverageFlags { @@ -80,6 +81,302 @@ struct MorphSubtableHeader void process(LEGlyphStorage &glyphStorage) const; }; +enum SubtableCoverageFlags2 +{ + scfVertical2 = 0x80000000, + scfReverse2 = 0x40000000, + scfIgnoreVt2 = 0x20000000, + scfReserved2 = 0x1FFFFF00, + scfTypeMask2 = 0x000000FF +}; + +struct MorphSubtableHeader2 +{ + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + void process(LEGlyphStorage &glyphStorage) const; +}; + +struct ChainHeader2 +{ + FeatureFlags defaultFlags; + le_uint32 chainLength; + le_uint32 nFeatureEntries; + le_uint32 nSubtables; + FeatureTableEntry featureTable[ANY_NUMBER]; +}; + +struct MorphTableHeader2 +{ + le_int32 version; + le_uint32 nChains; + ChainHeader2 chains[ANY_NUMBER]; + + void process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const; +}; + +/* + * AAT Font Features + * source: https://developer.apple.com/fonts/registry/ + * (plus addition from ATS/SFNTLayoutTypes.h) + */ + +enum { + + allTypographicFeaturesType = 0, + + allTypeFeaturesOnSelector = 0, + allTypeFeaturesOffSelector = 1, + + ligaturesType = 1, + + requiredLigaturesOnSelector = 0, + requiredLigaturesOffSelector = 1, + commonLigaturesOnSelector = 2, + commonLigaturesOffSelector = 3, + rareLigaturesOnSelector = 4, + rareLigaturesOffSelector = 5, + logosOnSelector = 6, + logosOffSelector = 7, + rebusPicturesOnSelector = 8, + rebusPicturesOffSelector = 9, + diphthongLigaturesOnSelector = 10, + diphthongLigaturesOffSelector = 11, + squaredLigaturesOnSelector = 12, + squaredLigaturesOffSelector = 13, + abbrevSquaredLigaturesOnSelector = 14, + abbrevSquaredLigaturesOffSelector = 15, + symbolLigaturesOnSelector = 16, + symbolLigaturesOffSelector = 17, + contextualLigaturesOnSelector = 18, + contextualLigaturesOffSelector = 19, + historicalLigaturesOnSelector = 20, + historicalLigaturesOffSelector = 21, + + cursiveConnectionType = 2, + + unconnectedSelector = 0, + partiallyConnectedSelector = 1, + cursiveSelector = 2, + + letterCaseType = 3, + + upperAndLowerCaseSelector = 0, + allCapsSelector = 1, + allLowerCaseSelector = 2, + smallCapsSelector = 3, + initialCapsSelector = 4, + initialCapsAndSmallCapsSelector = 5, + + verticalSubstitutionType = 4, + + substituteVerticalFormsOnSelector = 0, + substituteVerticalFormsOffSelector = 1, + + linguisticRearrangementType = 5, + + linguisticRearrangementOnSelector = 0, + linguisticRearrangementOffSelector = 1, + + numberSpacingType = 6, + + monospacedNumbersSelector = 0, + proportionalNumbersSelector = 1, + + /* + appleReserved1Type = 7, + */ + + smartSwashType = 8, + + wordInitialSwashesOnSelector = 0, + wordInitialSwashesOffSelector = 1, + wordFinalSwashesOnSelector = 2, + wordFinalSwashesOffSelector = 3, + lineInitialSwashesOnSelector = 4, + lineInitialSwashesOffSelector = 5, + lineFinalSwashesOnSelector = 6, + lineFinalSwashesOffSelector = 7, + nonFinalSwashesOnSelector = 8, + nonFinalSwashesOffSelector = 9, + + diacriticsType = 9, + + showDiacriticsSelector = 0, + hideDiacriticsSelector = 1, + decomposeDiacriticsSelector = 2, + + verticalPositionType = 10, + + normalPositionSelector = 0, + superiorsSelector = 1, + inferiorsSelector = 2, + ordinalsSelector = 3, + + fractionsType = 11, + + noFractionsSelector = 0, + verticalFractionsSelector = 1, + diagonalFractionsSelector = 2, + + /* + appleReserved2Type = 12, + */ + + overlappingCharactersType = 13, + + preventOverlapOnSelector = 0, + preventOverlapOffSelector = 1, + + typographicExtrasType = 14, + + hyphensToEmDashOnSelector = 0, + hyphensToEmDashOffSelector = 1, + hyphenToEnDashOnSelector = 2, + hyphenToEnDashOffSelector = 3, + unslashedZeroOnSelector = 4, + slashedZeroOffSelector = 4, + unslashedZeroOffSelector = 5, + slashedZeroOnSelector = 5, + formInterrobangOnSelector = 6, + formInterrobangOffSelector = 7, + smartQuotesOnSelector = 8, + smartQuotesOffSelector = 9, + periodsToEllipsisOnSelector = 10, + periodsToEllipsisOffSelector = 11, + + mathematicalExtrasType = 15, + + hyphenToMinusOnSelector = 0, + hyphenToMinusOffSelector = 1, + asteriskToMultiplyOnSelector = 2, + asteriskToMultiplyOffSelector = 3, + slashToDivideOnSelector = 4, + slashToDivideOffSelector = 5, + inequalityLigaturesOnSelector = 6, + inequalityLigaturesOffSelector = 7, + exponentsOnSelector = 8, + exponentsOffSelector = 9, + + ornamentSetsType = 16, + + noOrnamentsSelector = 0, + dingbatsSelector = 1, + piCharactersSelector = 2, + fleuronsSelector = 3, + decorativeBordersSelector = 4, + internationalSymbolsSelector = 5, + mathSymbolsSelector = 6, + + characterAlternativesType = 17, + + noAlternatesSelector = 0, + + designComplexityType = 18, + + designLevel1Selector = 0, + designLevel2Selector = 1, + designLevel3Selector = 2, + designLevel4Selector = 3, + designLevel5Selector = 4, + designLevel6Selector = 5, + designLevel7Selector = 6, + + styleOptionsType = 19, + + noStyleOptionsSelector = 0, + displayTextSelector = 1, + engravedTextSelector = 2, + illuminatedCapsSelector = 3, + titlingCapsSelector = 4, + tallCapsSelector = 5, + + characterShapeType = 20, + + traditionalCharactersSelector = 0, + simplifiedCharactersSelector = 1, + jis1978CharactersSelector = 2, + jis1983CharactersSelector = 3, + jis1990CharactersSelector = 4, + traditionalAltOneSelector = 5, + traditionalAltTwoSelector = 6, + traditionalAltThreeSelector = 7, + traditionalAltFourSelector = 8, + traditionalAltFiveSelector = 9, + expertCharactersSelector = 10, + + numberCaseType = 21, + + lowerCaseNumbersSelector = 0, + upperCaseNumbersSelector = 1, + + textSpacingType = 22, + + proportionalTextSelector = 0, + monospacedTextSelector = 1, + halfWidthTextSelector = 2, + normallySpacedTextSelector = 3, + + transliterationType = 23, + + noTransliterationSelector = 0, + hanjaToHangulSelector = 1, + hiraganaToKatakanaSelector = 2, + katakanaToHiraganaSelector = 3, + kanaToRomanizationSelector = 4, + romanizationToHiraganaSelector = 5, + romanizationToKatakanaSelector = 6, + hanjaToHangulAltOneSelector = 7, + hanjaToHangulAltTwoSelector = 8, + hanjaToHangulAltThreeSelector = 9, + + annotationType = 24, + + noAnnotationSelector = 0, + boxAnnotationSelector = 1, + roundedBoxAnnotationSelector = 2, + circleAnnotationSelector = 3, + invertedCircleAnnotationSelector = 4, + parenthesisAnnotationSelector = 5, + periodAnnotationSelector = 6, + romanNumeralAnnotationSelector = 7, + diamondAnnotationSelector = 8, + + kanaSpacingType = 25, + + fullWidthKanaSelector = 0, + proportionalKanaSelector = 1, + + ideographicSpacingType = 26, + + fullWidthIdeographsSelector = 0, + proportionalIdeographsSelector = 1, + + cjkRomanSpacingType = 103, + + halfWidthCJKRomanSelector = 0, + proportionalCJKRomanSelector = 1, + defaultCJKRomanSelector = 2, + fullWidthCJKRomanSelector = 3, + + rubyKanaType = 28, + + rubyKanaOnSelector = 2, + rubyKanaOffSelector = 3, + +/* The following types are provided for compatibility; note that + their use is deprecated. */ + + adobeCharacterSpacingType = 100, /* prefer 22 */ + adobeKanaSpacingType = 101, /* prefer 25 */ + adobeKanjiSpacingType = 102, /* prefer 26 */ + adobeSquareLigatures = 104, /* prefer 1 */ + + lastFeatureType = -1 +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/MorphTables2.cpp b/icu4c/source/layout/MorphTables2.cpp new file mode 100644 index 0000000000..0764195e1d --- /dev/null +++ b/icu4c/source/layout/MorphTables2.cpp @@ -0,0 +1,204 @@ +/* + * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutTables.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LigatureSubstProc2.h" +#include "NonContextualGlyphSubstProc2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +void MorphTableHeader2::process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const +{ + const ChainHeader2 *chainHeader = chains; + le_uint32 chainCount = SWAPL(this->nChains); + le_uint32 chain; + + for (chain = 0; chain < chainCount; chain++) { + FeatureFlags flag = SWAPL(chainHeader->defaultFlags); + le_uint32 chainLength = SWAPL(chainHeader->chainLength); + le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); + le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); + const MorphSubtableHeader2 *subtableHeader = + (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]; + le_uint32 subtable; + + if (typoFlags != 0) { + le_uint32 featureEntry; + + // Feature subtables + for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { + FeatureTableEntry featureTableEntry = chains->featureTable[featureEntry]; + le_int16 featureType = SWAPW(featureTableEntry.featureType); + le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); + le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); + le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags); + switch (featureType) { + case ligaturesType: + if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } else { + if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) || + ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) || + ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) || + ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } + } + break; + case letterCaseType: + if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case verticalSubstitutionType: + break; + case linguisticRearrangementType: + break; + case numberSpacingType: + break; + case smartSwashType: + if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } + break; + case diacriticsType: + break; + case verticalPositionType: + break; + case fractionsType: + if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) || + ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } else { + flag &= disableFlags; + } + break; + case typographicExtrasType: + if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case mathematicalExtrasType: + break; + case ornamentSetsType: + break; + case characterAlternativesType: + break; + case designComplexityType: + if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) || + ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) || + ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) || + ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) || + ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) || + ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) || + ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) { + + flag &= disableFlags; + flag |= enableFlags; + } + break; + case styleOptionsType: + break; + case characterShapeType: + break; + case numberCaseType: + break; + case textSpacingType: + break; + case transliterationType: + break; + case annotationType: + if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case kanaSpacingType: + break; + case ideographicSpacingType: + break; + case rubyKanaType: + if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case cjkRomanSpacingType: + break; + default: + break; + } + } + } + + for (subtable = 0; subtable < nSubtables; subtable++) { + le_uint32 length = SWAPL(subtableHeader->length); + le_uint32 coverage = SWAPL(subtableHeader->coverage); + FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); + // should check coverage more carefully... + if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { + subtableHeader->process(glyphStorage); + } + subtableHeader = (const MorphSubtableHeader2 *) ((char *)subtableHeader + length); + } + chainHeader = (const ChainHeader2 *)((char *)chainHeader + chainLength); + } +} + +void MorphSubtableHeader2::process(LEGlyphStorage &glyphStorage) const +{ + SubtableProcessor2 *processor = NULL; + + switch (SWAPL(coverage) & scfTypeMask2) + { + case mstIndicRearrangement: + processor = new IndicRearrangementProcessor2(this); + break; + + case mstContextualGlyphSubstitution: + processor = new ContextualGlyphSubstitutionProcessor2(this); + break; + + case mstLigatureSubstitution: + processor = new LigatureSubstitutionProcessor2(this); + break; + + case mstReservedUnused: + break; + + case mstNonContextualGlyphSubstitution: + processor = NonContextualGlyphSubstitutionProcessor2::createInstance(this); + break; + + + case mstContextualGlyphInsertion: + processor = new ContextualGlyphInsertionProcessor2(this); + break; + + default: + break; + } + + if (processor != NULL) { + processor->process(glyphStorage); + delete processor; + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/NonContextualGlyphSubst.h b/icu4c/source/layout/NonContextualGlyphSubst.h index ef2543a1a8..2a8285079b 100644 --- a/icu4c/source/layout/NonContextualGlyphSubst.h +++ b/icu4c/source/layout/NonContextualGlyphSubst.h @@ -1,7 +1,5 @@ /* - * %W% %E% - * - * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -25,6 +23,11 @@ struct NonContextualGlyphSubstitutionHeader : MorphSubtableHeader LookupTable table; }; +struct NonContextualGlyphSubstitutionHeader2 : MorphSubtableHeader2 +{ + LookupTable table; +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/NonContextualGlyphSubstProc2.cpp b/icu4c/source/layout/NonContextualGlyphSubstProc2.cpp new file mode 100644 index 0000000000..44aca0e60c --- /dev/null +++ b/icu4c/source/layout/NonContextualGlyphSubstProc2.cpp @@ -0,0 +1,60 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "SegmentSingleProcessor2.h" +#include "SegmentArrayProcessor2.h" +#include "SingleTableProcessor2.h" +#include "TrimmedArrayProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2() +{ +} + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : SubtableProcessor2(morphSubtableHeader) +{ +} + +NonContextualGlyphSubstitutionProcessor2::~NonContextualGlyphSubstitutionProcessor2() +{ +} + +SubtableProcessor2 *NonContextualGlyphSubstitutionProcessor2::createInstance(const MorphSubtableHeader2 *morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + switch (SWAPW(header->table.format)) + { + case ltfSimpleArray: + return new SimpleArrayProcessor2(morphSubtableHeader); + + case ltfSegmentSingle: + return new SegmentSingleProcessor2(morphSubtableHeader); + + case ltfSegmentArray: + return new SegmentArrayProcessor2(morphSubtableHeader); + + case ltfSingleTable: + return new SingleTableProcessor2(morphSubtableHeader); + + case ltfTrimmedArray: + return new TrimmedArrayProcessor2(morphSubtableHeader); + + default: + return NULL; + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/NonContextualGlyphSubstProc2.h b/icu4c/source/layout/NonContextualGlyphSubstProc2.h new file mode 100644 index 0000000000..8c102b0db1 --- /dev/null +++ b/icu4c/source/layout/NonContextualGlyphSubstProc2.h @@ -0,0 +1,43 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class NonContextualGlyphSubstitutionProcessor2 : public SubtableProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage) = 0; + + static SubtableProcessor2 *createInstance(const MorphSubtableHeader2 *morphSubtableHeader); + +protected: + NonContextualGlyphSubstitutionProcessor2(); + NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~NonContextualGlyphSubstitutionProcessor2(); + +private: + NonContextualGlyphSubstitutionProcessor2(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class + NonContextualGlyphSubstitutionProcessor2 &operator=(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/OpenTypeLayoutEngine.cpp b/icu4c/source/layout/OpenTypeLayoutEngine.cpp index 9b0c94a2a5..c89c05c050 100644 --- a/icu4c/source/layout/OpenTypeLayoutEngine.cpp +++ b/icu4c/source/layout/OpenTypeLayoutEngine.cpp @@ -1,7 +1,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2012 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -39,11 +39,27 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define loclFeatureTag LE_LOCL_FEATURE_TAG #define caltFeatureTag LE_CALT_FEATURE_TAG -// 'dlig' not used at the moment -#define dligFeatureTag 0x646C6967 +#define dligFeatureTag LE_DLIG_FEATURE_TAG +#define rligFeatureTag LE_RLIG_FEATURE_TAG +#define paltFeatureTag LE_PALT_FEATURE_TAG -// 'palt' -#define paltFeatureTag 0x70616C74 +#define hligFeatureTag LE_HLIG_FEATURE_TAG +#define smcpFeatureTag LE_SMCP_FEATURE_TAG +#define fracFeatureTag LE_FRAC_FEATURE_TAG +#define afrcFeatureTag LE_AFRC_FEATURE_TAG +#define zeroFeatureTag LE_ZERO_FEATURE_TAG +#define swshFeatureTag LE_SWSH_FEATURE_TAG +#define cswhFeatureTag LE_CSWH_FEATURE_TAG +#define saltFeatureTag LE_SALT_FEATURE_TAG +#define naltFeatureTag LE_NALT_FEATURE_TAG +#define rubyFeatureTag LE_RUBY_FEATURE_TAG +#define ss01FeatureTag LE_SS01_FEATURE_TAG +#define ss02FeatureTag LE_SS02_FEATURE_TAG +#define ss03FeatureTag LE_SS03_FEATURE_TAG +#define ss04FeatureTag LE_SS04_FEATURE_TAG +#define ss05FeatureTag LE_SS05_FEATURE_TAG +#define ss06FeatureTag LE_SS06_FEATURE_TAG +#define ss07FeatureTag LE_SS07_FEATURE_TAG #define ccmpFeatureMask 0x80000000UL #define ligaFeatureMask 0x40000000UL @@ -55,10 +71,27 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define loclFeatureMask 0x01000000UL #define caltFeatureMask 0x00800000UL +#define dligFeatureMask 0x00400000UL +#define rligFeatureMask 0x00200000UL +#define hligFeatureMask 0x00100000UL +#define smcpFeatureMask 0x00080000UL +#define fracFeatureMask 0x00040000UL +#define afrcFeatureMask 0x00020000UL +#define zeroFeatureMask 0x00010000UL +#define swshFeatureMask 0x00008000UL +#define cswhFeatureMask 0x00004000UL +#define saltFeatureMask 0x00002000UL +#define naltFeatureMask 0x00001000UL +#define rubyFeatureMask 0x00000800UL +#define ss01FeatureMask 0x00000400UL +#define ss02FeatureMask 0x00000200UL +#define ss03FeatureMask 0x00000100UL +#define ss04FeatureMask 0x00000080UL +#define ss05FeatureMask 0x00000040UL +#define ss06FeatureMask 0x00000020UL +#define ss07FeatureMask 0x00000010UL + #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask) -#define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures) -#define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures) -#define kernAndLigaFeatures (ligaFeatures | kernFeatures) static const FeatureMap featureMap[] = { @@ -70,7 +103,24 @@ static const FeatureMap featureMap[] = {markFeatureTag, markFeatureMask}, {mkmkFeatureTag, mkmkFeatureMask}, {loclFeatureTag, loclFeatureMask}, - {caltFeatureTag, caltFeatureMask} + {caltFeatureTag, caltFeatureMask}, + {hligFeatureTag, hligFeatureMask}, + {smcpFeatureTag, smcpFeatureMask}, + {fracFeatureTag, fracFeatureMask}, + {afrcFeatureTag, afrcFeatureMask}, + {zeroFeatureTag, zeroFeatureMask}, + {swshFeatureTag, swshFeatureMask}, + {cswhFeatureTag, cswhFeatureMask}, + {saltFeatureTag, saltFeatureMask}, + {naltFeatureTag, naltFeatureMask}, + {rubyFeatureTag, rubyFeatureMask}, + {ss01FeatureTag, ss01FeatureMask}, + {ss02FeatureTag, ss02FeatureMask}, + {ss03FeatureTag, ss03FeatureMask}, + {ss04FeatureTag, ss04FeatureMask}, + {ss05FeatureTag, ss05FeatureMask}, + {ss06FeatureTag, ss06FeatureMask}, + {ss07FeatureTag, ss07FeatureMask} }; static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); @@ -85,17 +135,65 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); - // todo: switch to more flags and bitfield rather than list of feature tags? - switch (typoFlags & ~0x80000000L) { - case 0: break; // default - case 1: fFeatureMask = kernFeatures; break; - case 2: fFeatureMask = ligaFeatures; break; - case 3: fFeatureMask = kernAndLigaFeatures; break; - default: break; + switch (typoFlags & (LE_SS01_FEATURE_FLAG + | LE_SS02_FEATURE_FLAG + | LE_SS03_FEATURE_FLAG + | LE_SS04_FEATURE_FLAG + | LE_SS05_FEATURE_FLAG + | LE_SS06_FEATURE_FLAG + | LE_SS07_FEATURE_FLAG)) { + case LE_SS01_FEATURE_FLAG: + fFeatureMask |= ss01FeatureMask; + break; + case LE_SS02_FEATURE_FLAG: + fFeatureMask |= ss02FeatureMask; + break; + case LE_SS03_FEATURE_FLAG: + fFeatureMask |= ss03FeatureMask; + break; + case LE_SS04_FEATURE_FLAG: + fFeatureMask |= ss04FeatureMask; + break; + case LE_SS05_FEATURE_FLAG: + fFeatureMask |= ss05FeatureMask; + break; + case LE_SS06_FEATURE_FLAG: + fFeatureMask |= ss06FeatureMask; + break; + case LE_SS07_FEATURE_FLAG: + fFeatureMask |= ss07FeatureMask; + break; } - if (typoFlags & 0x80000000L) { - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + if (typoFlags & LE_Kerning_FEATURE_FLAG) { + fFeatureMask |= (kernFeatureMask | paltFeatureMask); + // Convenience. + } + if (typoFlags & LE_Ligatures_FEATURE_FLAG) { + fFeatureMask |= (ligaFeatureMask | cligFeatureMask); + // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ? + } + if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask; + if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask; + if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask; + if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask; + if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask; + if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask; + if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask; + if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask; + if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask; + if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask; + if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask; + if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask; + if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask; + if (typoFlags & LE_NALT_FEATURE_FLAG) { + // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm + fFeatureMask = naltFeatureMask; + } + + if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { + // This isn't a font feature, but requests a Char Substitution Filter + fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); } setScriptAndLanguageTags(); diff --git a/icu4c/source/layout/SegmentArrayProcessor2.cpp b/icu4c/source/layout/SegmentArrayProcessor2.cpp new file mode 100644 index 0000000000..04bfe9b4ca --- /dev/null +++ b/icu4c/source/layout/SegmentArrayProcessor2.cpp @@ -0,0 +1,60 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentArrayProcessor2) + +SegmentArrayProcessor2::SegmentArrayProcessor2() +{ +} + +SegmentArrayProcessor2::SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table; +} + +SegmentArrayProcessor2::~SegmentArrayProcessor2() +{ +} + +void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSegment *segments = segmentArrayLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); + + if (lookupSegment != NULL) { + TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); + le_int16 offset = SWAPW(lookupSegment->value); + + if (offset != 0) { + TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); + TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/SegmentArrayProcessor2.h b/icu4c/source/layout/SegmentArrayProcessor2.h new file mode 100644 index 0000000000..6f34fa41df --- /dev/null +++ b/icu4c/source/layout/SegmentArrayProcessor2.h @@ -0,0 +1,58 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTARRAYPROCESSOR_H +#define __SEGMENTARRAYPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SegmentArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentArrayProcessor2(); + +protected: + const SegmentArrayLookupTable *segmentArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/layout/SegmentSingleProcessor2.cpp b/icu4c/source/layout/SegmentSingleProcessor2.cpp new file mode 100644 index 0000000000..1484c6b53c --- /dev/null +++ b/icu4c/source/layout/SegmentSingleProcessor2.cpp @@ -0,0 +1,54 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentSingleProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentSingleProcessor2) + +SegmentSingleProcessor2::SegmentSingleProcessor2() +{ +} + +SegmentSingleProcessor2::SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table; +} + +SegmentSingleProcessor2::~SegmentSingleProcessor2() +{ +} + +void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSegment *segments = segmentSingleLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); + + if (lookupSegment != NULL) { + TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/SegmentSingleProcessor2.h b/icu4c/source/layout/SegmentSingleProcessor2.h new file mode 100644 index 0000000000..cbced182b9 --- /dev/null +++ b/icu4c/source/layout/SegmentSingleProcessor2.h @@ -0,0 +1,58 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTSINGLEPROCESSOR_H +#define __SEGMENTSINGLEPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentSingleProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SegmentSingleProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentSingleProcessor2(); + +protected: + const SegmentSingleLookupTable *segmentSingleLookupTable; + +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/layout/SimpleArrayProcessor2.cpp b/icu4c/source/layout/SimpleArrayProcessor2.cpp new file mode 100644 index 0000000000..c136ed6d79 --- /dev/null +++ b/icu4c/source/layout/SimpleArrayProcessor2.cpp @@ -0,0 +1,51 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleArrayProcessor2) + +SimpleArrayProcessor2::SimpleArrayProcessor2() +{ +} + +SimpleArrayProcessor2::SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table; +} + +SimpleArrayProcessor2::~SimpleArrayProcessor2() +{ +} + +void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { + TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/SimpleArrayProcessor2.h b/icu4c/source/layout/SimpleArrayProcessor2.h new file mode 100644 index 0000000000..05780971c6 --- /dev/null +++ b/icu4c/source/layout/SimpleArrayProcessor2.h @@ -0,0 +1,58 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SIMPLEARRAYPROCESSOR2_H +#define __SIMPLEARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SimpleArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SimpleArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SimpleArrayProcessor2(); + +protected: + const SimpleArrayLookupTable *simpleArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/layout/SingleTableProcessor2.cpp b/icu4c/source/layout/SingleTableProcessor2.cpp new file mode 100644 index 0000000000..81e4b6c752 --- /dev/null +++ b/icu4c/source/layout/SingleTableProcessor2.cpp @@ -0,0 +1,51 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SingleTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SingleTableProcessor2) + +SingleTableProcessor2::SingleTableProcessor2() +{ +} + +SingleTableProcessor2::SingleTableProcessor2(const MorphSubtableHeader2 *moprhSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(moprhSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) moprhSubtableHeader; + + singleTableLookupTable = (const SingleTableLookupTable *) &header->table; +} + +SingleTableProcessor2::~SingleTableProcessor2() +{ +} + +void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSingle *entries = singleTableLookupTable->entries; + le_int32 glyph; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); + + if (lookupSingle != NULL) { + glyphStorage[glyph] = SWAPW(lookupSingle->value); + } + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/SingleTableProcessor2.h b/icu4c/source/layout/SingleTableProcessor2.h new file mode 100644 index 0000000000..11b1db9315 --- /dev/null +++ b/icu4c/source/layout/SingleTableProcessor2.h @@ -0,0 +1,57 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SINGLETABLEPROCESSOR2_H +#define __SINGLETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SingleTableProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SingleTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SingleTableProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SingleTableProcessor2(); + +protected: + const SingleTableLookupTable *singleTableLookupTable; + +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/StateTableProcessor2.cpp b/icu4c/source/layout/StateTableProcessor2.cpp new file mode 100644 index 0000000000..8ce3052cc0 --- /dev/null +++ b/icu4c/source/layout/StateTableProcessor2.cpp @@ -0,0 +1,167 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" +#include "LookupTables.h" +#include + +U_NAMESPACE_BEGIN + +StateTableProcessor2::StateTableProcessor2() +{ +} + +StateTableProcessor2::StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : SubtableProcessor2(morphSubtableHeader) +{ + stateTableHeader = (const MorphStateTableHeader2 *) morphSubtableHeader; + nClasses = SWAPL(stateTableHeader->stHeader.nClasses); + classTableOffset = SWAPL(stateTableHeader->stHeader.classTableOffset); + stateArrayOffset = SWAPL(stateTableHeader->stHeader.stateArrayOffset); + entryTableOffset = SWAPL(stateTableHeader->stHeader.entryTableOffset); + + classTable = (LookupTable *) ((char *) &stateTableHeader->stHeader + classTableOffset); + format = SWAPW(classTable->format); + + stateArray = (const EntryTableIndex2 *) ((char *) &stateTableHeader->stHeader + stateArrayOffset); +} + +StateTableProcessor2::~StateTableProcessor2() +{ +} + +void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) +{ + // Start at state 0 + // XXX: How do we know when to start at state 1? + le_uint16 currentState = 0; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + le_int32 currGlyph = 0; + if ((coverage & scfReverse2) != 0) { // process glyphs in descending order + currGlyph = glyphCount - 1; + dir = -1; + } else { + dir = 1; + } + + beginStateTable(); + switch (format) { + case ltfSimpleArray: { + printf("Lookup Table Format0 untested!\n"); + SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + classCode = SWAPW(lookupTable0->valueArray[gid]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset + } + break; + } + case ltfSegmentSingle: { + SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); + if (segment != NULL) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + case ltfSegmentArray: { + printf("Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: { + SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + if (segment != NULL) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + case ltfTrimmedArray: { + TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) classTable; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]); + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + default: + break; + } + + endStateTable(); +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/StateTableProcessor2.h b/icu4c/source/layout/StateTableProcessor2.h new file mode 100644 index 0000000000..69c5d7a3c7 --- /dev/null +++ b/icu4c/source/layout/StateTableProcessor2.h @@ -0,0 +1,59 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __STATETABLEPROCESSOR2_H +#define __STATETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "LookupTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class StateTableProcessor2 : public SubtableProcessor2 +{ +public: + void process(LEGlyphStorage &glyphStorage); + + virtual void beginStateTable() = 0; + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) = 0; + + virtual void endStateTable() = 0; + +protected: + StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~StateTableProcessor2(); + + StateTableProcessor2(); + + le_int32 dir; + le_uint16 format; + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; + + const LookupTable *classTable; + const EntryTableIndex2 *stateArray; + const MorphStateTableHeader2 *stateTableHeader; + +private: + StateTableProcessor2(const StateTableProcessor2 &other); // forbid copying of this class + StateTableProcessor2 &operator=(const StateTableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif diff --git a/icu4c/source/layout/StateTables.h b/icu4c/source/layout/StateTables.h index 8b5f867770..325ce92dbd 100644 --- a/icu4c/source/layout/StateTables.h +++ b/icu4c/source/layout/StateTables.h @@ -1,6 +1,6 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -25,6 +25,14 @@ struct StateTableHeader ByteOffset entryTableOffset; }; +struct StateTableHeader2 +{ + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; +}; + enum ClassCodes { classCodeEOT = 0, @@ -60,6 +68,14 @@ struct StateEntry le_int16 flags; }; +typedef le_uint16 EntryTableIndex2; + +struct StateEntry2 // same struct different interpretation +{ + le_uint16 newStateIndex; + le_uint16 flags; +}; + U_NAMESPACE_END #endif diff --git a/icu4c/source/layout/SubtableProcessor2.cpp b/icu4c/source/layout/SubtableProcessor2.cpp new file mode 100644 index 0000000000..2c0e97b8dd --- /dev/null +++ b/icu4c/source/layout/SubtableProcessor2.cpp @@ -0,0 +1,31 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +SubtableProcessor2::SubtableProcessor2() +{ +} + +SubtableProcessor2::SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) +{ + subtableHeader = morphSubtableHeader; + + length = SWAPL(subtableHeader->length); + coverage = SWAPL(subtableHeader->coverage); + subtableFeatures = SWAPL(subtableHeader->subtableFeatures); +} + +SubtableProcessor2::~SubtableProcessor2() +{ +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/SubtableProcessor2.h b/icu4c/source/layout/SubtableProcessor2.h new file mode 100644 index 0000000000..637e845ed3 --- /dev/null +++ b/icu4c/source/layout/SubtableProcessor2.h @@ -0,0 +1,46 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SUBTABLEPROCESSOR2_H +#define __SUBTABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SubtableProcessor2 : public UMemory { +public: + virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual ~SubtableProcessor2(); + +protected: + SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + SubtableProcessor2(); + + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + const MorphSubtableHeader2 *subtableHeader; + +private: + + SubtableProcessor2(const SubtableProcessor2 &other); // forbid copying of this class + SubtableProcessor2 &operator=(const SubtableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/layout/TrimmedArrayProcessor2.cpp b/icu4c/source/layout/TrimmedArrayProcessor2.cpp new file mode 100644 index 0000000000..c9a9b53de4 --- /dev/null +++ b/icu4c/source/layout/TrimmedArrayProcessor2.cpp @@ -0,0 +1,55 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "TrimmedArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TrimmedArrayProcessor2) + +TrimmedArrayProcessor2::TrimmedArrayProcessor2() +{ +} + +TrimmedArrayProcessor2::TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table; + firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); + lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); +} + +TrimmedArrayProcessor2::~TrimmedArrayProcessor2() +{ +} + +void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); + + if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { + TTGlyphID newGlyph = SWAPW(trimmedArrayLookupTable->valueArray[ttGlyph - firstGlyph]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/icu4c/source/layout/TrimmedArrayProcessor2.h b/icu4c/source/layout/TrimmedArrayProcessor2.h new file mode 100644 index 0000000000..1577931b9c --- /dev/null +++ b/icu4c/source/layout/TrimmedArrayProcessor2.h @@ -0,0 +1,60 @@ +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __TRIMMEDARRAYPROCESSOR2_H +#define __TRIMMEDARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class TrimmedArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~TrimmedArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + TrimmedArrayProcessor2(); + +protected: + TTGlyphID firstGlyph; + TTGlyphID lastGlyph; + const TrimmedArrayLookupTable *trimmedArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif + diff --git a/icu4c/source/test/letest/letest.cpp b/icu4c/source/test/letest/letest.cpp index 83df47c3e9..8e4523a8d2 100644 --- a/icu4c/source/test/letest/letest.cpp +++ b/icu4c/source/test/letest/letest.cpp @@ -1,7 +1,7 @@ /* ******************************************************************************* * - * Copyright (C) 1999-2008, International Business Machines + * Copyright (C) 1999-2013, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -413,7 +413,7 @@ static void checkFontVersion(PortableFontInstance *fontInstance, const char *tes const char *getSourceTestData() { const char *srcDataDir = NULL; #ifdef U_TOPSRCDIR - srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; + srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; #else srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r"); @@ -991,7 +991,7 @@ static const char *ctest_dataOutDir() */ #if defined (U_TOPBUILDDIR) { - dataOutDir = U_TOPBUILDDIR "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING; + dataOutDir = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; } #else