--- old/src/share/native/sun/font/layout/KernTable.cpp Mon Jun 17 13:04:34 2013 +++ new/src/share/native/sun/font/layout/KernTable.cpp Mon Jun 17 13:04:32 2013 @@ -96,7 +96,7 @@ * TODO: respect header flags */ KernTable::KernTable(const LETableReference& base, LEErrorCode &success) - : pairs(), pairsSwapped(NULL), fTable(base) + : pairsSwapped(NULL), fTable(base) { if(LE_FAILURE(success) || (fTable.isEmpty())) { #if DEBUG @@ -143,32 +143,36 @@ #endif if(LE_SUCCESS(success) && nPairs>0) { - // pairs is an instance member, and table is on the stack. - // set 'pairs' based on table.getAlias(). This will range check it. + // pairsSwapped is an instance member, and table is on the stack. + // set 'pairsSwapped' based on table.getAlias(). This will range check it. - pairs = LEReferenceToArrayOf(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))); - PairInfo *p = (PairInfo*)pairsSwapped; - for (int i = 0; LE_SUCCESS(success) && i < nPairs; i++, p++) { - memcpy(p, pairs.getAlias(i,success), KERN_PAIRINFO_SIZE); - p->key = SWAPL(p->key); + pairsSwapped = (PairInfo*)(fTable.getFont()->getKernPairs()); + if (pairsSwapped == NULL) { + LEReferenceToArrayOfpairs = + LEReferenceToArrayOf(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))); + PairInfo *p = (PairInfo*)pairsSwapped; + for (int i = 0; LE_SUCCESS(success) && i < nPairs; i++, p++) { + memcpy(p, pairs.getAlias(i,success), KERN_PAIRINFO_SIZE); + p->key = SWAPL(p->key); + } + fTable.getFont()->setKernPairs((void*)pairsSwapped); // store it } - 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, "coverage: %0.4x nPairs: %d pairs %p\n", coverage, nPairs, pairsSwapped); 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, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairsSwapped); fprintf(stderr, " searchRange(pairs): %d entrySelector: %d rangeShift(pairs): %d\n", searchRange, entrySelector, rangeShift); @@ -182,7 +186,7 @@ ids[id] = (char)i; } } - PairInfo *p = pairs; + PairInfo *p = pairsSwapped; for (int i = 0; i < nPairs; ++i, p++) { le_uint32 k = p->key; le_uint16 left = (k >> 16) & 0xffff; --- old/src/share/native/sun/font/layout/KernTable.h Mon Jun 17 13:04:38 2013 +++ new/src/share/native/sun/font/layout/KernTable.h Mon Jun 17 13:04:36 2013 @@ -57,7 +57,6 @@ private: le_uint16 coverage; le_uint16 nPairs; - LEReferenceToArrayOf pairs; PairInfo *pairsSwapped; const LETableReference &fTable; le_uint16 searchRange; --- old/src/share/native/sun/font/layout/LayoutEngine.cpp Mon Jun 17 13:04:42 2013 +++ new/src/share/native/sun/font/layout/LayoutEngine.cpp Mon Jun 17 13:04:40 2013 @@ -569,7 +569,6 @@ { if(fGlyphStorage!=NULL) { fGlyphStorage->reset(); - fGlyphStorage = NULL; } } --- /dev/null Mon Jun 17 13:04:46 2013 +++ new/test/java/awt/font/TextLayout/KerningLeak.java Mon Jun 17 13:04:44 2013 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * @bug 8015334 + * @summary Memory leak with kerning. + */ + +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.font.TextAttribute; +import java.util.HashMap; +import java.util.Map; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +public class KerningLeak { + + public static void main(String[] args) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + leak(); + } + }); + } + + private static void leak() { + Map textAttributes = new HashMap<>(); + textAttributes.put(TextAttribute.FAMILY, "Sans Serif"); + textAttributes.put(TextAttribute.SIZE, 12); + textAttributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); + Font font = Font.getFont(textAttributes); + JLabel label = new JLabel(); + int dummy = 0; + for (int i = 0; i < 500; i++) { + if (i % 10 == 0) System.out.println("Starting iter " + (i+1)); + for (int j = 0; j <1000; j++) { + FontMetrics fm = label.getFontMetrics(font); + dummy += SwingUtilities.computeStringWidth(fm, Integer.toString(j)); + } + } + System.out.println("done " + dummy); + } +}