# HG changeset patch # User andrew # Date 1365737071 -3600 # Node ID c7ddbf756d7f35d6e782eb91b86ce2938de44fb8 # Parent a5bbb8808ac9a6a8e20c5f267044bb0cef0bbdc1 8004986: Better handling of glyph table 8004987: Improve font layout 8004994: Improve checking of glyph table Reviewed-by: bae, mschoene, jgodinez Contributed-by: steven.loomis@oracle.com diff --git a/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp b/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp --- jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp +++ jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -155,17 +155,16 @@ UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine( const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags) - : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags) + : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG) { fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + /* OpenTypeLayoutEngine will allocate a substitution filter */ } UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() { - delete fSubstitutionFilter; + /* OpenTypeLayoutEngine will cleanup the substitution filter */ } // "glyphs", "indices" -> glyphs, indices diff --git a/src/share/native/sun/font/layout/LETypes.h b/src/share/native/sun/font/layout/LETypes.h --- jdk/src/share/native/sun/font/layout/LETypes.h +++ jdk/src/share/native/sun/font/layout/LETypes.h @@ -208,6 +208,35 @@ #define LE_CLIENT_SHIFT 24 +#ifndef LE_ASSERT_BAD_FONT +#define LE_ASSERT_BAD_FONT 0 +#endif + +#if LE_ASSERT_BAD_FONT +#include +#define LE_DEBUG_BAD_FONT(x) fprintf(stderr,"%s:%d: BAD FONT: %s\n", __FILE__, __LINE__, (x)); +#else +#define LE_DEBUG_BAD_FONT(x) +#endif + +/** + * Max value representable by a uintptr + */ +#ifndef UINTPTR_MAX +#ifndef UINT32_MAX +#define LE_UINTPTR_MAX 0xFFFFFFFFU +#else +#define LE_UINTPTR_MAX UINT32_MAX +#endif +#else +#define LE_UINTPTR_MAX UINTPTR_MAX +#endif + +/** + * Range check for overflow + */ +#define LE_RANGE_CHECK(type, count, ptrfn) (( (LE_UINTPTR_MAX / sizeof(type)) < count ) ? NULL : (ptrfn)) + /** * A convenience macro to get the Glyph ID part of an LEGlyphID. * @@ -599,6 +628,21 @@ */ #define LE_SUCCESS(code) ((code)<=LE_NO_ERROR) +enum LEFeatureENUMs { + LE_Kerning_FEATURE_ENUM = 0, + LE_Ligatures_FEATURE_ENUM = 1, + LE_CHAR_FILTER_FEATURE_ENUM = 31, +}; + +#define LE_Kerning_FEATURE_FLAG (1 << LE_Kerning_FEATURE_ENUM) +#define LE_Ligatures_FEATURE_FLAG (1 << LE_Ligatures_FEATURE_ENUM) + +#define LE_CHAR_FILTER_FEATURE_ENUM 31 + +#define LE_CHAR_FILTER_FEATURE_FLAG (1 << LE_CHAR_FILTER_FEATURE_ENUM) + +#define LE_DEFAULT_FEATURE_FLAG (LE_Kerning_FEATURE_FLAG | LE_Ligatures_FEATURE_FLAG) /**< default features */ + /** * A convenience macro to test for the failure of a LayoutEngine call. * diff --git a/src/share/native/sun/font/layout/LayoutEngine.cpp b/src/share/native/sun/font/layout/LayoutEngine.cpp --- jdk/src/share/native/sun/font/layout/LayoutEngine.cpp +++ jdk/src/share/native/sun/font/layout/LayoutEngine.cpp @@ -31,6 +31,7 @@ #include "LETypes.h" #include "LEScripts.h" +#include "LESwaps.h" #include "LELanguages.h" #include "LayoutEngine.h" @@ -387,7 +388,7 @@ adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); - if (fTypoFlags & 0x1) { /* kerning enabled */ + if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; KernTable kt(fFontInstance, getFontTable(kernTableTag)); @@ -538,7 +539,7 @@ { // 3 -> kerning and ligatures return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, - languageCode, 3, success); + languageCode, LE_DEFAULT_FEATURE_FLAG, success); } LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, @@ -621,7 +622,7 @@ const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - if (morphTable != NULL) { + if (morphTable != NULL && SWAPL(morphTable->version)==0x00010000) { result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable); } else { switch (scriptCode) { diff --git a/src/share/native/sun/font/layout/LigatureSubstProc.cpp b/src/share/native/sun/font/layout/LigatureSubstProc.cpp --- jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp +++ jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -76,6 +76,10 @@ } componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + currGlyph++; + return newState; } ByteOffset actionOffset = flags & lsfActionOffsetMask; @@ -99,7 +103,21 @@ offset = action & lafComponentOffsetMask; if (offset != 0) { const le_int16 *offsetTable = (const le_int16 *)((char *) &ligatureSubstitutionHeader->stHeader + 2 * SignExtend(offset, lafComponentOffsetMask)); + const le_int16 *tableEnd = (const le_int16 *)((char *) &ligatureSubstitutionHeader + 1 * SWAPW(ligatureSubstitutionHeader->length)); + // Check if the font is internally consistent + if(tableEnd < (const le_int16*)&ligatureSubstitutionHeader // stated end wrapped around? + || offsetTable > tableEnd) { // offset past end of stated length? + currGlyph++; + LE_DEBUG_BAD_FONT("off end of ligature substitution header"); + return newState; // get out! bad font + } + + if(componentGlyph > glyphStorage.getGlyphCount()) { + LE_DEBUG_BAD_FONT("preposterous componentGlyph"); + currGlyph++; + return newState; // get out! bad font + } i += SWAPW(offsetTable[LE_GET_GLYPH(glyphStorage[componentGlyph])]); if (action & (lafLast | lafStore)) { @@ -107,13 +125,22 @@ TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset); glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); + if(mm==nComponents) { + LE_DEBUG_BAD_FONT("exceeded nComponents"); + mm--; // don't overrun the stack. + } stack[++mm] = componentGlyph; i = 0; } else { glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); } } - } while (!(action & lafLast)); +#if LE_ASSERT_BAD_FONT + if(m<0) { + LE_DEBUG_BAD_FONT("m<0") + } +#endif + } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items while (mm >= 0) { if (++m >= nComponents) { diff --git a/src/share/native/sun/font/layout/LookupProcessor.cpp b/src/share/native/sun/font/layout/LookupProcessor.cpp --- jdk/src/share/native/sun/font/layout/LookupProcessor.cpp +++ jdk/src/share/native/sun/font/layout/LookupProcessor.cpp @@ -185,7 +185,7 @@ lookupSelectCount = lookupListCount; le_int32 count, order = 0; - le_int32 featureReferences = 0; + le_uint32 featureReferences = 0; const FeatureTable *featureTable = NULL; LETag featureTag; @@ -196,7 +196,7 @@ // be the maximum number of entries in the lookupOrderArray. We can't use // lookupListCount because some lookups might be referenced by more than // one feature. - for (le_int32 feature = 0; feature < featureCount; feature += 1) { + for (le_uint32 feature = 0; feature < featureCount; feature += 1) { le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); diff --git a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp --- jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp +++ jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp @@ -100,6 +100,14 @@ const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); + applyTypoFlags(); + +} + +void OpenTypeLayoutEngine::applyTypoFlags() { + const le_int32& typoFlags = fTypoFlags; + const LEFontInstance *fontInstance = fFontInstance; + // todo: switch to more flags and bitfield rather than list of feature tags? switch (typoFlags) { case 0: break; // default @@ -109,13 +117,6 @@ default: break; } - setScriptAndLanguageTags(); - - fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); - - if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { - fGPOSTable = gposTable; - } } void OpenTypeLayoutEngine::reset() @@ -133,11 +134,16 @@ fFeatureOrder(FALSE), fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) { + applyTypoFlags(); setScriptAndLanguageTags(); } OpenTypeLayoutEngine::~OpenTypeLayoutEngine() { + if (fTypoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { + delete fSubstitutionFilter; + fSubstitutionFilter = NULL; + } reset(); } diff --git a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h --- jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h +++ jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h @@ -150,6 +150,11 @@ */ static const LETag languageTags[]; + /** + * apply the typoflags. Only called by the c'tors. + */ + void applyTypoFlags(); + protected: /** * A set of "default" features. The default characterProcessing method diff --git a/src/share/native/sun/font/layout/StateTableProcessor.cpp b/src/share/native/sun/font/layout/StateTableProcessor.cpp --- jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp +++ jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp @@ -63,6 +63,9 @@ void StateTableProcessor::process(LEGlyphStorage &glyphStorage) { + + LE_STATE_PATIENCE_INIT(); + // Start at state 0 // XXX: How do we know when to start at state 1? ByteOffset currentState = stateArrayOffset; @@ -74,6 +77,7 @@ beginStateTable(); while (currGlyph <= glyphCount) { + if(LE_STATE_PATIENCE_DECR()) break; // patience exceeded. ClassCode classCode = classCodeOOB; if (currGlyph == glyphCount) { // XXX: How do we handle EOT vs. EOL? @@ -90,8 +94,9 @@ const EntryTableIndex *stateArray = (const EntryTableIndex *) ((char *) &stateTableHeader->stHeader + currentState); EntryTableIndex entryTableIndex = stateArray[(le_uint8)classCode]; - + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + LE_STATE_PATIENCE_INCR(currGlyph); } endStateTable(); diff --git a/src/share/native/sun/font/layout/StateTables.h b/src/share/native/sun/font/layout/StateTables.h --- jdk/src/share/native/sun/font/layout/StateTables.h +++ jdk/src/share/native/sun/font/layout/StateTables.h @@ -35,6 +35,41 @@ #include "LETypes.h" #include "LayoutTables.h" + + + +/* + * State table loop detection. + * Detects if too many ( LE_STATE_PATIENCE_COUNT ) state changes occur without moving the glyph index 'g'. + * + * Usage (pseudocode): + * + * { + * LE_STATE_PATIENCE_INIT(); + * + * int g=0; // the glyph index - expect it to be moving + * + * for(;;) { + * if(LE_STATE_PATIENCE_DECR()) { // decrements the patience counter + * // ran out of patience, get out. + * break; + * } + * + * LE_STATE_PATIENCE_CURR(int, g); // store the 'current' + * state = newState(state,g); + * g+= ; + * LE_STATE_PATIENCE_INCR(g); // if g has moved, increment the patience counter. Otherwise leave it. + * } + * + */ + +#define LE_STATE_PATIENCE_COUNT 4096 /**< give up if a state table doesn't move the glyph after this many iterations */ +#define LE_STATE_PATIENCE_INIT() le_uint32 le_patience_count = LE_STATE_PATIENCE_COUNT +#define LE_STATE_PATIENCE_DECR() --le_patience_count==0 +#define LE_STATE_PATIENCE_CURR(type,x) type le_patience_curr=(x) +#define LE_STATE_PATIENCE_INCR(x) if((x)!=le_patience_curr) ++le_patience_count; + + struct StateTableHeader { le_int16 stateSize;