# HG changeset patch
# User srl
# Date 1362581054 28800
# Node ID c2fff439d91a73076268c1b7a997722fa1caef21
# Parent  98ad2f1e25d13aca196ad77b2f227f85072c9b16
8009530: ICU Kern table support broken
Reviewed-by: prr, vadim

diff --git a/src/share/native/sun/font/layout/KernTable.cpp b/src/share/native/sun/font/layout/KernTable.cpp
--- openjdk/jdk/src/share/native/sun/font/layout/KernTable.cpp
+++ openjdk/jdk/src/share/native/sun/font/layout/KernTable.cpp
@@ -48,7 +48,7 @@
   le_int16  value; // fword, kern value in funits
 };
 #define KERN_PAIRINFO_SIZE 6
-
+LE_CORRECT_SIZE(PairInfo, KERN_PAIRINFO_SIZE)
 struct Subtable_0 {
   le_uint16 nPairs;
   le_uint16 searchRange;
@@ -56,6 +56,7 @@
   le_uint16 rangeShift;
 };
 #define KERN_SUBTABLE_0_HEADER_SIZE 8
+LE_CORRECT_SIZE(Subtable_0, KERN_SUBTABLE_0_HEADER_SIZE)
 
 // Kern table version 0 only
 struct SubtableHeader {
@@ -64,6 +65,7 @@
   le_uint16 coverage;
 };
 #define KERN_SUBTABLE_HEADER_SIZE 6
+LE_CORRECT_SIZE(SubtableHeader, KERN_SUBTABLE_HEADER_SIZE)
 
 // Version 0 only, version 1 has different layout
 struct KernTableHeader {
@@ -71,6 +73,7 @@
   le_uint16 nTables;
 };
 #define KERN_TABLE_HEADER_SIZE 4
+LE_CORRECT_SIZE(KernTableHeader, KERN_TABLE_HEADER_SIZE)
 
 #define COVERAGE_HORIZONTAL 0x1
 #define COVERAGE_MINIMUM 0x2
@@ -92,8 +95,8 @@
  * TODO: support multiple subtables
  * TODO: respect header flags
  */
