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;