Mercurial > hg > release > icedtea7-forest-2.2 > jdk
changeset 5272:a180f7cf764f
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
author | andrew |
---|---|
date | Wed, 10 Apr 2013 17:27:39 +0100 |
parents | 8e2af6c43702 |
children | 5f19d54801bf |
files | src/share/native/sun/font/layout/ArabicLayoutEngine.cpp src/share/native/sun/font/layout/LETableReference.h src/share/native/sun/font/layout/LETypes.h src/share/native/sun/font/layout/LayoutEngine.cpp src/share/native/sun/font/layout/LigatureSubstProc.cpp src/share/native/sun/font/layout/LookupProcessor.cpp src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp src/share/native/sun/font/layout/OpenTypeLayoutEngine.h src/share/native/sun/font/layout/StateTableProcessor.cpp src/share/native/sun/font/layout/StateTables.h |
diffstat | 10 files changed, 647 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -152,17 +152,16 @@ } UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) - : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) + : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) { 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/LETableReference.h Wed Apr 10 17:27:39 2013 +0100 @@ -0,0 +1,497 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * -*- c++ -*- + * + * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved + * + * Range checking + * + */ + +#ifndef __LETABLEREFERENCE_H +#define __LETABLEREFERENCE_H + +#include "LETypes.h" +#include "LEFontInstance.h" + + +#define kQuestionmarkTableTag 0x3F3F3F3FUL +#define kTildeTableTag 0x7e7e7e7eUL +#ifdef __cplusplus + +// internal - interface for range checking +U_NAMESPACE_BEGIN + +#if LE_ASSERT_BAD_FONT +class LETableReference; // fwd +/** + * defined in OpenTypeUtilities.cpp + * @internal + */ +U_INTERNAL void U_EXPORT2 _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len); + +#define LE_DEBUG_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0); +#define LE_DEBUG_TR3(x,y,z) _debug_LETableReference(__FILE__, __LINE__, x, this, (const void*)y, (size_t)z); +#if 0 +#define LE_TRACE_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0); +#else +#define LE_TRACE_TR(x) +#endif + +#else +#define LE_DEBUG_TR(x) +#define LE_DEBUG_TR3(x,y,z) +#define LE_TRACE_TR(x) +#endif + +/** + * @internal + */ +class LETableReference { +public: +/** + * @internal + * Construct from a specific tag + */ + LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) : + fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) { + loadTable(success); + LE_TRACE_TR("INFO: new table load") + } + + LETableReference(const LETableReference &parent, LEErrorCode &success) : fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), fStart(parent.fStart), fLength(parent.fLength) { + if(LE_FAILURE(success)) { + clear(); + } + LE_TRACE_TR("INFO: new clone") + } + + LETableReference(const le_uint8* data, size_t length = LE_UINTPTR_MAX) : + fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) { + LE_TRACE_TR("INFO: new raw") + } + LETableReference() : + fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) { + LE_TRACE_TR("INFO: new empty") + } + + ~LETableReference() { + fTag=kTildeTableTag; + LE_TRACE_TR("INFO: new dtor") + } + + /** + * @internal + * @param length if LE_UINTPTR_MAX means "whole table" + * subset + */ + LETableReference(const LETableReference &parent, size_t offset, size_t length, + LEErrorCode &err) : + fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), + fStart((parent.fStart)+offset), fLength(length) { + if(LE_SUCCESS(err)) { + if(isEmpty()) { + //err = LE_MISSING_FONT_TABLE_ERROR; + clear(); // it's just empty. Not an error. + } else if(offset >= fParent->fLength) { + LE_DEBUG_TR3("offset out of range: (%p) +%d", NULL, offset); + err = LE_INDEX_OUT_OF_BOUNDS_ERROR; + clear(); + } else { + if(fLength == LE_UINTPTR_MAX && + fParent->fLength != LE_UINTPTR_MAX) { + fLength = (fParent->fLength) - offset; // decrement length as base address is incremented + } + if(fLength != LE_UINTPTR_MAX) { // if we have bounds: + if(offset+fLength > fParent->fLength) { + LE_DEBUG_TR3("offset+fLength out of range: (%p) +%d", NULL, offset+fLength); + err = LE_INDEX_OUT_OF_BOUNDS_ERROR; // exceeded + clear(); + } + } + } + } else { + clear(); + } + LE_TRACE_TR("INFO: new subset") + } + + const void* getAlias() const { return (const void*)fStart; } + const void* getAliasTODO() const { LE_DEBUG_TR("getAliasTODO()"); return (const void*)fStart; } + le_bool isEmpty() const { return fStart==NULL || fLength==0; } + le_bool isValid() const { return !isEmpty(); } + le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; } + void clear() { fLength=0; fStart=NULL; } + size_t getLength() const { return fLength; } + const LEFontInstance* getFont() const { return fFont; } + LETag getTag() const { return fTag; } + const LETableReference* getParent() const { return fParent; } + + void addOffset(size_t offset, LEErrorCode &success) { + if(hasBounds()) { + if(offset > fLength) { + LE_DEBUG_TR("addOffset off end"); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + return; + } else { + fLength -= offset; + } + } + fStart += offset; + } + + size_t ptrToOffset(const void *atPtr, LEErrorCode &success) const { + if(atPtr==NULL) return 0; + if(LE_FAILURE(success)) return LE_UINTPTR_MAX; + if((atPtr < fStart) || + (hasBounds() && (atPtr > fStart+fLength))) { + LE_DEBUG_TR3("ptrToOffset args out of range: %p", atPtr, 0); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + return LE_UINTPTR_MAX; + } + return ((const le_uint8*)atPtr)-fStart; + } + + /** + * Clamp down the length, for range checking. + */ + size_t contractLength(size_t newLength) { + if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) { + fLength = newLength; + } + return fLength; + } + + /** + * Throw an error if offset+length off end + */ +public: + size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) { + if(isValid()&& + LE_SUCCESS(success) && + fLength!=LE_UINTPTR_MAX && length!=LE_UINTPTR_MAX && offset!=LE_UINTPTR_MAX && + (offset+length)>fLength) { + LE_DEBUG_TR3("verifyLength failed (%p) %d",NULL, offset+length); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; +#if LE_ASSERT_BAD_FONT + fprintf(stderr, "offset=%lu, len=%lu, would be at %p, (%lu) off end. End at %p\n", offset,length, fStart+offset+length, (offset+length-fLength), (offset+length-fLength)+fStart); +#endif + } + return fLength; + } + + le_bool isSubsetOf(const LETableReference& base) const { + if(this == &base) return true; + if(fStart < base.fStart) return false; + if(base.hasBounds()) { + if(fStart >= base.fStart + base.fLength) return false; + if(hasBounds()) { + if(fStart + fLength > base.fStart + base.fLength) return false; + } + } + return true; + } + + /** + * Change parent link to another + */ + LETableReference &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + /** + * remove parent link. Factory functions should do this. + */ + void orphan(void) { + fParent=NULL; + } + +protected: + const LEFontInstance* fFont; + LETag fTag; + const LETableReference *fParent; + const le_uint8 *fStart; // keep as 8 bit internally, for pointer math + size_t fLength; + + void loadTable(LEErrorCode &success) { + if(LE_SUCCESS(success)) { + fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error. + } + } + + void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) { + fFont = NULL; + fTag = kQuestionmarkTableTag; + fParent = NULL; + fStart = (const le_uint8*)data; + fLength = length; + } +}; + + +template<class T> +class LETableVarSizer { + public: + inline static size_t getSize(); +}; + +// base definition- could override for adjustments +template<class T> inline +size_t LETableVarSizer<T>::getSize() { + return sizeof(T); +} + +/** + * \def LE_VAR_ARRAY + * @param x Type (T) + * @param y some member that is of length ANY_NUMBER + * Call this after defining a class, for example: + * LE_VAR_ARRAY(FeatureListTable,featureRecordArray) + * this is roughly equivalent to: + * template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); } + * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size. + * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof. + */ +#define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); } + +/** + * Open a new entry based on an existing table + */ + +/** + * \def LE_UNBOUNDED_ARRAY + * define an array with no *known* bound. Will trim to available size. + * @internal + */ +#define LE_UNBOUNDED_ARRAY LE_UINT32_MAX + +template<class T> +class LEReferenceToArrayOf : public LETableReference { +public: + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count) + : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) { + LE_TRACE_TR("INFO: new RTAO by offset") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) { + fCount=0; + clear(); + } + } + + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count) + : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) { +LE_TRACE_TR("INFO: new RTAO") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) clear(); + } + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count) + : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) { +LE_TRACE_TR("INFO: new RTAO") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) clear(); + } + + LEReferenceToArrayOf() :LETableReference(), fCount(0) {} + + le_uint32 getCount() const { return fCount; } + + using LETableReference::getAlias; + + const T *getAlias(le_uint32 i, LEErrorCode &success) const { + if(LE_SUCCESS(success)&& i<getCount()) { + return ((const T*)getAlias())+i; + } else { + if(LE_SUCCESS(success)) { + LE_DEBUG_TR("getAlias(subscript) out of range"); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + } + return ((const T*)getAlias()); // return first item, so there's no crash + } + } + + const T *getAliasTODO() const { LE_DEBUG_TR("getAliasTODO<>"); return (const T*)fStart; } + + const T& getObject(le_uint32 i, LEErrorCode &success) const { + return *getAlias(i,success); + } + + const T& operator()(le_uint32 i, LEErrorCode &success) const { + return *getAlias(i,success); + } + + size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const { + if(LE_SUCCESS(success)&&i<getCount()) { + return LETableVarSizer<T>::getSize()*i; + } else { + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + } + return 0; + } + + LEReferenceToArrayOf<T> &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) { + LE_TRACE_TR("INFO: null RTAO") + } + + /** + * set this to point within our fParent, but based on 'base' as a subtable. + */ + void setToOffsetInParent(const LETableReference& base, size_t offset, le_uint32 count, LEErrorCode &success) { +LE_TRACE_TR("INFO: sTOIP") + if(LE_FAILURE(success)) return; + if(!fParent->isSubsetOf(base)) { // Ensure that 'base' is containable within our parent. + clear(); // otherwise, it's not a subtable of our parent. + LE_DEBUG_TR("setToOffsetInParents called on non subsets"); + success = LE_ILLEGAL_ARGUMENT_ERROR; return; + } + size_t baseOffset = fParent->ptrToOffset(((const le_uint8*)base.getAlias())+offset, success); + if(LE_FAILURE(success)) return; // base was outside of parent's range + if(fParent->hasBounds()) { + if((baseOffset >= fParent->getLength()) || // start off end of parent + (baseOffset+(count*LETableVarSizer<T>::getSize()) >= fParent->getLength()) || // or off end of parent + count > LE_UINTPTR_MAX/LETableVarSizer<T>::getSize()) { // or more than would fit in memory + LE_DEBUG_TR("setToOffsetInParent called with bad length"); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + clear(); + return; // start would go off end of parent + } + } + fStart = (const le_uint8*)(fParent->getAlias()) + baseOffset; + //fLength = count*LETableVarSizer<T>::getSize(); - no- do not shrink fLength. + if(fParent->hasBounds()) { + fLength = (fParent->getLength() - (fStart-(const le_uint8*)fParent->getAlias())); // reduces fLength accordingly. + } else { + fLength = LE_UINTPTR_MAX; // unbounded + } + if((fStart < fParent->getAlias()) || + (hasBounds()&&(fStart+fLength < fStart))) { // wrapped + LE_DEBUG_TR("setToOffsetInParent called with bad length"); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + clear(); + return; // start would go off end of parent + } + fCount = count; + } + +private: + le_uint32 fCount; +}; + + +template<class T> +class LEReferenceTo : public LETableReference { +public: + /** + * open a sub reference. + * @param parent parent reference + * @param success error status + * @param atPtr location of reference - if NULL, will be at offset zero (i.e. downcast of parent). Otherwise must be a pointer within parent's bounds. + */ + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr) + : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) { + verifyLength(parent.ptrToOffset(atPtr,success), LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + /** + * ptr plus offset + */ + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset) + : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset) + : LETableReference(parent, offset, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LETableReference &parent, LEErrorCode &success) + : LETableReference(parent, 0, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success) + : LETableReference(font, tableTag, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {} + LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {} + LEReferenceTo() : LETableReference(NULL) {} + + LEReferenceTo<T>& operator=(const T* other) { + setRaw(other); + return *this; + } + + LEReferenceTo<T> &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + /** + * roll forward by one <T> size. + * same as addOffset(LETableVarSizer<T>::getSize(),success) + */ + void addObject(LEErrorCode &success) { + addOffset(LETableVarSizer<T>::getSize(), success); + } + void addObject(size_t count, LEErrorCode &success) { + addOffset(LETableVarSizer<T>::getSize()*count, success); + } + + const T *operator->() const { return getAlias(); } + const T *getAlias() const { return (const T*)fStart; } + const T *getAliasTODO() const { LE_DEBUG_TR("getAliasTODO<>"); return (const T*)fStart; } +}; + + +U_NAMESPACE_END + +#endif + +#endif
--- a/src/share/native/sun/font/layout/LETypes.h Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/LETypes.h Wed Apr 10 17:27:39 2013 +0100 @@ -334,6 +334,34 @@ typedef struct LEPoint LEPoint; #endif +#ifndef LE_ASSERT_BAD_FONT +#define LE_ASSERT_BAD_FONT 0 +#endif + +#if LE_ASSERT_BAD_FONT +#include <stdio.h> +#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 length of an array. @@ -356,7 +384,7 @@ * * @internal */ -#define LE_NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type)) +#define LE_NEW_ARRAY(type, count) (type *) LE_RANGE_CHECK(type,count,uprv_malloc((count) * sizeof(type))) /** * Re-allocate an array of basic types. This is used to isolate the rest of @@ -587,6 +615,18 @@ LE_ZERO_FEATURE_TAG = 0x7A65726FUL /**< 'zero' */ }; +enum LEFeatureENUMs { + LE_Kerning_FEATURE_ENUM = 0, + LE_Ligatures_FEATURE_ENUM = 1, + LE_CHAR_FILTER_FEATURE_ENUM = 31, + 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_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 */ + /** * Error codes returned by the LayoutEngine. *
--- a/src/share/native/sun/font/layout/LayoutEngine.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/LayoutEngine.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -33,6 +33,7 @@ #include "LETypes.h" #include "LEScripts.h" #include "LELanguages.h" +#include "LESwaps.h" #include "LayoutEngine.h" #include "ArabicLayoutEngine.h" @@ -421,7 +422,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)); @@ -564,8 +565,8 @@ 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); + //kerning and ligatures - by default + return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); } LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) @@ -648,7 +649,7 @@ } else { const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - if (morphTable != NULL) { + if (morphTable != NULL && SWAPL(morphTable->version)==0x00010000) { // mort result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success); } else { switch (scriptCode) {
--- a/src/share/native/sun/font/layout/LigatureSubstProc.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/LigatureSubstProc.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -79,6 +79,10 @@ } componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + currGlyph++; + return newState; } ByteOffset actionOffset = flags & lsfActionOffsetMask; @@ -102,7 +106,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)) { @@ -110,13 +128,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) {
--- a/src/share/native/sun/font/layout/LookupProcessor.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/LookupProcessor.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -205,7 +205,7 @@ lookupSelectCount = lookupListCount; le_int32 count, order = 0; - le_int32 featureReferences = 0; + le_uint32 featureReferences = 0; const FeatureTable *featureTable = NULL; LETag featureTag; @@ -216,7 +216,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);
--- a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -90,7 +90,7 @@ {ccmpFeatureTag, ccmpFeatureMask}, {ligaFeatureTag, ligaFeatureMask}, {cligFeatureTag, cligFeatureMask}, - {kernFeatureTag, kernFeatureMask}, + {kernFeatureTag, kernFeatureMask}, {paltFeatureTag, paltFeatureMask}, {markFeatureTag, markFeatureMask}, {mkmkFeatureTag, mkmkFeatureMask}, @@ -110,6 +110,23 @@ static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); + applyTypoFlags(); + + setScriptAndLanguageTags(); + + fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); + +// JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font +// if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { + if (gposTable != NULL && gposTable->coversScript(fScriptTag)) { + fGPOSTable = gposTable; + } +} + +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 & ~0x80000000L) { case 0: break; // default @@ -123,15 +140,6 @@ fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); } - setScriptAndLanguageTags(); - - fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); - -// JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font -// if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { - if (gposTable != NULL && gposTable->coversScript(fScriptTag)) { - fGPOSTable = gposTable; - } } void OpenTypeLayoutEngine::reset() @@ -148,13 +156,15 @@ : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE), fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) { - setScriptAndLanguageTags(); + applyTypoFlags(); + setScriptAndLanguageTags(); } OpenTypeLayoutEngine::~OpenTypeLayoutEngine() { - if (fTypoFlags & 0x80000000L) { + if (fTypoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { delete fSubstitutionFilter; + fSubstitutionFilter = NULL; } reset();
--- a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h Wed Apr 10 17:27:39 2013 +0100 @@ -24,7 +24,7 @@ */ /* - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -184,6 +184,11 @@ */ static const LETag scriptTags[]; + /** + * apply the typoflags. Only called by the c'tors. + */ + void applyTypoFlags(); + protected: /** * A set of "default" features. The default characterProcessing method
--- a/src/share/native/sun/font/layout/StateTableProcessor.cpp Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/StateTableProcessor.cpp Wed Apr 10 17:27:39 2013 +0100 @@ -65,6 +65,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; @@ -76,6 +79,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? @@ -92,8 +96,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();
--- a/src/share/native/sun/font/layout/StateTables.h Wed Feb 13 10:47:15 2013 +0000 +++ b/src/share/native/sun/font/layout/StateTables.h Wed Apr 10 17:27:39 2013 +0100 @@ -42,6 +42,41 @@ U_NAMESPACE_BEGIN + + + +/* + * 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+= <something, could be zero>; + * 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;