-KernTable::KernTable(const LETableReference &table, LEErrorCode &success)
-  : pairs(table, success), pairsSwapped(NULL), fTable(table)
+KernTable::KernTable(const LETableReference& base, LEErrorCode &success)
+  : pairs(), pairsSwapped(NULL), fTable(base)
 {
   if(LE_FAILURE(success) || (fTable.isEmpty())) {
 #if DEBUG
@@ -106,7 +109,7 @@
 #if DEBUG
   // dump first 32 bytes of header
   for (int i = 0; i < 64; ++i) {
-    fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff);
+    fprintf(stderr, "%0.2x ", ((const char*)header.getAlias())[i]&0xff);
     if (((i+1)&0xf) == 0) {
       fprintf(stderr, "\n");
     } else if (((i+1)&0x7) == 0) {
@@ -140,7 +143,14 @@
 #endif
 
         if(LE_SUCCESS(success) && nPairs>0) {
-          pairs.setToOffsetInParent(table, KERN_SUBTABLE_0_HEADER_SIZE, nPairs, success);
+          // pairs is an instance member, and table is on the stack.
+          // set 'pairs' based on table.getAlias(). This will range check it.
+
+          pairs = LEReferenceToArrayOf<PairInfo>(fTable, // based on overall table
+                                                 success,
+                                                 (const PairInfo*)table.getAlias(),  // subtable 0 + ..
+                                                 KERN_SUBTABLE_0_HEADER_SIZE,  // .. offset of header size
+                                                 nPairs); // count
         }
         if (LE_SUCCESS(success) && pairs.isValid()) {
             pairsSwapped =  (PairInfo*)(malloc(nPairs*sizeof(PairInfo)));
@@ -152,6 +162,11 @@
             fTable.getFont()->setKernPairs((void*)pairsSwapped); // store it
         }
 
+#if 0
+        fprintf(stderr, "coverage: %0.4x nPairs: %d pairs %p\n", coverage, nPairs, pairs.getAlias());
+        fprintf(stderr, "  searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift);
+        fprintf(stderr, "[[ ignored font table entries: range %d selector %d shift %d ]]\n", SWAPW(table->searchRange), SWAPW(table->entrySelector), SWAPW(table->rangeShift));
+#endif
 #if DEBUG
         fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs);
         fprintf(stderr,
@@ -208,7 +223,8 @@
 
     le_uint32 key = storage[0]; // no need to mask off high bits
     float adjust = 0;
-    for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) {
+
+    for (int i = 1, e = storage.getGlyphCount(); LE_SUCCESS(success)&&  i < e; ++i) {
       key = key << 16 | (storage[i] & 0xffff);
 
       // argh, to do a binary search, we need to have the pair list in sorted order
diff --git a/src/share/native/sun/font/layout/LETableReference.h b/src/share/native/sun/font/layout/LETableReference.h
--- openjdk/jdk/src/share/native/sun/font/layout/LETableReference.h
+++ openjdk/jdk/src/share/native/sun/font/layout/LETableReference.h
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,7 +21,6 @@
  * 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.
- *
  */
 
 /*
@@ -52,7 +52,7 @@
  *  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);
+extern void _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);
@@ -204,18 +204,6 @@
     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
    */
@@ -278,6 +266,12 @@
  * 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)); }
+/**
+ * \def LE_CORRECT_SIZE
+ * @param x type (T)
+ * @param y fixed size for T
+ */
+#define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
 
 /**
  * Open a new entry based on an existing table
@@ -338,15 +332,7 @@
   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
-    }
+    return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
   }
 
   const T *getAliasTODO() const { LE_DEBUG_TR("getAliasTODO<>"); return (const T*)fStart; }
@@ -377,46 +363,6 @@
     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;
 };
@@ -433,7 +379,7 @@
    */
   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);
+    verifyLength(0, LETableVarSizer<T>::getSize(), success);
     if(LE_FAILURE(success)) clear();
   }
   /**
diff --git a/test/java/awt/font/TextLayout/TestKerning.java b/test/java/awt/font/TextLayout/TestKerning.java
new file mode 100644
--- /dev/null
+++ openjdk/jdk/test/java/awt/font/TextLayout/TestKerning.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @summary Test Kerning is working.
+ * @bug 8009530
+ */
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.font.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+
+public class TestKerning extends Applet {
+    private Panel panel;
+
+    static public void main(String[] args) {
+System.out.println(System.getProperty("os.name"));
+
+        Applet test = new TestKerning();
+        test.init();
+        test.start();
+
+        Frame f = new Frame("Test Kerning");
+        f.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+        });
+        f.add("Center", test);
+        f.pack();
+        f.setVisible(true);
+    }
+
+    public Dimension getPreferredSize() {
+        return new Dimension(500, 200);
+    }
+
+    public Dimension getMaximumSize() {
+        return getPreferredSize();
+    }
+
+    private static final String testString = "To WAVA 1,45 office glyph.";
+
+    public void paint(Graphics g) {
+        Graphics2D g2d = (Graphics2D)g;
+        Font f = new Font("Arial", Font.PLAIN, 36);
+        // testing Arial on Solaris.
+        if (!("SunOS".equals(System.getProperty("os.name")))) {
+           return;
+        }
+        if (!("Arial".equals(f.getFamily(Locale.ENGLISH)))) {
+            return;
+        }
+        Map m = new HashMap();
+        m.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
+        Font kf = f.deriveFont(m);
+        g.setFont(f);
+        FontMetrics fm1 = g.getFontMetrics();
+        int sw1 = fm1.stringWidth(testString);
+        g.drawString(testString, 10, 50);
+        g.setFont(kf);
+        FontMetrics fm2 = g.getFontMetrics();
+        int sw2 = fm2.stringWidth(testString);
+        g.drawString(testString, 10, 90);
+        if (sw1 == sw2) {
+            System.out.println(sw1+" " + sw2);
+            throw new RuntimeException("No kerning");
+        }
+    }
+}
