diff --git a/src/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/share/classes/sun/font/ExtendedTextSourceLabel.java index 6fdef170727e6ef507340e27087583c066a78a98..220f36975403f9d6fa51923f5a18ed110eddf917 100644 --- a/src/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -247,6 +247,10 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La float aw = 0f; float ah = cm.ascent + cm.descent; + if (charinfo == null || charinfo.length == 0) { + return new Rectangle2D.Float(al, at, aw, ah); + } + boolean lineIsLTR = (source.getLayoutFlags() & 0x8) == 0; int rn = info.length - numvals; if (lineIsLTR) { @@ -350,24 +354,42 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La public float getCharX(int index) { validate(index); - return getCharinfo()[l2v(index) * numvals + posx]; + float[] charinfo = getCharinfo(); + int idx = l2v(index) * numvals + posx; + if (charinfo == null || idx >= charinfo.length) { + return 0f; + } else { + return charinfo[idx]; + } } public float getCharY(int index) { validate(index); - return getCharinfo()[l2v(index) * numvals + posy]; + float[] charinfo = getCharinfo(); + int idx = l2v(index) * numvals + posy; + if (charinfo == null || idx >= charinfo.length) { + return 0f; + } else { + return charinfo[idx]; + } } public float getCharAdvance(int index) { validate(index); - return getCharinfo()[l2v(index) * numvals + advx]; + float[] charinfo = getCharinfo(); + int idx = l2v(index) * numvals + advx; + if (charinfo == null || idx >= charinfo.length) { + return 0f; + } else { + return charinfo[idx]; + } } public Rectangle2D handleGetCharVisualBounds(int index) { validate(index); float[] charinfo = getCharinfo(); index = l2v(index) * numvals; - if ((index+vish) >= charinfo.length) { + if (charinfo == null || (index+vish) >= charinfo.length) { return new Rectangle2D.Float(); } return new Rectangle2D.Float( @@ -463,7 +485,7 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La if (cidx >= charinfo.length) { break; // layout bailed for some reason } - float adv = charinfo[l2v(start) * numvals + advx]; + float adv = charinfo[cidx]; width -= adv; } @@ -512,7 +534,13 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La // } //} - return getCharinfo()[v * numvals + advx] != 0; + int idx = v * numvals + advx; + float[] charinfo = getCharinfo(); + if (charinfo == null || idx >= charinfo.length) { + return false; + } else { + return charinfo[idx] != 0; + } } private final float[] getCharinfo() { @@ -604,6 +632,9 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La */ int numGlyphs = gv.getNumGlyphs(); + if (numGlyphs == 0) { + return glyphinfo; + } int[] indices = gv.getGlyphCharIndices(0, numGlyphs, null); boolean DEBUG = false; diff --git a/src/share/classes/sun/font/GlyphLayout.java b/src/share/classes/sun/font/GlyphLayout.java index 100b66b9809edfb1ebac8b55618ca86faeeb5cce..d29ecf34cb25686c443eb7d7b59141371da0b90a 100644 --- a/src/share/classes/sun/font/GlyphLayout.java +++ b/src/share/classes/sun/font/GlyphLayout.java @@ -464,7 +464,12 @@ public final class GlyphLayout { break; } catch (IndexOutOfBoundsException e) { - _gvdata.grow(); + if (_gvdata._count >=0) { + _gvdata.grow(); + } + } + if (_gvdata._count < 0) { + break; } } } @@ -473,7 +478,19 @@ public final class GlyphLayout { // _gvdata.adjustPositions(txinfo.invdtx); // } - StandardGlyphVector gv = _gvdata.createGlyphVector(font, frc, result); + // If layout fails (negative glyph count) create an un-laid out GV instead. + // ie default positions. This will be a lot better than the alternative of + // a complete blank layout. + StandardGlyphVector gv; + if (_gvdata._count < 0) { + gv = new StandardGlyphVector(font, text, offset, count, frc); + if (FontUtilities.debugFonts()) { + FontUtilities.getLogger().warning("OpenType layout failed on font: " + + font); + } + } else { + gv = _gvdata.createGlyphVector(font, frc, result); + } // System.err.println("Layout returns: " + gv); return gv; } diff --git a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp index 5446f9bebace7ca44ae84481b418211f8c372aaa..8711f63483fed8d3e8447ee548aa2ed365c041e5 100644 --- a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp +++ b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp @@ -218,6 +218,9 @@ le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor * LEGlyphID glyph = glyphIterator->getCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(subRuleSetCount); @@ -267,6 +270,9 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor * LEGlyphID glyph = glyphIterator->getCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { const ClassDefinitionTable *classDefinitionTable = @@ -395,6 +401,9 @@ le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupPro LEGlyphID glyph = glyphIterator->getCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); @@ -466,6 +475,9 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupPro LEGlyphID glyph = glyphIterator->getCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { const ClassDefinitionTable *backtrackClassDefinitionTable = diff --git a/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp b/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp index ff8ac3bed767ee57f1641f4828ffa6a2f631c234..5d338e85fd2c6e62144466e9f0e0ae4beb43e597 100644 --- a/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp +++ b/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp @@ -45,7 +45,7 @@ le_uint32 CursiveAttachmentSubtable::process(const LEReferenceTo= eeCount) { + if (coverageIndex < 0 || coverageIndex >= eeCount || LE_FAILURE(success)) { glyphIterator->setCursiveGlyph(); return 0; } diff --git a/src/share/native/sun/font/layout/ExtensionSubtables.cpp b/src/share/native/sun/font/layout/ExtensionSubtables.cpp index 76d945d02d0c3f8a12fef8897e3d8288144bd03b..81056db9c9199a6a543b8913aa2750f9a94d4caf 100644 --- a/src/share/native/sun/font/layout/ExtensionSubtables.cpp +++ b/src/share/native/sun/font/layout/ExtensionSubtables.cpp @@ -44,10 +44,10 @@ U_NAMESPACE_BEGIN #define READ_LONG(code) (le_uint32)((SWAPW(*(le_uint16*)&code) << 16) + SWAPW(*(((le_uint16*)&code) + 1))) // FIXME: should look at the format too... maybe have a sub-class for it? -le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_uint16 lookupType, +le_uint32 ExtensionSubtable::process(const LEReferenceTo &thisRef, + const LookupProcessor *lookupProcessor, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { - const LEReferenceTo thisRef(lookupProcessor->getReference(), success); // create a reference to this if (LE_FAILURE(success)) { return 0; @@ -57,7 +57,7 @@ le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_ if (elt != lookupType) { le_uint32 extOffset = READ_LONG(extensionOffset); - LEReferenceTo subtable(thisRef, success, extOffset); + LEReferenceTo subtable(thisRef, success, extOffset); if(LE_SUCCESS(success)) { return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success); diff --git a/src/share/native/sun/font/layout/ExtensionSubtables.h b/src/share/native/sun/font/layout/ExtensionSubtables.h index 47476fc984b70967f97b946ce2fcc690beabcc16..d629ade7afaaa833780a23b35bb6dacc09eebb3b 100644 --- a/src/share/native/sun/font/layout/ExtensionSubtables.h +++ b/src/share/native/sun/font/layout/ExtensionSubtables.h @@ -52,7 +52,8 @@ struct ExtensionSubtable //: GlyphSubstitutionSubtable le_uint16 extensionLookupType; le_uint32 extensionOffset; - le_uint32 process(const LookupProcessor *lookupProcessor, le_uint16 lookupType, + le_uint32 process(const LEReferenceTo &extRef, + const LookupProcessor *lookupProcessor, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; diff --git a/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp b/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp index 08b6c048e91a0acc951f44ddc5ba164e64c5f8dd..9c6666d47a9475cd1a2872211e9de7b7ce82877d 100644 --- a/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp +++ b/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp @@ -168,7 +168,7 @@ le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); + delta = subtable->process(subtable, this, lookupType, glyphIterator, fontInstance, success); break; } diff --git a/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp b/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp index d7b65aa866033de9cc852cab0b99ed5b116cd3f0..d4fe59075fa6a75541fa9b6046b79bb662c40fdb 100644 --- a/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp +++ b/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp @@ -139,7 +139,7 @@ le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); + delta = subtable->process(subtable, this, lookupType, glyphIterator, fontInstance, success); break; } diff --git a/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp b/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp index 46e808f2b6edbde25885419cd7b68759c3cc2388..3a036c50772f06322403f72b37b4137c0f2e1b15 100644 --- a/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp +++ b/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp @@ -45,6 +45,10 @@ le_uint32 LigatureSubstitutionSubtable::process(const LETableReference &base, Gl LEGlyphID glyph = glyphIterator->getCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); + if (LE_FAILURE(success)) { + return 0; + } + if (coverageIndex >= 0) { Offset ligSetTableOffset = SWAPW(ligSetTableOffsetArray[coverageIndex]); const LigatureSetTable *ligSetTable = (const LigatureSetTable *) ((char *) this + ligSetTableOffset); diff --git a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp index 2878981b6be4578bfafe18000d46176cc5881d5a..50df2704a88b7ab99d168c92a929031e900aa61d 100644 --- a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp @@ -56,6 +56,10 @@ le_int32 MarkToBasePositioningSubtable::process(const LETableReference &base, Gl LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); + if (LE_FAILURE(success)) { + return 0; + } + if (markCoverage < 0) { // markGlyph isn't a covered mark glyph return 0; diff --git a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp index 8e93e079a7992300f0269ed482b229b7480f8f32..ab21f86d1c5c148cc7e672f95f596db1fe532a5a 100644 --- a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp @@ -55,6 +55,10 @@ le_int32 MarkToLigaturePositioningSubtable::process(const LETableReference &base LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); + if (LE_FAILURE(success)) { + return 0; + } + if (markCoverage < 0) { // markGlyph isn't a covered mark glyph return 0; diff --git a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp index aa0bcd43c7ca75d6ade8c7b132e5f4277f6c3393..b06a287e5d9e23776d625c11e07a30b5c6162765 100644 --- a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp @@ -56,6 +56,10 @@ le_int32 MarkToMarkPositioningSubtable::process(const LETableReference &base, Gl LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); + if (LE_FAILURE(success)) { + return 0; + } + if (markCoverage < 0) { // markGlyph isn't a covered mark glyph return 0; diff --git a/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp b/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp index 9d72ca8a16ca72589ec3230d517368a5f1b795f9..af94e623baba6075bf9cbbad2cdd9acbb7b91e0b 100644 --- a/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp +++ b/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp @@ -61,6 +61,10 @@ le_uint32 MultipleSubstitutionSubtable::process(const LETableReference &base, Gl le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); le_uint16 seqCount = SWAPW(sequenceCount); + if (LE_FAILURE(success)) { + return 0; + } + if (coverageIndex >= 0 && coverageIndex < seqCount) { Offset sequenceTableOffset = SWAPW(sequenceTableOffsetArray[coverageIndex]); const SequenceTable *sequenceTable = (const SequenceTable *) ((char *) this + sequenceTableOffset); diff --git a/src/share/native/sun/font/layout/PairPositioningSubtables.cpp b/src/share/native/sun/font/layout/PairPositioningSubtables.cpp index e54004692b5ecf370156889ebf73280faafef241..bba2b8707ad3d6085b6e4be986f96ef09a12a53d 100644 --- a/src/share/native/sun/font/layout/PairPositioningSubtables.cpp +++ b/src/share/native/sun/font/layout/PairPositioningSubtables.cpp @@ -126,6 +126,11 @@ le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTogetCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); + + if (LE_FAILURE(success)) { + return 0; + } + GlyphIterator tempIterator(*glyphIterator); if (coverageIndex >= 0 && glyphIterator->next()) { diff --git a/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp b/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp index 1e2d257a6f8efbdc1dcec019312bc8d7bd8bfbb2..2d2fe342cfeaf888b0aa505a1db1d9f0ef386132 100644 --- a/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp +++ b/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp @@ -70,6 +70,9 @@ le_uint32 SinglePositioningFormat1Subtable::process(const LEReferenceTogetCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { valueRecord.adjustPosition(SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance); @@ -84,6 +87,9 @@ le_uint32 SinglePositioningFormat2Subtable::process(const LEReferenceTogetCurrGlyphID(); le_int16 coverageIndex = (le_int16) getGlyphCoverage(base, glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { valueRecordArray[0].adjustPosition(coverageIndex, SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance); diff --git a/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp b/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp index 681958cf5ea4a8ad642b751318273e294b412d31..c32377d507101b517502f76fd0799281dd9c93fc 100644 --- a/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp +++ b/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp @@ -69,6 +69,9 @@ le_uint32 SingleSubstitutionFormat1Subtable::process(const LEReferenceTogetCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { TTGlyphID substitute = ((TTGlyphID) LE_GET_GLYPH(glyph)) + SWAPW(deltaGlyphID); @@ -87,6 +90,9 @@ le_uint32 SingleSubstitutionFormat2Subtable::process(const LEReferenceTogetCurrGlyphID(); le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); + if (LE_FAILURE(success)) { + return 0; + } if (coverageIndex >= 0) { TTGlyphID substitute = SWAPW(substituteArray[coverageIndex]); diff --git a/src/share/native/sun/font/layout/SunLayoutEngine.cpp b/src/share/native/sun/font/layout/SunLayoutEngine.cpp index c7db94829f46a8c0826d2fc0d15d776278e9c4b3..b32f2601b4dbde4cea05e611adf53a7e941a822e 100644 --- a/src/share/native/sun/font/layout/SunLayoutEngine.cpp +++ b/src/share/native/sun/font/layout/SunLayoutEngine.cpp @@ -203,16 +203,19 @@ JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout getFloat(env, pt, x, y); jboolean rtl = (typo_flags & TYPO_RTL) != 0; int glyphCount = engine->layoutChars(chars, start - min, limit - start, len, rtl, x, y, success); - // fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr); + // fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr); engine->getGlyphPosition(glyphCount, x, y, success); - // fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr); - - if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) { - // !!! hmmm, could use current value in positions array of GVData... - putFloat(env, pt, x, y); - } + // fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr); + if (LE_FAILURE(success)) { + env->SetIntField(gvdata, gvdCountFID, -1); // flag failure + } else { + if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) { + // !!! hmmm, could use current value in positions array of GVData... + putFloat(env, pt, x, y); + } + } if (chars != buffer) { free(chars); diff --git a/test/java/awt/font/LineBreakMeasurer/AllFontsLBM.java b/test/java/awt/font/LineBreakMeasurer/AllFontsLBM.java new file mode 100644 index 0000000000000000000000000000000000000000..e319c63db22b029cfefd1731f5af39a1af06fd63 --- /dev/null +++ b/test/java/awt/font/LineBreakMeasurer/AllFontsLBM.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8012617 + * @summary ArrayIndexOutOfBoundsException in LineBreakMeasurer + */ + +import java.awt.*; +import java.awt.image.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.text.*; +import java.util.Hashtable; + +public class AllFontsLBM { + + public static void main(String[] args) { + Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (int i=0;i