From 65172138addb03d7a8f7604aae550117e0772aea Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Thu, 7 Feb 2013 19:15:59 +0400 Subject: [PATCH 01/36] 8007014: Improve image handling Reviewed-by: prr, mschoene, jgodinez --- .../sun/awt/image/ByteComponentRaster.java | 12 +++- .../sun/awt/image/BytePackedRaster.java | 26 ++++++- .../sun/awt/image/IntegerComponentRaster.java | 71 ++++++++++++++----- .../awt/image/IntegerInterleavedRaster.java | 27 +------ .../sun/awt/image/ShortComponentRaster.java | 12 +++- .../native/sun/awt/image/awt_parseImage.c | 1 + .../native/sun/awt/medialib/awt_ImagingLib.c | 32 ++++++++- .../sun/awt/medialib/mlib_ImageCreate.c | 33 +++++++-- .../native/sun/awt/medialib/safe_alloc.h | 6 -- .../share/native/sun/awt/medialib/safe_math.h | 35 +++++++++ 10 files changed, 196 insertions(+), 59 deletions(-) create mode 100644 jdk/src/share/native/sun/awt/medialib/safe_math.h diff --git a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java index 49c642e37db..f2675dbf97d 100644 --- a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java @@ -868,6 +868,15 @@ public class ByteComponentRaster extends SunWritableRaster { * or if data buffer has not enough capacity. */ protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { throw new RasterFormatException("Data offsets for band " + i @@ -905,13 +914,14 @@ public class ByteComponentRaster extends SunWritableRaster { lastPixelOffset += lastScanOffset; for (int i = 0; i < numDataElements; i++) { - size = lastPixelOffset + dataOffsets[i]; if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { throw new RasterFormatException("Incorrect band offset: " + dataOffsets[i]); } + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; } diff --git a/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java b/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java index 8fec29e90b7..598d68dce47 100644 --- a/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java +++ b/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java @@ -1368,11 +1368,35 @@ public class BytePackedRaster extends SunWritableRaster { throw new RasterFormatException("Data offsets must be >= 0"); } + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + + + /* + * pixelBitstride was verified in constructor, so just make + * sure that it is safe to multiply it by width. + */ + if ((width - 1) > Integer.MAX_VALUE / pixelBitStride) { + throw new RasterFormatException("Invalid raster dimension"); + } + + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + throw new RasterFormatException("Invalid scanline stride"); + } + int lastbit = (dataBitOffset + (height-1) * scanlineStride * 8 + (width-1) * pixelBitStride + pixelBitStride - 1); - if (lastbit / 8 >= data.length) { + if (lastbit < 0 || lastbit / 8 >= data.length) { throw new RasterFormatException("raster dimensions overflow " + "array bounds"); } diff --git a/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java b/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java index 1f2c569b5bf..92bec9f944a 100644 --- a/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java +++ b/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java @@ -208,7 +208,7 @@ public class IntegerComponentRaster extends SunWritableRaster { " SinglePixelPackedSampleModel"); } - verify(false); + verify(); } @@ -629,16 +629,26 @@ public class IntegerComponentRaster extends SunWritableRaster { } /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. + * Verify that the layout parameters are consistent with the data. + * + * The method verifies whether scanline stride and pixel stride do not + * cause an integer overflow during calculation of a position of the pixel + * in data buffer. It also verifies whether the data buffer has enough data + * to correspond the raster layout attributes. + * + * @throws RasterFormatException if an integer overflow is detected, + * or if data buffer has not enough capacity. */ - private void verify (boolean strictCheck) { + protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + if (dataOffsets[0] < 0) { throw new RasterFormatException("Data offset ("+dataOffsets[0]+ ") must be >= 0"); @@ -647,17 +657,46 @@ public class IntegerComponentRaster extends SunWritableRaster { int maxSize = 0; int size; - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; + // we can be sure that width and height are greater than 0 + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + // integer overflow + throw new RasterFormatException("Incorrect scanline stride: " + + scanlineStride); + } + int lastScanOffset = (height - 1) * scanlineStride; + + if (pixelStride < 0 || + pixelStride > (Integer.MAX_VALUE / width)) + { + // integer overflow + throw new RasterFormatException("Incorrect pixel stride: " + + pixelStride); + } + int lastPixelOffset = (width - 1) * pixelStride; + + if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) { + // integer overflow + throw new RasterFormatException("Incorrect raster attributes"); + } + lastPixelOffset += lastScanOffset; + + for (int i = 0; i < numDataElements; i++) { + if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { + throw new RasterFormatException("Incorrect band offset: " + + dataOffsets[i]); + } + + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; } } if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize - +" but is "+data.length+" )"); + throw new RasterFormatException("Data array too small (should be " + + maxSize + " )"); } } diff --git a/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java b/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java index 90238f4cc4e..2d0d22ec59c 100644 --- a/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java +++ b/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java @@ -151,7 +151,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { throw new RasterFormatException("IntegerInterleavedRasters must have"+ " SinglePixelPackedSampleModel"); } - verify(false); + verify(); } @@ -540,31 +540,6 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { return createCompatibleWritableRaster(width,height); } - /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. - */ - private void verify (boolean strictCheck) { - int maxSize = 0; - int size; - - size = (height-1)*scanlineStride + (width-1) + dataOffsets[0]; - if (size > maxSize) { - maxSize = size; - } - if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize - +" but is "+data.length+" )"); - } - } - public String toString() { return new String ("IntegerInterleavedRaster: width = "+width +" height = " + height diff --git a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java index df2c0f7d663..3b33595c129 100644 --- a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java @@ -802,6 +802,15 @@ public class ShortComponentRaster extends SunWritableRaster { * or if data buffer has not enough capacity. */ protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { throw new RasterFormatException("Data offsets for band " + i @@ -839,12 +848,13 @@ public class ShortComponentRaster extends SunWritableRaster { lastPixelOffset += lastScanOffset; for (int i = 0; i < numDataElements; i++) { - size = lastPixelOffset + dataOffsets[i]; if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { throw new RasterFormatException("Incorrect band offset: " + dataOffsets[i]); } + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; } diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.c b/jdk/src/share/native/sun/awt/image/awt_parseImage.c index 498ac717913..310866acba3 100644 --- a/jdk/src/share/native/sun/awt/image/awt_parseImage.c +++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.c @@ -34,6 +34,7 @@ #include "java_awt_color_ColorSpace.h" #include "awt_Mlib.h" #include "safe_alloc.h" +#include "safe_math.h" static int setHints(JNIEnv *env, BufImageS_t *imageP); diff --git a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c index 4f1a2e1609a..5730734cefa 100644 --- a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c +++ b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c @@ -42,6 +42,7 @@ #include "awt_Mlib.h" #include "gdefs.h" #include "safe_alloc.h" +#include "safe_math.h" /*************************************************************************** * Definitions * @@ -1993,13 +1994,23 @@ cvtCustomToDefault(JNIEnv *env, BufImageS_t *imageP, int component, unsigned char *dP = dataP; #define NUM_LINES 10 int numLines = NUM_LINES; - int nbytes = rasterP->width*4*NUM_LINES; + /* it is safe to calculate the scan length, because width has been verified + * on creation of the mlib image + */ + int scanLength = rasterP->width * 4; + + int nbytes = 0; + if (!SAFE_TO_MULT(numLines, scanLength)) { + return -1; + } + + nbytes = numLines * scanLength; for (y=0; y < rasterP->height; y+=numLines) { /* getData, one scanline at a time */ if (y+numLines > rasterP->height) { numLines = rasterP->height - y; - nbytes = rasterP->width*4*numLines; + nbytes = numLines * scanLength; } jpixels = (*env)->CallObjectMethod(env, imageP->jimage, g_BImgGetRGBMID, 0, y, @@ -2129,8 +2140,14 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP, if (cvtToDefault) { int status = 0; *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height); + if (*mlibImagePP == NULL) { + return -1; + } cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); - /* Make sure the image is cleared */ + /* Make sure the image is cleared. + * NB: the image dimension is already verified, so we can + * safely calculate the length of the buffer. + */ memset(cDataP, 0, width*height*4); if (!isSrc) { @@ -2380,6 +2397,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP, case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES: *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedBCR(env, rasterP, -1, cDataP); @@ -2388,6 +2408,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP, if (rasterP->sppsm.maxBitSize <= 8) { *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedSCR(env, rasterP, -1, cDataP); @@ -2397,6 +2420,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP, if (rasterP->sppsm.maxBitSize <= 8) { *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedICR(env, rasterP, -1, cDataP); diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c index 40662d6b8cc..97caaa4bf43 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c @@ -120,6 +120,7 @@ #include "mlib_image.h" #include "mlib_ImageRowTable.h" #include "mlib_ImageCreate.h" +#include "safe_math.h" /***************************************************************/ mlib_image* mlib_ImageSet(mlib_image *image, @@ -247,28 +248,50 @@ mlib_image *mlib_ImageCreate(mlib_type type, return NULL; }; + if (!SAFE_TO_MULT(width, channels)) { + return NULL; + } + + wb = width * channels; + switch (type) { case MLIB_DOUBLE: - wb = width * channels * 8; + if (!SAFE_TO_MULT(wb, 8)) { + return NULL; + } + wb *= 8; break; case MLIB_FLOAT: case MLIB_INT: - wb = width * channels * 4; + if (!SAFE_TO_MULT(wb, 4)) { + return NULL; + } + wb *= 4; break; case MLIB_USHORT: case MLIB_SHORT: - wb = width * channels * 2; + if (!SAFE_TO_MULT(wb, 4)) { + return NULL; + } + wb *= 2; break; case MLIB_BYTE: - wb = width * channels; + // wb is ready break; case MLIB_BIT: - wb = (width * channels + 7) / 8; + if (!SAFE_TO_ADD(7, wb)) { + return NULL; + } + wb = (wb + 7) / 8; break; default: return NULL; } + if (!SAFE_TO_MULT(wb, height)) { + return NULL; + } + data = mlib_malloc(wb * height); if (data == NULL) { return NULL; diff --git a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h index 579d98638dc..6a0320e2179 100644 --- a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h +++ b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h @@ -41,10 +41,4 @@ (((w) > 0) && ((h) > 0) && ((sz) > 0) && \ (((0xffffffffu / ((juint)(w))) / ((juint)(h))) > ((juint)(sz)))) -#define SAFE_TO_MULT(a, b) \ - (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) - -#define SAFE_TO_ADD(a, b) \ - (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b))) - #endif // __SAFE_ALLOC_H__ diff --git a/jdk/src/share/native/sun/awt/medialib/safe_math.h b/jdk/src/share/native/sun/awt/medialib/safe_math.h new file mode 100644 index 00000000000..34c1fc56e9a --- /dev/null +++ b/jdk/src/share/native/sun/awt/medialib/safe_math.h @@ -0,0 +1,35 @@ +/* + * 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. 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. + */ + +#ifndef __SAFE_MATH_H__ +#define __SAFE_MATH_H__ + +#define SAFE_TO_MULT(a, b) \ + (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) + +#define SAFE_TO_ADD(a, b) \ + (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b))) + +#endif // __SAFE_MATH_H__ From 9f917b11d6fb6f4dd914d56b65053d094f5e4331 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 8 Feb 2013 17:32:25 +0400 Subject: [PATCH 02/36] 7200507: Refactor Introspector internals Reviewed-by: ahgross, art --- .../java/beans/ThreadGroupContext.java | 7 +- .../classes/java/beans/WeakIdentityMap.java | 181 ++++++++++++++++++ 2 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 jdk/src/share/classes/java/beans/WeakIdentityMap.java diff --git a/jdk/src/share/classes/java/beans/ThreadGroupContext.java b/jdk/src/share/classes/java/beans/ThreadGroupContext.java index dc1d38a1457..6236ec2b38c 100644 --- a/jdk/src/share/classes/java/beans/ThreadGroupContext.java +++ b/jdk/src/share/classes/java/beans/ThreadGroupContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -29,7 +29,6 @@ import com.sun.beans.finder.BeanInfoFinder; import com.sun.beans.finder.PropertyEditorFinder; import java.awt.GraphicsEnvironment; -import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; @@ -42,7 +41,7 @@ import java.util.WeakHashMap; */ final class ThreadGroupContext { - private static final Map contexts = new WeakHashMap<>(); + private static final WeakIdentityMap contexts = new WeakIdentityMap<>(); /** * Returns the appropriate {@code AppContext} for the caller, @@ -69,6 +68,8 @@ final class ThreadGroupContext { private BeanInfoFinder beanInfoFinder; private PropertyEditorFinder propertyEditorFinder; + private ThreadGroupContext() { + } boolean isDesignTime() { return this.isDesignTime; diff --git a/jdk/src/share/classes/java/beans/WeakIdentityMap.java b/jdk/src/share/classes/java/beans/WeakIdentityMap.java new file mode 100644 index 00000000000..42ac821a392 --- /dev/null +++ b/jdk/src/share/classes/java/beans/WeakIdentityMap.java @@ -0,0 +1,181 @@ +/* + * 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. 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. + */ + +package java.beans; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +/** + * Hash table based mapping, which uses weak references to store keys + * and reference-equality in place of object-equality to compare them. + * An entry will automatically be removed when its key is no longer + * in ordinary use. Both null values and the null key are supported. + * + * @see java.util.IdentityHashMap + * @see java.util.WeakHashMap + */ +final class WeakIdentityMap { + + private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two + private static final Object NULL = new Object(); // special object for null key + + private final ReferenceQueue queue = new ReferenceQueue(); + + private Entry[] table = newTable(1<<3); // table's length MUST be a power of two + private int threshold = 6; // the next size value at which to resize + private int size = 0; // the number of key-value mappings + + public T get(Object key) { + removeStaleEntries(); + if (key == null) { + key = NULL; + } + int hash = key.hashCode(); + int index = getIndex(this.table, hash); + for (Entry entry = this.table[index]; entry != null; entry = entry.next) { + if (entry.isMatched(key, hash)) { + return entry.value; + } + } + return null; + } + + public T put(Object key, T value) { + removeStaleEntries(); + if (key == null) { + key = NULL; + } + int hash = key.hashCode(); + int index = getIndex(this.table, hash); + for (Entry entry = this.table[index]; entry != null; entry = entry.next) { + if (entry.isMatched(key, hash)) { + T oldValue = entry.value; + entry.value = value; + return oldValue; + } + } + this.table[index] = new Entry(key, hash, value, this.queue, this.table[index]); + if (++this.size >= this.threshold) { + if (this.table.length == MAXIMUM_CAPACITY) { + this.threshold = Integer.MAX_VALUE; + } + else { + removeStaleEntries(); + Entry[] table = newTable(this.table.length * 2); + transfer(this.table, table); + + // If ignoring null elements and processing ref queue caused massive + // shrinkage, then restore old table. This should be rare, but avoids + // unbounded expansion of garbage-filled tables. + if (this.size >= this.threshold / 2) { + this.table = table; + this.threshold *= 2; + } + else { + transfer(table, this.table); + } + } + } + return null; + } + + private void removeStaleEntries() { + for (Object ref = this.queue.poll(); ref != null; ref = this.queue.poll()) { + @SuppressWarnings("unchecked") + Entry entry = (Entry) ref; + int index = getIndex(this.table, entry.hash); + + Entry prev = this.table[index]; + Entry current = prev; + while (current != null) { + Entry next = current.next; + if (current == entry) { + if (prev == entry) { + this.table[index] = next; + } + else { + prev.next = next; + } + entry.value = null; // Help GC + entry.next = null; // Help GC + this.size--; + break; + } + prev = current; + current = next; + } + } + } + + private void transfer(Entry[] oldTable, Entry[] newTable) { + for (int i = 0; i < oldTable.length; i++) { + Entry entry = oldTable[i]; + oldTable[i] = null; + while (entry != null) { + Entry next = entry.next; + Object key = entry.get(); + if (key == null) { + entry.value = null; // Help GC + entry.next = null; // Help GC + this.size--; + } + else { + int index = getIndex(newTable, entry.hash); + entry.next = newTable[index]; + newTable[index] = entry; + } + entry = next; + } + } + } + + + @SuppressWarnings("unchecked") + private Entry[] newTable(int length) { + return (Entry[]) new Entry[length]; + } + + private static int getIndex(Entry[] table, int hash) { + return hash & (table.length - 1); + } + + private static class Entry extends WeakReference { + private final int hash; + private T value; + private Entry next; + + Entry(Object key, int hash, T value, ReferenceQueue queue, Entry next) { + super(key, queue); + this.hash = hash; + this.value = value; + this.next = next; + } + + boolean isMatched(Object key, int hash) { + return (this.hash == hash) && (key == get()); + } + } +} From 724cfc189779e7c03392b69d635580d1c2aa91b9 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Wed, 13 Feb 2013 10:40:31 +0000 Subject: [PATCH 03/36] 8000724: Improve networking serialization Delegate InetAddress fields to a holder object Reviewed-by: alanb, chegar --- .../net/AbstractPlainDatagramSocketImpl.java | 2 +- .../share/classes/java/net/Inet4Address.java | 39 +++--- .../classes/java/net/Inet4AddressImpl.java | 2 +- .../share/classes/java/net/Inet6Address.java | 19 ++- .../classes/java/net/Inet6AddressImpl.java | 2 +- .../share/classes/java/net/InetAddress.java | 121 ++++++++++++++---- .../classes/java/net/InetSocketAddress.java | 4 +- jdk/src/share/native/java/net/InetAddress.c | 23 +++- jdk/src/share/native/java/net/net_util.c | 70 ++++++++-- jdk/src/share/native/java/net/net_util.h | 12 +- .../native/java/net/Inet4AddressImpl.c | 19 +-- .../native/java/net/Inet6AddressImpl.c | 13 +- .../native/java/net/NetworkInterface.c | 13 +- .../native/java/net/PlainDatagramSocketImpl.c | 51 +++----- jdk/src/solaris/native/java/net/net_util_md.c | 6 +- .../net/TwoStacksPlainDatagramSocketImpl.java | 2 +- .../native/java/net/Inet4AddressImpl.c | 14 +- .../native/java/net/Inet6AddressImpl.c | 13 +- .../native/java/net/NetworkInterface.c | 9 +- .../native/java/net/NetworkInterface.h | 1 - .../native/java/net/NetworkInterface_winXP.c | 6 +- .../net/TwoStacksPlainDatagramSocketImpl.c | 52 ++------ .../java/net/TwoStacksPlainSocketImpl.c | 9 +- jdk/src/windows/native/java/net/net_util_md.c | 6 +- 24 files changed, 289 insertions(+), 219 deletions(-) diff --git a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 349c9a00836..1ef64fbf0b4 100644 --- a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -122,7 +122,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl * not connected already. */ protected void disconnect() { - disconnect0(connectedAddress.family); + disconnect0(connectedAddress.holder().getFamily()); connected = false; connectedAddress = null; connectedPort = -1; diff --git a/jdk/src/share/classes/java/net/Inet4Address.java b/jdk/src/share/classes/java/net/Inet4Address.java index a9d8dfcb69f..529257fa90d 100644 --- a/jdk/src/share/classes/java/net/Inet4Address.java +++ b/jdk/src/share/classes/java/net/Inet4Address.java @@ -100,27 +100,28 @@ class Inet4Address extends InetAddress { Inet4Address() { super(); - hostName = null; - address = 0; - family = IPv4; + holder().hostName = null; + holder().address = 0; + holder().family = IPv4; } Inet4Address(String hostName, byte addr[]) { - this.hostName = hostName; - this.family = IPv4; + holder().hostName = hostName; + holder().family = IPv4; if (addr != null) { if (addr.length == INADDRSZ) { - address = addr[3] & 0xFF; + int address = addr[3] & 0xFF; address |= ((addr[2] << 8) & 0xFF00); address |= ((addr[1] << 16) & 0xFF0000); address |= ((addr[0] << 24) & 0xFF000000); + holder().address = address; } } } Inet4Address(String hostName, int address) { - this.hostName = hostName; - this.family = IPv4; - this.address = address; + holder().hostName = hostName; + holder().family = IPv4; + holder().address = address; } /** @@ -134,8 +135,8 @@ class Inet4Address extends InetAddress { private Object writeReplace() throws ObjectStreamException { // will replace the to be serialized 'this' object InetAddress inet = new InetAddress(); - inet.hostName = this.hostName; - inet.address = this.address; + inet.holder().hostName = holder().getHostName(); + inet.holder().address = holder().getAddress(); /** * Prior to 1.4 an InetAddress was created with a family @@ -143,7 +144,7 @@ class Inet4Address extends InetAddress { * For compatibility reasons we must therefore write the * the InetAddress with this family. */ - inet.family = 2; + inet.holder().family = 2; return inet; } @@ -157,7 +158,7 @@ class Inet4Address extends InetAddress { * @since JDK1.1 */ public boolean isMulticastAddress() { - return ((address & 0xf0000000) == 0xe0000000); + return ((holder().getAddress() & 0xf0000000) == 0xe0000000); } /** @@ -167,7 +168,7 @@ class Inet4Address extends InetAddress { * @since 1.4 */ public boolean isAnyLocalAddress() { - return address == 0; + return holder().getAddress() == 0; } /** @@ -195,6 +196,7 @@ class Inet4Address extends InetAddress { // defined in "Documenting Special Use IPv4 Address Blocks // that have been Registered with IANA" by Bill Manning // draft-manning-dsua-06.txt + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 169) && (((address >>> 16) & 0xFF) == 254); } @@ -211,6 +213,7 @@ class Inet4Address extends InetAddress { // 10/8 prefix // 172.16/12 prefix // 192.168/16 prefix + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 10) || ((((address >>> 24) & 0xFF) == 172) && (((address >>> 16) & 0xF0) == 16)) @@ -257,6 +260,7 @@ class Inet4Address extends InetAddress { */ public boolean isMCLinkLocal() { // 224.0.0/24 prefix and ttl == 1 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 224) && (((address >>> 16) & 0xFF) == 0) && (((address >>> 8) & 0xFF) == 0); @@ -272,6 +276,7 @@ class Inet4Address extends InetAddress { */ public boolean isMCSiteLocal() { // 239.255/16 prefix or ttl < 32 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 239) && (((address >>> 16) & 0xFF) == 255); } @@ -287,6 +292,7 @@ class Inet4Address extends InetAddress { */ public boolean isMCOrgLocal() { // 239.192 - 239.195 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 239) && (((address >>> 16) & 0xFF) >= 192) && (((address >>> 16) & 0xFF) <= 195); @@ -300,6 +306,7 @@ class Inet4Address extends InetAddress { * @return the raw IP address of this object. */ public byte[] getAddress() { + int address = holder().getAddress(); byte[] addr = new byte[INADDRSZ]; addr[0] = (byte) ((address >>> 24) & 0xFF); @@ -325,7 +332,7 @@ class Inet4Address extends InetAddress { * @return a hash code value for this IP address. */ public int hashCode() { - return address; + return holder().getAddress(); } /** @@ -346,7 +353,7 @@ class Inet4Address extends InetAddress { */ public boolean equals(Object obj) { return (obj != null) && (obj instanceof Inet4Address) && - (((InetAddress)obj).address == address); + (((InetAddress)obj).holder().getAddress() == holder().getAddress()); } // Utilities diff --git a/jdk/src/share/classes/java/net/Inet4AddressImpl.java b/jdk/src/share/classes/java/net/Inet4AddressImpl.java index 367ca22b9aa..6ca2d5c7bf0 100644 --- a/jdk/src/share/classes/java/net/Inet4AddressImpl.java +++ b/jdk/src/share/classes/java/net/Inet4AddressImpl.java @@ -40,7 +40,7 @@ class Inet4AddressImpl implements InetAddressImpl { public synchronized InetAddress anyLocalAddress() { if (anyLocalAddress == null) { anyLocalAddress = new Inet4Address(); // {0x00,0x00,0x00,0x00} - anyLocalAddress.hostName = "0.0.0.0"; + anyLocalAddress.holder().hostName = "0.0.0.0"; } return anyLocalAddress; } diff --git a/jdk/src/share/classes/java/net/Inet6Address.java b/jdk/src/share/classes/java/net/Inet6Address.java index 7329b2de687..a2e66f09b70 100644 --- a/jdk/src/share/classes/java/net/Inet6Address.java +++ b/jdk/src/share/classes/java/net/Inet6Address.java @@ -210,18 +210,18 @@ class Inet6Address extends InetAddress { Inet6Address() { super(); - hostName = null; + holder().hostName = null; ipaddress = new byte[INADDRSZ]; - family = IPv6; + holder().family = IPv6; } /* checking of value for scope_id should be done by caller * scope_id must be >= 0, or -1 to indicate not being set */ Inet6Address(String hostName, byte addr[], int scope_id) { - this.hostName = hostName; + holder().hostName = hostName; if (addr.length == INADDRSZ) { // normal IPv6 address - family = IPv6; + holder().family = IPv6; ipaddress = addr.clone(); } if (scope_id >= 0) { @@ -335,9 +335,9 @@ class Inet6Address extends InetAddress { private void initif(String hostName, byte addr[],NetworkInterface nif) throws UnknownHostException { - this.hostName = hostName; + holder().hostName = hostName; if (addr.length == INADDRSZ) { // normal IPv6 address - family = IPv6; + holder().family = IPv6; ipaddress = addr.clone(); } if (nif != null) { @@ -420,6 +420,11 @@ class Inet6Address extends InetAddress { */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + + if (getClass().getClassLoader() != null) { + throw new SecurityException ("invalid address type"); + } + s.defaultReadObject(); if (ifname != null && !ifname.equals("")) { @@ -447,7 +452,7 @@ class Inet6Address extends InetAddress { ipaddress.length); } - if (family != IPv6) { + if (holder().getFamily() != IPv6) { throw new InvalidObjectException("invalid address family type"); } } diff --git a/jdk/src/share/classes/java/net/Inet6AddressImpl.java b/jdk/src/share/classes/java/net/Inet6AddressImpl.java index 663c77ebccc..6512b998712 100644 --- a/jdk/src/share/classes/java/net/Inet6AddressImpl.java +++ b/jdk/src/share/classes/java/net/Inet6AddressImpl.java @@ -81,7 +81,7 @@ class Inet6AddressImpl implements InetAddressImpl { if (anyLocalAddress == null) { if (InetAddress.preferIPv6Address) { anyLocalAddress = new Inet6Address(); - anyLocalAddress.hostName = "::"; + anyLocalAddress.holder().hostName = "::"; } else { anyLocalAddress = (new Inet4AddressImpl()).anyLocalAddress(); } diff --git a/jdk/src/share/classes/java/net/InetAddress.java b/jdk/src/share/classes/java/net/InetAddress.java index e29d1dbc0d9..1154c9a80f4 100644 --- a/jdk/src/share/classes/java/net/InetAddress.java +++ b/jdk/src/share/classes/java/net/InetAddress.java @@ -35,8 +35,12 @@ import java.util.ArrayList; import java.util.ServiceLoader; import java.security.AccessController; import java.io.ObjectStreamException; +import java.io.ObjectStreamField; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.ObjectInputStream.GetField; +import java.io.ObjectOutputStream; +import java.io.ObjectOutputStream.PutField; import sun.security.action.*; import sun.net.InetAddressCachePolicy; import sun.net.util.IPAddressUtil; @@ -199,25 +203,48 @@ class InetAddress implements java.io.Serializable { /* Specify address family preference */ static transient boolean preferIPv6Address = false; - /** - * @serial - */ - String hostName; + static class InetAddressHolder { - /** - * Holds a 32-bit IPv4 address. - * - * @serial - */ - int address; + InetAddressHolder() {} - /** - * Specifies the address family type, for instance, '1' for IPv4 - * addresses, and '2' for IPv6 addresses. - * - * @serial - */ - int family; + InetAddressHolder(String hostName, int address, int family) { + this.hostName = hostName; + this.address = address; + this.family = family; + } + + String hostName; + + String getHostName() { + return hostName; + } + + /** + * Holds a 32-bit IPv4 address. + */ + int address; + + int getAddress() { + return address; + } + + /** + * Specifies the address family type, for instance, '1' for IPv4 + * addresses, and '2' for IPv6 addresses. + */ + int family; + + int getFamily() { + return family; + } + } + + /* Used to store the serializable fields of InetAddress */ + private final transient InetAddressHolder holder; + + InetAddressHolder holder() { + return holder; + } /* Used to store the name service provider */ private static List nameServices = null; @@ -251,6 +278,7 @@ class InetAddress implements java.io.Serializable { * put in the address cache, since it is not created by name. */ InetAddress() { + holder = new InetAddressHolder(); } /** @@ -263,7 +291,7 @@ class InetAddress implements java.io.Serializable { */ private Object readResolve() throws ObjectStreamException { // will replace the deserialized 'this' object - return new Inet4Address(this.hostName, this.address); + return new Inet4Address(holder().getHostName(), holder().getAddress()); } /** @@ -500,10 +528,10 @@ class InetAddress implements java.io.Serializable { * @see SecurityManager#checkConnect */ String getHostName(boolean check) { - if (hostName == null) { - hostName = InetAddress.getHostFromNameService(this, check); + if (holder().getHostName() == null) { + holder().hostName = InetAddress.getHostFromNameService(this, check); } - return hostName; + return holder().getHostName(); } /** @@ -666,6 +694,7 @@ class InetAddress implements java.io.Serializable { * @return a string representation of this IP address. */ public String toString() { + String hostName = holder().getHostName(); return ((hostName != null) ? hostName : "") + "/" + getHostAddress(); } @@ -1522,14 +1551,58 @@ class InetAddress implements java.io.Serializable { } } + private static final long FIELDS_OFFSET; + private static final sun.misc.Unsafe UNSAFE; + + static { + try { + sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + FIELDS_OFFSET = unsafe.objectFieldOffset( + InetAddress.class.getDeclaredField("holder") + ); + UNSAFE = unsafe; + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } + private void readObject (ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject (); if (getClass().getClassLoader() != null) { - hostName = null; - address = 0; throw new SecurityException ("invalid address type"); } + GetField gf = s.readFields(); + String host = (String)gf.get("hostName", null); + int address= gf.get("address", 0); + int family= gf.get("family", 0); + InetAddressHolder h = new InetAddressHolder(host, address, family); + UNSAFE.putObject(this, FIELDS_OFFSET, h); + } + + /* needed because the serializable fields no longer exist */ + + /** + * @serialField hostName String + * @serialField address int + * @serialField family int + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("hostName", String.class), + new ObjectStreamField("address", int.class), + new ObjectStreamField("family", int.class), + }; + + private void writeObject (ObjectOutputStream s) throws + IOException { + if (getClass().getClassLoader() != null) { + throw new SecurityException ("invalid address type"); + } + PutField pf = s.putFields(); + pf.put("hostName", holder().getHostName()); + pf.put("address", holder().getAddress()); + pf.put("family", holder().getFamily()); + s.writeFields(); + s.flush(); } } diff --git a/jdk/src/share/classes/java/net/InetSocketAddress.java b/jdk/src/share/classes/java/net/InetSocketAddress.java index d4322e9b427..4ad95043470 100644 --- a/jdk/src/share/classes/java/net/InetSocketAddress.java +++ b/jdk/src/share/classes/java/net/InetSocketAddress.java @@ -87,8 +87,8 @@ public class InetSocketAddress if (hostname != null) return hostname; if (addr != null) { - if (addr.hostName != null) - return addr.hostName; + if (addr.holder().getHostName() != null) + return addr.holder().getHostName(); else return addr.getHostAddress(); } diff --git a/jdk/src/share/native/java/net/InetAddress.c b/jdk/src/share/native/java/net/InetAddress.c index 27a4a93d4d6..31115739b7e 100644 --- a/jdk/src/share/native/java/net/InetAddress.c +++ b/jdk/src/share/native/java/net/InetAddress.c @@ -33,8 +33,11 @@ */ jclass ia_class; -jfieldID ia_addressID; -jfieldID ia_familyID; +jclass iac_class; +jfieldID ia_holderID; +jfieldID iac_addressID; +jfieldID iac_familyID; +jfieldID iac_hostNameID; jfieldID ia_preferIPv6AddressID; /* @@ -48,10 +51,18 @@ Java_java_net_InetAddress_init(JNIEnv *env, jclass cls) { CHECK_NULL(c); ia_class = (*env)->NewGlobalRef(env, c); CHECK_NULL(ia_class); - ia_addressID = (*env)->GetFieldID(env, ia_class, "address", "I"); - CHECK_NULL(ia_addressID); - ia_familyID = (*env)->GetFieldID(env, ia_class, "family", "I"); - CHECK_NULL(ia_familyID); + c = (*env)->FindClass(env,"java/net/InetAddress$InetAddressHolder"); + CHECK_NULL(c); + iac_class = (*env)->NewGlobalRef(env, c); + ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;"); + CHECK_NULL(ia_holderID); ia_preferIPv6AddressID = (*env)->GetStaticFieldID(env, ia_class, "preferIPv6Address", "Z"); CHECK_NULL(ia_preferIPv6AddressID); + + iac_addressID = (*env)->GetFieldID(env, iac_class, "address", "I"); + CHECK_NULL(iac_addressID); + iac_familyID = (*env)->GetFieldID(env, iac_class, "family", "I"); + CHECK_NULL(iac_familyID); + iac_hostNameID = (*env)->GetFieldID(env, iac_class, "hostName", "Ljava/lang/String;"); + CHECK_NULL(iac_hostNameID); } diff --git a/jdk/src/share/native/java/net/net_util.c b/jdk/src/share/native/java/net/net_util.c index d7a6de2073d..5d15f9d9b0e 100644 --- a/jdk/src/share/native/java/net/net_util.c +++ b/jdk/src/share/native/java/net/net_util.c @@ -84,6 +84,58 @@ void init(JNIEnv *env) { } } +/* The address, and family fields used to be in InetAddress + * but are now in an implementation object. So, there is an extra + * level of indirection to access them now. + */ + +extern jclass iac_class; +extern jfieldID ia_holderID; +extern jfieldID iac_addressID; +extern jfieldID iac_familyID; + +void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetIntField(env, holder, iac_addressID, address); +} + +void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetIntField(env, holder, iac_familyID, family); +} + +void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetObjectField(env, holder, iac_hostNameID, host); +} + +int getInetAddress_addr(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetIntField(env, holder, iac_addressID); +} + +int getInetAddress_family(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetIntField(env, holder, iac_familyID); +} + +jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetObjectField(env, holder, iac_hostNameID); +} + JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; @@ -110,8 +162,8 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); CHECK_NULL_RETURN(iaObj, NULL); address = NET_IPv4MappedToIPv4(caddr); - (*env)->SetIntField(env, iaObj, ia_addressID, address); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv4); + setInetAddress_addr(env, iaObj, address); + setInetAddress_family(env, iaObj, IPv4); } else { static jclass inet6Cls = 0; jint scope; @@ -131,7 +183,7 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv6); + setInetAddress_family(env, iaObj, IPv6); scope = getScopeID(him); (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); if (scope > 0) @@ -153,9 +205,8 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { } iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); CHECK_NULL_RETURN(iaObj, NULL); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv4); - (*env)->SetIntField(env, iaObj, ia_addressID, - ntohl(him4->sin_addr.s_addr)); + setInetAddress_family(env, iaObj, IPv4); + setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); *port = ntohs(him4->sin_port); } return iaObj; @@ -167,8 +218,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) jint family = AF_INET; #ifdef AF_INET6 - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? - AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; if (him->sa_family == AF_INET6) { #ifdef WIN32 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; @@ -183,7 +233,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) return JNI_FALSE; } addrNew = NET_IPv4MappedToIPv4(caddrNew); - addrCur = (*env)->GetIntField(env, iaObj, ia_addressID); + addrCur = getInetAddress_addr(env, iaObj); if (addrNew == addrCur) { return JNI_TRUE; } else { @@ -215,7 +265,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) return JNI_FALSE; } addrNew = ntohl(him4->sin_addr.s_addr); - addrCur = (*env)->GetIntField(env, iaObj, ia_addressID); + addrCur = getInetAddress_addr(env, iaObj); if (addrNew == addrCur) { return JNI_TRUE; } else { diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h index 6f040fa3ff6..0fd5b6c427f 100644 --- a/jdk/src/share/native/java/net/net_util.h +++ b/jdk/src/share/native/java/net/net_util.h @@ -53,10 +53,18 @@ * i.e. psi_timeoutID is PlainSocketImpl's timeout field's ID. */ extern jclass ia_class; -extern jfieldID ia_addressID; -extern jfieldID ia_familyID; +extern jfieldID iac_addressID; +extern jfieldID iac_familyID; +extern jfieldID iac_hostNameID; extern jfieldID ia_preferIPv6AddressID; +extern void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address); +extern void setInetAddress_family(JNIEnv *env, jobject iaObj, int family); +extern void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject h); +extern int getInetAddress_addr(JNIEnv *env, jobject iaObj); +extern int getInetAddress_family(JNIEnv *env, jobject iaObj); +extern jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj); + extern jclass ia4_class; extern jmethodID ia4_ctrID; diff --git a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c index 71acfcdb5b1..3c75f781e25 100644 --- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c +++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c @@ -135,9 +135,6 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -238,9 +235,8 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, name); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, name); (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj); i++; iterator = iterator->ai_next; @@ -372,9 +368,6 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { static jclass ni_iacls; static jclass ni_ia4cls; static jmethodID ni_ia4ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static int initialized = 0; /* @@ -403,9 +396,6 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -499,9 +489,8 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, i++, iaObj); iterator = iterator->ai_next; } diff --git a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c index 6b7e233d940..4fc64867f8b 100644 --- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c +++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c @@ -120,9 +120,6 @@ static jclass ni_ia4cls; static jclass ni_ia6cls; static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static int initialized = 0; @@ -159,9 +156,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); initialized = 1; } @@ -315,9 +309,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); inetIndex++; } else if (iterator->ai_family == AF_INET6) { @@ -342,7 +335,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); } (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); inet6Index++; } diff --git a/jdk/src/solaris/native/java/net/NetworkInterface.c b/jdk/src/solaris/native/java/net/NetworkInterface.c index 55c131cf339..af979b03fd9 100644 --- a/jdk/src/solaris/native/java/net/NetworkInterface.c +++ b/jdk/src/solaris/native/java/net/NetworkInterface.c @@ -118,8 +118,6 @@ static jclass ni_ibcls; static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; static jmethodID ni_ibctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static jfieldID ni_ibaddressID; static jfieldID ni_ib4broadcastID; @@ -195,8 +193,6 @@ Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) { ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "", "()V"); ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;"); ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;"); @@ -300,7 +296,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 netif *ifs, *curr; #ifdef AF_INET6 - int family = ( (*env)->GetIntField(env, iaObj, ni_iafamilyID) == IPv4 ) ? AF_INET : AF_INET6; + int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6; #else int family = AF_INET; #endif @@ -325,7 +321,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 if (family == addrP->family) { if (family == AF_INET) { int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr); - int address2 = (*env)->GetIntField(env, iaObj, ni_iaaddressID); + int address2 = getInetAddress_addr(env, iaObj); if (address1 == address2) { match = JNI_TRUE; @@ -651,7 +647,7 @@ jobject createNetworkInterface(JNIEnv *env, netif *ifs) { if (addrP->family == AF_INET) { iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); if (iaObj) { - (*env)->SetIntField(env, iaObj, ni_iaaddressID, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); } ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj) { @@ -660,8 +656,7 @@ jobject createNetworkInterface(JNIEnv *env, netif *ifs) { jobject ia2Obj = NULL; ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); if (ia2Obj) { - (*env)->SetIntField(env, ia2Obj, ni_iaaddressID, - htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); } diff --git a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c index e5607af9132..27c78f23a42 100644 --- a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c +++ b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c @@ -552,14 +552,13 @@ Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); #ifdef AF_INET6 - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? - AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; #else family = AF_INET; #endif if (family == AF_INET) { /* this API can't handle IPV6 addresses */ - int address = (*env)->GetIntField(env, iaObj, ia_addressID); - (*env)->SetIntField(env, addressObj, ia_addressID, address); + int address = getInetAddress_addr(env, iaObj); + setInetAddress_addr(env, addressObj, address); } return port; } @@ -1028,23 +1027,18 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env, */ static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) { static jfieldID ni_addrsID; - static jfieldID ia_addressID; struct in_addr in; jobjectArray addrArray; jsize len; jobject addr; int i; - if (ni_addrsID == NULL || ia_addressID == NULL) { + if (ni_addrsID == NULL ) { jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); CHECK_NULL(c); ni_addrsID = (*env)->GetFieldID(env, c, "addrs", "[Ljava/net/InetAddress;"); CHECK_NULL(ni_addrsID); - c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); } addrArray = (*env)->GetObjectField(env, value, ni_addrsID); @@ -1065,8 +1059,8 @@ static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject val */ for (i = 0; i < len; i++) { addr = (*env)->GetObjectArrayElement(env, addrArray, i); - if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) { - in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + if (getInetAddress_family(env, addr) == IPv4) { + in.s_addr = htonl(getInetAddress_addr(env, addr)); break; } } @@ -1116,17 +1110,9 @@ static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject val * Throw exception if failed. */ static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) { - static jfieldID ia_addressID; struct in_addr in; - if (ia_addressID == NULL) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); - } - - in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) ); + in.s_addr = htonl( getInetAddress_addr(env, value) ); if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&in, sizeof(in)) < 0) { @@ -1456,7 +1442,6 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { if (isIPV4) { static jclass inet4_class; static jmethodID inet4_ctrID; - static jfieldID inet4_addrID; static jclass ni_class; static jmethodID ni_ctrID; @@ -1486,15 +1471,13 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { CHECK_NULL_RETURN(c, NULL); inet4_ctrID = (*env)->GetMethodID(env, c, "", "()V"); CHECK_NULL_RETURN(inet4_ctrID, NULL); - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN(inet4_addrID, NULL); inet4_class = (*env)->NewGlobalRef(env, c); CHECK_NULL_RETURN(inet4_class, NULL); } addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); CHECK_NULL_RETURN(addr, NULL); - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr)); + setInetAddress_addr(env, addr, ntohl(in.s_addr)); /* * For IP_MULTICAST_IF return InetAddress @@ -1942,7 +1925,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, ipv6_join_leave = ipv6_available(); #ifdef __linux__ - if ((*env)->GetIntField(env, iaObj, ia_familyID) == IPv4) { + if (getInetAddress_family(env, iaObj) == IPv4) { ipv6_join_leave = JNI_FALSE; } #endif @@ -1989,7 +1972,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, CHECK_NULL(ni_indexID); } - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname.imr_address.s_addr = 0; mname.imr_ifindex = (*env)->GetIntField(env, niObj, ni_indexID); mname_len = sizeof(struct ip_mreqn); @@ -2007,11 +1990,11 @@ static void mcast_join_leave(JNIEnv *env, jobject this, } addr = (*env)->GetObjectArrayElement(env, addrArray, 0); - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); #ifdef __linux__ - mname.imr_address.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + mname.imr_address.s_addr = htonl(getInetAddress_addr(env, addr)); #else - mname.imr_interface.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + mname.imr_interface.s_addr = htonl(getInetAddress_addr(env, addr)); #endif mname_len = sizeof(struct ip_mreq); } @@ -2046,7 +2029,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, return; } - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname.imr_address.s_addr = 0 ; mname.imr_ifindex = index; mname_len = sizeof(struct ip_mreqn); @@ -2068,7 +2051,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, #else mname.imr_interface.s_addr = in.s_addr; #endif - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname_len = sizeof(struct ip_mreq); } } @@ -2133,10 +2116,10 @@ static void mcast_join_leave(JNIEnv *env, jobject this, jbyte caddr[16]; jint family; jint address; - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; if (family == AF_INET) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); caddr[10] = 0xff; caddr[11] = 0xff; diff --git a/jdk/src/solaris/native/java/net/net_util_md.c b/jdk/src/solaris/native/java/net/net_util_md.c index c700cfd0b75..004b6aa5d92 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.c +++ b/jdk/src/solaris/native/java/net/net_util_md.c @@ -777,7 +777,7 @@ JNIEXPORT int JNICALL NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress) { jint family; - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); #ifdef AF_INET6 /* needs work. 1. family 2. clean up him6 etc deallocate memory */ if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) { @@ -789,7 +789,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr if (family == IPv4) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { /* we would always prefer IPv6 wildcard address caddr[10] = 0xff; @@ -898,7 +898,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr return -1; } memset((char *) him4, 0, sizeof(struct sockaddr_in)); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); him4->sin_port = htons((short) port); him4->sin_addr.s_addr = (uint32_t) htonl(address); him4->sin_family = AF_INET; diff --git a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java index 5fa9dbf285b..2d89d601869 100644 --- a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java +++ b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java @@ -102,7 +102,7 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl if ((fd != null && fd1 != null) && !connected) { return anyLocalBoundAddr; } - int family = connectedAddress == null ? -1 : connectedAddress.family; + int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily(); return socketLocalAddress(family); } else return super.getOption(optID); diff --git a/jdk/src/windows/native/java/net/Inet4AddressImpl.c b/jdk/src/windows/native/java/net/Inet4AddressImpl.c index 4bbcfc782b3..d7cf8e5a395 100644 --- a/jdk/src/windows/native/java/net/Inet4AddressImpl.c +++ b/jdk/src/windows/native/java/net/Inet4AddressImpl.c @@ -114,9 +114,6 @@ Java_java_net_Inet4AddressImpl_getLocalHostName (JNIEnv *env, jobject this) { static jclass ni_iacls; static jclass ni_ia4cls; static jmethodID ni_ia4ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static int initialized = 0; /* @@ -149,9 +146,6 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -208,8 +202,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(address)); + setInetAddress_addr(env, iaObj, ntohl(address)); (*env)->SetObjectArrayElement(env, ret, 0, iaObj); JNU_ReleaseStringPlatformChars(env, host, hostname); return ret; @@ -242,9 +235,8 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl((*addrp)->s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, i, iaObj); addrp++; i++; diff --git a/jdk/src/windows/native/java/net/Inet6AddressImpl.c b/jdk/src/windows/native/java/net/Inet6AddressImpl.c index 20b42b18508..6f46d7eb642 100644 --- a/jdk/src/windows/native/java/net/Inet6AddressImpl.c +++ b/jdk/src/windows/native/java/net/Inet6AddressImpl.c @@ -77,9 +77,6 @@ static jclass ni_ia4cls; static jclass ni_ia6cls; static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static int initialized = 0; @@ -104,9 +101,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); initialized = 1; } @@ -243,9 +237,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); inetIndex ++; } else if (iterator->ai_family == AF_INET6) { @@ -269,7 +262,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); } (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); inet6Index ++; } diff --git a/jdk/src/windows/native/java/net/NetworkInterface.c b/jdk/src/windows/native/java/net/NetworkInterface.c index 6d144659235..429dfee9bdb 100644 --- a/jdk/src/windows/native/java/net/NetworkInterface.c +++ b/jdk/src/windows/native/java/net/NetworkInterface.c @@ -66,7 +66,6 @@ jfieldID ni_nameID; /* NetworkInterface.name */ jfieldID ni_displayNameID; /* NetworkInterface.displayName */ jfieldID ni_childsID; /* NetworkInterface.childs */ jclass ni_iacls; /* InetAddress */ -jfieldID ni_iaAddr; /* InetAddress.address */ jclass ni_ia4cls; /* Inet4Address */ jmethodID ni_ia4Ctor; /* Inet4Address() */ @@ -480,7 +479,6 @@ Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) ni_iacls = (*env)->FindClass(env, "java/net/InetAddress"); ni_iacls = (*env)->NewGlobalRef(env, ni_iacls); - ni_iaAddr = (*env)->GetFieldID(env, ni_iacls, "address", "I"); ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); @@ -568,7 +566,7 @@ jobject createNetworkInterface } /* default ctor will set family to AF_INET */ - (*env)->SetIntField(env, iaObj, ni_iaAddr, ntohl(addrs->addr.him4.sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, ntohl(addrs->addr.him4.sin_addr.s_addr)); if (addrs->mask != -1) { ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj == NULL) { @@ -581,8 +579,7 @@ jobject createNetworkInterface free_netaddr(netaddrP); return NULL; } - (*env)->SetIntField(env, ia2Obj, ni_iaAddr, - ntohl(addrs->brdcast.him4.sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.him4.sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); @@ -736,7 +733,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 (JNIEnv *env, jclass cls, jobject iaObj) { netif *ifList, *curr; - jint addr = (*env)->GetIntField(env, iaObj, ni_iaAddr); + jint addr = getInetAddress_addr(env, iaObj); jobject netifObj = NULL; // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack diff --git a/jdk/src/windows/native/java/net/NetworkInterface.h b/jdk/src/windows/native/java/net/NetworkInterface.h index 22744c1eb6c..a73c62c66b3 100644 --- a/jdk/src/windows/native/java/net/NetworkInterface.h +++ b/jdk/src/windows/native/java/net/NetworkInterface.h @@ -71,7 +71,6 @@ extern jfieldID ni_displayNameID; /* NetworkInterface.displayName */ extern jfieldID ni_childsID; /* NetworkInterface.childs */ extern jclass ni_iacls; /* InetAddress */ -extern jfieldID ni_iaAddr; /* InetAddress.address */ extern jclass ni_ia4cls; /* Inet4Address */ extern jmethodID ni_ia4Ctor; /* Inet4Address() */ diff --git a/jdk/src/windows/native/java/net/NetworkInterface_winXP.c b/jdk/src/windows/native/java/net/NetworkInterface_winXP.c index afc31abcd5f..fbe744c6fe2 100644 --- a/jdk/src/windows/native/java/net/NetworkInterface_winXP.c +++ b/jdk/src/windows/native/java/net/NetworkInterface_winXP.c @@ -33,6 +33,7 @@ #include "jni_util.h" #include "NetworkInterface.h" +#include "net_util.h" /* * Windows implementation of the java.net.NetworkInterface native methods. @@ -477,7 +478,7 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs) } /* default ctor will set family to AF_INET */ - (*env)->SetIntField(env, iaObj, ni_iaAddr, ntohl(addrs->addr.him4.sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, ntohl(addrs->addr.him4.sin_addr.s_addr)); ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj == NULL) { @@ -490,8 +491,7 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs) free_netaddr(netaddrP); return NULL; } - (*env)->SetIntField(env, ia2Obj, ni_iaAddr, - ntohl(addrs->brdcast.him4.sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.him4.sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); diff --git a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c index ce6bfbd8c57..e81f408b3c4 100644 --- a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c +++ b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c @@ -432,7 +432,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, int lcladdrlen; int address; - family = (*env)->GetIntField(env, addressObj, ia_familyID); + family = getInetAddress_family(env, addressObj); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); @@ -452,7 +452,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "argument address"); return; } else { - address = (*env)->GetIntField(env, addressObj, ia_addressID); + address = getInetAddress_addr(env, addressObj); } if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) { @@ -552,9 +552,9 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject thi return; } - addr = (*env)->GetIntField(env, address, ia_addressID); + addr = getInetAddress_addr(env, address); - family = (*env)->GetIntField(env, address, ia_familyID); + family = getInetAddress_family(env, address); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); @@ -670,7 +670,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this, return; } - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); if (family == IPv4) { fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); } else { @@ -714,7 +714,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this, if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6. * Check is not necessary on these OSes */ if (connected) { - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); } else { address = ntohl(rmtaddr.him4.sin_addr.s_addr); } @@ -823,7 +823,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, if (IS_NULL(addressObj)) { JNU_ThrowNullPointerException(env, "Null address in peek()"); } else { - address = (*env)->GetIntField(env, addressObj, ia_addressID); + address = getInetAddress_addr(env, addressObj); /* We only handle IPv4 for now. Will support IPv6 once its in the os */ family = AF_INET; } @@ -905,9 +905,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0); return 0; } - (*env)->SetIntField(env, addressObj, ia_addressID, - ntohl(remote_addr.sin_addr.s_addr)); - (*env)->SetIntField(env, addressObj, ia_familyID, IPv4); + setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr)); + setInetAddress_family(env, addressObj, IPv4); /* return port */ return ntohs(remote_addr.sin_port); @@ -1574,21 +1573,16 @@ static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iad { jobjectArray addrArray; static jfieldID ni_addrsID=0; - static jfieldID ia_familyID=0; jsize len; jobject addr; int i; - if (ni_addrsID == NULL || ia_familyID == NULL) { + if (ni_addrsID == NULL ) { jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); CHECK_NULL_RETURN (c, -1); ni_addrsID = (*env)->GetFieldID(env, c, "addrs", "[Ljava/net/InetAddress;"); CHECK_NULL_RETURN (ni_addrsID, -1); - c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL_RETURN (c, -1); - ia_familyID = (*env)->GetFieldID(env, c, "family", "I"); - CHECK_NULL_RETURN (ia_familyID, -1); } addrArray = (*env)->GetObjectField(env, nif, ni_addrsID); @@ -1606,7 +1600,7 @@ static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iad for (i=0; iGetObjectArrayElement(env, addrArray, i); - fam = (*env)->GetIntField(env, addr, ia_familyID); + fam = getInetAddress_family(env, addr); if (fam == family) { *iaddr = addr; return 0; @@ -1618,20 +1612,13 @@ static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iad static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr) { jobject addr; - static jfieldID ia_addressID; int ret = getInetAddrFromIf (env, IPv4, nif, &addr); if (ret == -1) { return -1; } - if (ia_addressID == 0) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL_RETURN (c, -1); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN (ia_addressID, -1); - } - iaddr->s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + iaddr->s_addr = htonl(getInetAddress_addr(env, addr)); return 0; } @@ -1706,17 +1693,9 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, } opt = java_net_SocketOptions_IP_MULTICAST_IF2; } else { - static jfieldID ia_addressID; struct in_addr in; - if (ia_addressID == NULL) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); - } - - in.s_addr = htonl((*env)->GetIntField(env, value, ia_addressID)); + in.s_addr = htonl(getInetAddress_addr(env, value)); if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&in, sizeof(in)) < 0) { @@ -1945,7 +1924,6 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o if (isIPV4) { static jclass inet4_class; static jmethodID inet4_ctrID; - static jfieldID inet4_addrID; static jclass ni_class; static jmethodID ni_ctrID; @@ -1975,15 +1953,13 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o CHECK_NULL_RETURN(c, NULL); inet4_ctrID = (*env)->GetMethodID(env, c, "", "()V"); CHECK_NULL_RETURN(inet4_ctrID, NULL); - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN(inet4_addrID, NULL); inet4_class = (*env)->NewGlobalRef(env, c); CHECK_NULL_RETURN(inet4_class, NULL); } addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); CHECK_NULL_RETURN(addr, NULL); - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr)); + setInetAddress_addr(env, addr, ntohl(in.s_addr)); /* * For IP_MULTICAST_IF return InetAddress diff --git a/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c b/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c index 4b34384ab1f..73a799f6055 100644 --- a/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c +++ b/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c @@ -411,7 +411,7 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, fdObj = (*env)->GetObjectField(env, this, psi_fdID); fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -724,9 +724,8 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, return; } - (*env)->SetIntField(env, socketAddressObj, ia_addressID, - ntohl(him.him4.sin_addr.s_addr)); - (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv4); + setInetAddress_addr(env, socketAddressObj, ntohl(him.him4.sin_addr.s_addr)); + setInetAddress_family(env, socketAddressObj, IPv4); (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); } else { jbyteArray addr; @@ -754,7 +753,7 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, } addr = (*env)->GetObjectField (env, socketAddressObj, ia6_ipaddressID); (*env)->SetByteArrayRegion (env, addr, 0, 16, (const char *)&him.him6.sin6_addr); - (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv6); + setInetAddress_family(env, socketAddressObj, IPv6); scope = him.him6.sin6_scope_id; (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, scope); if(scope>0) { diff --git a/jdk/src/windows/native/java/net/net_util_md.c b/jdk/src/windows/native/java/net/net_util_md.c index c0c44d74eb7..99629ba85ac 100644 --- a/jdk/src/windows/native/java/net/net_util_md.c +++ b/jdk/src/windows/native/java/net/net_util_md.c @@ -804,7 +804,7 @@ JNIEXPORT int JNICALL NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress) { jint family, iafam; - iafam = (*env)->GetIntField(env, iaObj, ia_familyID); + iafam = getInetAddress_family(env, iaObj); family = (iafam == IPv4)? AF_INET : AF_INET6; if (ipv6_available() && !(family == AF_INET && v4MappedAddress == JNI_FALSE)) { struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; @@ -815,7 +815,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr if (family == AF_INET) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { /* we would always prefer IPv6 wildcard address caddr[10] = 0xff; @@ -854,7 +854,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr return -1; } memset((char *) him4, 0, sizeof(struct sockaddr_in)); - address = (int)(*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); him4->sin_port = htons((short) port); him4->sin_addr.s_addr = (u_long) htonl(address); him4->sin_family = AF_INET; From 009c674511cb17c1aa21c7148cfc2b70759a8a3a Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Tue, 26 Feb 2013 11:12:40 -0800 Subject: [PATCH 04/36] 8000897: VM crash in CompileBroker Fixed to use the corresponding digest length when generating output. Reviewed-by: mullan --- jdk/src/share/classes/sun/security/provider/SHA2.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/sun/security/provider/SHA2.java b/jdk/src/share/classes/sun/security/provider/SHA2.java index 54f34545918..23007c96527 100644 --- a/jdk/src/share/classes/sun/security/provider/SHA2.java +++ b/jdk/src/share/classes/sun/security/provider/SHA2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -101,7 +101,7 @@ abstract class SHA2 extends DigestBase { i2bBig4((int)bitsProcessed, buffer, 60); implCompress(buffer, 0); - i2bBig(state, 0, out, ofs, 32); + i2bBig(state, 0, out, ofs, engineGetDigestLength()); } /** From d4eb03976492c1781ba3033e5e13319d9e3f389f Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Wed, 27 Feb 2013 14:17:05 -0800 Subject: [PATCH 05/36] 8001040: Rework RMI model Reviewed-by: alanb, ahgross, coffeys, dmocek --- .../sun/rmi/server/MarshalInputStream.java | 14 ++- .../classPathCodebase/ClassPathCodebase.java | 3 +- .../java/rmi/registry/readTest/readTest.sh | 3 +- .../DownloadArrayClass.java | 4 + .../downloadArrayClass/security.policy | 2 + .../loadProxyClasses/LoadProxyClasses.java | 3 +- .../UseCodebaseOnlyDefault.java | 100 ++++++++++++++++++ jdk/test/java/rmi/testlibrary/RMID.java | 3 + 8 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java diff --git a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java index e24a8fb3fdb..4f67941a5d5 100644 --- a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java +++ b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java @@ -55,13 +55,19 @@ import java.rmi.server.RMIClassLoader; public class MarshalInputStream extends ObjectInputStream { /** - * value of "java.rmi.server.useCodebaseOnly" property, + * Value of "java.rmi.server.useCodebaseOnly" property, * as cached at class initialization time. + * + * The default value is true. That is, the value is true + * if the property is absent or is not equal to "false". + * The value is only false when the property is present + * and is equal to "false". */ private static final boolean useCodebaseOnlyProperty = - java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "java.rmi.server.useCodebaseOnly")).booleanValue(); + ! java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction( + "java.rmi.server.useCodebaseOnly", "true")) + .equalsIgnoreCase("false"); /** table to hold sun classes to which access is explicitly permitted */ protected static Map> permittedSunClasses diff --git a/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java b/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java index 99ac5f091a6..b4be7376298 100644 --- a/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java +++ b/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java @@ -31,7 +31,8 @@ * * @library ../../testlibrary * @build TestLibrary Dummy - * @run main/othervm/policy=security.policy ClassPathCodebase + * @run main/othervm/policy=security.policy + * -Djava.rmi.server.useCodebaseOnly=false ClassPathCodebase */ import java.io.*; diff --git a/jdk/test/java/rmi/registry/readTest/readTest.sh b/jdk/test/java/rmi/registry/readTest/readTest.sh index dad6847f304..bb37f65b4cc 100644 --- a/jdk/test/java/rmi/registry/readTest/readTest.sh +++ b/jdk/test/java/rmi/registry/readTest/readTest.sh @@ -61,7 +61,8 @@ RMIREG_OUT=rmi.out #start rmiregistry without any local classes on classpath cd rmi_tmp # NOTE: This RMI Registry port must match TestLibrary.READTEST_REGISTRY_PORT -${TESTJAVA}${FS}bin${FS}rmiregistry ${TESTTOOLVMOPTS} 64005 > ..${FS}${RMIREG_OUT} 2>&1 & +${TESTJAVA}${FS}bin${FS}rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false \ + ${TESTTOOLVMOPTS} 64005 > ..${FS}${RMIREG_OUT} 2>&1 & RMIREG_PID=$! # allow some time to start sleep 3 diff --git a/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java b/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java index 9df187ab3a3..c0a94697053 100644 --- a/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java +++ b/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java @@ -64,6 +64,10 @@ public class DownloadArrayClass TestLibrary.bomb(e); } + System.err.println("Setting codebase property to: " + remoteCodebase); + System.setProperty("java.rmi.server.codebase", + remoteCodebase.toString()); + /* * Load Foo from a non-RMI class loader so that it won't be already * loaded by an RMI class loader in this VM (for whatever that's diff --git a/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy b/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy index 706a3cdfcbc..ac4ce020733 100644 --- a/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy +++ b/jdk/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy @@ -7,6 +7,8 @@ grant codeBase "file:${java.home}/lib/ext/*" { }; grant { + permission java.util.PropertyPermission + "java.rmi.server.codebase", "read,write"; // permissions needed to move classes into separate codebase directories permission java.io.FilePermission diff --git a/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java b/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java index 6d29cb2468f..b5bfcac63f1 100644 --- a/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java +++ b/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java @@ -32,7 +32,8 @@ * @library ../../../testlibrary * @build TestLibrary FnnClass FnnUnmarshal NonpublicInterface * NonpublicInterface1 PublicInterface PublicInterface1 - * @run main/othervm/policy=security.policy LoadProxyClasses + * @run main/othervm/policy=security.policy + * -Djava.rmi.server.useCodebaseOnly=false LoadProxyClasses */ import java.rmi.server.RMIClassLoader; diff --git a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java new file mode 100644 index 00000000000..80dfd7d704a --- /dev/null +++ b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java @@ -0,0 +1,100 @@ +/* + * 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 8001040 + * @summary Tests proper parsing and defaulting of the + * "java.rmi.server.useCodebaseOnly" property. + * + * @run main/othervm UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=xyzzy UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=true UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=false UseCodebaseOnlyDefault false + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import sun.rmi.server.MarshalInputStream; + +/** + * usage: UseCodebaseOnlyDefault expected + * + * 'expected' is the expected value of useCodebaseOnly, which + * must be "true" or "false". + */ +public class UseCodebaseOnlyDefault { + static final String USAGE = "usage: UseCodebaseOnlyDefault boolean"; + static final String PROPNAME = "java.rmi.server.useCodebaseOnly"; + + /** + * Gets the actual useCodebaseOnly value by creating an instance + * of MarshalInputStream and reflecting on the useCodebaseOnly field. + */ + static boolean getActualValue() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("foo"); + oos.close(); + + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + MarshalInputStream mis = new MarshalInputStream(bais); + + Field f = MarshalInputStream.class.getDeclaredField("useCodebaseOnly"); + f.setAccessible(true); + return f.getBoolean(mis); + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new IllegalArgumentException(USAGE); + } + + boolean expected; + if (args[0].equals("true")) { + expected = true; + } else if (args[0].equals("false")) { + expected = false; + } else { + throw new IllegalArgumentException(USAGE); + } + System.out.println("expected = " + expected); + + String prop = System.getProperty(PROPNAME); + System.out.print("Property " + PROPNAME); + if (prop == null) { + System.out.println(" is not set"); + } else { + System.out.println(" = '" + prop + "'"); + } + + boolean actual = getActualValue(); + System.out.println("actual = " + actual); + + if (expected != actual) + throw new AssertionError("actual does not match expected value"); + } +} diff --git a/jdk/test/java/rmi/testlibrary/RMID.java b/jdk/test/java/rmi/testlibrary/RMID.java index 8b0f3e26bd4..f528b2058fe 100644 --- a/jdk/test/java/rmi/testlibrary/RMID.java +++ b/jdk/test/java/rmi/testlibrary/RMID.java @@ -108,6 +108,9 @@ public class RMID extends JavaVM { if (!TestParams.testClasses.equals("")) { args += " -C-Dtest.classes=" + TestParams.testClasses; } + + args += " -C-Djava.rmi.server.useCodebaseOnly=false "; + args += " " + getCodeCoverageArgs(); return args; } From e064f7ea781f8b6358e73f048701d7c746f6f788 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 14 Mar 2013 13:10:32 +0100 Subject: [PATCH 06/36] 8001322: Refactor deserialization Reviewed-by: mchung, skoivu, smarks --- .../classes/java/io/ObjectInputStream.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/jdk/src/share/classes/java/io/ObjectInputStream.java b/jdk/src/share/classes/java/io/ObjectInputStream.java index 0a530dd6db6..ca0400539f9 100644 --- a/jdk/src/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/share/classes/java/io/ObjectInputStream.java @@ -41,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import static java.io.ObjectStreamClass.processQueue; +import sun.reflect.misc.ReflectUtil; /** * An ObjectInputStream deserializes primitive data and objects previously @@ -1519,6 +1520,12 @@ public class ObjectInputStream } } + private boolean isCustomSubclass() { + // Return true if this class is a custom subclass of ObjectInputStream + return getClass().getClassLoader() + != ObjectInputStream.class.getClassLoader(); + } + /** * Reads in and returns class descriptor for a dynamic proxy class. Sets * passHandle to proxy class descriptor's assigned handle. If proxy class @@ -1548,6 +1555,15 @@ public class ObjectInputStream try { if ((cl = resolveProxyClass(ifaces)) == null) { resolveEx = new ClassNotFoundException("null class"); + } else if (!Proxy.isProxyClass(cl)) { + throw new InvalidClassException("Not a proxy"); + } else { + // ReflectUtil.checkProxyPackageAccess makes a test + // equivalent to isCustomSubclass so there's no need + // to condition this call to isCustomSubclass == true here. + ReflectUtil.checkProxyPackageAccess( + getClass().getClassLoader(), + cl.getInterfaces()); } } catch (ClassNotFoundException ex) { resolveEx = ex; @@ -1589,9 +1605,12 @@ public class ObjectInputStream Class cl = null; ClassNotFoundException resolveEx = null; bin.setBlockDataMode(true); + final boolean checksRequired = isCustomSubclass(); try { if ((cl = resolveClass(readDesc)) == null) { resolveEx = new ClassNotFoundException("null class"); + } else if (checksRequired) { + ReflectUtil.checkPackageAccess(cl); } } catch (ClassNotFoundException ex) { resolveEx = ex; From 1bb9122f6983ff0a4234c4d5d98eeb3d23187bde Mon Sep 17 00:00:00 2001 From: Darryl Mocek Date: Tue, 5 Feb 2013 16:38:25 -0800 Subject: [PATCH 07/36] 8001329: Augment RMI logging Reviewed-by: smarks, hawtin, alanb --- jdk/src/share/classes/java/rmi/server/LogStream.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/rmi/server/LogStream.java b/jdk/src/share/classes/java/rmi/server/LogStream.java index 625e841ce8f..60adea3d965 100644 --- a/jdk/src/share/classes/java/rmi/server/LogStream.java +++ b/jdk/src/share/classes/java/rmi/server/LogStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -120,6 +120,13 @@ public class LogStream extends PrintStream { */ @Deprecated public static synchronized void setDefaultStream(PrintStream newDefault) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + sm.checkPermission( + new java.util.logging.LoggingPermission("control", null)); + } + defaultStream = newDefault; } From 3b34f3b493b277f5442a812fb7a1cdf218a2bc35 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 20 Dec 2012 13:40:27 +0000 Subject: [PATCH 08/36] 8003335: Better handling of Finalizer thread Reviewed-by: alanb, ahgross --- .../share/classes/java/lang/ref/Finalizer.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/java/lang/ref/Finalizer.java b/jdk/src/share/classes/java/lang/ref/Finalizer.java index 4e148c28fdc..cdba65e4820 100644 --- a/jdk/src/share/classes/java/lang/ref/Finalizer.java +++ b/jdk/src/share/classes/java/lang/ref/Finalizer.java @@ -38,9 +38,9 @@ final class Finalizer extends FinalReference { /* Package-private; must be in */ static native void invokeFinalizeMethod(Object o) throws Throwable; - static private ReferenceQueue queue = new ReferenceQueue(); - static private Finalizer unfinalized = null; - static private Object lock = new Object(); + private static ReferenceQueue queue = new ReferenceQueue(); + private static Finalizer unfinalized = null; + private static final Object lock = new Object(); private Finalizer next = null, @@ -142,7 +142,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in /* Called by Runtime.runFinalization() */ static void runFinalization() { forkSecondaryFinalizer(new Runnable() { + private volatile boolean running; public void run() { + if (running) + return; + running = true; for (;;) { Finalizer f = (Finalizer)queue.poll(); if (f == null) break; @@ -155,7 +159,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in /* Invoked by java.lang.Shutdown */ static void runAllFinalizers() { forkSecondaryFinalizer(new Runnable() { + private volatile boolean running; public void run() { + if (running) + return; + running = true; for (;;) { Finalizer f; synchronized (lock) { @@ -168,10 +176,14 @@ final class Finalizer extends FinalReference { /* Package-private; must be in } private static class FinalizerThread extends Thread { + private volatile boolean running; FinalizerThread(ThreadGroup g) { super(g, "Finalizer"); } public void run() { + if (running) + return; + running = true; for (;;) { try { Finalizer f = (Finalizer)queue.remove(); From 0c8b65724ac9ef86c2f3a585010ebc8506afd55d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 15 Feb 2013 13:49:38 +0400 Subject: [PATCH 09/36] 8004261: Improve input validation Reviewed-by: art, mschoene, amenkov --- .../sun/media/sound/AbstractMidiDevice.java | 25 ++++++++++--------- .../com/sun/media/sound/FastShortMessage.java | 2 +- .../com/sun/media/sound/FastSysexMessage.java | 2 +- .../com/sun/media/sound/MidiOutDevice.java | 16 +++++++----- .../sun/media/sound/RealTimeSequencer.java | 2 +- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java b/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java index a0f06c3ed07..dacefba8f49 100644 --- a/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java +++ b/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java @@ -56,7 +56,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice // from simultaneous creation and destruction // reduces possibility of deadlock, compared to // synchronizing to the class instance - private Object traRecLock = new Object(); + private final Object traRecLock = new Object(); // DEVICE ATTRIBUTES @@ -474,7 +474,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice This is necessary for Receivers retrieved via MidiSystem.getReceiver() (which opens the device implicitely). */ - protected abstract class AbstractReceiver implements MidiDeviceReceiver { + abstract class AbstractReceiver implements MidiDeviceReceiver { private boolean open = true; @@ -483,24 +483,24 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice Receiver. Therefore, subclasses should not override this method. Instead, they should implement implSend(). */ - public synchronized void send(MidiMessage message, long timeStamp) { - if (open) { - implSend(message, timeStamp); - } else { + @Override + public final synchronized void send(final MidiMessage message, + final long timeStamp) { + if (!open) { throw new IllegalStateException("Receiver is not open"); } + implSend(message, timeStamp); } - - protected abstract void implSend(MidiMessage message, long timeStamp); - + abstract void implSend(MidiMessage message, long timeStamp); /** Close the Receiver. * Here, the call to the magic method closeInternal() takes place. * Therefore, subclasses that override this method must call * 'super.close()'. */ - public void close() { + @Override + public final void close() { open = false; synchronized (AbstractMidiDevice.this.traRecLock) { AbstractMidiDevice.this.getReceiverList().remove(this); @@ -508,11 +508,12 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice AbstractMidiDevice.this.closeInternal(this); } - public MidiDevice getMidiDevice() { + @Override + public final MidiDevice getMidiDevice() { return AbstractMidiDevice.this; } - protected boolean isOpen() { + final boolean isOpen() { return open; } diff --git a/jdk/src/share/classes/com/sun/media/sound/FastShortMessage.java b/jdk/src/share/classes/com/sun/media/sound/FastShortMessage.java index b4ca9c82ce8..39f85da154c 100644 --- a/jdk/src/share/classes/com/sun/media/sound/FastShortMessage.java +++ b/jdk/src/share/classes/com/sun/media/sound/FastShortMessage.java @@ -32,7 +32,7 @@ import javax.sound.midi.*; * * @author Florian Bomers */ -class FastShortMessage extends ShortMessage { +final class FastShortMessage extends ShortMessage { private int packedMsg; public FastShortMessage(int packedMsg) throws InvalidMidiDataException { diff --git a/jdk/src/share/classes/com/sun/media/sound/FastSysexMessage.java b/jdk/src/share/classes/com/sun/media/sound/FastSysexMessage.java index d00ec68aa63..7f2e2def2ee 100644 --- a/jdk/src/share/classes/com/sun/media/sound/FastSysexMessage.java +++ b/jdk/src/share/classes/com/sun/media/sound/FastSysexMessage.java @@ -32,7 +32,7 @@ import javax.sound.midi.*; * * @author Florian Bomers */ -class FastSysexMessage extends SysexMessage { +final class FastSysexMessage extends SysexMessage { FastSysexMessage(byte[] data) throws InvalidMidiDataException { super(data); diff --git a/jdk/src/share/classes/com/sun/media/sound/MidiOutDevice.java b/jdk/src/share/classes/com/sun/media/sound/MidiOutDevice.java index e1ada68a80e..a9193005e5f 100644 --- a/jdk/src/share/classes/com/sun/media/sound/MidiOutDevice.java +++ b/jdk/src/share/classes/com/sun/media/sound/MidiOutDevice.java @@ -103,9 +103,9 @@ class MidiOutDevice extends AbstractMidiDevice { class MidiOutReceiver extends AbstractReceiver { - protected void implSend(MidiMessage message, long timeStamp) { - int length = message.getLength(); - int status = message.getStatus(); + void implSend(final MidiMessage message, final long timeStamp) { + final int length = message.getLength(); + final int status = message.getStatus(); if (length <= 3 && status != 0xF0 && status != 0xF7) { int packedMsg; if (message instanceof ShortMessage) { @@ -140,11 +140,15 @@ class MidiOutDevice extends AbstractMidiDevice { } nSendShortMessage(id, packedMsg, timeStamp); } else { + final byte[] data; if (message instanceof FastSysexMessage) { - nSendLongMessage(id, ((FastSysexMessage) message).getReadOnlyMessage(), - length, timeStamp); + data = ((FastSysexMessage) message).getReadOnlyMessage(); } else { - nSendLongMessage(id, message.getMessage(), length, timeStamp); + data = message.getMessage(); + } + final int dataLength = Math.min(length, data.length); + if (dataLength > 0) { + nSendLongMessage(id, data, dataLength, timeStamp); } } } diff --git a/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java b/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java index 8b4ae6e7ad1..93b7b0612eb 100644 --- a/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java +++ b/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java @@ -1026,7 +1026,7 @@ class RealTimeSequencer extends AbstractMidiDevice implements Sequencer, AutoCon class SequencerReceiver extends AbstractReceiver { - protected void implSend(MidiMessage message, long timeStamp) { + void implSend(MidiMessage message, long timeStamp) { if (recording) { long tickPos = 0; From 3c0be232bebc9b31b903a2b3bc58a5aefa89a79c Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Fri, 22 Feb 2013 17:49:15 +0400 Subject: [PATCH 10/36] 8005942: (process) Improved Runtime.exec Reviewed-by: alanb, ahgross --- .../classes/java/lang/ProcessBuilder.java | 16 ++- .../classes/java/lang/ProcessImpl.java | 125 +++++++++++++++--- 2 files changed, 118 insertions(+), 23 deletions(-) diff --git a/jdk/src/share/classes/java/lang/ProcessBuilder.java b/jdk/src/share/classes/java/lang/ProcessBuilder.java index 4af24b6430b..64f56d77829 100644 --- a/jdk/src/share/classes/java/lang/ProcessBuilder.java +++ b/jdk/src/share/classes/java/lang/ProcessBuilder.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; +import java.security.AccessControlException; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @@ -1024,13 +1025,24 @@ public final class ProcessBuilder redirects, redirectErrorStream); } catch (IOException e) { + String exceptionInfo = ": " + e.getMessage(); + Throwable cause = e; + if (security != null) { + // Can not disclose the fail reason for read-protected files. + try { + security.checkRead(prog); + } catch (AccessControlException ace) { + exceptionInfo = ""; + cause = ace; + } + } // It's much easier for us to create a high-quality error // message than the low-level C code which found the problem. throw new IOException( "Cannot run program \"" + prog + "\"" + (dir == null ? "" : " (in directory \"" + dir + "\")") - + ": " + e.getMessage(), - e); + + exceptionInfo, + cause); } } } diff --git a/jdk/src/windows/classes/java/lang/ProcessImpl.java b/jdk/src/windows/classes/java/lang/ProcessImpl.java index d4cdc6c7eec..87c89bb11e6 100644 --- a/jdk/src/windows/classes/java/lang/ProcessImpl.java +++ b/jdk/src/windows/classes/java/lang/ProcessImpl.java @@ -145,6 +145,88 @@ final class ProcessImpl extends Process { } + // We guarantee the only command file execution for implicit [cmd.exe] run. + // http://technet.microsoft.com/en-us/library/bb490954.aspx + private static final char CMD_BAT_ESCAPE[] = {' ', '\t', '<', '>', '&', '|', '^'}; + private static final char WIN32_EXECUTABLE_ESCAPE[] = {' ', '\t', '<', '>'}; + + private static boolean isQuoted(boolean noQuotesInside, String arg, + String errorMessage) { + int lastPos = arg.length() - 1; + if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { + // The argument has already been quoted. + if (noQuotesInside) { + if (arg.indexOf('"', 1) != lastPos) { + // There is ["] inside. + throw new IllegalArgumentException(errorMessage); + } + } + return true; + } + if (noQuotesInside) { + if (arg.indexOf('"') >= 0) { + // There is ["] inside. + throw new IllegalArgumentException(errorMessage); + } + } + return false; + } + + private static boolean needsEscaping(boolean isCmdFile, String arg) { + // Switch off MS heuristic for internal ["]. + // Please, use the explicit [cmd.exe] call + // if you need the internal ["]. + // Example: "cmd.exe", "/C", "Extended_MS_Syntax" + + // For [.exe] or [.com] file the unpaired/internal ["] + // in the argument is not a problem. + boolean argIsQuoted = isQuoted(isCmdFile, arg, + "Argument has embedded quote, use the explicit CMD.EXE call."); + + if (!argIsQuoted) { + char testEscape[] = isCmdFile + ? CMD_BAT_ESCAPE + : WIN32_EXECUTABLE_ESCAPE; + for (int i = 0; i < testEscape.length; ++i) { + if (arg.indexOf(testEscape[i]) >= 0) { + return true; + } + } + } + return false; + } + + private static String getExecutablePath(String path) + throws IOException + { + boolean pathIsQuoted = isQuoted(true, path, + "Executable name has embedded quote, split the arguments"); + + // Win32 CreateProcess requires path to be normalized + File fileToRun = new File(pathIsQuoted + ? path.substring(1, path.length() - 1) + : path); + + // From the [CreateProcess] function documentation: + // + // "If the file name does not contain an extension, .exe is appended. + // Therefore, if the file name extension is .com, this parameter + // must include the .com extension. If the file name ends in + // a period (.) with no extension, or if the file name contains a path, + // .exe is not appended." + // + // "If the file name !does not contain a directory path!, + // the system searches for the executable file in the following + // sequence:..." + // + // In practice ANY non-existent path is extended by [.exe] extension + // in the [CreateProcess] funcion with the only exception: + // the path ends by (.) + + return fileToRun.getPath(); + } + + private long handle = 0; private OutputStream stdin_stream; private InputStream stdout_stream; @@ -157,30 +239,31 @@ final class ProcessImpl extends Process { final boolean redirectErrorStream) throws IOException { - // Win32 CreateProcess requires cmd[0] to be normalized - cmd[0] = new File(cmd[0]).getPath(); + // The [executablePath] is not quoted for any case. + String executablePath = getExecutablePath(cmd[0]); + + // We need to extend the argument verification procedure + // to guarantee the only command file execution for implicit [cmd.exe] + // run. + String upPath = executablePath.toUpperCase(); + boolean isCmdFile = (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); StringBuilder cmdbuf = new StringBuilder(80); - for (int i = 0; i < cmd.length; i++) { - if (i > 0) { - cmdbuf.append(' '); - } + + // Quotation protects from interpretation of the [path] argument as + // start of longer path with spaces. Quotation has no influence to + // [.exe] extension heuristic. + cmdbuf.append('"'); + cmdbuf.append(executablePath); + cmdbuf.append('"'); + + for (int i = 1; i < cmd.length; i++) { + cmdbuf.append(' '); String s = cmd[i]; - if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) { - if (s.charAt(0) != '"') { - cmdbuf.append('"'); - cmdbuf.append(s); - if (s.endsWith("\\")) { - cmdbuf.append("\\"); - } - cmdbuf.append('"'); - } else if (s.endsWith("\"")) { - /* The argument has already been quoted. */ - cmdbuf.append(s); - } else { - /* Unmatched quote for the argument. */ - throw new IllegalArgumentException(); - } + if (needsEscaping(isCmdFile, s)) { + cmdbuf.append('"'); + cmdbuf.append(s); + cmdbuf.append('"'); } else { cmdbuf.append(s); } From e3fdd3983dda996ad8ab347b05e0c641985b9fdd Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Tue, 5 Mar 2013 00:02:24 +0400 Subject: [PATCH 11/36] 8006435: Improvements in JMX Improvements in JMX Reviewed-by: dfuchs, skoivu, alanb, mchung --- .../sun/jmx/mbeanserver/MBeanInstantiator.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java index ab62660be49..1adb4dd9373 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -32,6 +32,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.security.Permission; import java.util.Map; import java.util.logging.Level; @@ -213,7 +214,6 @@ public class MBeanInstantiator { Object moi; - // ------------------------------ // ------------------------------ Constructor cons = findConstructor(theClass, null); @@ -224,6 +224,7 @@ public class MBeanInstantiator { // Instantiate the new object try { ReflectUtil.checkPackageAccess(theClass); + ensureClassAccess(theClass); moi= cons.newInstance(); } catch (InvocationTargetException e) { // Wrap the exception. @@ -270,7 +271,6 @@ public class MBeanInstantiator { checkMBeanPermission(theClass, null, null, "instantiate"); // Instantiate the new object - // ------------------------------ // ------------------------------ final Class[] tab; @@ -300,6 +300,7 @@ public class MBeanInstantiator { } try { ReflectUtil.checkPackageAccess(theClass); + ensureClassAccess(theClass); moi = cons.newInstance(params); } catch (NoSuchMethodError error) { @@ -741,4 +742,13 @@ public class MBeanInstantiator { sm.checkPermission(perm); } } + + private static void ensureClassAccess(Class clazz) + throws IllegalAccessException + { + int mod = clazz.getModifiers(); + if (!Modifier.isPublic(mod)) { + throw new IllegalAccessException("Class is not public and can't be instantiated"); + } + } } From 46a46798f151197d66b135cb0b4a16351899efb2 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 8 Feb 2013 09:15:01 -0800 Subject: [PATCH 12/36] 8006795: Improve font warning messages Reviewed-by: bae, jgodinez --- jdk/src/share/classes/sun/font/CMap.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jdk/src/share/classes/sun/font/CMap.java b/jdk/src/share/classes/sun/font/CMap.java index 0dd595ceb9f..f2554bd3b6c 100644 --- a/jdk/src/share/classes/sun/font/CMap.java +++ b/jdk/src/share/classes/sun/font/CMap.java @@ -841,7 +841,6 @@ abstract class CMap { CMapFormat6(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat8 is untested."); bbuffer.position(offset+6); CharBuffer buffer = bbuffer.asCharBuffer(); firstCode = buffer.get(); @@ -884,7 +883,6 @@ abstract class CMap { CMapFormat8(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat8 is untested."); bbuffer.position(12); bbuffer.get(is32); nGroups = bbuffer.getInt(); @@ -915,7 +913,6 @@ abstract class CMap { CMapFormat10(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat10 is untested."); firstCode = bbuffer.getInt() & INTMASK; entryCount = bbuffer.getInt() & INTMASK; bbuffer.position(offset+20); From 243470f47e03e5da719471e185506014784f798a Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 19 Feb 2013 11:47:42 +0400 Subject: [PATCH 13/36] 8007617: Better validation of images Reviewed-by: prr, mschoene, jgodinez --- .../sun/awt/image/ImageRepresentation.java | 19 +- .../share/native/sun/awt/image/awt_ImageRep.c | 173 +++++++++++++++--- 2 files changed, 156 insertions(+), 36 deletions(-) diff --git a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java index 23b33212602..18fb13ed69b 100644 --- a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java +++ b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java @@ -333,10 +333,10 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer hints = h; } - private native void setICMpixels(int x, int y, int w, int h, int[] lut, + private native boolean setICMpixels(int x, int y, int w, int h, int[] lut, byte[] pix, int off, int scansize, IntegerComponentRaster ict); - private native int setDiffICM(int x, int y, int w, int h, int[] lut, + private native boolean setDiffICM(int x, int y, int w, int h, int[] lut, int transPix, int numLut, IndexColorModel icm, byte[] pix, int off, int scansize, ByteComponentRaster bct, int chanOff); @@ -426,10 +426,10 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer IndexColorModel icm = (IndexColorModel) model; ByteComponentRaster bct = (ByteComponentRaster) biRaster; int numlut = numSrcLUT; - if (setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex, + if (!setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex, numSrcLUT, icm, pix, off, scansize, bct, - bct.getDataOffset(0)) == 0) { + bct.getDataOffset(0))) { convertToRGB(); } else { @@ -470,9 +470,14 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer if (s_useNative) { // Note that setICMpixels modifies the raster directly // so we must mark it as changed afterwards - setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, - iraster); - iraster.markDirty(); + if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, + iraster)) + { + iraster.markDirty(); + } else { + abort(); + return; + } } else { int[] storage = new int[w*h]; diff --git a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c index aa1521e42a4..e091be36eab 100644 --- a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c +++ b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c @@ -45,6 +45,53 @@ static int findIdx(unsigned int rgb, unsigned int *lut, int numLut1); # define TRUE 1 #endif +#define CHECK_STRIDE(yy, hh, ss) \ + if ((ss) != 0) { \ + int limit = 0x7fffffff / ((ss) > 0 ? (ss) : -(ss)); \ + if (limit < (yy) || limit < ((yy) + (hh) - 1)) { \ + /* integer oveflow */ \ + return JNI_FALSE; \ + } \ + } \ + +#define CHECK_SRC() \ + do { \ + int pixeloffset; \ + if (off < 0 || off >= srcDataLength) { \ + return JNI_FALSE; \ + } \ + CHECK_STRIDE(0, h, scansize); \ + \ + /* check scansize */ \ + pixeloffset = scansize * (h - 1); \ + if ((w - 1) > (0x7fffffff - pixeloffset)) { \ + return JNI_FALSE; \ + } \ + pixeloffset += (w - 1); \ + \ + if (off > (0x7fffffff - pixeloffset)) { \ + return JNI_FALSE; \ + } \ + } while (0) \ + +#define CHECK_DST(xx, yy) \ + do { \ + int soffset = (yy) * sStride; \ + int poffset = (xx) * pixelStride; \ + if (poffset > (0x7fffffff - soffset)) { \ + return JNI_FALSE; \ + } \ + poffset += soffset; \ + if (dstDataOff > (0x7fffffff - poffset)) { \ + return JNI_FALSE; \ + } \ + poffset += dstDataOff; \ + \ + if (poffset < 0 || poffset >= dstDataLength) { \ + return JNI_FALSE; \ + } \ + } while (0) \ + static jfieldID s_JnumSrcLUTID; static jfieldID s_JsrcLUTtransIndexID; @@ -58,7 +105,7 @@ Java_sun_awt_image_ImageRepresentation_initIDs(JNIEnv *env, jclass cls) { /* * This routine is used to draw ICM pixels into a default color model */ -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, jint x, jint y, jint w, jint h, jintArray jlut, @@ -67,7 +114,10 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, jobject jict) { unsigned char *srcData = NULL; + jint srcDataLength; int *dstData; + jint dstDataLength; + jint dstDataOff; int *dstP, *dstyP; unsigned char *srcyP, *srcP; int *srcLUT = NULL; @@ -80,12 +130,20 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, if (JNU_IsNull(env, jlut)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return; + return JNI_FALSE; } if (JNU_IsNull(env, jpix)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return; + return JNI_FALSE; + } + + if (x < 0 || w < 1 || (0x7fffffff - x) < w) { + return JNI_FALSE; + } + + if (y < 0 || h < 1 || (0x7fffffff - y) < h) { + return JNI_FALSE; } sStride = (*env)->GetIntField(env, jict, g_ICRscanstrID); @@ -93,10 +151,47 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, joffs = (*env)->GetObjectField(env, jict, g_ICRdataOffsetsID); jdata = (*env)->GetObjectField(env, jict, g_ICRdataID); + if (JNU_IsNull(env, jdata)) { + /* no destination buffer */ + return JNI_FALSE; + } + + if (JNU_IsNull(env, joffs) || (*env)->GetArrayLength(env, joffs) < 1) { + /* invalid data offstes in raster */ + return JNI_FALSE; + } + + srcDataLength = (*env)->GetArrayLength(env, jpix); + dstDataLength = (*env)->GetArrayLength(env, jdata); + + cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL); + if (cOffs == NULL) { + JNU_ThrowNullPointerException(env, "Null channel offset array"); + return JNI_FALSE; + } + + dstDataOff = cOffs[0]; + + /* the offset array is not needed anymore and can be released */ + (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); + joffs = NULL; + cOffs = NULL; + + /* do basic validation: make sure that offsets for + * first pixel and for last pixel are safe to calculate and use */ + CHECK_STRIDE(y, h, sStride); + CHECK_STRIDE(x, w, pixelStride); + + CHECK_DST(x, y); + CHECK_DST(x + w -1, y + h - 1); + + /* check source array */ + CHECK_SRC(); + srcLUT = (int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) { JNU_ThrowNullPointerException(env, "Null IndexColorModel LUT"); - return; + return JNI_FALSE; } srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix, @@ -104,27 +199,18 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, if (srcData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); JNU_ThrowNullPointerException(env, "Null data array"); - return; - } - - cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL); - if (cOffs == NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - JNU_ThrowNullPointerException(env, "Null channel offset array"); - return; + return JNI_FALSE; } dstData = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL); if (dstData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); JNU_ThrowNullPointerException(env, "Null tile data array"); - return; + return JNI_FALSE; } - dstyP = dstData + cOffs[0] + y*sStride + x*pixelStride; + dstyP = dstData + dstDataOff + y*sStride + x*pixelStride; srcyP = srcData + off; for (yIdx = 0; yIdx < h; yIdx++, srcyP += scansize, dstyP+=sStride) { srcP = srcyP; @@ -137,12 +223,12 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, /* Release the locked arrays */ (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); + return JNI_TRUE; } -JNIEXPORT jint JNICALL +JNIEXPORT jboolean JNICALL Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jint x, jint y, jint w, jint h, jintArray jlut, @@ -150,7 +236,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jobject jicm, jbyteArray jpix, jint off, jint scansize, - jobject jbct, jint chanOff) + jobject jbct, jint dstDataOff) { unsigned int *srcLUT = NULL; unsigned int *newLUT = NULL; @@ -159,6 +245,8 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, int mapSize; jobject jdata = NULL; jobject jnewlut = NULL; + jint srcDataLength; + jint dstDataLength; unsigned char *srcData; unsigned char *dstData; unsigned char *dataP; @@ -174,14 +262,23 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, if (JNU_IsNull(env, jlut)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return 0; + return JNI_FALSE; } if (JNU_IsNull(env, jpix)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return 0; + return JNI_FALSE; } + if (x < 0 || w < 1 || (0x7fffffff - x) < w) { + return JNI_FALSE; + } + + if (y < 0 || h < 1 || (0x7fffffff - y) < h) { + return JNI_FALSE; + } + + sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID); pixelStride =(*env)->GetIntField(env, jbct, g_BCRpixstrID); jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID); @@ -193,13 +290,31 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, of byte data type, so we have to convert the image data to default representation. */ - return 0; + return JNI_FALSE; } + + if (JNU_IsNull(env, jdata)) { + /* no destination buffer */ + return JNI_FALSE; + } + + srcDataLength = (*env)->GetArrayLength(env, jpix); + dstDataLength = (*env)->GetArrayLength(env, jdata); + + CHECK_STRIDE(y, h, sStride); + CHECK_STRIDE(x, w, pixelStride); + + CHECK_DST(x, y); + CHECK_DST(x + w -1, y + h - 1); + + /* check source array */ + CHECK_SRC(); + srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) { /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } newLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jnewlut, @@ -208,7 +323,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } newNumLut = numLut; @@ -219,7 +334,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT); - return 0; + return JNI_FALSE; } /* Don't need these any more */ @@ -239,7 +354,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, NULL); if (srcData == NULL) { /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata, @@ -247,10 +362,10 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, if (dstData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } - ydataP = dstData + chanOff + y*sStride + x*pixelStride; + ydataP = dstData + dstDataOff + y*sStride + x*pixelStride; ypixP = srcData + off; for (i=0; i < h; i++) { @@ -268,7 +383,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); - return 1; + return JNI_TRUE; } static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx, From 57d870834fed69a5cc13f639499faee4d9414181 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 26 Feb 2013 00:41:40 +0400 Subject: [PATCH 14/36] 8007667: Better image reading Reviewed-by: prr, jgodinez, mschoene --- .../imageio/plugins/jpeg/JPEGImageReader.java | 291 +++++++++++++----- .../native/sun/awt/image/jpeg/imageioJPEG.c | 27 +- 2 files changed, 231 insertions(+), 87 deletions(-) diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 219f5bf5873..d69200c1408 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -243,12 +243,17 @@ public class JPEGImageReader extends ImageReader { * sending warnings to listeners. */ protected void warningOccurred(int code) { - if ((code < 0) || (code > MAX_WARNING)){ - throw new InternalError("Invalid warning index"); + cbLock.lock(); + try { + if ((code < 0) || (code > MAX_WARNING)){ + throw new InternalError("Invalid warning index"); + } + processWarningOccurred + ("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources", + Integer.toString(code)); + } finally { + cbLock.unlock(); } - processWarningOccurred - ("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources", - Integer.toString(code)); } /** @@ -265,7 +270,12 @@ public class JPEGImageReader extends ImageReader { * library warnings from being printed to stderr. */ protected void warningWithMessage(String msg) { - processWarningOccurred(msg); + cbLock.lock(); + try { + processWarningOccurred(msg); + } finally { + cbLock.unlock(); + } } public void setInput(Object input, @@ -274,18 +284,55 @@ public class JPEGImageReader extends ImageReader { { setThreadLock(); try { + cbLock.check(); + super.setInput(input, seekForwardOnly, ignoreMetadata); this.ignoreMetadata = ignoreMetadata; resetInternalState(); iis = (ImageInputStream) input; // Always works - setSource(structPointer, iis); + setSource(structPointer); } finally { clearThreadLock(); } } - private native void setSource(long structPointer, - ImageInputStream source); + /** + * This method is called from native code in order to fill + * native input buffer. + * + * We block any attempt to change the reading state during this + * method, in order to prevent a corruption of the native decoder + * state. + * + * @return number of bytes read from the stream. + */ + private int readInputData(byte[] buf, int off, int len) throws IOException { + cbLock.lock(); + try { + return iis.read(buf, off, len); + } finally { + cbLock.unlock(); + } + } + + /** + * This method is called from the native code in order to + * skip requested number of bytes in the input stream. + * + * @param n + * @return + * @throws IOException + */ + private long skipInputBytes(long n) throws IOException { + cbLock.lock(); + try { + return iis.skipBytes(n); + } finally { + cbLock.unlock(); + } + } + + private native void setSource(long structPointer); private void checkTablesOnly() throws IOException { if (debug) { @@ -337,6 +384,8 @@ public class JPEGImageReader extends ImageReader { public int getNumImages(boolean allowSearch) throws IOException { setThreadLock(); try { // locked thread + cbLock.check(); + return getNumImagesOnThread(allowSearch); } finally { clearThreadLock(); @@ -536,8 +585,13 @@ public class JPEGImageReader extends ImageReader { if (debug) { System.out.println("pushing back " + num + " bytes"); } - iis.seek(iis.getStreamPosition()-num); - // The buffer is clear after this, so no need to set haveSeeked. + cbLock.lock(); + try { + iis.seek(iis.getStreamPosition()-num); + // The buffer is clear after this, so no need to set haveSeeked. + } finally { + cbLock.unlock(); + } } /** @@ -644,7 +698,12 @@ public class JPEGImageReader extends ImageReader { * Ignore this profile. */ iccCS = null; - warningOccurred(WARNING_IGNORE_INVALID_ICC); + cbLock.lock(); + try { + warningOccurred(WARNING_IGNORE_INVALID_ICC); + } finally { + cbLock.unlock(); + } } } } @@ -653,6 +712,7 @@ public class JPEGImageReader extends ImageReader { setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } return width; @@ -665,6 +725,7 @@ public class JPEGImageReader extends ImageReader { setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } return height; @@ -693,6 +754,8 @@ public class JPEGImageReader extends ImageReader { setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); + readHeader(imageIndex, true); } @@ -716,6 +779,7 @@ public class JPEGImageReader extends ImageReader { private Iterator getImageTypesOnThread(int imageIndex) throws IOException { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } @@ -931,6 +995,7 @@ public class JPEGImageReader extends ImageReader { setThreadLock(); try { if (!tablesOnlyChecked) { + cbLock.check(); checkTablesOnly(); } return streamMetadata; @@ -951,6 +1016,8 @@ public class JPEGImageReader extends ImageReader { return imageMetadata; } + cbLock.check(); + gotoImage(imageIndex); imageMetadata = new JPEGMetadata(false, false, iis, this); @@ -967,6 +1034,7 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + cbLock.check(); try { readInternal(imageIndex, param, false); } catch (RuntimeException e) { @@ -1196,58 +1264,63 @@ public class JPEGImageReader extends ImageReader { } target.setRect(destROI.x, destROI.y + y, raster); - processImageUpdate(image, - destROI.x, destROI.y+y, - raster.getWidth(), 1, - 1, 1, - destinationBands); - if ((y > 0) && (y%progInterval == 0)) { - int height = target.getHeight()-1; - float percentOfPass = ((float)y)/height; - if (progressive) { - if (knownPassCount != UNKNOWN) { - processImageProgress((pass + percentOfPass)*100.0F - / knownPassCount); - } else if (maxProgressivePass != Integer.MAX_VALUE) { - // Use the range of allowed progressive passes - processImageProgress((pass + percentOfPass)*100.0F - / (maxProgressivePass - minProgressivePass + 1)); - } else { - // Assume there are a minimum of MIN_ESTIMATED_PASSES - // and that there is always one more pass - // Compute the percentage as the percentage at the end - // of the previous pass, plus the percentage of this - // pass scaled to be the percentage of the total remaining, - // assuming a minimum of MIN_ESTIMATED_PASSES passes and - // that there is always one more pass. This is monotonic - // and asymptotic to 1.0, which is what we need. - int remainingPasses = // including this one - Math.max(2, MIN_ESTIMATED_PASSES-pass); - int totalPasses = pass + remainingPasses-1; - progInterval = Math.max(height/20*totalPasses, - totalPasses); - if (y%progInterval == 0) { - percentToDate = previousPassPercentage + - (1.0F - previousPassPercentage) - * (percentOfPass)/remainingPasses; - if (debug) { - System.out.print("pass= " + pass); - System.out.print(", y= " + y); - System.out.print(", progInt= " + progInterval); - System.out.print(", % of pass: " + percentOfPass); - System.out.print(", rem. passes: " - + remainingPasses); - System.out.print(", prev%: " - + previousPassPercentage); - System.out.print(", %ToDate: " + percentToDate); - System.out.print(" "); + cbLock.lock(); + try { + processImageUpdate(image, + destROI.x, destROI.y+y, + raster.getWidth(), 1, + 1, 1, + destinationBands); + if ((y > 0) && (y%progInterval == 0)) { + int height = target.getHeight()-1; + float percentOfPass = ((float)y)/height; + if (progressive) { + if (knownPassCount != UNKNOWN) { + processImageProgress((pass + percentOfPass)*100.0F + / knownPassCount); + } else if (maxProgressivePass != Integer.MAX_VALUE) { + // Use the range of allowed progressive passes + processImageProgress((pass + percentOfPass)*100.0F + / (maxProgressivePass - minProgressivePass + 1)); + } else { + // Assume there are a minimum of MIN_ESTIMATED_PASSES + // and that there is always one more pass + // Compute the percentage as the percentage at the end + // of the previous pass, plus the percentage of this + // pass scaled to be the percentage of the total remaining, + // assuming a minimum of MIN_ESTIMATED_PASSES passes and + // that there is always one more pass. This is monotonic + // and asymptotic to 1.0, which is what we need. + int remainingPasses = // including this one + Math.max(2, MIN_ESTIMATED_PASSES-pass); + int totalPasses = pass + remainingPasses-1; + progInterval = Math.max(height/20*totalPasses, + totalPasses); + if (y%progInterval == 0) { + percentToDate = previousPassPercentage + + (1.0F - previousPassPercentage) + * (percentOfPass)/remainingPasses; + if (debug) { + System.out.print("pass= " + pass); + System.out.print(", y= " + y); + System.out.print(", progInt= " + progInterval); + System.out.print(", % of pass: " + percentOfPass); + System.out.print(", rem. passes: " + + remainingPasses); + System.out.print(", prev%: " + + previousPassPercentage); + System.out.print(", %ToDate: " + percentToDate); + System.out.print(" "); + } + processImageProgress(percentToDate*100.0F); } - processImageProgress(percentToDate*100.0F); } + } else { + processImageProgress(percentOfPass * 100.0F); } - } else { - processImageProgress(percentOfPass * 100.0F); } + } finally { + cbLock.unlock(); } } @@ -1260,33 +1333,58 @@ public class JPEGImageReader extends ImageReader { } private void passStarted (int pass) { - this.pass = pass; - previousPassPercentage = percentToDate; - processPassStarted(image, - pass, - minProgressivePass, - maxProgressivePass, - 0, 0, - 1,1, - destinationBands); + cbLock.lock(); + try { + this.pass = pass; + previousPassPercentage = percentToDate; + processPassStarted(image, + pass, + minProgressivePass, + maxProgressivePass, + 0, 0, + 1,1, + destinationBands); + } finally { + cbLock.unlock(); + } } private void passComplete () { - processPassComplete(image); + cbLock.lock(); + try { + processPassComplete(image); + } finally { + cbLock.unlock(); + } } void thumbnailStarted(int thumbnailIndex) { - processThumbnailStarted(currentImage, thumbnailIndex); + cbLock.lock(); + try { + processThumbnailStarted(currentImage, thumbnailIndex); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailProgress(float percentageDone) { - processThumbnailProgress(percentageDone); + cbLock.lock(); + try { + processThumbnailProgress(percentageDone); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailComplete() { - processThumbnailComplete(); + cbLock.lock(); + try { + processThumbnailComplete(); + } finally { + cbLock.unlock(); + } } /** @@ -1310,6 +1408,11 @@ public class JPEGImageReader extends ImageReader { public void abort() { setThreadLock(); try { + /** + * NB: we do not check the call back lock here, + * we allow to abort the reader any time. + */ + super.abort(); abortRead(structPointer); } finally { @@ -1332,6 +1435,7 @@ public class JPEGImageReader extends ImageReader { setThreadLock(); Raster retval = null; try { + cbLock.check(); /* * This could be further optimized by not resetting the dest. * offset and creating a translated raster in readInternal() @@ -1371,6 +1475,8 @@ public class JPEGImageReader extends ImageReader { public int getNumThumbnails(int imageIndex) throws IOException { setThreadLock(); try { + cbLock.check(); + getImageMetadata(imageIndex); // checks iis state for us // Now check the jfif segments JFIFMarkerSegment jfif = @@ -1391,6 +1497,8 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1409,6 +1517,8 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1428,6 +1538,8 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1468,6 +1580,7 @@ public class JPEGImageReader extends ImageReader { public void reset() { setThreadLock(); try { + cbLock.check(); super.reset(); } finally { clearThreadLock(); @@ -1479,6 +1592,8 @@ public class JPEGImageReader extends ImageReader { public void dispose() { setThreadLock(); try { + cbLock.check(); + if (structPointer != 0) { disposerRecord.dispose(); structPointer = 0; @@ -1540,6 +1655,36 @@ public class JPEGImageReader extends ImageReader { theThread = null; } } + + private CallBackLock cbLock = new CallBackLock(); + + private static class CallBackLock { + + private State lockState; + + CallBackLock() { + lockState = State.Unlocked; + } + + void check() { + if (lockState != State.Unlocked) { + throw new IllegalStateException("Access to the reader is not allowed"); + } + } + + private void lock() { + lockState = State.Locked; + } + + private void unlock() { + lockState = State.Unlocked; + } + + private static enum State { + Unlocked, + Locked + } + } } /** diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index b405618be98..be90087d108 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -57,8 +57,8 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* Cached Java method ids */ -static jmethodID ImageInputStream_readID; -static jmethodID ImageInputStream_skipBytesID; +static jmethodID JPEGImageReader_readInputDataID; +static jmethodID JPEGImageReader_skipInputBytesID; static jmethodID JPEGImageReader_warningOccurredID; static jmethodID JPEGImageReader_warningWithMessageID; static jmethodID JPEGImageReader_setImageDataID; @@ -923,7 +923,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallIntMethod(env, sb->stream, - ImageInputStream_readID, + JPEGImageReader_readInputDataID, sb->hstreamBuffer, 0, sb->bufferLength); if ((*env)->ExceptionOccurred(env) @@ -1013,7 +1013,7 @@ imageio_fill_suspended_buffer(j_decompress_ptr cinfo) } ret = (*env)->CallIntMethod(env, sb->stream, - ImageInputStream_readID, + JPEGImageReader_readInputDataID, sb->hstreamBuffer, offset, buflen); if ((*env)->ExceptionOccurred(env) @@ -1107,7 +1107,7 @@ imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallLongMethod(env, sb->stream, - ImageInputStream_skipBytesID, + JPEGImageReader_skipInputBytesID, (jlong) num_bytes); if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, data, &(src->next_input_byte))) { @@ -1382,13 +1382,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initReaderIDs jclass qTableClass, jclass huffClass) { - ImageInputStream_readID = (*env)->GetMethodID(env, - ImageInputStreamClass, - "read", + JPEGImageReader_readInputDataID = (*env)->GetMethodID(env, + cls, + "readInputData", "([BII)I"); - ImageInputStream_skipBytesID = (*env)->GetMethodID(env, - ImageInputStreamClass, - "skipBytes", + JPEGImageReader_skipInputBytesID = (*env)->GetMethodID(env, + cls, + "skipInputBytes", "(J)J"); JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env, cls, @@ -1531,8 +1531,7 @@ JNIEXPORT void JNICALL Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource (JNIEnv *env, jobject this, - jlong ptr, - jobject source) { + jlong ptr) { imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_common_ptr cinfo; @@ -1546,7 +1545,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource cinfo = data->jpegObj; - imageio_set_stream(env, cinfo, data, source); + imageio_set_stream(env, cinfo, data, this); imageio_init_source((j_decompress_ptr) cinfo); } From b15549ed0b002939f3714dfebdc91b2a7a4d49d1 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 26 Feb 2013 01:41:36 +0400 Subject: [PATCH 15/36] 8007918: Better image writing Reviewed-by: mschoene, prr, jgodinez --- .../imageio/plugins/jpeg/JPEGImageWriter.java | 147 +++++++++++++++--- .../native/sun/awt/image/jpeg/imageioJPEG.c | 18 +-- 2 files changed, 131 insertions(+), 34 deletions(-) diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index bc8d435d464..b8564176df8 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -183,8 +183,7 @@ public class JPEGImageWriter extends ImageWriter { return null; } }); - initWriterIDs(ImageOutputStream.class, - JPEGQTable.class, + initWriterIDs(JPEGQTable.class, JPEGHuffmanTable.class); } @@ -200,11 +199,13 @@ public class JPEGImageWriter extends ImageWriter { public void setOutput(Object output) { setThreadLock(); try { + cbLock.check(); + super.setOutput(output); // validates output resetInternalState(); ios = (ImageOutputStream) output; // so this will always work // Set the native destination - setDest(structPointer, ios); + setDest(structPointer); } finally { clearThreadLock(); } @@ -359,6 +360,8 @@ public class JPEGImageWriter extends ImageWriter { ImageWriteParam param) throws IOException { setThreadLock(); try { + cbLock.check(); + writeOnThread(streamMetadata, image, param); } finally { clearThreadLock(); @@ -1082,13 +1085,18 @@ public class JPEGImageWriter extends ImageWriter { haveMetadata, restartInterval); - if (aborted) { - processWriteAborted(); - } else { - processImageComplete(); - } + cbLock.lock(); + try { + if (aborted) { + processWriteAborted(); + } else { + processImageComplete(); + } - ios.flush(); + ios.flush(); + } finally { + cbLock.unlock(); + } currentImage++; // After a successful write } @@ -1096,6 +1104,8 @@ public class JPEGImageWriter extends ImageWriter { throws IOException { setThreadLock(); try { + cbLock.check(); + prepareWriteSequenceOnThread(streamMetadata); } finally { clearThreadLock(); @@ -1175,6 +1185,8 @@ public class JPEGImageWriter extends ImageWriter { throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1188,6 +1200,8 @@ public class JPEGImageWriter extends ImageWriter { public void endWriteSequence() throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1200,6 +1214,10 @@ public class JPEGImageWriter extends ImageWriter { public synchronized void abort() { setThreadLock(); try { + /** + * NB: we do not check the call back lock here, we allow to abort + * the reader any time. + */ super.abort(); abortWrite(structPointer); } finally { @@ -1223,6 +1241,8 @@ public class JPEGImageWriter extends ImageWriter { public void reset() { setThreadLock(); try { + cbLock.check(); + super.reset(); } finally { clearThreadLock(); @@ -1232,6 +1252,8 @@ public class JPEGImageWriter extends ImageWriter { public void dispose() { setThreadLock(); try { + cbLock.check(); + if (structPointer != 0) { disposerRecord.dispose(); structPointer = 0; @@ -1251,13 +1273,18 @@ public class JPEGImageWriter extends ImageWriter { * sending warnings to listeners. */ void warningOccurred(int code) { - if ((code < 0) || (code > MAX_WARNING)){ - throw new InternalError("Invalid warning index"); + cbLock.lock(); + try { + if ((code < 0) || (code > MAX_WARNING)){ + throw new InternalError("Invalid warning index"); + } + processWarningOccurred + (currentImage, + "com.sun.imageio.plugins.jpeg.JPEGImageWriterResources", + Integer.toString(code)); + } finally { + cbLock.unlock(); } - processWarningOccurred - (currentImage, - "com.sun.imageio.plugins.jpeg.JPEGImageWriterResources", - Integer.toString(code)); } /** @@ -1274,21 +1301,41 @@ public class JPEGImageWriter extends ImageWriter { * library warnings from being printed to stderr. */ void warningWithMessage(String msg) { - processWarningOccurred(currentImage, msg); + cbLock.lock(); + try { + processWarningOccurred(currentImage, msg); + } finally { + cbLock.unlock(); + } } void thumbnailStarted(int thumbnailIndex) { - processThumbnailStarted(currentImage, thumbnailIndex); + cbLock.lock(); + try { + processThumbnailStarted(currentImage, thumbnailIndex); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailProgress(float percentageDone) { - processThumbnailProgress(percentageDone); + cbLock.lock(); + try { + processThumbnailProgress(percentageDone); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailComplete() { - processThumbnailComplete(); + cbLock.lock(); + try { + processThumbnailComplete(); + } finally { + cbLock.unlock(); + } } ///////// End of Package-access API @@ -1615,16 +1662,14 @@ public class JPEGImageWriter extends ImageWriter { ////////////// Native methods and callbacks /** Sets up static native structures. */ - private static native void initWriterIDs(Class iosClass, - Class qTableClass, + private static native void initWriterIDs(Class qTableClass, Class huffClass); /** Sets up per-writer native structure and returns a pointer to it. */ private native long initJPEGImageWriter(); /** Sets up native structures for output stream */ - private native void setDest(long structPointer, - ImageOutputStream ios); + private native void setDest(long structPointer); /** * Returns true if the write was aborted. @@ -1749,7 +1794,12 @@ public class JPEGImageWriter extends ImageWriter { } raster.setRect(sourceLine); if ((y > 7) && (y%8 == 0)) { // Every 8 scanlines - processImageProgress((float) y / (float) sourceHeight * 100.0F); + cbLock.lock(); + try { + processImageProgress((float) y / (float) sourceHeight * 100.0F); + } finally { + cbLock.unlock(); + } } } @@ -1777,6 +1827,25 @@ public class JPEGImageWriter extends ImageWriter { } } + /** + * This method is called from native code in order to write encoder + * output to the destination. + * + * We block any attempt to change the writer state during this + * method, in order to prevent a corruption of the native encoder + * state. + */ + private void writeOutputData(byte[] data, int offset, int len) + throws IOException + { + cbLock.lock(); + try { + ios.write(data, offset, len); + } finally { + cbLock.unlock(); + } + } + private Thread theThread = null; private int theLockCount = 0; @@ -1811,4 +1880,34 @@ public class JPEGImageWriter extends ImageWriter { theThread = null; } } + + private CallBackLock cbLock = new CallBackLock(); + + private static class CallBackLock { + + private State lockState; + + CallBackLock() { + lockState = State.Unlocked; + } + + void check() { + if (lockState != State.Unlocked) { + throw new IllegalStateException("Access to the writer is not allowed"); + } + } + + private void lock() { + lockState = State.Locked; + } + + private void unlock() { + lockState = State.Unlocked; + } + + private static enum State { + Unlocked, + Locked + } + } } diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index be90087d108..7411c34bb83 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -66,7 +66,7 @@ static jmethodID JPEGImageReader_acceptPixelsID; static jmethodID JPEGImageReader_pushBackID; static jmethodID JPEGImageReader_passStartedID; static jmethodID JPEGImageReader_passCompleteID; -static jmethodID ImageOutputStream_writeID; +static jmethodID JPEGImageWriter_writeOutputDataID; static jmethodID JPEGImageWriter_warningOccurredID; static jmethodID JPEGImageWriter_warningWithMessageID; static jmethodID JPEGImageWriter_writeMetadataID; @@ -2290,7 +2290,7 @@ imageio_empty_output_buffer (j_compress_ptr cinfo) (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, sb->bufferLength); @@ -2327,7 +2327,7 @@ imageio_term_destination (j_compress_ptr cinfo) (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, datacount); @@ -2365,13 +2365,12 @@ JNIEXPORT void JNICALL Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs (JNIEnv *env, jclass cls, - jclass IOSClass, jclass qTableClass, jclass huffClass) { - ImageOutputStream_writeID = (*env)->GetMethodID(env, - IOSClass, - "write", + JPEGImageWriter_writeOutputDataID = (*env)->GetMethodID(env, + cls, + "writeOutputData", "([BII)V"); JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env, @@ -2495,8 +2494,7 @@ JNIEXPORT void JNICALL Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest (JNIEnv *env, jobject this, - jlong ptr, - jobject destination) { + jlong ptr) { imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_compress_ptr cinfo; @@ -2510,7 +2508,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest cinfo = (j_compress_ptr) data->jpegObj; - imageio_set_stream(env, data->jpegObj, data, destination); + imageio_set_stream(env, data->jpegObj, data, this); // Don't call the init method, as that depends on pinned arrays From 046d36e089c078ae418d42db3eda28e8477ac688 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Sun, 3 Mar 2013 10:07:52 +0000 Subject: [PATCH 16/36] 8009063: Improve reliability of ConcurrentHashMap Reviewed-by: alanb, ahgross --- .../util/concurrent/ConcurrentHashMap.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java index 66ae51667d5..b7c8bde6ba7 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -34,6 +34,7 @@ */ package java.util.concurrent; +import java.io.ObjectInputStream; import java.util.concurrent.locks.*; import java.util.*; import java.io.Serializable; @@ -1483,7 +1484,23 @@ public class ConcurrentHashMap extends AbstractMap @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); + // Don't call defaultReadObject() + ObjectInputStream.GetField oisFields = s.readFields(); + final Segment[] oisSegments = (Segment[])oisFields.get("segments", null); + + final int ssize = oisSegments.length; + if (ssize < 1 || ssize > MAX_SEGMENTS + || (ssize & (ssize-1)) != 0 ) // ssize not power of two + throw new java.io.InvalidObjectException("Bad number of segments:" + + ssize); + int sshift = 0, ssizeTmp = ssize; + while (ssizeTmp > 1) { + ++sshift; + ssizeTmp >>>= 1; + } + UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift); + UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1); + UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments); // set hashMask UNSAFE.putIntVolatile(this, HASHSEED_OFFSET, @@ -1517,6 +1534,9 @@ public class ConcurrentHashMap extends AbstractMap private static final long TBASE; private static final int TSHIFT; private static final long HASHSEED_OFFSET; + private static final long SEGSHIFT_OFFSET; + private static final long SEGMASK_OFFSET; + private static final long SEGMENTS_OFFSET; static { int ss, ts; @@ -1530,6 +1550,12 @@ public class ConcurrentHashMap extends AbstractMap ss = UNSAFE.arrayIndexScale(sc); HASHSEED_OFFSET = UNSAFE.objectFieldOffset( ConcurrentHashMap.class.getDeclaredField("hashSeed")); + SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segmentShift")); + SEGMASK_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segmentMask")); + SEGMENTS_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segments")); } catch (Exception e) { throw new Error(e); } From 78478633f93b2ce40b85a0fbac095ad7d27c935a Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 14 Mar 2013 18:41:42 +0100 Subject: [PATCH 17/36] 8009305: Improve AWT data transfer Reviewed-by: art, skoivu, smarks, ant --- .../awt/datatransfer/TransferableProxy.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java b/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java index 295aa20d6a8..ed688aa3362 100644 --- a/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java +++ b/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java @@ -102,11 +102,11 @@ public class TransferableProxy implements Transferable { protected final boolean isLocal; } -class ClassLoaderObjectOutputStream extends ObjectOutputStream { +final class ClassLoaderObjectOutputStream extends ObjectOutputStream { private final Map, ClassLoader> map = new HashMap, ClassLoader>(); - public ClassLoaderObjectOutputStream(OutputStream os) throws IOException { + ClassLoaderObjectOutputStream(OutputStream os) throws IOException { super(os); } @@ -140,16 +140,16 @@ class ClassLoaderObjectOutputStream extends ObjectOutputStream { map.put(s, classLoader); } - public Map, ClassLoader> getClassLoaderMap() { + Map, ClassLoader> getClassLoaderMap() { return new HashMap(map); } } -class ClassLoaderObjectInputStream extends ObjectInputStream { +final class ClassLoaderObjectInputStream extends ObjectInputStream { private final Map, ClassLoader> map; - public ClassLoaderObjectInputStream(InputStream is, - Map, ClassLoader> map) + ClassLoaderObjectInputStream(InputStream is, + Map, ClassLoader> map) throws IOException { super(is); if (map == null) { @@ -166,8 +166,11 @@ class ClassLoaderObjectInputStream extends ObjectInputStream { s.add(className); ClassLoader classLoader = map.get(s); - - return Class.forName(className, false, classLoader); + if (classLoader != null) { + return Class.forName(className, false, classLoader); + } else { + return super.resolveClass(classDesc); + } } protected Class resolveProxyClass(String[] interfaces) @@ -179,6 +182,9 @@ class ClassLoaderObjectInputStream extends ObjectInputStream { } ClassLoader classLoader = map.get(s); + if (classLoader == null) { + return super.resolveProxyClass(interfaces); + } // The code below is mostly copied from the superclass. ClassLoader nonPublicLoader = null; From 28441d3ff34daf829b21757473421d6e6b6fbbc4 Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Fri, 8 Mar 2013 13:35:15 +0400 Subject: [PATCH 18/36] 8009463: Regression test test\java\lang\Runtime\exec\ArgWithSpaceAndFinalBackslash.java failing Reviewed-by: alanb, ahgross --- .../windows/classes/java/lang/ProcessImpl.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/jdk/src/windows/classes/java/lang/ProcessImpl.java b/jdk/src/windows/classes/java/lang/ProcessImpl.java index 87c89bb11e6..5f772aee8fb 100644 --- a/jdk/src/windows/classes/java/lang/ProcessImpl.java +++ b/jdk/src/windows/classes/java/lang/ProcessImpl.java @@ -263,6 +263,22 @@ final class ProcessImpl extends Process { if (needsEscaping(isCmdFile, s)) { cmdbuf.append('"'); cmdbuf.append(s); + + // The code protects the [java.exe] and console command line + // parser, that interprets the [\"] combination as an escape + // sequence for the ["] char. + // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + // + // If the argument is an FS path, doubling of the tail [\] + // char is not a problem for non-console applications. + // + // The [\"] sequence is not an escape sequence for the [cmd.exe] + // command line parser. The case of the [""] tail escape + // sequence could not be realized due to the argument validation + // procedure. + if (!isCmdFile && s.endsWith("\\")) { + cmdbuf.append('\\'); + } cmdbuf.append('"'); } else { cmdbuf.append(s); From c5d72546c0f102eebccecaf608b1b1b3848a49da Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Mon, 11 Mar 2013 20:18:32 -0700 Subject: [PATCH 19/36] 8009610: Blacklist certificate used with malware Updated the black list and the reg test with the new cert. Reviewed-by: weijun --- .../security/util/UntrustedCertificates.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java index 03fdbc78332..73495df5bcc 100644 --- a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java +++ b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java @@ -843,5 +843,52 @@ public final class UntrustedCertificates { "zCOfhbsRWdMLYepauaNZOIMZXmFwcrIl0TGMkTAtATz+XmZc\n" + "-----END CERTIFICATE-----"); + // + // Revoked code signing certificate w/ a stolen key issued by GoDaddy + // used to sign malware + // + + // Subject: CN=CLEARESULT CONSULTING INC., OU=Corporate IT, + // O=CLEARESULT CONSULTING INC., L=Austin, ST=TX, C=US + // Issuer: SERIALNUMBER=07969287, + // CN=Go Daddy Secure Certification Authority, + // OU=http://certificates.godaddy.com/repository, + // O="GoDaddy.com, Inc.", + // L=Scottsdale, + // ST=Arizona, + // C=US + // Serial: 2b:73:43:2a:a8:4f:44 + add("clearesult-consulting-inc-2AA84F44", + "-----BEGIN CERTIFICATE-----\n" + + "MIIFYjCCBEqgAwIBAgIHK3NDKqhPRDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + + "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + + "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + + "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + + "ODcwHhcNMTIwMjE1MjEwOTA2WhcNMTQwMjE1MjEwOTA2WjCBjDELMAkGA1UEBgwC\n" + + "VVMxCzAJBgNVBAgMAlRYMQ8wDQYDVQQHDAZBdXN0aW4xIzAhBgNVBAoMGkNMRUFS\n" + + "RVNVTFQgQ09OU1VMVElORyBJTkMuMRUwEwYDVQQLDAxDb3Jwb3JhdGUgSVQxIzAh\n" + + "BgNVBAMMGkNMRUFSRVNVTFQgQ09OU1VMVElORyBJTkMuMIIBIjANBgkqhkiG9w0B\n" + + "AQEFAAOCAQ8AMIIBCgKCAQEAtIOjCKeAicull+7ZIzt0/4ya3IeXUFlfypqKMLkU\n" + + "IbKjn0P5uMj6VE3rlbZr44RCegxvdnR6umBh1c0ZXoN3o+yc0JKcKcLiApmJJ277\n" + + "p7IbLwYDhBXRQNoIJm187IOMRPIxsKN4hL91txn9jGBmW+9zKlJlNhR5R7vjwU2E\n" + + "jrH/6oqsc9EM2yYpfjlNv6+3jSwAYZCkSWr+27PQOV+YHKmIxtJjX0upFz5FdIrV\n" + + "9CCX+L2Kji1THOkSgG4QTbYxmEcHqGViWz8hXLeNXjcbEsPuIiAu3hknxRHfUTE/\n" + + "U0Lh0Ug1e3LrJu+WnxM2SmUY4krsZ22c0yWUW9hzWITIjQIDAQABo4IBhzCCAYMw\n" + + "DwYDVR0TAQH/BAUwAwEBADATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8E\n" + + "BAMCB4AwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5LmNvbS9n\n" + + "ZHM1LTE2LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcCMDkwNwYIKwYBBQUH\n" + + "AgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS8w\n" + + "gYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRk\n" + + "eS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHku\n" + + "Y29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSMEGDAWgBT9\n" + + "rGEyk2xF1uLuhV+auud2mWjM5zAdBgNVHQ4EFgQUDtdeKqeN2QkcbEp1HovFieNB\n" + + "XiowDQYJKoZIhvcNAQEFBQADggEBAD74Agw5tvi2aBl4/f/s7/VE/BClzDsKMb9K\n" + + "v9qpeC45ZA/jelxV11HKbQnVF194gDb7D2H9OsAsRUy8HVKbXEcc/8dKvwOqb+BC\n" + + "2i/EmfjLgmCfezNFtLq8xcPxF3zIRc44vPrK0z4YZsaHdH+yTEJ51p5EMdTqaLaP\n" + + "4n5m8LX3RfqlQB9dYFe6dUoYZjKm9d/pIRww3VqfOzjl42Edi1w6dWmBVMx1NZuR\n" + + "DBabJH1vJ9Gd+KwxMCmBZ6pQPl28JDimhJhI2LNqU349uADQVV0HJosddN/ARyyI\n" + + "LSIQO7BnNVKVG9Iujf33bvPNeg0qNz5qw+rKKq97Pqeum+L5oKU=\n" + + "-----END CERTIFICATE-----"); } } From d059d367eb459a65c77d5cc875945f9fa55e3f9e Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Mon, 18 Mar 2013 13:30:20 -0400 Subject: [PATCH 20/36] 8009814: Better driver management Reviewed-by: alanb, skoivu --- jdk/src/share/classes/java/sql/DriverManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java index b0ca1cd4dea..a97595da5d1 100644 --- a/jdk/src/share/classes/java/sql/DriverManager.java +++ b/jdk/src/share/classes/java/sql/DriverManager.java @@ -556,7 +556,7 @@ public class DriverManager { */ try{ while(driversIterator.hasNext()) { - println(" Loading done by the java.util.ServiceLoader : "+driversIterator.next()); + driversIterator.next(); } } catch(Throwable t) { // Do nothing From 3a4936696cfb9be500a5dd250bd513bba0758065 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Mon, 18 Mar 2013 18:15:59 -0700 Subject: [PATCH 21/36] 8009857: Problem with plugin Reviewed-by: jdn, mchung --- .../classes/sun/reflect/misc/MethodUtil.java | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java index 9d9c5ab6015..24abe866761 100644 --- a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java @@ -46,8 +46,28 @@ import sun.misc.IOUtils; class Trampoline { + static { + if (Trampoline.class.getClassLoader() == null) { + throw new Error( + "Trampoline must not be defined by the bootstrap classloader"); + } + } + + private static void ensureInvocableMethod(Method m) + throws InvocationTargetException + { + Class clazz = m.getDeclaringClass(); + if (clazz.equals(AccessController.class) || + clazz.equals(Method.class) || + clazz.getName().startsWith("java.lang.invoke.")) + throw new InvocationTargetException( + new UnsupportedOperationException("invocation not supported")); + } + private static Object invoke(Method m, Object obj, Object[] params) - throws InvocationTargetException, IllegalAccessException { + throws InvocationTargetException, IllegalAccessException + { + ensureInvocableMethod(m); return m.invoke(obj, params); } } @@ -251,16 +271,6 @@ public final class MethodUtil extends SecureClassLoader { */ public static Object invoke(Method m, Object obj, Object[] params) throws InvocationTargetException, IllegalAccessException { - if (m.getDeclaringClass().equals(AccessController.class) || - (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.class) - && m.getName().equals("lookup")) || - (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.Lookup.class) - && (m.getName().startsWith("find") || - m.getName().startsWith("bind") || - m.getName().startsWith("unreflect"))) || - m.getDeclaringClass().equals(Method.class)) - throw new InvocationTargetException( - new UnsupportedOperationException("invocation not supported")); try { return bounce.invoke(null, new Object[] {m, obj, params}); } catch (InvocationTargetException ie) { @@ -293,10 +303,10 @@ public final class MethodUtil extends SecureClassLoader { Method.class, Object.class, Object[].class }; Method b = t.getDeclaredMethod("invoke", types); - ((AccessibleObject)b).setAccessible(true); - return b; - } - }); + b.setAccessible(true); + return b; + } + }); } catch (Exception e) { throw new InternalError("bouncer cannot be found", e); } From ae5b3c931010c11cb25d6ece1e9bb1cad1382705 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 15 Feb 2013 13:07:17 -0800 Subject: [PATCH 22/36] 8008249: Sync ICU into JDK Reviewed-by: bae, jgodinez --- jdk/make/sun/font/FILES_c.gmk | 16 +- .../font/layout/ContextualGlyphInsertion.h | 15 +- .../layout/ContextualGlyphInsertionProc2.cpp | 168 +++++++ .../layout/ContextualGlyphInsertionProc2.h | 89 ++++ .../font/layout/ContextualGlyphSubstProc2.cpp | 160 +++++++ .../font/layout/ContextualGlyphSubstProc2.h | 92 ++++ .../font/layout/ContextualGlyphSubstitution.h | 13 +- .../sun/font/layout/GXLayoutEngine2.cpp | 91 ++++ .../native/sun/font/layout/GXLayoutEngine2.h | 149 ++++++ .../sun/font/layout/IndicClassTables.cpp | 6 +- .../sun/font/layout/IndicRearrangement.h | 10 +- .../layout/IndicRearrangementProcessor2.cpp | 423 ++++++++++++++++++ .../layout/IndicRearrangementProcessor2.h | 88 ++++ .../sun/font/layout/IndicReordering.cpp | 10 +- .../native/sun/font/layout/IndicReordering.h | 6 +- .../native/sun/font/layout/LEFontInstance.h | 19 + .../native/sun/font/layout/LEGlyphFilter.h | 4 +- .../native/sun/font/layout/LEInsertionList.h | 4 +- .../share/native/sun/font/layout/LEScripts.h | 23 +- .../share/native/sun/font/layout/LETypes.h | 132 +++++- .../native/sun/font/layout/LayoutEngine.cpp | 63 ++- .../native/sun/font/layout/LayoutEngine.h | 17 +- .../sun/font/layout/LigatureSubstProc2.cpp | 141 ++++++ .../sun/font/layout/LigatureSubstProc2.h | 96 ++++ .../sun/font/layout/LigatureSubstitution.h | 19 +- .../sun/font/layout/LookupProcessor.cpp | 23 +- .../native/sun/font/layout/MPreFixups.cpp | 6 +- .../native/sun/font/layout/MorphStateTables.h | 7 +- .../native/sun/font/layout/MorphTables.h | 297 ++++++++++++ .../native/sun/font/layout/MorphTables2.cpp | 229 ++++++++++ .../sun/font/layout/NonContextualGlyphSubst.h | 7 +- .../layout/NonContextualGlyphSubstProc2.cpp | 85 ++++ .../layout/NonContextualGlyphSubstProc2.h | 68 +++ .../sun/font/layout/OpenTypeLayoutEngine.cpp | 142 +++++- .../sun/font/layout/ScriptAndLanguageTags.cpp | 15 +- .../sun/font/layout/ScriptAndLanguageTags.h | 13 +- .../font/layout/SegmentArrayProcessor2.cpp | 85 ++++ .../sun/font/layout/SegmentArrayProcessor2.h | 82 ++++ .../font/layout/SegmentSingleProcessor2.cpp | 79 ++++ .../sun/font/layout/SegmentSingleProcessor2.h | 82 ++++ .../sun/font/layout/SimpleArrayProcessor2.cpp | 76 ++++ .../sun/font/layout/SimpleArrayProcessor2.h | 82 ++++ .../sun/font/layout/SingleTableProcessor2.cpp | 76 ++++ .../sun/font/layout/SingleTableProcessor2.h | 82 ++++ .../sun/font/layout/StateTableProcessor2.cpp | 193 ++++++++ .../sun/font/layout/StateTableProcessor2.h | 84 ++++ .../native/sun/font/layout/StateTables.h | 18 +- .../sun/font/layout/SubtableProcessor2.cpp | 56 +++ .../sun/font/layout/SubtableProcessor2.h | 70 +++ .../font/layout/TrimmedArrayProcessor2.cpp | 80 ++++ .../sun/font/layout/TrimmedArrayProcessor2.h | 84 ++++ 51 files changed, 3878 insertions(+), 97 deletions(-) create mode 100644 jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h create mode 100644 jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h create mode 100644 jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h create mode 100644 jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h create mode 100644 jdk/src/share/native/sun/font/layout/MorphTables2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h create mode 100644 jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/StateTableProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/SubtableProcessor2.h create mode 100644 jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp create mode 100644 jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h diff --git a/jdk/make/sun/font/FILES_c.gmk b/jdk/make/sun/font/FILES_c.gmk index c9437064216..b1895c50f16 100644 --- a/jdk/make/sun/font/FILES_c.gmk +++ b/jdk/make/sun/font/FILES_c.gmk @@ -106,7 +106,21 @@ FILES_cpp_shared = \ OpenTypeLayoutEngine.cpp \ ThaiLayoutEngine.cpp \ ScriptAndLanguageTags.cpp \ - FontInstanceAdapter.cpp + FontInstanceAdapter.cpp \ + ContextualGlyphInsertionProc2.cpp \ + ContextualGlyphSubstProc2.cpp \ + GXLayoutEngine2.cpp \ + IndicRearrangementProcessor2.cpp \ + LigatureSubstProc2.cpp \ + MorphTables2.cpp \ + NonContextualGlyphSubstProc2.cpp \ + SegmentArrayProcessor2.cpp \ + SegmentSingleProcessor2.cpp \ + SimpleArrayProcessor2.cpp \ + SingleTableProcessor2.cpp \ + StateTableProcessor2.cpp \ + SubtableProcessor2.cpp \ + TrimmedArrayProcessor2.cpp ifeq ($(PLATFORM),windows) diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h index 40f47afcc0e..2285711b0a7 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,11 @@ struct ContextualGlyphInsertionHeader : MorphStateTableHeader { }; +struct ContextualGlyphInsertionHeader2 : MorphStateTableHeader2 +{ + le_uint32 insertionTableOffset; +}; + enum ContextualGlyphInsertionFlags { cgiSetMark = 0x8000, @@ -61,11 +66,17 @@ enum ContextualGlyphInsertionFlags cgiMarkedInsertCountMask = 0x001F }; -struct LigatureSubstitutionStateEntry : StateEntry +struct ContextualGlyphInsertionStateEntry : StateEntry { ByteOffset currentInsertionListOffset; ByteOffset markedInsertionListOffset; }; +struct ContextualGlyphInsertionStateEntry2 : StateEntry2 +{ + le_uint16 currentInsertionListIndex; + le_uint16 markedInsertionListIndex; +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp new file mode 100644 index 00000000000..a7a2386fa3c --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp @@ -0,0 +1,168 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) + +ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + contextualGlyphHeader = (const ContextualGlyphInsertionHeader2 *) morphSubtableHeader; + le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); + insertionTable = ((le_uint16 *) ((char *)&stateTableHeader->stHeader + insertionTableOffset)); + entryTable = (const ContextualGlyphInsertionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() +{ +} + +void ContextualGlyphInsertionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const ContextualGlyphInsertionStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); + le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); + int i = 0; + + if (markIndex > 0) { + le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; + if (!(flags & cgiMarkedIsKashidaLike)) { + // extra glyph(s) will be added directly before/after the specified marked glyph + if (!(flags & cgiMarkInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + for (i = 0; i < count; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + insertGlyphs[i] = glyphStorage[markGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + insertGlyphs[0] = glyphStorage[markGlyph]; + for (i = 1; i < count + 1; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + glyphStorage.applyInsertions(); + } + } else { + // inserted as a split-vowel-like insertion + // extra glyph(s) will be inserted some distance away from the marked glyph + if (!(flags & cgiMarkInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + for (i = 0; i < count; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + insertGlyphs[i] = glyphStorage[markGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); + insertGlyphs[0] = glyphStorage[markGlyph]; + for (i = 1; i < count + 1; i++, markIndex++) { + insertGlyphs[i] = insertionTable[markIndex]; + } + glyphStorage.applyInsertions(); + } + } + } + + if (currIndex > 0) { + le_int16 count = flags & cgiCurrentInsertCountMask; + if (!(flags & cgiCurrentIsKashidaLike)) { + // extra glyph(s) will be added directly before/after the specified current glyph + if (!(flags & cgiCurrentInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + for (i = 0; i < count; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + insertGlyphs[i] = glyphStorage[currGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + insertGlyphs[0] = glyphStorage[currGlyph]; + for (i = 1; i < count + 1; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + glyphStorage.applyInsertions(); + } + } else { + // inserted as a split-vowel-like insertion + // extra glyph(s) will be inserted some distance away from the current glyph + if (!(flags & cgiCurrentInsertBefore)) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + for (i = 0; i < count; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + insertGlyphs[i] = glyphStorage[currGlyph]; + glyphStorage.applyInsertions(); + } else { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); + insertGlyphs[0] = glyphStorage[currGlyph]; + for (i = 1; i < count + 1; i++, currIndex++) { + insertGlyphs[i] = insertionTable[currIndex]; + } + glyphStorage.applyInsertions(); + } + } + } + + if (flags & cgiSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgiDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +void ContextualGlyphInsertionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h new file mode 100644 index 00000000000..c53c4c9352b --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h @@ -0,0 +1,89 @@ +/* + * 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) Copyright IBM Corp. and others 2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "ContextualGlyphInsertion.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphInsertionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~ContextualGlyphInsertionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphInsertionProcessor2(); + +protected: + le_int32 markGlyph; + const le_uint16* insertionTable; + const ContextualGlyphInsertionStateEntry2 *entryTable; + const ContextualGlyphInsertionHeader2 *contextualGlyphHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp new file mode 100644 index 00000000000..1d7bc399a9b --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp @@ -0,0 +1,160 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" +#include + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor2) + +ContextualGlyphSubstitutionProcessor2::ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + contextualGlyphHeader = (const ContextualGlyphHeader2 *) morphSubtableHeader; + le_uint32 perGlyphTableOffset = SWAPL(contextualGlyphHeader->perGlyphTableOffset); + perGlyphTable = ((le_uint32 *) ((char *)&stateTableHeader->stHeader + perGlyphTableOffset)); + entryTable = (const ContextualGlyphStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +ContextualGlyphSubstitutionProcessor2::~ContextualGlyphSubstitutionProcessor2() +{ +} + +void ContextualGlyphSubstitutionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const ContextualGlyphStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + le_int16 markIndex = SWAPW(entry->markIndex); + le_int16 currIndex = SWAPW(entry->currIndex); + + if (markIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable[markIndex]); + LEGlyphID mGlyph = glyphStorage[markGlyph]; + TTGlyphID newGlyph = lookup(offset, mGlyph); + glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); + } + + if (currIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable[currIndex]); + LEGlyphID thisGlyph = glyphStorage[currGlyph]; + TTGlyphID newGlyph = lookup(offset, thisGlyph); + glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + + if (flags & cgsSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgsDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyphID gid) +{ + LookupTable *lookupTable = ((LookupTable *) ((char *)perGlyphTable + offset)); + le_int16 format = SWAPW(lookupTable->format); + TTGlyphID newGlyph = 0xFFFF; + + switch (format) { + case ltfSimpleArray: { +#ifdef TEST_FORMAT + // Disabled pending for design review + SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) lookupTable; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + newGlyph = SWAPW(lookupTable0->valueArray[glyphCode]); +#endif + break; + } + case ltfSegmentSingle: { +#ifdef TEST_FORMAT + // Disabled pending for design review + SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) lookupTable; + const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfSegmentArray: { + printf("Context Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: + { +#ifdef TEST_FORMAT + // Disabled pending for design review + SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) lookupTable; + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfTrimmedArray: { + TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) lookupTable; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + newGlyph = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + } + } + default: + break; + } + return newGlyph; +} + +void ContextualGlyphSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h new file mode 100644 index 00000000000..0f63012c7f5 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h @@ -0,0 +1,92 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~ContextualGlyphSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphSubstitutionProcessor2(); + TTGlyphID lookup(le_uint32 offset, LEGlyphID gid); + +protected: + const le_uint32* perGlyphTable; + const ContextualGlyphStateEntry2 *entryTable; + + le_int16 perGlyphTableFormat; + le_int32 markGlyph; + + const ContextualGlyphHeader2 *contextualGlyphHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h index e4e5b3ab6ba..531be23695c 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,11 @@ struct ContextualGlyphSubstitutionHeader : MorphStateTableHeader ByteOffset substitutionTableOffset; }; +struct ContextualGlyphHeader2 : MorphStateTableHeader2 +{ + le_uint32 perGlyphTableOffset; // no more substitution tables +}; + enum ContextualGlyphSubstitutionFlags { cgsSetMark = 0x8000, @@ -62,5 +67,11 @@ struct ContextualGlyphSubstitutionStateEntry : StateEntry WordOffset currOffset; }; +struct ContextualGlyphStateEntry2 : StateEntry2 +{ + le_uint16 markIndex; + le_uint16 currIndex; +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp new file mode 100644 index 00000000000..ae070c2f6ff --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp @@ -0,0 +1,91 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutEngine.h" +#include "GXLayoutEngine2.h" +#include "LEGlyphStorage.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine2) + +GXLayoutEngine2::GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMorphTable(morphTable) +{ + // nothing else to do? +} + +GXLayoutEngine2::~GXLayoutEngine2() +{ + reset(); +} + +// apply 'morx' table +le_int32 GXLayoutEngine2::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return 0; + } + + if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); + + if (LE_FAILURE(success)) { + return 0; + } + + fMorphTable->process(glyphStorage, fTypoFlags); + return count; +} + +// apply positional tables +void GXLayoutEngine2::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/, + LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return; + } + + if (chars == NULL || offset < 0 || count < 0) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return; + } + + // FIXME: no positional processing yet... +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h new file mode 100644 index 00000000000..9eded230c13 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h @@ -0,0 +1,149 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __GXLAYOUTENGINE2_H +#define __GXLAYOUTENGINE2_H + +#include "LETypes.h" +#include "LayoutEngine.h" + +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEFontInstance; +class LEGlyphStorage; + +/** + * This class implements layout for QuickDraw GX or Apple Advanced Typograyph (AAT) + * fonts. A font is a GX or AAT font if it contains a 'mort' table. See Apple's + * TrueType Reference Manual (http://fonts.apple.com/TTRefMan/index.html) for details. + * Information about 'mort' tables is in the chapter titled "Font Files." + * + * @internal + */ +class GXLayoutEngine2 : public LayoutEngine +{ +public: + /** + * This is the main constructor. It constructs an instance of GXLayoutEngine for + * a particular font, script and language. It takes the 'mort' table as a parameter since + * LayoutEngine::layoutEngineFactory has to read the 'mort' table to know that it has a + * GX font. + * + * Note: GX and AAT fonts don't contain any script and language specific tables, so + * the script and language are ignored. + * + * @param fontInstance - the font + * @param scriptCode - the script + * @param langaugeCode - the language + * @param morphTable - the 'mort' table + * @param success - set to an error code if the operation fails + * + * @see LayoutEngine::layoutEngineFactory + * @see ScriptAndLangaugeTags.h for script and language codes + * + * @internal + */ + GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success); + + /** + * The destructor, virtual for correct polymorphic invocation. + * + * @internal + */ + virtual ~GXLayoutEngine2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + + /** + * The address of the 'mort' table + * + * @internal + */ + const MorphTableHeader2 *fMorphTable; + + /** + * This method does GX layout using the font's 'mort' table. It converts the + * input character codes to glyph indices using mapCharsToGlyphs, and then + * applies the 'mort' table. + * + * Input parameters: + * @param chars - the input character context + * @param offset - the index of the first character to process + * @param count - the number of characters to process + * @param max - the number of characters in the input context + * @param rightToLeft - TRUE if the text is in a right to left directional run + * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @return the number of glyphs in the glyph index array + * + * @internal + */ + virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + + /** + * This method adjusts the glyph positions using the font's + * 'kern', 'trak', 'bsln', 'opbd' and 'just' tables. + * + * Input parameters: + * @param glyphStorage - the object holding the glyph storage. The positions will be updated as needed. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @internal + */ + virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/IndicClassTables.cpp b/jdk/src/share/native/sun/font/layout/IndicClassTables.cpp index 73cd2cfd718..8b499f8a37a 100644 --- a/jdk/src/share/native/sun/font/layout/IndicClassTables.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicClassTables.cpp @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -186,13 +186,15 @@ static const IndicClassTable::CharClass tamlCharClasses[] = }; // FIXME: Should some of the bb's be pb's? (KA, NA, MA, YA, VA, etc. (approx 13)) +// U+C43 and U+C44 are _lm here not _dr. Similar to the situation with U+CC3 and +// U+CC4 in Kannada below. static const IndicClassTable::CharClass teluCharClasses[] = { _xx, _mp, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _iv, // 0C00 - 0C0F _iv, _xx, _iv, _iv, _iv, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, // 0C10 - 0C1F _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _bb, // 0C20 - 0C2F _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _xx, _xx, _xx, _xx, _da, _da, // 0C30 - 0C3F - _da, _dr, _dr, _dr, _dr, _xx, _a1, _da, _s1, _xx, _da, _da, _da, _vr, _xx, _xx, // 0C40 - 0C4F + _da, _dr, _dr, _lm, _lm, _xx, _a1, _da, _s1, _xx, _da, _da, _da, _vr, _xx, _xx, // 0C40 - 0C4F _xx, _xx, _xx, _xx, _xx, _da, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0C50 - 0C5F _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx // 0C60 - 0C6F }; diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangement.h b/jdk/src/share/native/sun/font/layout/IndicRearrangement.h index 881e2521bca..72d5eb20530 100644 --- a/jdk/src/share/native/sun/font/layout/IndicRearrangement.h +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangement.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,10 @@ struct IndicRearrangementSubtableHeader : MorphStateTableHeader { }; +struct IndicRearrangementSubtableHeader2 : MorphStateTableHeader2 +{ +}; + enum IndicRearrangementFlags { irfMarkFirst = 0x8000, @@ -85,6 +89,10 @@ struct IndicRearrangementStateEntry : StateEntry { }; +struct IndicRearrangementStateEntry2 : StateEntry2 +{ +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp new file mode 100644 index 00000000000..35d6e43ac6b --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp @@ -0,0 +1,423 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2) + +IndicRearrangementProcessor2::IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader2 *) morphSubtableHeader; + entryTable = (const IndicRearrangementStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +IndicRearrangementProcessor2::~IndicRearrangementProcessor2() +{ +} + +void IndicRearrangementProcessor2::beginStateTable() +{ + firstGlyph = 0; + lastGlyph = 0; +} + +le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const IndicRearrangementStateEntry2 *entry = &entryTable[index]; + le_uint16 newState = SWAPW(entry->newStateIndex); // index to the new state + IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags); + + if (flags & irfMarkFirst) { + firstGlyph = currGlyph; + } + + if (flags & irfMarkLast) { + lastGlyph = currGlyph; + } + + doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask)); + + if (!(flags & irfDontAdvance)) { + currGlyph += dir; + } + + return newState; // index to new state +} + +void IndicRearrangementProcessor2::endStateTable() +{ +} + +void IndicRearrangementProcessor2::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const +{ + LEGlyphID a, b, c, d; + le_int32 ia, ib, ic, id, ix, x; + LEErrorCode success = LE_NO_ERROR; + + switch(verb) + { + case irvNoAction: + break; + + case irvxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + x = firstGlyph + 1; + + while (x <= lastGlyph) { + glyphStorage[x - 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 1, ix, success); + x += 1; + } + + glyphStorage[lastGlyph] = a; + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDx: + d = glyphStorage[lastGlyph]; + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 1; + + while (x >= firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage.setCharIndex(firstGlyph, id, success); + break; + + case irvDxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + break; + + case irvDCx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + break; + + case irvCDxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvCDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDCxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + default: + break; + } + +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h new file mode 100644 index 00000000000..3d83f21ce3b --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h @@ -0,0 +1,88 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __INDICREARRANGEMENTPROCESSOR2_H +#define __INDICREARRANGEMENTPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangement.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class IndicRearrangementProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; + + IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~IndicRearrangementProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + le_int32 firstGlyph; + le_int32 lastGlyph; + + const IndicRearrangementStateEntry2 *entryTable; + const IndicRearrangementSubtableHeader2 *indicRearrangementSubtableHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/IndicReordering.cpp b/jdk/src/share/native/sun/font/layout/IndicReordering.cpp index 9b28ada355d..9bf3a2a5c65 100644 --- a/jdk/src/share/native/sun/font/layout/IndicReordering.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicReordering.cpp @@ -266,7 +266,7 @@ public: le_uint32 saveAuxData = fGlyphStorage.getAuxData(i+inv_count,success); const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); int j; - for (j = 0 ; *(splitMatra)[j] != 0 ; j++) { + for (j = 0 ; j < SM_MAX_PIECES && *(splitMatra)[j] != 0 ; j++) { LEUnicode piece = (*splitMatra)[j]; if ( j == 0 ) { fOutChars[i+inv_count] = piece; @@ -357,7 +357,7 @@ public: const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); int i; - for (i = 0; i < 3 && (*splitMatra)[i] != 0; i += 1) { + for (i = 0; i < SM_MAX_PIECES && (*splitMatra)[i] != 0; i += 1) { LEUnicode piece = (*splitMatra)[i]; IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece); @@ -1224,7 +1224,6 @@ void IndicReordering::getDynamicProperties( DynamicProperties *, const IndicClas LEUnicode currentChar; - LEUnicode virama; LEUnicode workChars[2]; LEGlyphStorage workGlyphs; @@ -1232,14 +1231,17 @@ void IndicReordering::getDynamicProperties( DynamicProperties *, const IndicClas //le_int32 offset = 0; +#if 0 +// TODO: Should this section of code have actually been doing something? // First find the relevant virama for the script we are dealing with - + LEUnicode virama; for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { if ( classTable->isVirama(currentChar)) { virama = currentChar; break; } } +#endif for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { if ( classTable->isConsonant(currentChar)) { diff --git a/jdk/src/share/native/sun/font/layout/IndicReordering.h b/jdk/src/share/native/sun/font/layout/IndicReordering.h index 2a5b10e9369..36f7276c792 100644 --- a/jdk/src/share/native/sun/font/layout/IndicReordering.h +++ b/jdk/src/share/native/sun/font/layout/IndicReordering.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -96,7 +96,9 @@ U_NAMESPACE_BEGIN #define SF_POST_BASE_LIMIT_MASK 0x0000FFFFU #define SF_NO_POST_BASE_LIMIT 0x00007FFFU -typedef LEUnicode SplitMatra[3]; +#define SM_MAX_PIECES 3 + +typedef LEUnicode SplitMatra[SM_MAX_PIECES]; class MPreFixups; class LEGlyphStorage; diff --git a/jdk/src/share/native/sun/font/layout/LEFontInstance.h b/jdk/src/share/native/sun/font/layout/LEFontInstance.h index 1f1d415b820..c03b77c8cd4 100644 --- a/jdk/src/share/native/sun/font/layout/LEFontInstance.h +++ b/jdk/src/share/native/sun/font/layout/LEFontInstance.h @@ -190,6 +190,25 @@ public: */ virtual const void *getFontTable(LETag tableTag) const = 0; + /** + * This method reads a table from the font. Note that in general, + * it only makes sense to call this method on an LEFontInstance + * which represents a physical font - i.e. one which has been returned by + * getSubFont(). This is because each subfont in a composite font + * will have different tables, and there's no way to know which subfont to access. + * + * Subclasses which represent composite fonts should always return NULL. + * + * This version sets a length, for range checking. + * + * @param tableTag - the four byte table tag. (e.g. 'cmap') + * @param length - ignored on entry, on exit will be the length of the table if known, or -1 if unknown. + * @return the address of the table in memory, or NULL + * if the table doesn't exist. + * @internal + */ + virtual const void* getFontTable(LETag tableTag, size_t &length) const { length=-1; return getFontTable(tableTag); } /* -1 = unknown length */ + virtual void *getKernPairs() const = 0; virtual void setKernPairs(void *pairs) const = 0; diff --git a/jdk/src/share/native/sun/font/layout/LEGlyphFilter.h b/jdk/src/share/native/sun/font/layout/LEGlyphFilter.h index 3fdafe4bdc1..7f1662a0050 100644 --- a/jdk/src/share/native/sun/font/layout/LEGlyphFilter.h +++ b/jdk/src/share/native/sun/font/layout/LEGlyphFilter.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -36,6 +36,7 @@ U_NAMESPACE_BEGIN +#ifndef U_HIDE_INTERNAL_API /** * This is a helper class that is used to * recognize a set of glyph indices. @@ -63,6 +64,7 @@ public: */ virtual le_bool accept(LEGlyphID glyph) const = 0; }; +#endif /* U_HIDE_INTERNAL_API */ U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/LEInsertionList.h b/jdk/src/share/native/sun/font/layout/LEInsertionList.h index 6a48227973e..231b5f63304 100644 --- a/jdk/src/share/native/sun/font/layout/LEInsertionList.h +++ b/jdk/src/share/native/sun/font/layout/LEInsertionList.h @@ -25,7 +25,7 @@ /* ********************************************************************** - * Copyright (C) 1998-2008, International Business Machines + * Copyright (C) 1998-2013, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -39,6 +39,7 @@ U_NAMESPACE_BEGIN struct InsertionRecord; +#ifndef U_HIDE_INTERNAL_API /** * This class encapsulates the callback used by LEInsertionList * to apply an insertion from the insertion list. @@ -194,6 +195,7 @@ private: */ le_bool append; }; +#endif /* U_HIDE_INTERNAL_API */ U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/LEScripts.h b/jdk/src/share/native/sun/font/layout/LEScripts.h index ed25b604413..beb3bbedc6e 100644 --- a/jdk/src/share/native/sun/font/layout/LEScripts.h +++ b/jdk/src/share/native/sun/font/layout/LEScripts.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -241,8 +241,27 @@ enum ScriptCodes { palmScriptCode = 144, sindScriptCode = 145, waraScriptCode = 146, +/** + * @stable ICU 4.8 + */ - scriptCodeCount = 147 + afakScriptCode = 147, + jurcScriptCode = 148, + mrooScriptCode = 149, + nshuScriptCode = 150, + shrdScriptCode = 151, + soraScriptCode = 152, + takrScriptCode = 153, + tangScriptCode = 154, + woleScriptCode = 155, +/** + * @stable ICU 49 + */ + + khojScriptCode = 156, + tirhScriptCode = 157, + + scriptCodeCount = 158 }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/LETypes.h b/jdk/src/share/native/sun/font/layout/LETypes.h index be0441b538f..26cbeb363f1 100644 --- a/jdk/src/share/native/sun/font/layout/LETypes.h +++ b/jdk/src/share/native/sun/font/layout/LETypes.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -50,14 +50,15 @@ #endif #include "unicode/utypes.h" + +#ifdef __cplusplus #include "unicode/uobject.h" +#endif + #ifdef LE_USE_CMEMORY #include "cmemory.h" #endif -#endif /* not standalone */ - - -U_NAMESPACE_BEGIN +#endif /*! * \file @@ -296,12 +297,14 @@ typedef UChar LEUnicode16; */ typedef UChar32 LEUnicode32; +#ifndef U_HIDE_DEPRECATED_API /** * Used to represent 16-bit Unicode code points. * * @deprecated since ICU 2.4. Use LEUnicode16 instead */ typedef UChar LEUnicode; +#endif /* U_HIDE_DEPRECATED_API */ /** * Used to hold a pair of (x, y) values which represent a point. @@ -325,7 +328,7 @@ struct LEPoint float fY; }; -#ifndef XP_CPLUSPLUS +#ifndef __cplusplus /** * Used to hold a pair of (x, y) values which represent a point. * @@ -335,6 +338,7 @@ typedef struct LEPoint LEPoint; #endif +#ifndef U_HIDE_INTERNAL_API /** * A convenience macro to get the length of an array. * @@ -373,7 +377,52 @@ typedef struct LEPoint LEPoint; * @internal */ #define LE_DELETE_ARRAY(array) uprv_free((void *) (array)) -#endif +#else +/* !LE_USE_CMEMORY - Not using ICU memory - use C std lib versions */ + +#include +#include + +/** + * A convenience macro to get the length of an array. + * + * @internal + */ +#define LE_ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +/** + * A convenience macro for copying an array. + * + * @internal + */ +#define LE_ARRAY_COPY(dst, src, count) memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0]) + +/** + * Allocate an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_NEW_ARRAY(type, count) (type *) malloc((count) * sizeof(type)) + +/** + * Re-allocate an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_GROW_ARRAY(array, newSize) realloc((void *) (array), (newSize) * sizeof (array)[0]) + + /** + * Free an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_DELETE_ARRAY(array) free((void *) (array)) + +#endif /* LE_USE_CMEMORY */ +#endif /* U_HIDE_INTERNAL_API */ /** * A macro to construct the four-letter tags used to @@ -536,7 +585,7 @@ enum LEFeatureTags { LE_RAND_FEATURE_TAG = 0x72616E64UL, /**< 'rand' */ LE_RLIG_FEATURE_TAG = 0x726C6967UL, /**< 'rlig' */ LE_RPHF_FEATURE_TAG = 0x72706866UL, /**< 'rphf' */ - LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ + LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ LE_RTBD_FEATURE_TAG = 0x72746264UL, /**< 'rtbd' */ LE_RTLA_FEATURE_TAG = 0x72746C61UL, /**< 'rtla' */ LE_RUBY_FEATURE_TAG = 0x72756279UL, /**< 'ruby' */ @@ -587,6 +636,66 @@ enum LEFeatureTags { LE_ZERO_FEATURE_TAG = 0x7A65726FUL /**< 'zero' */ }; +/** + * @internal + */ +enum LEFeatureENUMs { + LE_Kerning_FEATURE_ENUM = 0, /**< Requests Kerning. Formerly LayoutEngine::kTypoFlagKern */ + LE_Ligatures_FEATURE_ENUM = 1, /**< Requests Ligatures. Formerly LayoutEngine::kTypoFlagLiga */ + LE_NoCanon_FEATURE_ENUM = 2, /**< Requests No Canonical Processing */ + LE_CLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_DLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_HLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_LIGA_FEATURE_ENUM, /**< Feature specific enum */ + LE_RLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_SMCP_FEATURE_ENUM, /**< Feature specific enum */ + LE_FRAC_FEATURE_ENUM, /**< Feature specific enum */ + LE_AFRC_FEATURE_ENUM, /**< Feature specific enum */ + LE_ZERO_FEATURE_ENUM, /**< Feature specific enum */ + LE_SWSH_FEATURE_ENUM, /**< Feature specific enum */ + LE_CSWH_FEATURE_ENUM, /**< Feature specific enum */ + LE_SALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_NALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_RUBY_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS01_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS02_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS03_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS04_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS05_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS06_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS07_FEATURE_ENUM, /**< Feature specific enum */ + + LE_CHAR_FILTER_FEATURE_ENUM = 31, /**< Apply CharSubstitutionFilter */ + 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_NoCanon_FEATURE_FLAG (1 << LE_NoCanon_FEATURE_ENUM) +#define LE_CLIG_FEATURE_FLAG (1 << LE_CLIG_FEATURE_ENUM) +#define LE_DLIG_FEATURE_FLAG (1 << LE_DLIG_FEATURE_ENUM) +#define LE_HLIG_FEATURE_FLAG (1 << LE_HLIG_FEATURE_ENUM) +#define LE_LIGA_FEATURE_FLAG (1 << LE_LIGA_FEATURE_ENUM) +#define LE_RLIG_FEATURE_FLAG (1 << LE_RLIG_FEATURE_ENUM) +#define LE_SMCP_FEATURE_FLAG (1 << LE_SMCP_FEATURE_ENUM) +#define LE_FRAC_FEATURE_FLAG (1 << LE_FRAC_FEATURE_ENUM) +#define LE_AFRC_FEATURE_FLAG (1 << LE_AFRC_FEATURE_ENUM) +#define LE_ZERO_FEATURE_FLAG (1 << LE_ZERO_FEATURE_ENUM) +#define LE_SWSH_FEATURE_FLAG (1 << LE_SWSH_FEATURE_ENUM) +#define LE_CSWH_FEATURE_FLAG (1 << LE_CSWH_FEATURE_ENUM) +#define LE_SALT_FEATURE_FLAG (1 << LE_SALT_FEATURE_ENUM) +#define LE_NALT_FEATURE_FLAG (1 << LE_NALT_FEATURE_ENUM) +#define LE_RUBY_FEATURE_FLAG (1 << LE_RUBY_FEATURE_ENUM) +#define LE_SS01_FEATURE_FLAG (1 << LE_SS01_FEATURE_ENUM) +#define LE_SS02_FEATURE_FLAG (1 << LE_SS02_FEATURE_ENUM) +#define LE_SS03_FEATURE_FLAG (1 << LE_SS03_FEATURE_ENUM) +#define LE_SS04_FEATURE_FLAG (1 << LE_SS04_FEATURE_ENUM) +#define LE_SS05_FEATURE_FLAG (1 << LE_SS05_FEATURE_ENUM) +#define LE_SS06_FEATURE_FLAG (1 << LE_SS06_FEATURE_ENUM) +#define LE_SS07_FEATURE_FLAG (1 << LE_SS07_FEATURE_ENUM) + +#define LE_CHAR_FILTER_FEATURE_FLAG (1 << LE_CHAR_FILTER_FEATURE_ENUM) + /** * Error codes returned by the LayoutEngine. * @@ -611,7 +720,7 @@ enum LEErrorCode { }; #endif -#ifndef XP_CPLUSPLUS +#ifndef __cplusplus /** * Error codes returned by the LayoutEngine. * @@ -638,7 +747,4 @@ typedef enum LEErrorCode LEErrorCode; #define LE_FAILURE(code) (U_FAILURE((UErrorCode)code)) #endif -U_NAMESPACE_END -#endif - - +#endif /* __LETYPES_H */ diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp index 90aafde2a80..689b85cd2e7 100644 --- a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp @@ -33,6 +33,7 @@ #include "LETypes.h" #include "LEScripts.h" #include "LELanguages.h" +#include "LESwaps.h" #include "LayoutEngine.h" #include "ArabicLayoutEngine.h" @@ -44,6 +45,8 @@ #include "ThaiLayoutEngine.h" #include "TibetanLayoutEngine.h" #include "GXLayoutEngine.h" +#include "GXLayoutEngine2.h" + #include "ScriptAndLanguageTags.h" #include "CharSubstitutionFilter.h" @@ -63,6 +66,10 @@ U_NAMESPACE_BEGIN /* Leave this copyright notice here! It needs to go somewhere in this library. */ static const char copyright[] = U_COPYRIGHT_STRING; +/* TODO: remove these? */ +const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; +const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; + const LEUnicode32 DefaultCharMapper::controlChars[] = { 0x0009, 0x000A, 0x000D, /*0x200C, 0x200D,*/ 0x200E, 0x200F, @@ -251,7 +258,7 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off return 0; } - if ((fTypoFlags & 0x4) == 0) { // no canonical processing + if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing return count; } @@ -572,6 +579,7 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan { static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; + static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; if (LE_FAILURE(success)) { return NULL; @@ -608,6 +616,11 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; + case hebrScriptCode: + // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 + result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); + break; + case hangScriptCode: result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; @@ -646,26 +659,29 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan break; } } else { - const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - - if (morphTable != NULL) { - result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success); + MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); + if (morxTable != NULL) { + result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); } else { - switch (scriptCode) { - case bengScriptCode: - case devaScriptCode: - case gujrScriptCode: - case kndaScriptCode: - case mlymScriptCode: - case oryaScriptCode: - case guruScriptCode: - case tamlScriptCode: - case teluScriptCode: - case sinhScriptCode: - { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; - } + const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); + if (mortTable != NULL) { // mort + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + } else { + switch (scriptCode) { + case bengScriptCode: + case devaScriptCode: + case gujrScriptCode: + case kndaScriptCode: + case mlymScriptCode: + case oryaScriptCode: + case guruScriptCode: + case tamlScriptCode: + case teluScriptCode: + case sinhScriptCode: + { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } case arabScriptCode: //case hebrScriptCode: @@ -683,9 +699,10 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); break; - default: - result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + default: + result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } } } } diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.h b/jdk/src/share/native/sun/font/layout/LayoutEngine.h index 4334ce355d4..9293167dba6 100644 --- a/jdk/src/share/native/sun/font/layout/LayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.h @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -90,6 +90,14 @@ class LEGlyphStorage; * @stable ICU 2.8 */ class U_LAYOUT_API LayoutEngine : public UObject { +public: +#ifndef U_HIDE_INTERNAL_API + /** @internal Flag to request kerning. Use LE_Kerning_FEATURE_FLAG instead. */ + static const le_int32 kTypoFlagKern; + /** @internal Flag to request ligatures. Use LE_Ligatures_FEATURE_FLAG instead. */ + static const le_int32 kTypoFlagLiga; +#endif /* U_HIDE_INTERNAL_API */ + protected: /** * The object which holds the glyph storage @@ -140,6 +148,7 @@ protected: */ le_bool fFilterZeroWidth; +#ifndef U_HIDE_INTERNAL_API /** * This constructs an instance for a given font, script and language. Subclass constructors * must call this constructor. @@ -161,7 +170,10 @@ protected: le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success); +#endif /* U_HIDE_INTERNAL_API */ + // Do not enclose the protected default constructor with #ifndef U_HIDE_INTERNAL_API + // or else the compiler will create a public default constructor. /** * This overrides the default no argument constructor to make it * difficult for clients to call it. Clients are expected to call @@ -302,6 +314,7 @@ protected: */ virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphStorage &glyphStorage, LEErrorCode &success); +#ifndef U_HIDE_INTERNAL_API /** * This is a convenience method that forces the advance width of mark * glyphs to be zero, which is required for proper selection and highlighting. @@ -336,7 +349,7 @@ protected: * @internal */ static void adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success); - +#endif /* U_HIDE_INTERNAL_API */ public: /** diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp new file mode 100644 index 00000000000..c26442da723 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp @@ -0,0 +1,141 @@ +/* + * 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) Copyright IBM Corp and Others. 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +#define ExtendedComplement(m) ((le_int32) (~((le_uint32) (m)))) +#define SignBit(m) ((ExtendedComplement(m) >> 1) & (le_int32)(m)) +#define SignExtend(v,m) (((v) & SignBit(m))? ((v) | ExtendedComplement(m)): (v)) + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor2) + +LigatureSubstitutionProcessor2::LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : StateTableProcessor2(morphSubtableHeader) +{ + ligatureSubstitutionHeader = (const LigatureSubstitutionHeader2 *) morphSubtableHeader; + ligActionOffset = SWAPL(ligatureSubstitutionHeader->ligActionOffset); + componentOffset = SWAPL(ligatureSubstitutionHeader->componentOffset); + ligatureOffset = SWAPL(ligatureSubstitutionHeader->ligatureOffset); + + entryTable = (const LigatureSubstitutionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); +} + +LigatureSubstitutionProcessor2::~LigatureSubstitutionProcessor2() +{ +} + +void LigatureSubstitutionProcessor2::beginStateTable() +{ + m = -1; +} + +le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +{ + const LigatureSubstitutionStateEntry2 *entry = &entryTable[index]; + le_uint16 nextStateIndex = SWAPW(entry->nextStateIndex); + le_uint16 flags = SWAPW(entry->entryFlags); + le_uint16 ligActionIndex = SWAPW(entry->ligActionIndex); + + if (flags & lsfSetComponent) { + if (++m >= nComponents) { + m = 0; + } + componentStack[m] = currGlyph; + } + + ByteOffset actionOffset = flags & lsfPerformAction; + + if (actionOffset != 0) { + const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + ligActionOffset) + ligActionIndex; + const TTGlyphID *ligatureTable = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + ligatureOffset); + LigatureActionEntry action; + le_int32 offset, i = 0; + le_int32 stack[nComponents]; + le_int16 mm = -1; + + const le_uint16 *componentTable = (const le_uint16 *)((char *) &ligatureSubstitutionHeader->stHeader + componentOffset); + + do { + le_uint32 componentGlyph = componentStack[m--]; // pop off + + action = SWAPL(*ap++); + + if (m < 0) { + m = nComponents - 1; + } + + offset = action & lafComponentOffsetMask; + if (offset != 0) { + + i += SWAPW(componentTable[LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask))]); + + if (action & (lafLast | lafStore)) { + TTGlyphID ligatureGlyph = SWAPW(ligatureTable[i]); + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); + stack[++mm] = componentGlyph; + i = 0; + } else { + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); + } + } + } while (!(action & lafLast)); + + while (mm >= 0) { + if (++m >= nComponents) { + m = 0; + } + + componentStack[m] = stack[mm--]; + } + } + + if (!(flags & lsfDontAdvance)) { + currGlyph += dir; + } + + return nextStateIndex; +} + +void LigatureSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h new file mode 100644 index 00000000000..81ab8b56e8a --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h @@ -0,0 +1,96 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __LIGATURESUBSTITUTIONPROCESSOR2_H +#define __LIGATURESUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +#define nComponents 16 + +class LigatureSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + + virtual void endStateTable(); + + LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~LigatureSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + LigatureSubstitutionProcessor2(); + +protected: + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; + + const LigatureSubstitutionStateEntry2 *entryTable; + + le_int32 componentStack[nComponents]; + le_int16 m; + + const LigatureSubstitutionHeader2 *ligatureSubstitutionHeader; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstitution.h b/jdk/src/share/native/sun/font/layout/LigatureSubstitution.h index e58a739d264..b45d56e8c78 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstitution.h +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstitution.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -52,17 +52,32 @@ struct LigatureSubstitutionHeader : MorphStateTableHeader ByteOffset ligatureTableOffset; }; +struct LigatureSubstitutionHeader2 : MorphStateTableHeader2 +{ + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; +}; + enum LigatureSubstitutionFlags { lsfSetComponent = 0x8000, lsfDontAdvance = 0x4000, - lsfActionOffsetMask = 0x3FFF + lsfActionOffsetMask = 0x3FFF, // N/A in morx + lsfPerformAction = 0x2000 }; struct LigatureSubstitutionStateEntry : StateEntry { }; +struct LigatureSubstitutionStateEntry2 +{ + le_uint16 nextStateIndex; + le_uint16 entryFlags; + le_uint16 ligActionIndex; +}; + typedef le_uint32 LigatureActionEntry; enum LigatureActionFlags diff --git a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp index 88e9f25ddeb..6e74130989b 100644 --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -95,10 +95,9 @@ le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdj if (selectMask != 0) { const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup); - - if (!lookupTable) + if (!lookupTable) { continue; - + } le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); glyphIterator.reset(lookupFlags, selectMask); @@ -143,9 +142,9 @@ le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, Featur for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) { le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]); - - if (lookupListIndex >= lookupSelectCount) + if (lookupListIndex >= lookupSelectCount) { continue; + } lookupSelectArray[lookupListIndex] |= featureMask; lookupOrderArray[store++] = lookupListIndex; @@ -224,13 +223,17 @@ LookupProcessor::LookupProcessor(const char *baseAddress, le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); - - if (!featureTable) - continue; - + if (!featureTable) { + continue; + } featureReferences += SWAPW(featureTable->lookupCount); } + if (!featureTable) { + success = LE_INTERNAL_ERROR; + return; + } + if (requiredFeatureIndex != 0xFFFF) { requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag); featureReferences += SWAPW(featureTable->lookupCount); diff --git a/jdk/src/share/native/sun/font/layout/MPreFixups.cpp b/jdk/src/share/native/sun/font/layout/MPreFixups.cpp index 254b3b01ace..add1613dc85 100644 --- a/jdk/src/share/native/sun/font/layout/MPreFixups.cpp +++ b/jdk/src/share/native/sun/font/layout/MPreFixups.cpp @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 2002-2008 - All Rights Reserved + * (C) Copyright IBM Corp. 2002-2013 - All Rights Reserved * */ @@ -65,9 +65,9 @@ void MPreFixups::add(le_int32 baseIndex, le_int32 mpreIndex) } } -void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& leSuccess) +void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& success) { - if (LE_FAILURE(leSuccess)) { + if (LE_FAILURE(success)) { return; } diff --git a/jdk/src/share/native/sun/font/layout/MorphStateTables.h b/jdk/src/share/native/sun/font/layout/MorphStateTables.h index 11644ca5f65..e3c9c72b038 100644 --- a/jdk/src/share/native/sun/font/layout/MorphStateTables.h +++ b/jdk/src/share/native/sun/font/layout/MorphStateTables.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,5 +49,10 @@ struct MorphStateTableHeader : MorphSubtableHeader StateTableHeader stHeader; }; +struct MorphStateTableHeader2 : MorphSubtableHeader2 +{ + StateTableHeader2 stHeader; +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MorphTables.h b/jdk/src/share/native/sun/font/layout/MorphTables.h index c9bbf8750f4..f58c1985a64 100644 --- a/jdk/src/share/native/sun/font/layout/MorphTables.h +++ b/jdk/src/share/native/sun/font/layout/MorphTables.h @@ -76,6 +76,7 @@ struct MorphTableHeader }; typedef le_int16 SubtableCoverage; +typedef le_uint32 SubtableCoverage2; enum SubtableCoverageFlags { @@ -105,6 +106,302 @@ struct MorphSubtableHeader void process(LEGlyphStorage &glyphStorage) const; }; +enum SubtableCoverageFlags2 +{ + scfVertical2 = 0x80000000, + scfReverse2 = 0x40000000, + scfIgnoreVt2 = 0x20000000, + scfReserved2 = 0x1FFFFF00, + scfTypeMask2 = 0x000000FF +}; + +struct MorphSubtableHeader2 +{ + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + void process(LEGlyphStorage &glyphStorage) const; +}; + +struct ChainHeader2 +{ + FeatureFlags defaultFlags; + le_uint32 chainLength; + le_uint32 nFeatureEntries; + le_uint32 nSubtables; + FeatureTableEntry featureTable[ANY_NUMBER]; +}; + +struct MorphTableHeader2 +{ + le_int32 version; + le_uint32 nChains; + ChainHeader2 chains[ANY_NUMBER]; + + void process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const; +}; + +/* + * AAT Font Features + * source: https://developer.apple.com/fonts/registry/ + * (plus addition from ATS/SFNTLayoutTypes.h) + */ + +enum { + + allTypographicFeaturesType = 0, + + allTypeFeaturesOnSelector = 0, + allTypeFeaturesOffSelector = 1, + + ligaturesType = 1, + + requiredLigaturesOnSelector = 0, + requiredLigaturesOffSelector = 1, + commonLigaturesOnSelector = 2, + commonLigaturesOffSelector = 3, + rareLigaturesOnSelector = 4, + rareLigaturesOffSelector = 5, + logosOnSelector = 6, + logosOffSelector = 7, + rebusPicturesOnSelector = 8, + rebusPicturesOffSelector = 9, + diphthongLigaturesOnSelector = 10, + diphthongLigaturesOffSelector = 11, + squaredLigaturesOnSelector = 12, + squaredLigaturesOffSelector = 13, + abbrevSquaredLigaturesOnSelector = 14, + abbrevSquaredLigaturesOffSelector = 15, + symbolLigaturesOnSelector = 16, + symbolLigaturesOffSelector = 17, + contextualLigaturesOnSelector = 18, + contextualLigaturesOffSelector = 19, + historicalLigaturesOnSelector = 20, + historicalLigaturesOffSelector = 21, + + cursiveConnectionType = 2, + + unconnectedSelector = 0, + partiallyConnectedSelector = 1, + cursiveSelector = 2, + + letterCaseType = 3, + + upperAndLowerCaseSelector = 0, + allCapsSelector = 1, + allLowerCaseSelector = 2, + smallCapsSelector = 3, + initialCapsSelector = 4, + initialCapsAndSmallCapsSelector = 5, + + verticalSubstitutionType = 4, + + substituteVerticalFormsOnSelector = 0, + substituteVerticalFormsOffSelector = 1, + + linguisticRearrangementType = 5, + + linguisticRearrangementOnSelector = 0, + linguisticRearrangementOffSelector = 1, + + numberSpacingType = 6, + + monospacedNumbersSelector = 0, + proportionalNumbersSelector = 1, + + /* + appleReserved1Type = 7, + */ + + smartSwashType = 8, + + wordInitialSwashesOnSelector = 0, + wordInitialSwashesOffSelector = 1, + wordFinalSwashesOnSelector = 2, + wordFinalSwashesOffSelector = 3, + lineInitialSwashesOnSelector = 4, + lineInitialSwashesOffSelector = 5, + lineFinalSwashesOnSelector = 6, + lineFinalSwashesOffSelector = 7, + nonFinalSwashesOnSelector = 8, + nonFinalSwashesOffSelector = 9, + + diacriticsType = 9, + + showDiacriticsSelector = 0, + hideDiacriticsSelector = 1, + decomposeDiacriticsSelector = 2, + + verticalPositionType = 10, + + normalPositionSelector = 0, + superiorsSelector = 1, + inferiorsSelector = 2, + ordinalsSelector = 3, + + fractionsType = 11, + + noFractionsSelector = 0, + verticalFractionsSelector = 1, + diagonalFractionsSelector = 2, + + /* + appleReserved2Type = 12, + */ + + overlappingCharactersType = 13, + + preventOverlapOnSelector = 0, + preventOverlapOffSelector = 1, + + typographicExtrasType = 14, + + hyphensToEmDashOnSelector = 0, + hyphensToEmDashOffSelector = 1, + hyphenToEnDashOnSelector = 2, + hyphenToEnDashOffSelector = 3, + unslashedZeroOnSelector = 4, + slashedZeroOffSelector = 4, + unslashedZeroOffSelector = 5, + slashedZeroOnSelector = 5, + formInterrobangOnSelector = 6, + formInterrobangOffSelector = 7, + smartQuotesOnSelector = 8, + smartQuotesOffSelector = 9, + periodsToEllipsisOnSelector = 10, + periodsToEllipsisOffSelector = 11, + + mathematicalExtrasType = 15, + + hyphenToMinusOnSelector = 0, + hyphenToMinusOffSelector = 1, + asteriskToMultiplyOnSelector = 2, + asteriskToMultiplyOffSelector = 3, + slashToDivideOnSelector = 4, + slashToDivideOffSelector = 5, + inequalityLigaturesOnSelector = 6, + inequalityLigaturesOffSelector = 7, + exponentsOnSelector = 8, + exponentsOffSelector = 9, + + ornamentSetsType = 16, + + noOrnamentsSelector = 0, + dingbatsSelector = 1, + piCharactersSelector = 2, + fleuronsSelector = 3, + decorativeBordersSelector = 4, + internationalSymbolsSelector = 5, + mathSymbolsSelector = 6, + + characterAlternativesType = 17, + + noAlternatesSelector = 0, + + designComplexityType = 18, + + designLevel1Selector = 0, + designLevel2Selector = 1, + designLevel3Selector = 2, + designLevel4Selector = 3, + designLevel5Selector = 4, + designLevel6Selector = 5, + designLevel7Selector = 6, + + styleOptionsType = 19, + + noStyleOptionsSelector = 0, + displayTextSelector = 1, + engravedTextSelector = 2, + illuminatedCapsSelector = 3, + titlingCapsSelector = 4, + tallCapsSelector = 5, + + characterShapeType = 20, + + traditionalCharactersSelector = 0, + simplifiedCharactersSelector = 1, + jis1978CharactersSelector = 2, + jis1983CharactersSelector = 3, + jis1990CharactersSelector = 4, + traditionalAltOneSelector = 5, + traditionalAltTwoSelector = 6, + traditionalAltThreeSelector = 7, + traditionalAltFourSelector = 8, + traditionalAltFiveSelector = 9, + expertCharactersSelector = 10, + + numberCaseType = 21, + + lowerCaseNumbersSelector = 0, + upperCaseNumbersSelector = 1, + + textSpacingType = 22, + + proportionalTextSelector = 0, + monospacedTextSelector = 1, + halfWidthTextSelector = 2, + normallySpacedTextSelector = 3, + + transliterationType = 23, + + noTransliterationSelector = 0, + hanjaToHangulSelector = 1, + hiraganaToKatakanaSelector = 2, + katakanaToHiraganaSelector = 3, + kanaToRomanizationSelector = 4, + romanizationToHiraganaSelector = 5, + romanizationToKatakanaSelector = 6, + hanjaToHangulAltOneSelector = 7, + hanjaToHangulAltTwoSelector = 8, + hanjaToHangulAltThreeSelector = 9, + + annotationType = 24, + + noAnnotationSelector = 0, + boxAnnotationSelector = 1, + roundedBoxAnnotationSelector = 2, + circleAnnotationSelector = 3, + invertedCircleAnnotationSelector = 4, + parenthesisAnnotationSelector = 5, + periodAnnotationSelector = 6, + romanNumeralAnnotationSelector = 7, + diamondAnnotationSelector = 8, + + kanaSpacingType = 25, + + fullWidthKanaSelector = 0, + proportionalKanaSelector = 1, + + ideographicSpacingType = 26, + + fullWidthIdeographsSelector = 0, + proportionalIdeographsSelector = 1, + + cjkRomanSpacingType = 103, + + halfWidthCJKRomanSelector = 0, + proportionalCJKRomanSelector = 1, + defaultCJKRomanSelector = 2, + fullWidthCJKRomanSelector = 3, + + rubyKanaType = 28, + + rubyKanaOnSelector = 2, + rubyKanaOffSelector = 3, + +/* The following types are provided for compatibility; note that + their use is deprecated. */ + + adobeCharacterSpacingType = 100, /* prefer 22 */ + adobeKanaSpacingType = 101, /* prefer 25 */ + adobeKanjiSpacingType = 102, /* prefer 26 */ + adobeSquareLigatures = 104, /* prefer 1 */ + + lastFeatureType = -1 +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MorphTables2.cpp b/jdk/src/share/native/sun/font/layout/MorphTables2.cpp new file mode 100644 index 00000000000..c9951a5f411 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/MorphTables2.cpp @@ -0,0 +1,229 @@ +/* + * 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) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutTables.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LigatureSubstProc2.h" +#include "NonContextualGlyphSubstProc2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +void MorphTableHeader2::process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const +{ + const ChainHeader2 *chainHeader = chains; + le_uint32 chainCount = SWAPL(this->nChains); + le_uint32 chain; + + for (chain = 0; chain < chainCount; chain++) { + FeatureFlags flag = SWAPL(chainHeader->defaultFlags); + le_uint32 chainLength = SWAPL(chainHeader->chainLength); + le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); + le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); + const MorphSubtableHeader2 *subtableHeader = + (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]; + le_uint32 subtable; + + if (typoFlags != 0) { + le_uint32 featureEntry; + + // Feature subtables + for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { + FeatureTableEntry featureTableEntry = chains->featureTable[featureEntry]; + le_int16 featureType = SWAPW(featureTableEntry.featureType); + le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); + le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); + le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags); + switch (featureType) { + case ligaturesType: + if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } else { + if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) || + ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) || + ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) || + ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } + } + break; + case letterCaseType: + if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case verticalSubstitutionType: + break; + case linguisticRearrangementType: + break; + case numberSpacingType: + break; + case smartSwashType: + if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } + break; + case diacriticsType: + break; + case verticalPositionType: + break; + case fractionsType: + if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) || + ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } else { + flag &= disableFlags; + } + break; + case typographicExtrasType: + if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case mathematicalExtrasType: + break; + case ornamentSetsType: + break; + case characterAlternativesType: + break; + case designComplexityType: + if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) || + ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) || + ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) || + ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) || + ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) || + ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) || + ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) { + + flag &= disableFlags; + flag |= enableFlags; + } + break; + case styleOptionsType: + break; + case characterShapeType: + break; + case numberCaseType: + break; + case textSpacingType: + break; + case transliterationType: + break; + case annotationType: + if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case kanaSpacingType: + break; + case ideographicSpacingType: + break; + case rubyKanaType: + if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case cjkRomanSpacingType: + break; + default: + break; + } + } + } + + for (subtable = 0; subtable < nSubtables; subtable++) { + le_uint32 length = SWAPL(subtableHeader->length); + le_uint32 coverage = SWAPL(subtableHeader->coverage); + FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); + // should check coverage more carefully... + if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { + subtableHeader->process(glyphStorage); + } + subtableHeader = (const MorphSubtableHeader2 *) ((char *)subtableHeader + length); + } + chainHeader = (const ChainHeader2 *)((char *)chainHeader + chainLength); + } +} + +void MorphSubtableHeader2::process(LEGlyphStorage &glyphStorage) const +{ + SubtableProcessor2 *processor = NULL; + + switch (SWAPL(coverage) & scfTypeMask2) + { + case mstIndicRearrangement: + processor = new IndicRearrangementProcessor2(this); + break; + + case mstContextualGlyphSubstitution: + processor = new ContextualGlyphSubstitutionProcessor2(this); + break; + + case mstLigatureSubstitution: + processor = new LigatureSubstitutionProcessor2(this); + break; + + case mstReservedUnused: + break; + + case mstNonContextualGlyphSubstitution: + processor = NonContextualGlyphSubstitutionProcessor2::createInstance(this); + break; + + + case mstContextualGlyphInsertion: + processor = new ContextualGlyphInsertionProcessor2(this); + break; + + default: + break; + } + + if (processor != NULL) { + processor->process(glyphStorage); + delete processor; + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubst.h b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubst.h index 3c30dd84d90..47428b45d0a 100644 --- a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubst.h +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubst.h @@ -26,7 +26,7 @@ /* * * - * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -50,6 +50,11 @@ struct NonContextualGlyphSubstitutionHeader : MorphSubtableHeader LookupTable table; }; +struct NonContextualGlyphSubstitutionHeader2 : MorphSubtableHeader2 +{ + LookupTable table; +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp new file mode 100644 index 00000000000..8c304912400 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp @@ -0,0 +1,85 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "SegmentSingleProcessor2.h" +#include "SegmentArrayProcessor2.h" +#include "SingleTableProcessor2.h" +#include "TrimmedArrayProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2() +{ +} + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : SubtableProcessor2(morphSubtableHeader) +{ +} + +NonContextualGlyphSubstitutionProcessor2::~NonContextualGlyphSubstitutionProcessor2() +{ +} + +SubtableProcessor2 *NonContextualGlyphSubstitutionProcessor2::createInstance(const MorphSubtableHeader2 *morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + switch (SWAPW(header->table.format)) + { + case ltfSimpleArray: + return new SimpleArrayProcessor2(morphSubtableHeader); + + case ltfSegmentSingle: + return new SegmentSingleProcessor2(morphSubtableHeader); + + case ltfSegmentArray: + return new SegmentArrayProcessor2(morphSubtableHeader); + + case ltfSingleTable: + return new SingleTableProcessor2(morphSubtableHeader); + + case ltfTrimmedArray: + return new TrimmedArrayProcessor2(morphSubtableHeader); + + default: + return NULL; + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h new file mode 100644 index 00000000000..6354bc92069 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h @@ -0,0 +1,68 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class NonContextualGlyphSubstitutionProcessor2 : public SubtableProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage) = 0; + + static SubtableProcessor2 *createInstance(const MorphSubtableHeader2 *morphSubtableHeader); + +protected: + NonContextualGlyphSubstitutionProcessor2(); + NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~NonContextualGlyphSubstitutionProcessor2(); + +private: + NonContextualGlyphSubstitutionProcessor2(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class + NonContextualGlyphSubstitutionProcessor2 &operator=(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp index 45eaadf4b7a..375327b55da 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -64,11 +64,27 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define loclFeatureTag LE_LOCL_FEATURE_TAG #define caltFeatureTag LE_CALT_FEATURE_TAG -// 'dlig' not used at the moment -#define dligFeatureTag 0x646C6967 +#define dligFeatureTag LE_DLIG_FEATURE_TAG +#define rligFeatureTag LE_RLIG_FEATURE_TAG +#define paltFeatureTag LE_PALT_FEATURE_TAG -// 'palt' -#define paltFeatureTag 0x70616C74 +#define hligFeatureTag LE_HLIG_FEATURE_TAG +#define smcpFeatureTag LE_SMCP_FEATURE_TAG +#define fracFeatureTag LE_FRAC_FEATURE_TAG +#define afrcFeatureTag LE_AFRC_FEATURE_TAG +#define zeroFeatureTag LE_ZERO_FEATURE_TAG +#define swshFeatureTag LE_SWSH_FEATURE_TAG +#define cswhFeatureTag LE_CSWH_FEATURE_TAG +#define saltFeatureTag LE_SALT_FEATURE_TAG +#define naltFeatureTag LE_NALT_FEATURE_TAG +#define rubyFeatureTag LE_RUBY_FEATURE_TAG +#define ss01FeatureTag LE_SS01_FEATURE_TAG +#define ss02FeatureTag LE_SS02_FEATURE_TAG +#define ss03FeatureTag LE_SS03_FEATURE_TAG +#define ss04FeatureTag LE_SS04_FEATURE_TAG +#define ss05FeatureTag LE_SS05_FEATURE_TAG +#define ss06FeatureTag LE_SS06_FEATURE_TAG +#define ss07FeatureTag LE_SS07_FEATURE_TAG #define ccmpFeatureMask 0x80000000UL #define ligaFeatureMask 0x40000000UL @@ -80,10 +96,27 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define loclFeatureMask 0x01000000UL #define caltFeatureMask 0x00800000UL +#define dligFeatureMask 0x00400000UL +#define rligFeatureMask 0x00200000UL +#define hligFeatureMask 0x00100000UL +#define smcpFeatureMask 0x00080000UL +#define fracFeatureMask 0x00040000UL +#define afrcFeatureMask 0x00020000UL +#define zeroFeatureMask 0x00010000UL +#define swshFeatureMask 0x00008000UL +#define cswhFeatureMask 0x00004000UL +#define saltFeatureMask 0x00002000UL +#define naltFeatureMask 0x00001000UL +#define rubyFeatureMask 0x00000800UL +#define ss01FeatureMask 0x00000400UL +#define ss02FeatureMask 0x00000200UL +#define ss03FeatureMask 0x00000100UL +#define ss04FeatureMask 0x00000080UL +#define ss05FeatureMask 0x00000040UL +#define ss06FeatureMask 0x00000020UL +#define ss07FeatureMask 0x00000010UL + #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask) -#define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures) -#define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures) -#define kernAndLigaFeatures (ligaFeatures | kernFeatures) static const FeatureMap featureMap[] = { @@ -95,7 +128,24 @@ static const FeatureMap featureMap[] = {markFeatureTag, markFeatureMask}, {mkmkFeatureTag, mkmkFeatureMask}, {loclFeatureTag, loclFeatureMask}, - {caltFeatureTag, caltFeatureMask} + {caltFeatureTag, caltFeatureMask}, + {hligFeatureTag, hligFeatureMask}, + {smcpFeatureTag, smcpFeatureMask}, + {fracFeatureTag, fracFeatureMask}, + {afrcFeatureTag, afrcFeatureMask}, + {zeroFeatureTag, zeroFeatureMask}, + {swshFeatureTag, swshFeatureMask}, + {cswhFeatureTag, cswhFeatureMask}, + {saltFeatureTag, saltFeatureMask}, + {naltFeatureTag, naltFeatureMask}, + {rubyFeatureTag, rubyFeatureMask}, + {ss01FeatureTag, ss01FeatureMask}, + {ss02FeatureTag, ss02FeatureMask}, + {ss03FeatureTag, ss03FeatureMask}, + {ss04FeatureTag, ss04FeatureMask}, + {ss05FeatureTag, ss05FeatureMask}, + {ss06FeatureTag, ss06FeatureMask}, + {ss07FeatureTag, ss07FeatureMask} }; static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); @@ -110,17 +160,65 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); - // todo: switch to more flags and bitfield rather than list of feature tags? - switch (typoFlags & ~0x80000000L) { - case 0: break; // default - case 1: fFeatureMask = kernFeatures; break; - case 2: fFeatureMask = ligaFeatures; break; - case 3: fFeatureMask = kernAndLigaFeatures; break; - default: break; + switch (typoFlags & (LE_SS01_FEATURE_FLAG + | LE_SS02_FEATURE_FLAG + | LE_SS03_FEATURE_FLAG + | LE_SS04_FEATURE_FLAG + | LE_SS05_FEATURE_FLAG + | LE_SS06_FEATURE_FLAG + | LE_SS07_FEATURE_FLAG)) { + case LE_SS01_FEATURE_FLAG: + fFeatureMask |= ss01FeatureMask; + break; + case LE_SS02_FEATURE_FLAG: + fFeatureMask |= ss02FeatureMask; + break; + case LE_SS03_FEATURE_FLAG: + fFeatureMask |= ss03FeatureMask; + break; + case LE_SS04_FEATURE_FLAG: + fFeatureMask |= ss04FeatureMask; + break; + case LE_SS05_FEATURE_FLAG: + fFeatureMask |= ss05FeatureMask; + break; + case LE_SS06_FEATURE_FLAG: + fFeatureMask |= ss06FeatureMask; + break; + case LE_SS07_FEATURE_FLAG: + fFeatureMask |= ss07FeatureMask; + break; } - if (typoFlags & 0x80000000L) { - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + if (typoFlags & LE_Kerning_FEATURE_FLAG) { + fFeatureMask |= (kernFeatureMask | paltFeatureMask); + // Convenience. + } + if (typoFlags & LE_Ligatures_FEATURE_FLAG) { + fFeatureMask |= (ligaFeatureMask | cligFeatureMask); + // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ? + } + if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask; + if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask; + if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask; + if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask; + if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask; + if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask; + if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask; + if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask; + if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask; + if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask; + if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask; + if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask; + if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask; + if (typoFlags & LE_NALT_FEATURE_FLAG) { + // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm + fFeatureMask = naltFeatureMask; + } + + if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { + // This isn't a font feature, but requests a Char Substitution Filter + fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); } setScriptAndLanguageTags(); @@ -325,7 +423,7 @@ le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 o { LEUnicode *outChars = NULL; LEGlyphStorage fakeGlyphStorage; - le_int32 outCharCount, outGlyphCount, fakeGlyphCount; + le_int32 outCharCount, outGlyphCount; if (LE_FAILURE(success)) { return 0; @@ -343,11 +441,13 @@ le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 o } if (outChars != NULL) { - fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount); } else { - fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount); } diff --git a/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp b/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp index c7d46c631bc..3f89c46e4da 100644 --- a/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp +++ b/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -186,7 +186,18 @@ const LETag OpenTypeLayoutEngine::scriptTags[] = { nbatScriptTag, /* 'nbat' (NBAT) */ palmScriptTag, /* 'palm' (PALM) */ sindScriptTag, /* 'sind' (SIND) */ - waraScriptTag /* 'wara' (WARA) */ + waraScriptTag, /* 'wara' (WARA) */ + afakScriptTag, /* 'afak' (AFAK) */ + jurcScriptTag, /* 'jurc' (JURC) */ + mrooScriptTag, /* 'mroo' (MROO) */ + nshuScriptTag, /* 'nshu' (NSHU) */ + shrdScriptTag, /* 'shrd' (SHARADA) */ + soraScriptTag, /* 'sora' (SORA_SOMPENG) */ + takrScriptTag, /* 'takr' (TAKRI) */ + tangScriptTag, /* 'tang' (TANG) */ + woleScriptTag, /* 'wole' (WOLE) */ + khojScriptTag, /* 'khoj' (KHOJ) */ + tirhScriptTag /* 'tirh' (TIRH) */ }; const LETag OpenTypeLayoutEngine::languageTags[] = { diff --git a/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.h b/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.h index 885b50c0da2..d70a3e49ee9 100644 --- a/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.h +++ b/jdk/src/share/native/sun/font/layout/ScriptAndLanguageTags.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -201,6 +201,17 @@ const LETag nbatScriptTag = 0x6E626174; /* 'nbat' (NBAT) */ const LETag palmScriptTag = 0x70616C6D; /* 'palm' (PALM) */ const LETag sindScriptTag = 0x73696E64; /* 'sind' (SIND) */ const LETag waraScriptTag = 0x77617261; /* 'wara' (WARA) */ +const LETag afakScriptTag = 0x6166616B; /* 'afak' (AFAK) */ +const LETag jurcScriptTag = 0x6A757263; /* 'jurc' (JURC) */ +const LETag mrooScriptTag = 0x6D726F6F; /* 'mroo' (MROO) */ +const LETag nshuScriptTag = 0x6E736875; /* 'nshu' (NSHU) */ +const LETag shrdScriptTag = 0x73687264; /* 'shrd' (SHARADA) */ +const LETag soraScriptTag = 0x736F7261; /* 'sora' (SORA_SOMPENG) */ +const LETag takrScriptTag = 0x74616B72; /* 'takr' (TAKRI) */ +const LETag tangScriptTag = 0x74616E67; /* 'tang' (TANG) */ +const LETag woleScriptTag = 0x776F6C65; /* 'wole' (WOLE) */ +const LETag khojScriptTag = 0x6B686F6A; /* 'khoj' (KHOJ) */ +const LETag tirhScriptTag = 0x74697268; /* 'tirh' (TIRH) */ const LETag nullScriptTag = 0x00000000; /* '' (NULL) */ diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp new file mode 100644 index 00000000000..e50fdf0604e --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp @@ -0,0 +1,85 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentArrayProcessor2) + +SegmentArrayProcessor2::SegmentArrayProcessor2() +{ +} + +SegmentArrayProcessor2::SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table; +} + +SegmentArrayProcessor2::~SegmentArrayProcessor2() +{ +} + +void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSegment *segments = segmentArrayLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); + + if (lookupSegment != NULL) { + TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); + le_int16 offset = SWAPW(lookupSegment->value); + + if (offset != 0) { + TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); + TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h new file mode 100644 index 00000000000..71999b76a8a --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h @@ -0,0 +1,82 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTARRAYPROCESSOR_H +#define __SEGMENTARRAYPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SegmentArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentArrayProcessor2(); + +protected: + const SegmentArrayLookupTable *segmentArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp new file mode 100644 index 00000000000..e571cce9b87 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp @@ -0,0 +1,79 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentSingleProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentSingleProcessor2) + +SegmentSingleProcessor2::SegmentSingleProcessor2() +{ +} + +SegmentSingleProcessor2::SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table; +} + +SegmentSingleProcessor2::~SegmentSingleProcessor2() +{ +} + +void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSegment *segments = segmentSingleLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); + + if (lookupSegment != NULL) { + TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h new file mode 100644 index 00000000000..00def985133 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h @@ -0,0 +1,82 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTSINGLEPROCESSOR_H +#define __SEGMENTSINGLEPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentSingleProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SegmentSingleProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentSingleProcessor2(); + +protected: + const SegmentSingleLookupTable *segmentSingleLookupTable; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp new file mode 100644 index 00000000000..fa15b71215e --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp @@ -0,0 +1,76 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleArrayProcessor2) + +SimpleArrayProcessor2::SimpleArrayProcessor2() +{ +} + +SimpleArrayProcessor2::SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table; +} + +SimpleArrayProcessor2::~SimpleArrayProcessor2() +{ +} + +void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { + TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h new file mode 100644 index 00000000000..94bbbad858c --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h @@ -0,0 +1,82 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SIMPLEARRAYPROCESSOR2_H +#define __SIMPLEARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SimpleArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SimpleArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SimpleArrayProcessor2(); + +protected: + const SimpleArrayLookupTable *simpleArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp new file mode 100644 index 00000000000..dc0b8fc53c4 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp @@ -0,0 +1,76 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SingleTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SingleTableProcessor2) + +SingleTableProcessor2::SingleTableProcessor2() +{ +} + +SingleTableProcessor2::SingleTableProcessor2(const MorphSubtableHeader2 *moprhSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(moprhSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) moprhSubtableHeader; + + singleTableLookupTable = (const SingleTableLookupTable *) &header->table; +} + +SingleTableProcessor2::~SingleTableProcessor2() +{ +} + +void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage) +{ + const LookupSingle *entries = singleTableLookupTable->entries; + le_int32 glyph; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); + + if (lookupSingle != NULL) { + glyphStorage[glyph] = SWAPW(lookupSingle->value); + } + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h new file mode 100644 index 00000000000..e52d819a4b0 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h @@ -0,0 +1,82 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SINGLETABLEPROCESSOR2_H +#define __SINGLETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SingleTableProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + SingleTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~SingleTableProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SingleTableProcessor2(); + +protected: + const SingleTableLookupTable *singleTableLookupTable; + +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp new file mode 100644 index 00000000000..d4766cb0bf3 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp @@ -0,0 +1,193 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" +#include "LookupTables.h" +#include + +U_NAMESPACE_BEGIN + +StateTableProcessor2::StateTableProcessor2() +{ +} + +StateTableProcessor2::StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : SubtableProcessor2(morphSubtableHeader) +{ + stateTableHeader = (const MorphStateTableHeader2 *) morphSubtableHeader; + nClasses = SWAPL(stateTableHeader->stHeader.nClasses); + classTableOffset = SWAPL(stateTableHeader->stHeader.classTableOffset); + stateArrayOffset = SWAPL(stateTableHeader->stHeader.stateArrayOffset); + entryTableOffset = SWAPL(stateTableHeader->stHeader.entryTableOffset); + + classTable = (LookupTable *) ((char *) &stateTableHeader->stHeader + classTableOffset); + format = SWAPW(classTable->format); + + stateArray = (const EntryTableIndex2 *) ((char *) &stateTableHeader->stHeader + stateArrayOffset); +} + +StateTableProcessor2::~StateTableProcessor2() +{ +} + +void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) +{ + // Start at state 0 + // XXX: How do we know when to start at state 1? + le_uint16 currentState = 0; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + le_int32 currGlyph = 0; + if ((coverage & scfReverse2) != 0) { // process glyphs in descending order + currGlyph = glyphCount - 1; + dir = -1; + } else { + dir = 1; + } + + beginStateTable(); + switch (format) { + case ltfSimpleArray: { +#ifdef TEST_FORMAT + SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + classCode = SWAPW(lookupTable0->valueArray[gid]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset + } +#endif + break; + } + case ltfSegmentSingle: { + SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); + if (segment != NULL) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + case ltfSegmentArray: { + printf("Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: { + SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) classTable; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + if (segment != NULL) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + case ltfTrimmedArray: { + TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) classTable; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]); + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + } + break; + } + default: + break; + } + + endStateTable(); +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h new file mode 100644 index 00000000000..5b5c6c18baf --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h @@ -0,0 +1,84 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __STATETABLEPROCESSOR2_H +#define __STATETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "LookupTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class StateTableProcessor2 : public SubtableProcessor2 +{ +public: + void process(LEGlyphStorage &glyphStorage); + + virtual void beginStateTable() = 0; + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) = 0; + + virtual void endStateTable() = 0; + +protected: + StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + virtual ~StateTableProcessor2(); + + StateTableProcessor2(); + + le_int32 dir; + le_uint16 format; + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; + + const LookupTable *classTable; + const EntryTableIndex2 *stateArray; + const MorphStateTableHeader2 *stateTableHeader; + +private: + StateTableProcessor2(const StateTableProcessor2 &other); // forbid copying of this class + StateTableProcessor2 &operator=(const StateTableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/StateTables.h b/jdk/src/share/native/sun/font/layout/StateTables.h index fbd316bcae9..13177f5498a 100644 --- a/jdk/src/share/native/sun/font/layout/StateTables.h +++ b/jdk/src/share/native/sun/font/layout/StateTables.h @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -50,6 +50,14 @@ struct StateTableHeader ByteOffset entryTableOffset; }; +struct StateTableHeader2 +{ + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; +}; + enum ClassCodes { classCodeEOT = 0, @@ -85,6 +93,14 @@ struct StateEntry le_int16 flags; }; +typedef le_uint16 EntryTableIndex2; + +struct StateEntry2 // same struct different interpretation +{ + le_uint16 newStateIndex; + le_uint16 flags; +}; + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp new file mode 100644 index 00000000000..30d1426679c --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp @@ -0,0 +1,56 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +SubtableProcessor2::SubtableProcessor2() +{ +} + +SubtableProcessor2::SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) +{ + subtableHeader = morphSubtableHeader; + + length = SWAPL(subtableHeader->length); + coverage = SWAPL(subtableHeader->coverage); + subtableFeatures = SWAPL(subtableHeader->subtableFeatures); +} + +SubtableProcessor2::~SubtableProcessor2() +{ +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h new file mode 100644 index 00000000000..13af854666a --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h @@ -0,0 +1,70 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SUBTABLEPROCESSOR2_H +#define __SUBTABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SubtableProcessor2 : public UMemory { +public: + virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual ~SubtableProcessor2(); + +protected: + SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + SubtableProcessor2(); + + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + const MorphSubtableHeader2 *subtableHeader; + +private: + + SubtableProcessor2(const SubtableProcessor2 &other); // forbid copying of this class + SubtableProcessor2 &operator=(const SubtableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp new file mode 100644 index 00000000000..f32b216326a --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp @@ -0,0 +1,80 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "TrimmedArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TrimmedArrayProcessor2) + +TrimmedArrayProcessor2::TrimmedArrayProcessor2() +{ +} + +TrimmedArrayProcessor2::TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +{ + const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + + trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table; + firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); + lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); +} + +TrimmedArrayProcessor2::~TrimmedArrayProcessor2() +{ +} + +void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage) +{ + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); + + if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { + TTGlyphID newGlyph = SWAPW(trimmedArrayLookupTable->valueArray[ttGlyph - firstGlyph]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h new file mode 100644 index 00000000000..1ebe4187784 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h @@ -0,0 +1,84 @@ +/* + * 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) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __TRIMMEDARRAYPROCESSOR2_H +#define __TRIMMEDARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class TrimmedArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage); + + TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + + virtual ~TrimmedArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + TrimmedArrayProcessor2(); + +protected: + TTGlyphID firstGlyph; + TTGlyphID lastGlyph; + const TrimmedArrayLookupTable *trimmedArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif From ae2454b3e56c1b7376a547b7ad8e957bde9e4fff Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 26 Feb 2013 10:07:26 -0800 Subject: [PATCH 23/36] 8004986: Better handling of glyph table 8004987: Improve font layout 8004994: Improve checking of glyph table Reviewed-by: srl, jgodinez --- .../sun/font/layout/ArabicLayoutEngine.cpp | 9 +++-- .../font/layout/ContextualGlyphSubstProc2.cpp | 3 +- .../share/native/sun/font/layout/LETypes.h | 35 +++++++++++++++++-- .../native/sun/font/layout/LayoutEngine.cpp | 10 +++--- .../sun/font/layout/LigatureSubstProc.cpp | 31 ++++++++++++++-- .../sun/font/layout/LigatureSubstProc2.cpp | 32 +++++++++++++++-- .../sun/font/layout/LookupProcessor.cpp | 4 +-- .../sun/font/layout/OpenTypeLayoutEngine.cpp | 34 +++++++++++------- .../sun/font/layout/OpenTypeLayoutEngine.h | 7 +++- .../sun/font/layout/StateTableProcessor.cpp | 7 +++- .../sun/font/layout/StateTableProcessor2.cpp | 34 ++++++++++++++++-- .../native/sun/font/layout/StateTables.h | 35 +++++++++++++++++++ 12 files changed, 205 insertions(+), 36 deletions(-) diff --git a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp index 807a072410c..dabcf880ba8 100644 --- a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp @@ -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 @@ void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], l } 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 diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp index 1d7bc399a9b..0bd09752cc3 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp @@ -38,7 +38,6 @@ #include "ContextualGlyphSubstProc2.h" #include "LEGlyphStorage.h" #include "LESwaps.h" -#include U_NAMESPACE_BEGIN @@ -123,7 +122,7 @@ TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyp break; } case ltfSegmentArray: { - printf("Context Lookup Table Format4: specific interpretation needed!\n"); + //printf("Context Lookup Table Format4: specific interpretation needed!\n"); break; } case ltfSingleTable: diff --git a/jdk/src/share/native/sun/font/layout/LETypes.h b/jdk/src/share/native/sun/font/layout/LETypes.h index 26cbeb363f1..d3801fc2450 100644 --- a/jdk/src/share/native/sun/font/layout/LETypes.h +++ b/jdk/src/share/native/sun/font/layout/LETypes.h @@ -339,6 +339,35 @@ typedef struct LEPoint LEPoint; #ifndef U_HIDE_INTERNAL_API + +#ifndef LE_ASSERT_BAD_FONT +#define LE_ASSERT_BAD_FONT 0 +#endif + +#if LE_ASSERT_BAD_FONT +#include +#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. * @@ -360,7 +389,7 @@ typedef struct LEPoint LEPoint; * * @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 @@ -403,7 +432,7 @@ typedef struct LEPoint LEPoint; * * @internal */ -#define LE_NEW_ARRAY(type, count) (type *) malloc((count) * sizeof(type)) +#define LE_NEW_ARRAY(type, count) LE_RANGE_CHECK(type,count,(type *) malloc((count) * sizeof(type))) /** * Re-allocate an array of basic types. This is used to isolate the rest of @@ -696,6 +725,8 @@ enum LEFeatureENUMs { #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. * diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp index 689b85cd2e7..1fadbf9f792 100644 --- a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp @@ -428,7 +428,7 @@ void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset 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)); @@ -571,8 +571,8 @@ void LayoutEngine::reset() 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) @@ -660,11 +660,11 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan } } else { MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); - if (morxTable != NULL) { + if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); } else { const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - if (mortTable != NULL) { // mort + if (mortTable != NULL && SWAPL(mortTable->version)==0x00010000) { // mort result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); } else { switch (scriptCode) { diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp index 6fabb6e749d..842b095e085 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp @@ -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 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp } componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + currGlyph++; + return newState; } ByteOffset actionOffset = flags & lsfActionOffsetMask; @@ -102,7 +106,21 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp 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 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp 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) { diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp index c26442da723..f36be1b26ad 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp @@ -79,6 +79,11 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp m = 0; } componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + LE_DEBUG_BAD_FONT("m==-1") + currGlyph+= dir; + return nextStateIndex; } ByteOffset actionOffset = flags & lsfPerformAction; @@ -93,6 +98,16 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp const le_uint16 *componentTable = (const le_uint16 *)((char *) &ligatureSubstitutionHeader->stHeader + componentOffset); + const le_uint16 *tableEnd = (const le_uint16 *)((char *) &ligatureSubstitutionHeader + SWAPL(ligatureSubstitutionHeader->length)); + + // Check if the font is internally consistent + if(tableEnd < (const le_uint16*)&ligatureSubstitutionHeader // stated end wrapped around? + || componentTable > tableEnd) { // offset past end of stated length? + currGlyph+= dir; + LE_DEBUG_BAD_FONT("ligatureSubstHeader off end of table") + return nextStateIndex; // get out! bad font + } + do { le_uint32 componentGlyph = componentStack[m--]; // pop off @@ -104,19 +119,32 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp offset = action & lafComponentOffsetMask; if (offset != 0) { - + if(componentGlyph > glyphStorage.getGlyphCount()) { + LE_DEBUG_BAD_FONT("preposterous componentGlyph"); + currGlyph+= dir; + return nextStateIndex; // get out! bad font + } i += SWAPW(componentTable[LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask))]); if (action & (lafLast | lafStore)) { TTGlyphID ligatureGlyph = SWAPW(ligatureTable[i]); 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) { diff --git a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp index 6e74130989b..db672efb98b 100644 --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp @@ -208,7 +208,7 @@ LookupProcessor::LookupProcessor(const char *baseAddress, lookupSelectCount = lookupListCount; le_int32 count, order = 0; - le_int32 featureReferences = 0; + le_uint32 featureReferences = 0; const FeatureTable *featureTable = NULL; LETag featureTag; @@ -219,7 +219,7 @@ LookupProcessor::LookupProcessor(const char *baseAddress, // 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); diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp index 375327b55da..a561a135182 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp @@ -123,7 +123,7 @@ static const FeatureMap featureMap[] = {ccmpFeatureTag, ccmpFeatureMask}, {ligaFeatureTag, ligaFeatureMask}, {cligFeatureTag, cligFeatureMask}, - {kernFeatureTag, kernFeatureMask}, + {kernFeatureTag, kernFeatureMask}, {paltFeatureTag, paltFeatureMask}, {markFeatureTag, markFeatureMask}, {mkmkFeatureTag, mkmkFeatureMask}, @@ -160,6 +160,23 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l 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; + switch (typoFlags & (LE_SS01_FEATURE_FLAG | LE_SS02_FEATURE_FLAG | LE_SS03_FEATURE_FLAG @@ -221,15 +238,6 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l 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() @@ -246,13 +254,15 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l : 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(); diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h index cf257fb8131..7a89df46a4a 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h @@ -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 @@ private: */ 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 diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp b/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp index c76086afd2a..3146cc53210 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp @@ -65,6 +65,9 @@ StateTableProcessor::~StateTableProcessor() 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 @@ void StateTableProcessor::process(LEGlyphStorage &glyphStorage) 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 @@ void StateTableProcessor::process(LEGlyphStorage &glyphStorage) 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(); diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp index d4766cb0bf3..5bd9c253012 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp @@ -38,7 +38,6 @@ #include "LEGlyphStorage.h" #include "LESwaps.h" #include "LookupTables.h" -#include U_NAMESPACE_BEGIN @@ -72,6 +71,8 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) le_uint16 currentState = 0; le_int32 glyphCount = glyphStorage.getGlyphCount(); + LE_STATE_PATIENCE_INIT(); + le_int32 currGlyph = 0; if ((coverage & scfReverse2) != 0) { // process glyphs in descending order currGlyph = glyphCount - 1; @@ -86,6 +87,10 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) #ifdef TEST_FORMAT SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) classTable; while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if(LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } LookupValue classCode = classCodeOOB; if (currGlyph == glyphCount || currGlyph == -1) { // XXX: How do we handle EOT vs. EOL? @@ -101,7 +106,9 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) } } EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset + LE_STATE_PATIENCE_INCR(currGlyph); } #endif break; @@ -109,6 +116,10 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) case ltfSegmentSingle: { SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) classTable; while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if(LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } LookupValue classCode = classCodeOOB; if (currGlyph == glyphCount || currGlyph == -1) { // XXX: How do we handle EOT vs. EOL? @@ -127,21 +138,31 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) } } EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + LE_STATE_PATIENCE_INCR(currGlyph); } break; } case ltfSegmentArray: { - printf("Lookup Table Format4: specific interpretation needed!\n"); + //printf("Lookup Table Format4: specific interpretation needed!\n"); break; } case ltfSingleTable: { SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) classTable; while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if(LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } LookupValue classCode = classCodeOOB; if (currGlyph == glyphCount || currGlyph == -1) { // XXX: How do we handle EOT vs. EOL? classCode = classCodeEOT; + } else if(currGlyph > glyphCount) { + // note if > glyphCount, we've run off the end (bad font) + currGlyph = glyphCount; + classCode = classCodeEOT; } else { LEGlyphID gid = glyphStorage[currGlyph]; TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); @@ -156,7 +177,9 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) } } EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + LE_STATE_PATIENCE_INCR(currGlyph); } break; } @@ -166,6 +189,11 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if(LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } + LookupValue classCode = classCodeOOB; if (currGlyph == glyphCount || currGlyph == -1) { // XXX: How do we handle EOT vs. EOL? @@ -179,7 +207,9 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) } } EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + LE_STATE_PATIENCE_INCR(currGlyph); } break; } diff --git a/jdk/src/share/native/sun/font/layout/StateTables.h b/jdk/src/share/native/sun/font/layout/StateTables.h index 13177f5498a..6c6fdced933 100644 --- a/jdk/src/share/native/sun/font/layout/StateTables.h +++ b/jdk/src/share/native/sun/font/layout/StateTables.h @@ -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+= ; + * 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; From 05882c2a521336bc85c8a75ea7c7efac0424e392 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 7 Mar 2013 10:02:20 -0800 Subject: [PATCH 24/36] 8001031: Better font processing Reviewed-by: srl, vadim --- .../native/sun/font/FontInstanceAdapter.cpp | 47 +- .../native/sun/font/FontInstanceAdapter.h | 1 + .../share/native/sun/font/fontscalerdefs.h | 21 +- .../font/layout/AlternateSubstSubtables.cpp | 11 +- .../sun/font/layout/AlternateSubstSubtables.h | 6 +- .../sun/font/layout/ArabicLayoutEngine.cpp | 29 +- .../sun/font/layout/ArabicLayoutEngine.h | 2 +- .../native/sun/font/layout/ArabicShaping.cpp | 14 +- .../native/sun/font/layout/ArabicShaping.h | 2 + .../sun/font/layout/AttachmentPosnSubtables.h | 6 +- .../native/sun/font/layout/CanonData.cpp | 5 + .../native/sun/font/layout/CanonShaping.cpp | 10 +- .../native/sun/font/layout/CanonShaping.h | 2 + .../sun/font/layout/ClassDefinitionTables.cpp | 104 +++-- .../sun/font/layout/ClassDefinitionTables.h | 27 +- .../layout/ContextualGlyphInsertionProc2.cpp | 137 +++--- .../layout/ContextualGlyphInsertionProc2.h | 29 +- .../font/layout/ContextualGlyphSubstProc.cpp | 48 +- .../font/layout/ContextualGlyphSubstProc.h | 8 +- .../font/layout/ContextualGlyphSubstProc2.cpp | 55 ++- .../font/layout/ContextualGlyphSubstProc2.h | 12 +- .../font/layout/ContextualSubstSubtables.cpp | 8 +- .../font/layout/ContextualSubstSubtables.h | 22 + .../native/sun/font/layout/CoverageTables.h | 3 + .../layout/CursiveAttachmentSubtables.cpp | 6 +- .../font/layout/CursiveAttachmentSubtables.h | 3 +- .../native/sun/font/layout/DeviceTables.h | 1 + .../sun/font/layout/ExtensionSubtables.cpp | 8 +- .../share/native/sun/font/layout/Features.cpp | 12 +- .../native/sun/font/layout/GDEFMarkFilter.cpp | 7 +- .../native/sun/font/layout/GDEFMarkFilter.h | 4 +- .../native/sun/font/layout/GXLayoutEngine.cpp | 5 +- .../native/sun/font/layout/GXLayoutEngine.h | 4 +- .../sun/font/layout/GXLayoutEngine2.cpp | 8 +- .../native/sun/font/layout/GXLayoutEngine2.h | 4 +- .../sun/font/layout/GlyphDefinitionTables.cpp | 28 +- .../sun/font/layout/GlyphDefinitionTables.h | 20 +- .../native/sun/font/layout/GlyphIterator.cpp | 27 +- .../native/sun/font/layout/GlyphIterator.h | 6 +- .../sun/font/layout/GlyphLookupTables.cpp | 15 +- .../sun/font/layout/GlyphLookupTables.h | 4 +- .../font/layout/GlyphPositioningTables.cpp | 6 +- .../sun/font/layout/GlyphPositioningTables.h | 5 +- .../sun/font/layout/GlyphPosnLookupProc.cpp | 36 +- .../sun/font/layout/GlyphPosnLookupProc.h | 4 +- .../sun/font/layout/GlyphSubstLookupProc.cpp | 28 +- .../sun/font/layout/GlyphSubstLookupProc.h | 4 +- .../font/layout/GlyphSubstitutionTables.cpp | 7 +- .../sun/font/layout/GlyphSubstitutionTables.h | 5 +- .../sun/font/layout/HanLayoutEngine.cpp | 2 +- .../native/sun/font/layout/HanLayoutEngine.h | 2 +- .../sun/font/layout/HangulLayoutEngine.cpp | 2 +- .../sun/font/layout/HangulLayoutEngine.h | 2 +- .../native/sun/font/layout/ICUFeatures.h | 9 +- .../sun/font/layout/IndicLayoutEngine.cpp | 2 +- .../sun/font/layout/IndicLayoutEngine.h | 2 +- .../layout/IndicRearrangementProcessor.cpp | 14 +- .../font/layout/IndicRearrangementProcessor.h | 7 +- .../layout/IndicRearrangementProcessor2.cpp | 14 +- .../layout/IndicRearrangementProcessor2.h | 8 +- .../sun/font/layout/IndicReordering.cpp | 5 + .../native/sun/font/layout/KernTable.cpp | 77 +-- .../share/native/sun/font/layout/KernTable.h | 12 +- .../sun/font/layout/KhmerLayoutEngine.cpp | 2 +- .../sun/font/layout/KhmerLayoutEngine.h | 2 +- .../share/native/sun/font/layout/LEScripts.h | 7 +- .../native/sun/font/layout/LETableReference.h | 442 ++++++++++++++++++ .../share/native/sun/font/layout/LETypes.h | 9 +- .../native/sun/font/layout/LayoutEngine.cpp | 96 ++-- .../native/sun/font/layout/LayoutEngine.h | 8 +- .../sun/font/layout/LigatureSubstProc.cpp | 67 ++- .../sun/font/layout/LigatureSubstProc.h | 6 +- .../sun/font/layout/LigatureSubstProc2.cpp | 41 +- .../sun/font/layout/LigatureSubstProc2.h | 9 +- .../font/layout/LigatureSubstSubtables.cpp | 4 +- .../sun/font/layout/LigatureSubstSubtables.h | 5 +- .../sun/font/layout/LookupProcessor.cpp | 114 +++-- .../native/sun/font/layout/LookupProcessor.h | 19 +- .../native/sun/font/layout/LookupTables.cpp | 29 +- .../native/sun/font/layout/LookupTables.h | 10 +- .../share/native/sun/font/layout/Lookups.cpp | 36 +- .../share/native/sun/font/layout/Lookups.h | 29 +- .../share/native/sun/font/layout/MarkArrays.h | 1 + .../font/layout/MarkToBasePosnSubtables.cpp | 6 +- .../sun/font/layout/MarkToBasePosnSubtables.h | 4 +- .../layout/MarkToLigaturePosnSubtables.cpp | 6 +- .../font/layout/MarkToLigaturePosnSubtables.h | 5 +- .../font/layout/MarkToMarkPosnSubtables.cpp | 6 +- .../sun/font/layout/MarkToMarkPosnSubtables.h | 4 +- .../native/sun/font/layout/MorphTables.cpp | 40 +- .../native/sun/font/layout/MorphTables.h | 13 +- .../native/sun/font/layout/MorphTables2.cpp | 65 ++- .../font/layout/MultipleSubstSubtables.cpp | 4 +- .../sun/font/layout/MultipleSubstSubtables.h | 4 +- .../layout/NonContextualGlyphSubstProc.cpp | 23 +- .../font/layout/NonContextualGlyphSubstProc.h | 6 +- .../layout/NonContextualGlyphSubstProc2.cpp | 21 +- .../layout/NonContextualGlyphSubstProc2.h | 6 +- .../sun/font/layout/OpenTypeLayoutEngine.cpp | 57 ++- .../sun/font/layout/OpenTypeLayoutEngine.h | 9 +- .../native/sun/font/layout/OpenTypeTables.h | 3 +- .../sun/font/layout/OpenTypeUtilities.cpp | 100 ++-- .../sun/font/layout/OpenTypeUtilities.h | 13 +- .../font/layout/PairPositioningSubtables.cpp | 29 +- .../font/layout/PairPositioningSubtables.h | 10 +- .../sun/font/layout/ScriptAndLanguage.cpp | 65 ++- .../sun/font/layout/ScriptAndLanguage.h | 9 +- .../sun/font/layout/SegmentArrayProcessor.cpp | 20 +- .../sun/font/layout/SegmentArrayProcessor.h | 6 +- .../font/layout/SegmentArrayProcessor2.cpp | 15 +- .../sun/font/layout/SegmentArrayProcessor2.h | 6 +- .../font/layout/SegmentSingleProcessor.cpp | 17 +- .../sun/font/layout/SegmentSingleProcessor.h | 6 +- .../font/layout/SegmentSingleProcessor2.cpp | 14 +- .../sun/font/layout/SegmentSingleProcessor2.h | 6 +- .../sun/font/layout/ShapingTypeData.cpp | 2 + .../sun/font/layout/SimpleArrayProcessor.cpp | 20 +- .../sun/font/layout/SimpleArrayProcessor.h | 6 +- .../sun/font/layout/SimpleArrayProcessor2.cpp | 14 +- .../sun/font/layout/SimpleArrayProcessor2.h | 7 +- .../layout/SinglePositioningSubtables.cpp | 18 +- .../font/layout/SinglePositioningSubtables.h | 7 +- .../layout/SingleSubstitutionSubtables.cpp | 18 +- .../font/layout/SingleSubstitutionSubtables.h | 7 +- .../sun/font/layout/SingleTableProcessor.cpp | 13 +- .../sun/font/layout/SingleTableProcessor.h | 6 +- .../sun/font/layout/SingleTableProcessor2.cpp | 13 +- .../sun/font/layout/SingleTableProcessor2.h | 6 +- .../sun/font/layout/StateTableProcessor.cpp | 19 +- .../sun/font/layout/StateTableProcessor.h | 9 +- .../sun/font/layout/StateTableProcessor2.cpp | 71 +-- .../sun/font/layout/StateTableProcessor2.h | 13 +- .../native/sun/font/layout/StateTables.h | 1 + .../sun/font/layout/SubtableProcessor.cpp | 6 +- .../sun/font/layout/SubtableProcessor.h | 6 +- .../sun/font/layout/SubtableProcessor2.cpp | 11 +- .../sun/font/layout/SubtableProcessor2.h | 6 +- .../sun/font/layout/ThaiLayoutEngine.cpp | 9 +- .../sun/font/layout/TibetanLayoutEngine.cpp | 2 +- .../sun/font/layout/TibetanLayoutEngine.h | 2 +- .../sun/font/layout/TrimmedArrayProcessor.cpp | 20 +- .../sun/font/layout/TrimmedArrayProcessor.h | 6 +- .../font/layout/TrimmedArrayProcessor2.cpp | 14 +- .../sun/font/layout/TrimmedArrayProcessor2.h | 8 +- .../native/sun/font/layout/ValueRecords.h | 1 + jdk/src/share/native/sun/font/sunFont.c | 18 +- 146 files changed, 1879 insertions(+), 1038 deletions(-) create mode 100644 jdk/src/share/native/sun/font/layout/LETableReference.h diff --git a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp index 824f296cc5c..4214078e06b 100644 --- a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp +++ b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp @@ -66,8 +66,21 @@ FontInstanceAdapter::FontInstanceAdapter(JNIEnv *theEnv, yScalePixelsToUnits = upem / yppem; }; + const void *FontInstanceAdapter::getFontTable(LETag tableTag) const { + size_t ignored = 0; + return getFontTable(tableTag, ignored); +} + +static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = { + GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG +}; + +const void *FontInstanceAdapter::getFontTable(LETag tableTag, size_t &length) const +{ + length = 0; + if (!layoutTables) { // t1 font return 0; } @@ -75,14 +88,19 @@ const void *FontInstanceAdapter::getFontTable(LETag tableTag) const // cache in font's pscaler object // font disposer will handle for us - switch(tableTag) { - case GSUB_TAG: if (layoutTables->gsub_len != -1) return (void*)layoutTables->gsub; break; - case GPOS_TAG: if (layoutTables->gpos_len != -1) return (void*)layoutTables->gpos; break; - case GDEF_TAG: if (layoutTables->gdef_len != -1) return (void*)layoutTables->gdef; break; - case MORT_TAG: if (layoutTables->mort_len != -1) return (void*)layoutTables->mort; break; - case KERN_TAG: if (layoutTables->kern_len != -1) return (void*)layoutTables->kern; break; - default: - //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag); + int cacheIdx; + for (cacheIdx=0;cacheIdxentries[cacheIdx].len != -1) { + length = layoutTables->entries[cacheIdx].len; + return layoutTables->entries[cacheIdx].ptr; + } + } else { + //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag); + // (don't load any other tables) return 0; } @@ -96,16 +114,13 @@ const void *FontInstanceAdapter::getFontTable(LETag tableTag) const env->GetByteArrayRegion(tableBytes, 0, len, result); } - switch(tableTag) { - case GSUB_TAG: layoutTables->gsub = (void*)result; layoutTables->gsub_len = len; break; - case GPOS_TAG: layoutTables->gpos = (void*)result; layoutTables->gpos_len = len; break; - case GDEF_TAG: layoutTables->gdef = (void*)result; layoutTables->gdef_len = len; break; - case MORT_TAG: layoutTables->mort = (void*)result; layoutTables->mort_len = len; break; - case KERN_TAG: layoutTables->kern = (void*)result; layoutTables->kern_len = len; break; - default: break; + if (cacheIdxentries[cacheIdx].len = len; + layoutTables->entries[cacheIdx].ptr = (const void*)result; } - return (void*)result; + length = len; + return (const void*)result; }; LEGlyphID FontInstanceAdapter::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const diff --git a/jdk/src/share/native/sun/font/FontInstanceAdapter.h b/jdk/src/share/native/sun/font/FontInstanceAdapter.h index b78bdb4cabd..264cf27bdd6 100644 --- a/jdk/src/share/native/sun/font/FontInstanceAdapter.h +++ b/jdk/src/share/native/sun/font/FontInstanceAdapter.h @@ -86,6 +86,7 @@ public: // tables are cached with the native font scaler data // only supports gsub, gpos, gdef, mort tables at present virtual const void *getFontTable(LETag tableTag) const; + virtual const void *getFontTable(LETag tableTag, size_t &len) const; virtual void *getKernPairs() const { return layoutTables->kernPairs; diff --git a/jdk/src/share/native/sun/font/fontscalerdefs.h b/jdk/src/share/native/sun/font/fontscalerdefs.h index 8f142752af9..7d84d84a536 100644 --- a/jdk/src/share/native/sun/font/fontscalerdefs.h +++ b/jdk/src/share/native/sun/font/fontscalerdefs.h @@ -120,20 +120,19 @@ typedef struct GlyphInfo { #define GPOS_TAG 0x47504F53 /* 'GPOS' */ #define GDEF_TAG 0x47444546 /* 'GDEF' */ #define MORT_TAG 0x6D6F7274 /* 'mort' */ +#define MORX_TAG 0x6D6F7278 /* 'morx' */ #define KERN_TAG 0x6B65726E /* 'kern' */ +typedef struct TTLayoutTableCacheEntry { + const void* ptr; + int len; +} TTLayoutTableCacheEntry; + +#define LAYOUTCACHE_ENTRIES 6 + typedef struct TTLayoutTableCache { - void* gsub; - void* gpos; - void* gdef; - void* mort; - void* kern; - void* kernPairs; - int gsub_len; - int gpos_len; - int gdef_len; - int mort_len; - int kern_len; + TTLayoutTableCacheEntry entries[LAYOUTCACHE_ENTRIES]; + void* kernPairs; } TTLayoutTableCache; #include "sunfontids.h" diff --git a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp index c099c25a7a7..493cea36843 100644 --- a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp @@ -39,19 +39,20 @@ U_NAMESPACE_BEGIN -le_uint32 AlternateSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 AlternateSubstitutionSubtable::process(const LEReferenceTo &base, + GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { // NOTE: For now, we'll just pick the first alternative... LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); - if (coverageIndex >= 0) { + if (coverageIndex >= 0 && LE_SUCCESS(success)) { le_uint16 altSetCount = SWAPW(alternateSetCount); if (coverageIndex < altSetCount) { Offset alternateSetTableOffset = SWAPW(alternateSetTableOffsetArray[coverageIndex]); - const AlternateSetTable *alternateSetTable = - (const AlternateSetTable *) ((char *) this + alternateSetTableOffset); + const LEReferenceTo alternateSetTable(base, success, + (const AlternateSetTable *) ((char *) this + alternateSetTableOffset)); TTGlyphID alternate = SWAPW(alternateSetTable->alternateArray[0]); if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, alternate))) { diff --git a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h index fbc41212f1a..e2f250e691e 100644 --- a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h +++ b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h @@ -51,13 +51,17 @@ struct AlternateSetTable TTGlyphID alternateArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AlternateSetTable, alternateArray) + struct AlternateSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 alternateSetCount; Offset alternateSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(AlternateSubstitutionSubtable, alternateSetTableOffsetArray) + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp index dabcf880ba8..834a253a4b4 100644 --- a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp @@ -58,15 +58,18 @@ le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) -ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) +ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, + le_int32 languageCode, le_int32 typoFlags, + const LEReferenceTo &gsubTable, + LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); fFeatureOrder = TRUE; } -ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, +ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, + le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) { @@ -88,8 +91,9 @@ ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() // Input: characters // Output: characters, char indices, tags // Returns: output character count -le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, - LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) +le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, + le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, + LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; @@ -137,22 +141,21 @@ void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], l return; } - if (fGPOSTable != NULL) { + if (!fGPOSTable.isEmpty()) { OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); - } else if (fGDEFTable != NULL) { - GDEFMarkFilter filter(fGDEFTable); - + } else if (!fGDEFTable.isEmpty()) { + GDEFMarkFilter filter(fGDEFTable, success); adjustMarkGlyphs(glyphStorage, &filter, success); } else { - GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - GDEFMarkFilter filter(gdefTable); + LEReferenceTo gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); + GDEFMarkFilter filter(gdefTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); } } UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) - : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) + : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) { fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; @@ -232,7 +235,7 @@ void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode cha return; } - GDEFMarkFilter filter(fGDEFTable); + GDEFMarkFilter filter(fGDEFTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); } diff --git a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h index 956b3d50f8c..239ae1816b4 100644 --- a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h @@ -75,7 +75,7 @@ public: * @internal */ ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known diff --git a/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp b/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp index 7c91f4f9721..0b56b4bacf2 100644 --- a/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp +++ b/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp @@ -58,14 +58,16 @@ const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] = */ ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c) { - const ClassDefinitionTable *joiningTypes = (const ClassDefinitionTable *) ArabicShaping::shapingTypeTable; - le_int32 joiningType = joiningTypes->getGlyphClass(c); + LEErrorCode success = LE_NO_ERROR; + const LEReferenceTo joiningTypes((const ClassDefinitionTable *) ArabicShaping::shapingTypeTable, + ArabicShaping::shapingTypeTableLen); + le_int32 joiningType = joiningTypes->getGlyphClass(joiningTypes, c, success); - if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT) { - return ArabicShaping::shapeTypes[joiningType]; - } + if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT && LE_SUCCESS(success)) { + return ArabicShaping::shapeTypes[joiningType]; + } - return ArabicShaping::ST_NOSHAPE_NONE; + return ArabicShaping::ST_NOSHAPE_NONE; } #define isolFeatureTag LE_ISOL_FEATURE_TAG diff --git a/jdk/src/share/native/sun/font/layout/ArabicShaping.h b/jdk/src/share/native/sun/font/layout/ArabicShaping.h index 3838e168d41..40923ecb496 100644 --- a/jdk/src/share/native/sun/font/layout/ArabicShaping.h +++ b/jdk/src/share/native/sun/font/layout/ArabicShaping.h @@ -93,6 +93,8 @@ private: static ShapeType getShapeType(LEUnicode c); static const le_uint8 shapingTypeTable[]; + static const size_t shapingTypeTableLen; + static const ShapeType shapeTypes[]; static void adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage); diff --git a/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h b/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h index 2ed8d9d270c..e7a27608ff4 100644 --- a/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h +++ b/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h @@ -52,14 +52,14 @@ struct AttachmentPositioningSubtable : GlyphPositioningSubtable Offset markArrayOffset; Offset baseArrayOffset; - inline le_int32 getBaseCoverage(LEGlyphID baseGlyphId) const; + inline le_int32 getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphId, LEErrorCode &success) const; le_uint32 process(GlyphIterator *glyphIterator) const; }; -inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(LEGlyphID baseGlyphID) const +inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphID, LEErrorCode &success) const { - return getGlyphCoverage(baseCoverageTableOffset, baseGlyphID); + return getGlyphCoverage(base, baseCoverageTableOffset, baseGlyphID, success); } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/CanonData.cpp b/jdk/src/share/native/sun/font/layout/CanonData.cpp index 41d4bc213ae..49b13ab1c10 100644 --- a/jdk/src/share/native/sun/font/layout/CanonData.cpp +++ b/jdk/src/share/native/sun/font/layout/CanonData.cpp @@ -3641,4 +3641,9 @@ const le_uint8 CanonShaping::glyphDefinitionTable[] = { 0x00, 0xE6, 0xD2, 0x42, 0xD2, 0x44, 0x00, 0xE6 }; + +const size_t CanonShaping::glyphSubstitutionTableLen = sizeof(glyphSubstitutionTable)/sizeof(glyphSubstitutionTable[0]); + +const size_t CanonShaping::glyphDefinitionTableLen = sizeof(glyphDefinitionTable)/sizeof(glyphDefinitionTable[0]); + U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/CanonShaping.cpp b/jdk/src/share/native/sun/font/layout/CanonShaping.cpp index 498ffa8f2de..86f2ebc89c1 100644 --- a/jdk/src/share/native/sun/font/layout/CanonShaping.cpp +++ b/jdk/src/share/native/sun/font/layout/CanonShaping.cpp @@ -59,15 +59,15 @@ void CanonShaping::sortMarks(le_int32 *indices, const le_int32 *combiningClasses void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft, LEUnicode *outChars, LEGlyphStorage &glyphStorage) { - const GlyphDefinitionTableHeader *gdefTable = (const GlyphDefinitionTableHeader *) glyphDefinitionTable; - const ClassDefinitionTable *classTable = gdefTable->getMarkAttachClassDefinitionTable(); + LEErrorCode success = LE_NO_ERROR; + LEReferenceTo gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); + LEReferenceTo classTable = gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success); le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount); le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount); - LEErrorCode status = LE_NO_ERROR; le_int32 i; for (i = 0; i < charCount; i += 1) { - combiningClasses[i] = classTable->getGlyphClass((LEGlyphID) inChars[i]); + combiningClasses[i] = classTable->getGlyphClass(classTable, (LEGlyphID) inChars[i], success); indices[i] = i; } @@ -96,7 +96,7 @@ void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le le_int32 index = indices[i]; outChars[i] = inChars[index]; - glyphStorage.setCharIndex(out, index, status); + glyphStorage.setCharIndex(out, index, success); } LE_DELETE_ARRAY(indices); diff --git a/jdk/src/share/native/sun/font/layout/CanonShaping.h b/jdk/src/share/native/sun/font/layout/CanonShaping.h index 62ad919b965..5d6a097e11c 100644 --- a/jdk/src/share/native/sun/font/layout/CanonShaping.h +++ b/jdk/src/share/native/sun/font/layout/CanonShaping.h @@ -42,7 +42,9 @@ class U_LAYOUT_API CanonShaping /* not : public UObject because all members are { public: static const le_uint8 glyphSubstitutionTable[]; + static const size_t glyphSubstitutionTableLen; static const le_uint8 glyphDefinitionTable[]; + static const size_t glyphDefinitionTableLen; static void reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft, LEUnicode *outChars, LEGlyphStorage &glyphStorage); diff --git a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp index af600444007..08e7f7732c8 100644 --- a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp +++ b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp @@ -37,24 +37,51 @@ U_NAMESPACE_BEGIN -le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const +le_int32 ClassDefinitionTable::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo thisRef(base, success); + if (LE_FAILURE(success)) return 0; + + switch(SWAPW(classFormat)) { + case 0: + return 0; + + case 1: + { + const LEReferenceTo f1Table(thisRef, success); + return f1Table->getGlyphClass(f1Table, glyphID, success); + } + + case 2: + { + const LEReferenceTo f2Table(thisRef, success); + return f2Table->getGlyphClass(f2Table, glyphID, success); + } + + default: + return 0; + } +} + +le_bool ClassDefinitionTable::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const +{ + LEReferenceTo thisRef(base, success); + if (LE_FAILURE(success)) return 0; + switch(SWAPW(classFormat)) { case 0: return 0; case 1: { - const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this; - - return f1Table->getGlyphClass(glyphID); + const LEReferenceTo f1Table(thisRef, success); + return f1Table->hasGlyphClass(f1Table, glyphClass, success); } case 2: { - const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this; - - return f2Table->getGlyphClass(glyphID); + const LEReferenceTo f2Table(thisRef, success); + return f2Table->hasGlyphClass(f2Table, glyphClass, success); } default: @@ -62,51 +89,32 @@ le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const } } -le_bool ClassDefinitionTable::hasGlyphClass(le_int32 glyphClass) const +le_int32 ClassDefFormat1Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { - switch(SWAPW(classFormat)) { - case 0: - return 0; + if(LE_FAILURE(success)) return 0; - case 1: - { - const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this; - - return f1Table->hasGlyphClass(glyphClass); - } - - case 2: - { - const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this; - - return f2Table->hasGlyphClass(glyphClass); - } - - default: - return 0; - } -} - -le_int32 ClassDefFormat1Table::getGlyphClass(LEGlyphID glyphID) const -{ + le_uint16 count = SWAPW(glyphCount); + LEReferenceToArrayOf classValueArrayRef(base, success, &classValueArray[0], count); TTGlyphID ttGlyphID = (TTGlyphID) LE_GET_GLYPH(glyphID); TTGlyphID firstGlyph = SWAPW(startGlyph); - TTGlyphID lastGlyph = firstGlyph + SWAPW(glyphCount); + TTGlyphID lastGlyph = firstGlyph + count; - if (ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) { - return SWAPW(classValueArray[ttGlyphID - firstGlyph]); + if (LE_SUCCESS(success) && ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) { + return SWAPW( classValueArrayRef(ttGlyphID - firstGlyph, success) ); } return 0; } -le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const +le_bool ClassDefFormat1Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const { - le_uint16 count = SWAPW(glyphCount); + if(LE_FAILURE(success)) return 0; + le_uint16 count = SWAPW(glyphCount); + LEReferenceToArrayOf classValueArrayRef(base, success, &classValueArray[0], count); int i; - for (i = 0; i < count; i += 1) { - if (SWAPW(classValueArray[i]) == glyphClass) { + for (i = 0; LE_SUCCESS(success)&& (i < count); i += 1) { + if (SWAPW(classValueArrayRef(i,success)) == glyphClass) { return TRUE; } } @@ -114,27 +122,31 @@ le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const return FALSE; } -le_int32 ClassDefFormat2Table::getGlyphClass(LEGlyphID glyphID) const +le_int32 ClassDefFormat2Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { + if(LE_FAILURE(success)) return 0; TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyphID); le_uint16 rangeCount = SWAPW(classRangeCount); + LEReferenceToArrayOf classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount); le_int32 rangeIndex = - OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArray, rangeCount); + OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArrayRef, success); - if (rangeIndex < 0) { + if (rangeIndex < 0 || LE_FAILURE(success)) { return 0; } - return SWAPW(classRangeRecordArray[rangeIndex].rangeValue); + return SWAPW(classRangeRecordArrayRef(rangeIndex, success).rangeValue); } -le_bool ClassDefFormat2Table::hasGlyphClass(le_int32 glyphClass) const +le_bool ClassDefFormat2Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const { + if(LE_FAILURE(success)) return 0; le_uint16 rangeCount = SWAPW(classRangeCount); + LEReferenceToArrayOf classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount); int i; - for (i = 0; i < rangeCount; i += 1) { - if (SWAPW(classRangeRecordArray[i].rangeValue) == glyphClass) { + for (i = 0; i < rangeCount && LE_SUCCESS(success); i += 1) { + if (SWAPW(classRangeRecordArrayRef(i,success).rangeValue) == glyphClass) { return TRUE; } } diff --git a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h index a298e85c626..410119145a5 100644 --- a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h +++ b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h @@ -46,8 +46,20 @@ struct ClassDefinitionTable { le_uint16 classFormat; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; + + le_int32 getGlyphClass(LEGlyphID glyphID) const { + LETableReference base((const le_uint8*)this); + LEErrorCode ignored = LE_NO_ERROR; + return getGlyphClass(base,glyphID,ignored); + } + + le_bool hasGlyphClass(le_int32 glyphClass) const { + LETableReference base((const le_uint8*)this); + LEErrorCode ignored = LE_NO_ERROR; + return hasGlyphClass(base,glyphClass,ignored); + } }; struct ClassDefFormat1Table : ClassDefinitionTable @@ -56,9 +68,11 @@ struct ClassDefFormat1Table : ClassDefinitionTable le_uint16 glyphCount; le_uint16 classValueArray[ANY_NUMBER]; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; }; +LE_VAR_ARRAY(ClassDefFormat1Table, classValueArray) + struct ClassRangeRecord { @@ -72,9 +86,10 @@ struct ClassDefFormat2Table : ClassDefinitionTable le_uint16 classRangeCount; GlyphRangeRecord classRangeRecordArray[ANY_NUMBER]; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; }; +LE_VAR_ARRAY(ClassDefFormat2Table, classRangeRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp index a7a2386fa3c..85f9fc7ab22 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp @@ -43,13 +43,15 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) -ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : StateTableProcessor2(morphSubtableHeader) +ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2( + const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success) { - contextualGlyphHeader = (const ContextualGlyphInsertionHeader2 *) morphSubtableHeader; - le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); - insertionTable = ((le_uint16 *) ((char *)&stateTableHeader->stHeader + insertionTableOffset)); - entryTable = (const ContextualGlyphInsertionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + contextualGlyphHeader = LEReferenceTo(morphSubtableHeader, success); + if(LE_FAILURE(success) || !contextualGlyphHeader.isValid()) return; + le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); + insertionTable = LEReferenceToArrayOf(stHeader, success, insertionTableOffset, LE_UNBOUNDED_ARRAY); + entryTable = LEReferenceToArrayOf(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); } ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() @@ -61,93 +63,62 @@ void ContextualGlyphInsertionProcessor2::beginStateTable() markGlyph = 0; } -le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +void ContextualGlyphInsertionProcessor2::doInsertion(LEGlyphStorage &glyphStorage, + le_int16 atGlyph, + le_int16 &index, + le_int16 count, + le_bool /* isKashidaLike */, + le_bool isBefore, + LEErrorCode &success) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(atGlyph, count + 1, success); + + if(LE_FAILURE(success) || insertGlyphs==NULL) { + return; + } + + // Note: Kashida vs Split Vowel seems to only affect selection and highlighting. + // We note the flag, but do not layout different. + // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6mort.html + + le_int16 targetIndex = 0; + if(isBefore) { + // insert at beginning + insertGlyphs[targetIndex++] = glyphStorage[atGlyph]; + } else { + // insert at end + insertGlyphs[count] = glyphStorage[atGlyph]; + } + + while(count--) { + insertGlyphs[targetIndex++] = insertionTable.getObject(index++, success); + } + glyphStorage.applyInsertions(); +} + +le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) { - const ContextualGlyphInsertionStateEntry2 *entry = &entryTable[index]; + const ContextualGlyphInsertionStateEntry2 *entry = entryTable.getAlias(index, success); + + if(LE_FAILURE(success)) return 0; // TODO- which state? + le_uint16 newState = SWAPW(entry->newStateIndex); le_uint16 flags = SWAPW(entry->flags); - le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); - le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); - int i = 0; + le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); if (markIndex > 0) { le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; - if (!(flags & cgiMarkedIsKashidaLike)) { - // extra glyph(s) will be added directly before/after the specified marked glyph - if (!(flags & cgiMarkInsertBefore)) { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); - for (i = 0; i < count; i++, markIndex++) { - insertGlyphs[i] = insertionTable[markIndex]; - } - insertGlyphs[i] = glyphStorage[markGlyph]; - glyphStorage.applyInsertions(); - } else { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); - insertGlyphs[0] = glyphStorage[markGlyph]; - for (i = 1; i < count + 1; i++, markIndex++) { - insertGlyphs[i] = insertionTable[markIndex]; - } - glyphStorage.applyInsertions(); - } - } else { - // inserted as a split-vowel-like insertion - // extra glyph(s) will be inserted some distance away from the marked glyph - if (!(flags & cgiMarkInsertBefore)) { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); - for (i = 0; i < count; i++, markIndex++) { - insertGlyphs[i] = insertionTable[markIndex]; - } - insertGlyphs[i] = glyphStorage[markGlyph]; - glyphStorage.applyInsertions(); - } else { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); - insertGlyphs[0] = glyphStorage[markGlyph]; - for (i = 1; i < count + 1; i++, markIndex++) { - insertGlyphs[i] = insertionTable[markIndex]; - } - glyphStorage.applyInsertions(); - } - } + le_bool isKashidaLike = (flags & cgiMarkedIsKashidaLike); + le_bool isBefore = (flags & cgiMarkInsertBefore); + doInsertion(glyphStorage, markGlyph, markIndex, count, isKashidaLike, isBefore, success); } + le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); if (currIndex > 0) { le_int16 count = flags & cgiCurrentInsertCountMask; - if (!(flags & cgiCurrentIsKashidaLike)) { - // extra glyph(s) will be added directly before/after the specified current glyph - if (!(flags & cgiCurrentInsertBefore)) { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); - for (i = 0; i < count; i++, currIndex++) { - insertGlyphs[i] = insertionTable[currIndex]; - } - insertGlyphs[i] = glyphStorage[currGlyph]; - glyphStorage.applyInsertions(); - } else { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); - insertGlyphs[0] = glyphStorage[currGlyph]; - for (i = 1; i < count + 1; i++, currIndex++) { - insertGlyphs[i] = insertionTable[currIndex]; - } - glyphStorage.applyInsertions(); - } - } else { - // inserted as a split-vowel-like insertion - // extra glyph(s) will be inserted some distance away from the current glyph - if (!(flags & cgiCurrentInsertBefore)) { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); - for (i = 0; i < count; i++, currIndex++) { - insertGlyphs[i] = insertionTable[currIndex]; - } - insertGlyphs[i] = glyphStorage[currGlyph]; - glyphStorage.applyInsertions(); - } else { - LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); - insertGlyphs[0] = glyphStorage[currGlyph]; - for (i = 1; i < count + 1; i++, currIndex++) { - insertGlyphs[i] = insertionTable[currIndex]; - } - glyphStorage.applyInsertions(); - } - } + le_bool isKashidaLike = (flags & cgiCurrentIsKashidaLike); + le_bool isBefore = (flags & cgiCurrentInsertBefore); + doInsertion(glyphStorage, currGlyph, currIndex, count, isKashidaLike, isBefore, success); } if (flags & cgiSetMark) { diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h index c53c4c9352b..c02da35ed6d 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h @@ -53,11 +53,12 @@ class ContextualGlyphInsertionProcessor2 : public StateTableProcessor2 public: virtual void beginStateTable(); - virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, + le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); virtual void endStateTable(); - ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + ContextualGlyphInsertionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~ContextualGlyphInsertionProcessor2(); /** @@ -77,12 +78,28 @@ public: private: ContextualGlyphInsertionProcessor2(); + /** + * Perform the actual insertion + * @param atGlyph index of glyph to insert at + * @param index index into the insertionTable (in/out) + * @param count number of insertions + * @param isKashidaLike Kashida like (vs Split Vowel like). No effect currently. + * @param isBefore if true, insert extra glyphs before the marked glyph + */ + void doInsertion(LEGlyphStorage &glyphStorage, + le_int16 atGlyph, + le_int16 &index, + le_int16 count, + le_bool isKashidaLike, + le_bool isBefore, + LEErrorCode &success); + + protected: le_int32 markGlyph; - const le_uint16* insertionTable; - const ContextualGlyphInsertionStateEntry2 *entryTable; - const ContextualGlyphInsertionHeader2 *contextualGlyphHeader; - + LEReferenceToArrayOf insertionTable; + LEReferenceToArrayOf entryTable; + LEReferenceTo contextualGlyphHeader; }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp index 7c659534f09..87fdf4d3aab 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp @@ -43,13 +43,18 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor) -ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) +ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor(morphSubtableHeader, success), entryTable(), contextualGlyphSubstitutionHeader(morphSubtableHeader, success) { - contextualGlyphSubstitutionHeader = (const ContextualGlyphSubstitutionHeader *) morphSubtableHeader; - substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset); + contextualGlyphSubstitutionHeader.orphan(); + substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset); - entryTable = (const ContextualGlyphSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + + entryTable = LEReferenceToArrayOf(stateTableHeader, success, + (const ContextualGlyphSubstitutionStateEntry*)(&stateTableHeader->stHeader), + entryTableOffset, LE_UNBOUNDED_ARRAY); + int16Table = LEReferenceToArrayOf(stateTableHeader, success, (const le_int16*)(&stateTableHeader->stHeader), + 0, LE_UNBOUNDED_ARRAY); // rest of the table as le_int16s } ContextualGlyphSubstitutionProcessor::~ContextualGlyphSubstitutionProcessor() @@ -63,27 +68,26 @@ void ContextualGlyphSubstitutionProcessor::beginStateTable() ByteOffset ContextualGlyphSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const ContextualGlyphSubstitutionStateEntry *entry = &entryTable[index]; - ByteOffset newState = SWAPW(entry->newStateOffset); - le_int16 flags = SWAPW(entry->flags); - WordOffset markOffset = SWAPW(entry->markOffset); - WordOffset currOffset = SWAPW(entry->currOffset); + LEErrorCode success = LE_NO_ERROR; + const ContextualGlyphSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + ByteOffset newState = SWAPW(entry->newStateOffset); + le_int16 flags = SWAPW(entry->flags); + WordOffset markOffset = SWAPW(entry->markOffset); + WordOffset currOffset = SWAPW(entry->currOffset); - if (markOffset != 0) { - const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + markOffset * 2); - LEGlyphID mGlyph = glyphStorage[markGlyph]; - TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(mGlyph)]); + if (markOffset != 0 && LE_SUCCESS(success)) { + LEGlyphID mGlyph = glyphStorage[markGlyph]; + TTGlyphID newGlyph = SWAPW(int16Table.getObject(markOffset + LE_GET_GLYPH(mGlyph), success)); // whew. - glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); - } + glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); + } - if (currOffset != 0) { - const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + currOffset * 2); - LEGlyphID thisGlyph = glyphStorage[currGlyph]; - TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(thisGlyph)]); + if (currOffset != 0) { + LEGlyphID thisGlyph = glyphStorage[currGlyph]; + TTGlyphID newGlyph = SWAPW(int16Table.getObject(currOffset + LE_GET_GLYPH(thisGlyph), success)); // whew. - glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); - } + glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } if (flags & cgsSetMark) { markGlyph = currGlyph; diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h index e93585e9bcb..136398f7661 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h @@ -56,7 +56,7 @@ public: virtual void endStateTable(); - ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + ContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~ContextualGlyphSubstitutionProcessor(); /** @@ -78,11 +78,11 @@ private: protected: ByteOffset substitutionTableOffset; - const ContextualGlyphSubstitutionStateEntry *entryTable; - + LEReferenceToArrayOf entryTable; + LEReferenceToArrayOf int16Table; le_int32 markGlyph; - const ContextualGlyphSubstitutionHeader *contextualGlyphSubstitutionHeader; + LEReferenceTo contextualGlyphSubstitutionHeader; }; diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp index 0bd09752cc3..6e8d070be99 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp @@ -43,13 +43,14 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor2) -ContextualGlyphSubstitutionProcessor2::ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : StateTableProcessor2(morphSubtableHeader) +ContextualGlyphSubstitutionProcessor2::ContextualGlyphSubstitutionProcessor2( + const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), contextualGlyphHeader(morphSubtableHeader, success) { - contextualGlyphHeader = (const ContextualGlyphHeader2 *) morphSubtableHeader; + if(LE_FAILURE(success)) return; le_uint32 perGlyphTableOffset = SWAPL(contextualGlyphHeader->perGlyphTableOffset); - perGlyphTable = ((le_uint32 *) ((char *)&stateTableHeader->stHeader + perGlyphTableOffset)); - entryTable = (const ContextualGlyphStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + perGlyphTable = LEReferenceToArrayOf (stHeader, success, perGlyphTableOffset, LE_UNBOUNDED_ARRAY); + entryTable = LEReferenceToArrayOf(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); } ContextualGlyphSubstitutionProcessor2::~ContextualGlyphSubstitutionProcessor2() @@ -61,25 +62,28 @@ void ContextualGlyphSubstitutionProcessor2::beginStateTable() markGlyph = 0; } -le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) { - const ContextualGlyphStateEntry2 *entry = &entryTable[index]; + if(LE_FAILURE(success)) return 0; + const ContextualGlyphStateEntry2 *entry = entryTable.getAlias(index, success); + if(LE_FAILURE(success)) return 0; le_uint16 newState = SWAPW(entry->newStateIndex); le_uint16 flags = SWAPW(entry->flags); le_int16 markIndex = SWAPW(entry->markIndex); le_int16 currIndex = SWAPW(entry->currIndex); if (markIndex != -1) { - le_uint32 offset = SWAPL(perGlyphTable[markIndex]); + le_uint32 offset = SWAPL(perGlyphTable(markIndex, success)); LEGlyphID mGlyph = glyphStorage[markGlyph]; - TTGlyphID newGlyph = lookup(offset, mGlyph); + TTGlyphID newGlyph = lookup(offset, mGlyph, success); glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); } if (currIndex != -1) { - le_uint32 offset = SWAPL(perGlyphTable[currIndex]); + le_uint32 offset = SWAPL(perGlyphTable(currIndex, success)); LEGlyphID thisGlyph = glyphStorage[currGlyph]; - TTGlyphID newGlyph = lookup(offset, thisGlyph); + TTGlyphID newGlyph = lookup(offset, thisGlyph, success); glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } @@ -94,26 +98,30 @@ le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorag return newState; } -TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyphID gid) +TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyphID gid, LEErrorCode &success) { - LookupTable *lookupTable = ((LookupTable *) ((char *)perGlyphTable + offset)); - le_int16 format = SWAPW(lookupTable->format); TTGlyphID newGlyph = 0xFFFF; + if(LE_FAILURE(success)) return newGlyph; + LEReferenceTo lookupTable(perGlyphTable, success, offset); + if(LE_FAILURE(success)) return newGlyph; + le_int16 format = SWAPW(lookupTable->format); switch (format) { case ltfSimpleArray: { #ifdef TEST_FORMAT // Disabled pending for design review - SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) lookupTable; + LEReferenceTo lookupTable0(lookupTable, success); + LEReferenceToArrayOf valueArray(lookupTable0, success, &lookupTable0->valueArray[0], LE_UNBOUNDED_ARRAY); + if(LE_FAILURE(success)) return newGlyph; TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); - newGlyph = SWAPW(lookupTable0->valueArray[glyphCode]); + newGlyph = SWAPW(lookupTable0->valueArray(glyphCode, success)); #endif break; } case ltfSegmentSingle: { #ifdef TEST_FORMAT // Disabled pending for design review - SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) lookupTable; + LEReferenceTo lookupTable2 = (SegmentSingleLookupTable *) lookupTable; const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); if (segment != NULL) { newGlyph = SWAPW(segment->value); @@ -129,8 +137,8 @@ TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyp { #ifdef TEST_FORMAT // Disabled pending for design review - SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) lookupTable; - const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + LEReferenceTo lookupTable6 = (SingleTableLookupTable *) lookupTable; + const LEReferenceTo segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); if (segment != NULL) { newGlyph = SWAPW(segment->value); } @@ -138,12 +146,15 @@ TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyp break; } case ltfTrimmedArray: { - TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) lookupTable; + LEReferenceTo lookupTable8(lookupTable, success); + if (LE_FAILURE(success)) return newGlyph; TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); - TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + TTGlyphID glyphCount = SWAPW(lookupTable8->glyphCount); + TTGlyphID lastGlyph = firstGlyph + glyphCount; TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { - newGlyph = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + LEReferenceToArrayOf valueArray(lookupTable8, success, &lookupTable8->valueArray[0], glyphCount); + newGlyph = SWAPW(valueArray(glyphCode - firstGlyph, success)); } } default: diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h index 0f63012c7f5..e60d8c6a7cf 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h @@ -52,11 +52,11 @@ class ContextualGlyphSubstitutionProcessor2 : public StateTableProcessor2 public: virtual void beginStateTable(); - virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); virtual void endStateTable(); - ContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + ContextualGlyphSubstitutionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~ContextualGlyphSubstitutionProcessor2(); /** @@ -75,16 +75,16 @@ public: private: ContextualGlyphSubstitutionProcessor2(); - TTGlyphID lookup(le_uint32 offset, LEGlyphID gid); + TTGlyphID lookup(le_uint32 offset, LEGlyphID gid, LEErrorCode &success); protected: - const le_uint32* perGlyphTable; - const ContextualGlyphStateEntry2 *entryTable; + LEReferenceToArrayOf perGlyphTable; + LEReferenceToArrayOf entryTable; le_int16 perGlyphTableFormat; le_int32 markGlyph; - const ContextualGlyphHeader2 *contextualGlyphHeader; + LEReferenceTo contextualGlyphHeader; }; diff --git a/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp b/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp index c799fc957e8..5446f9bebac 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp @@ -217,7 +217,7 @@ le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor * } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(subRuleSetCount); @@ -266,7 +266,7 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor * } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { const ClassDefinitionTable *classDefinitionTable = @@ -394,7 +394,7 @@ le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupPro } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); @@ -465,7 +465,7 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupPro } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { const ClassDefinitionTable *backtrackClassDefinitionTable = diff --git a/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.h b/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.h index 9df57fee2eb..d230699ec48 100644 --- a/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.h +++ b/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.h @@ -43,6 +43,7 @@ #include "GlyphSubstitutionTables.h" #include "GlyphIterator.h" #include "LookupProcessor.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -88,6 +89,8 @@ struct ContextualSubstitutionFormat1Subtable : ContextualSubstitutionSubtable le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat1Subtable, subRuleSetTableOffsetArray) + struct SubRuleSetTable { @@ -95,6 +98,7 @@ struct SubRuleSetTable Offset subRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubRuleSetTable, subRuleTableOffsetArray) // NOTE: Multiple variable size arrays!! struct SubRuleTable @@ -104,6 +108,7 @@ struct SubRuleTable TTGlyphID inputGlyphArray[ANY_NUMBER]; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubRuleTable, inputGlyphArray) struct ContextualSubstitutionFormat2Subtable : ContextualSubstitutionSubtable { @@ -113,12 +118,16 @@ struct ContextualSubstitutionFormat2Subtable : ContextualSubstitutionSubtable le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat2Subtable, subClassSetTableOffsetArray) + struct SubClassSetTable { le_uint16 subClassRuleCount; Offset subClassRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubClassSetTable, subClassRuleTableOffsetArray) + // NOTE: Multiple variable size arrays!! struct SubClassRuleTable @@ -128,6 +137,8 @@ struct SubClassRuleTable le_uint16 classArray[ANY_NUMBER]; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubClassRuleTable, classArray) + // NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause // it has an array of coverage tables instead of a single coverage table... @@ -143,6 +154,7 @@ struct ContextualSubstitutionFormat3Subtable le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat3Subtable, coverageTableOffsetArray) struct ChainingContextualSubstitutionSubtable : ContextualSubstitutionBase { @@ -156,6 +168,8 @@ struct ChainingContextualSubstitutionFormat1Subtable : ChainingContextualSubstit le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat1Subtable, chainSubRuleSetTableOffsetArray) + struct ChainSubRuleSetTable { @@ -163,6 +177,7 @@ struct ChainSubRuleSetTable Offset chainSubRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubRuleSetTable, chainSubRuleTableOffsetArray) // NOTE: Multiple variable size arrays!! struct ChainSubRuleTable @@ -176,6 +191,7 @@ struct ChainSubRuleTable //le_uint16 substCount; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubRuleTable, backtrackGlyphArray) struct ChainingContextualSubstitutionFormat2Subtable : ChainingContextualSubstitutionSubtable { @@ -187,12 +203,15 @@ struct ChainingContextualSubstitutionFormat2Subtable : ChainingContextualSubstit le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat2Subtable, chainSubClassSetTableOffsetArray) struct ChainSubClassSetTable { le_uint16 chainSubClassRuleCount; Offset chainSubClassRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubClassSetTable, chainSubClassRuleTableOffsetArray) + // NOTE: Multiple variable size arrays!! struct ChainSubClassRuleTable @@ -206,6 +225,7 @@ struct ChainSubClassRuleTable //le_uint16 substCount; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubClassRuleTable, backtrackClassArray) // NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause // it has arrays of coverage tables instead of a single coverage table... @@ -225,6 +245,8 @@ struct ChainingContextualSubstitutionFormat3Subtable le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat3Subtable, backtrackCoverageTableOffsetArray) + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/CoverageTables.h b/jdk/src/share/native/sun/font/layout/CoverageTables.h index 9705a841b69..dd47716a101 100644 --- a/jdk/src/share/native/sun/font/layout/CoverageTables.h +++ b/jdk/src/share/native/sun/font/layout/CoverageTables.h @@ -56,6 +56,8 @@ struct CoverageFormat1Table : CoverageTable le_int32 getGlyphCoverage(LEGlyphID glyphID) const; }; +LE_VAR_ARRAY(CoverageFormat1Table, glyphArray) + struct CoverageFormat2Table : CoverageTable { @@ -64,6 +66,7 @@ struct CoverageFormat2Table : CoverageTable le_int32 getGlyphCoverage(LEGlyphID glyphID) const; }; +LE_VAR_ARRAY(CoverageFormat2Table, rangeRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp b/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp index e3a7d041efc..ff8ac3bed76 100644 --- a/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp @@ -39,10 +39,10 @@ U_NAMESPACE_BEGIN -le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 CursiveAttachmentSubtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyphID = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyphID); + le_int32 coverageIndex = getGlyphCoverage(base, glyphID, success); le_uint16 eeCount = SWAPW(entryExitCount); if (coverageIndex < 0 || coverageIndex >= eeCount) { @@ -51,7 +51,7 @@ le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const } LEPoint entryAnchor, exitAnchor; - Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor); + Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor); // TODO Offset exitOffset = SWAPW(entryExitRecords[coverageIndex].exitAnchor); if (entryOffset != 0) { diff --git a/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h b/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h index 88d10b6097c..2e1fdd62141 100644 --- a/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h +++ b/jdk/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h @@ -57,8 +57,9 @@ struct CursiveAttachmentSubtable : GlyphPositioningSubtable le_uint16 entryExitCount; EntryExitRecord entryExitRecords[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(CursiveAttachmentSubtable, entryExitRecords) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/DeviceTables.h b/jdk/src/share/native/sun/font/layout/DeviceTables.h index cf471b869d6..ba9e534249f 100644 --- a/jdk/src/share/native/sun/font/layout/DeviceTables.h +++ b/jdk/src/share/native/sun/font/layout/DeviceTables.h @@ -57,6 +57,7 @@ private: static const le_uint16 fieldSignBits[]; static const le_uint16 fieldBits[]; }; +LE_VAR_ARRAY(DeviceTable, deltaValues) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/ExtensionSubtables.cpp b/jdk/src/share/native/sun/font/layout/ExtensionSubtables.cpp index 7ecd2685635..76d945d02d0 100644 --- a/jdk/src/share/native/sun/font/layout/ExtensionSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/ExtensionSubtables.cpp @@ -47,6 +47,8 @@ U_NAMESPACE_BEGIN le_uint32 ExtensionSubtable::process(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; } @@ -55,9 +57,11 @@ le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_ if (elt != lookupType) { le_uint32 extOffset = READ_LONG(extensionOffset); - LookupSubtable *subtable = (LookupSubtable *) ((char *) this + extOffset); + LEReferenceTo subtable(thisRef, success, extOffset); - return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success); + if(LE_SUCCESS(success)) { + return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success); + } } return 0; diff --git a/jdk/src/share/native/sun/font/layout/Features.cpp b/jdk/src/share/native/sun/font/layout/Features.cpp index c83ac05d97d..b44ae2e8e87 100644 --- a/jdk/src/share/native/sun/font/layout/Features.cpp +++ b/jdk/src/share/native/sun/font/layout/Features.cpp @@ -38,19 +38,20 @@ U_NAMESPACE_BEGIN -const FeatureTable *FeatureListTable::getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const +LEReferenceTo FeatureListTable::getFeatureTable(const LETableReference &base, le_uint16 featureIndex, LETag *featureTag, LEErrorCode &success) const { - if (featureIndex >= SWAPW(featureCount)) { - return 0; - } + if (featureIndex >= SWAPW(featureCount) || LE_FAILURE(success)) { + return LEReferenceTo(); + } Offset featureTableOffset = featureRecordArray[featureIndex].featureTableOffset; *featureTag = SWAPT(featureRecordArray[featureIndex].featureTag); - return (const FeatureTable *) ((char *) this + SWAPW(featureTableOffset)); + return LEReferenceTo(base, success, SWAPW(featureTableOffset)); } +#if 0 /* * Note: according to the OpenType Spec. v 1.4, the entries in the Feature * List Table are sorted alphabetically by feature tag; however, there seem @@ -82,5 +83,6 @@ const FeatureTable *FeatureListTable::getFeatureTable(LETag featureTag) const return 0; #endif } +#endif U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.cpp b/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.cpp index 173935cfd9c..ddd56b44494 100644 --- a/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.cpp +++ b/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.cpp @@ -36,9 +36,12 @@ U_NAMESPACE_BEGIN -GDEFMarkFilter::GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable) +GDEFMarkFilter::GDEFMarkFilter(const LEReferenceTo &gdefTable, LEErrorCode &success) + : classDefTable(gdefTable->getGlyphClassDefinitionTable(gdefTable, success)) { - classDefTable = gdefTable->getGlyphClassDefinitionTable(); + if(!classDefTable.isValid()) { + success = LE_INTERNAL_ERROR; + } } GDEFMarkFilter::~GDEFMarkFilter() diff --git a/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.h b/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.h index 64f79b862c7..c2ee9e758a2 100644 --- a/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.h +++ b/jdk/src/share/native/sun/font/layout/GDEFMarkFilter.h @@ -46,13 +46,13 @@ U_NAMESPACE_BEGIN class GDEFMarkFilter : public UMemory, public LEGlyphFilter { private: - const GlyphClassDefinitionTable *classDefTable; + const LEReferenceTo classDefTable; GDEFMarkFilter(const GDEFMarkFilter &other); // forbid copying of this class GDEFMarkFilter &operator=(const GDEFMarkFilter &other); // forbid copying of this class public: - GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable); + GDEFMarkFilter(const LEReferenceTo &gdefTable, LEErrorCode &success); virtual ~GDEFMarkFilter(); virtual le_bool accept(LEGlyphID glyph) const; diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/GXLayoutEngine.cpp index 9321d5a01e2..e6da45df8cb 100644 --- a/jdk/src/share/native/sun/font/layout/GXLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine.cpp @@ -41,9 +41,10 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine) -GXLayoutEngine::GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success) + GXLayoutEngine::GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo &morphTable, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, 0, success), fMorphTable(morphTable) { + fMorphTable.orphan(); // nothing else to do? } @@ -70,7 +71,7 @@ le_int32 GXLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, return 0; } - fMorphTable->process(glyphStorage); + fMorphTable->process(fMorphTable, glyphStorage, success); return count; } diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine.h b/jdk/src/share/native/sun/font/layout/GXLayoutEngine.h index b7aa296ca0d..cc900a195a7 100644 --- a/jdk/src/share/native/sun/font/layout/GXLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine.h @@ -74,7 +74,7 @@ public: * * @internal */ - GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success); + GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo &morphTable, LEErrorCode &success); /** * The destructor, virtual for correct polymorphic invocation. @@ -104,7 +104,7 @@ protected: * * @internal */ - const MorphTableHeader *fMorphTable; + LEReferenceTo fMorphTable; /** * This method does GX layout using the font's 'mort' table. It converts the diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp index ae070c2f6ff..d4e385097fc 100644 --- a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.cpp @@ -39,10 +39,10 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine2) -GXLayoutEngine2::GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success) - : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMorphTable(morphTable) +GXLayoutEngine2::GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo &morphTable, le_int32 typoFlags, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMorphTable(morphTable) { - // nothing else to do? + // nothing else to do? } GXLayoutEngine2::~GXLayoutEngine2() @@ -68,7 +68,7 @@ le_int32 GXLayoutEngine2::computeGlyphs(const LEUnicode chars[], le_int32 offset return 0; } - fMorphTable->process(glyphStorage, fTypoFlags); + fMorphTable->process(fMorphTable, glyphStorage, fTypoFlags, success); return count; } diff --git a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h index 9eded230c13..3b11f1409d1 100644 --- a/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h +++ b/jdk/src/share/native/sun/font/layout/GXLayoutEngine2.h @@ -73,7 +73,7 @@ public: * * @internal */ - GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader2 *morphTable, le_int32 typoFlags, LEErrorCode &success); + GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo &morphTable, le_int32 typoFlags, LEErrorCode &success); /** * The destructor, virtual for correct polymorphic invocation. @@ -103,7 +103,7 @@ protected: * * @internal */ - const MorphTableHeader2 *fMorphTable; + const LEReferenceTo fMorphTable; /** * This method does GX layout using the font's 'mort' table. It converts the diff --git a/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp b/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp index 03e95cf9f84..f751b82d0d0 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp @@ -36,24 +36,36 @@ U_NAMESPACE_BEGIN -const GlyphClassDefinitionTable *GlyphDefinitionTableHeader::getGlyphClassDefinitionTable() const +const LEReferenceTo +GlyphDefinitionTableHeader::getGlyphClassDefinitionTable(const LEReferenceTo& base, + LEErrorCode &success) const { - return (const GlyphClassDefinitionTable *) ((char *) this + SWAPW(glyphClassDefOffset)); + if(LE_FAILURE(success)) return LEReferenceTo(); + return LEReferenceTo(base, success, SWAPW(glyphClassDefOffset)); } -const AttachmentListTable *GlyphDefinitionTableHeader::getAttachmentListTable() const +const LEReferenceTo +GlyphDefinitionTableHeader::getAttachmentListTable(const LEReferenceTo& base, + LEErrorCode &success) const { - return (const AttachmentListTable *) ((char *) this + SWAPW(attachListOffset)); + if(LE_FAILURE(success)) return LEReferenceTo(); + return LEReferenceTo(base, success, SWAPW(attachListOffset)); } -const LigatureCaretListTable *GlyphDefinitionTableHeader::getLigatureCaretListTable() const +const LEReferenceTo +GlyphDefinitionTableHeader::getLigatureCaretListTable(const LEReferenceTo& base, + LEErrorCode &success) const { - return (const LigatureCaretListTable *) ((char *) this + SWAPW(ligCaretListOffset)); + if(LE_FAILURE(success)) return LEReferenceTo(); + return LEReferenceTo(base, success, SWAPW(ligCaretListOffset)); } -const MarkAttachClassDefinitionTable *GlyphDefinitionTableHeader::getMarkAttachClassDefinitionTable() const +const LEReferenceTo +GlyphDefinitionTableHeader::getMarkAttachClassDefinitionTable(const LEReferenceTo& base, + LEErrorCode &success) const { - return (const MarkAttachClassDefinitionTable *) ((char *) this + SWAPW(MarkAttachClassDefOffset)); + if(LE_FAILURE(success)) return LEReferenceTo(); + return LEReferenceTo(base, success, SWAPW(MarkAttachClassDefOffset)); } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.h b/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.h index 631bf690376..6bf7ebc1044 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.h +++ b/jdk/src/share/native/sun/font/layout/GlyphDefinitionTables.h @@ -60,12 +60,14 @@ struct AttachmentListTable le_uint16 glyphCount; Offset attachPointTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AttachmentListTable, attachPointTableOffsetArray) struct AttachPointTable { le_uint16 pointCount; le_uint16 pointIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AttachPointTable, pointIndexArray) struct LigatureCaretListTable { @@ -73,12 +75,14 @@ struct LigatureCaretListTable le_uint16 ligGlyphCount; Offset ligGlyphTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureCaretListTable, ligGlyphTableOffsetArray) struct LigatureGlyphTable { le_uint16 caretCount; Offset caretValueTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureGlyphTable, caretValueTableOffsetArray) struct CaretValueTable { @@ -111,10 +115,18 @@ struct GlyphDefinitionTableHeader Offset ligCaretListOffset; Offset MarkAttachClassDefOffset; - const GlyphClassDefinitionTable *getGlyphClassDefinitionTable() const; - const AttachmentListTable *getAttachmentListTable()const ; - const LigatureCaretListTable *getLigatureCaretListTable() const; - const MarkAttachClassDefinitionTable *getMarkAttachClassDefinitionTable() const; + const LEReferenceTo + getGlyphClassDefinitionTable(const LEReferenceTo& base, + LEErrorCode &success) const; + const LEReferenceTo + getAttachmentListTable(const LEReferenceTo& base, + LEErrorCode &success)const ; + const LEReferenceTo + getLigatureCaretListTable(const LEReferenceTo& base, + LEErrorCode &success) const; + const LEReferenceTo + getMarkAttachClassDefinitionTable(const LEReferenceTo& base, + LEErrorCode &success) const; }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GlyphIterator.cpp b/jdk/src/share/native/sun/font/layout/GlyphIterator.cpp index 2fea0e9df23..d0cd46732ed 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphIterator.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphIterator.cpp @@ -41,18 +41,21 @@ U_NAMESPACE_BEGIN GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, - FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader) + FeatureMask theFeatureMask, const LEReferenceTo &theGlyphDefinitionTableHeader) : direction(1), position(-1), nextLimit(-1), prevLimit(-1), glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments), srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0), - glyphClassDefinitionTable(NULL), markAttachClassDefinitionTable(NULL) + glyphClassDefinitionTable(), markAttachClassDefinitionTable() { + LEErrorCode success = LE_NO_ERROR; // TODO le_int32 glyphCount = glyphStorage.getGlyphCount(); - if (theGlyphDefinitionTableHeader != NULL) { - glyphClassDefinitionTable = theGlyphDefinitionTableHeader->getGlyphClassDefinitionTable(); - markAttachClassDefinitionTable = theGlyphDefinitionTableHeader->getMarkAttachClassDefinitionTable(); + if (theGlyphDefinitionTableHeader.isValid()) { + glyphClassDefinitionTable = theGlyphDefinitionTableHeader + -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success); + markAttachClassDefinitionTable = theGlyphDefinitionTableHeader + ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success); } nextLimit = glyphCount; @@ -380,6 +383,7 @@ void GlyphIterator::setCursiveGlyph() le_bool GlyphIterator::filterGlyph(le_uint32 index) const { + LEErrorCode success = LE_NO_ERROR; LEGlyphID glyphID = glyphStorage[index]; le_int32 glyphClass = gcdNoGlyphClass; @@ -387,8 +391,8 @@ le_bool GlyphIterator::filterGlyph(le_uint32 index) const return TRUE; } - if (glyphClassDefinitionTable != NULL) { - glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphID); + if (glyphClassDefinitionTable.isValid()) { + glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphClassDefinitionTable, glyphID, success); } switch (glyphClass) @@ -410,8 +414,9 @@ le_bool GlyphIterator::filterGlyph(le_uint32 index) const le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift; - if ((markAttachType != 0) && (markAttachClassDefinitionTable != NULL)) { - return markAttachClassDefinitionTable->getGlyphClass(glyphID) != markAttachType; + if ((markAttachType != 0) && (markAttachClassDefinitionTable.isValid())) { + return markAttachClassDefinitionTable + -> getGlyphClass(markAttachClassDefinitionTable, glyphID, success) != markAttachType; } return FALSE; @@ -461,6 +466,7 @@ le_bool GlyphIterator::nextInternal(le_uint32 delta) while (newPosition != nextLimit && delta > 0) { do { newPosition += direction; + //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != nextLimit && filterGlyph(newPosition)); delta -= 1; @@ -468,6 +474,7 @@ le_bool GlyphIterator::nextInternal(le_uint32 delta) position = newPosition; + //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != nextLimit; } @@ -483,6 +490,7 @@ le_bool GlyphIterator::prevInternal(le_uint32 delta) while (newPosition != prevLimit && delta > 0) { do { newPosition -= direction; + //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != prevLimit && filterGlyph(newPosition)); delta -= 1; @@ -490,6 +498,7 @@ le_bool GlyphIterator::prevInternal(le_uint32 delta) position = newPosition; + //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != prevLimit; } diff --git a/jdk/src/share/native/sun/font/layout/GlyphIterator.h b/jdk/src/share/native/sun/font/layout/GlyphIterator.h index 63d0aedda00..d8db62a1298 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphIterator.h +++ b/jdk/src/share/native/sun/font/layout/GlyphIterator.h @@ -49,7 +49,7 @@ class GlyphPositionAdjustments; class GlyphIterator : public UMemory { public: GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, - FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader); + FeatureMask theFeatureMask, const LEReferenceTo &theGlyphDefinitionTableHeader); GlyphIterator(GlyphIterator &that); @@ -117,8 +117,8 @@ private: FeatureMask featureMask; le_int32 glyphGroup; - const GlyphClassDefinitionTable *glyphClassDefinitionTable; - const MarkAttachClassDefinitionTable *markAttachClassDefinitionTable; + LEReferenceTo glyphClassDefinitionTable; + LEReferenceTo markAttachClassDefinitionTable; GlyphIterator &operator=(const GlyphIterator &other); // forbid copying of this class }; diff --git a/jdk/src/share/native/sun/font/layout/GlyphLookupTables.cpp b/jdk/src/share/native/sun/font/layout/GlyphLookupTables.cpp index 9cc6c06e5e8..179bf60d328 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphLookupTables.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphLookupTables.cpp @@ -37,21 +37,22 @@ U_NAMESPACE_BEGIN -le_bool GlyphLookupTableHeader::coversScript(LETag scriptTag) const +le_bool GlyphLookupTableHeader::coversScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const { - const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset)); + LEReferenceTo scriptListTable(base, success, SWAPW(scriptListOffset)); - return scriptListOffset != 0 && scriptListTable->findScript(scriptTag) != NULL; + return (scriptListOffset != 0) && scriptListTable->findScript(scriptListTable, scriptTag, success) .isValid(); } -le_bool GlyphLookupTableHeader::coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const +le_bool GlyphLookupTableHeader::coversScriptAndLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { - const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset)); - const LangSysTable *langSysTable = scriptListTable->findLanguage(scriptTag, languageTag, exactMatch); + LEReferenceTo scriptListTable(base, success, SWAPW(scriptListOffset)); + LEReferenceTo langSysTable = scriptListTable->findLanguage(scriptListTable, + scriptTag, languageTag, success, exactMatch); // FIXME: could check featureListOffset, lookupListOffset, and lookup count... // Note: don't have to SWAPW langSysTable->featureCount to check for non-zero. - return langSysTable != NULL && langSysTable->featureCount != 0; + return LE_SUCCESS(success)&&langSysTable.isValid() && langSysTable->featureCount != 0; } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GlyphLookupTables.h b/jdk/src/share/native/sun/font/layout/GlyphLookupTables.h index 4159c3814c6..ea1751a2bad 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphLookupTables.h +++ b/jdk/src/share/native/sun/font/layout/GlyphLookupTables.h @@ -49,8 +49,8 @@ struct GlyphLookupTableHeader Offset featureListOffset; Offset lookupListOffset; - le_bool coversScript(LETag scriptTag) const; - le_bool coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const; + le_bool coversScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const; + le_bool coversScriptAndLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.cpp b/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.cpp index dd3894e33d4..55883199031 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.cpp @@ -41,16 +41,16 @@ U_NAMESPACE_BEGIN -void GlyphPositioningTableHeader::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, +void GlyphPositioningTableHeader::process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success, + const LEReferenceTo &glyphDefinitionTableHeader, LEErrorCode &success, const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const { if (LE_FAILURE(success)) { return; } - GlyphPositioningLookupProcessor processor(this, scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success); + GlyphPositioningLookupProcessor processor(base, scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success); if (LE_FAILURE(success)) { return; } diff --git a/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.h b/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.h index ef3c5e652f5..0c1066baeaf 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.h +++ b/jdk/src/share/native/sun/font/layout/GlyphPositioningTables.h @@ -40,6 +40,7 @@ #include "OpenTypeTables.h" #include "Lookups.h" #include "GlyphLookupTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -51,9 +52,9 @@ struct GlyphDefinitionTableHeader; struct GlyphPositioningTableHeader : public GlyphLookupTableHeader { - void process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, + void process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success, + const LEReferenceTo &glyphDefinitionTableHeader, LEErrorCode &success, const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const; }; diff --git a/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp b/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp index 22d251586a7..08b6c048e91 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp @@ -57,7 +57,7 @@ typedef ContextualSubstitutionSubtable ContextualPositioningSubtable; typedef ChainingContextualSubstitutionSubtable ChainingContextualPositioningSubtable; GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor( - const GlyphPositioningTableHeader *glyphPositioningTableHeader, + const LEReferenceTo &glyphPositioningTableHeader, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, @@ -65,7 +65,7 @@ GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor( le_bool featureOrder, LEErrorCode& success) : LookupProcessor( - (char *) glyphPositioningTableHeader, + glyphPositioningTableHeader, SWAPW(glyphPositioningTableHeader->scriptListOffset), SWAPW(glyphPositioningTableHeader->featureListOffset), SWAPW(glyphPositioningTableHeader->lookupListOffset), @@ -84,7 +84,7 @@ GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor() { } -le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, +le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LEReferenceTo &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const @@ -102,55 +102,55 @@ le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *l case gpstSingle: { - const SinglePositioningSubtable *subtable = (const SinglePositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstPair: { - const PairPositioningSubtable *subtable = (const PairPositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstCursive: { - const CursiveAttachmentSubtable *subtable = (const CursiveAttachmentSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToBase: { - const MarkToBasePositioningSubtable *subtable = (const MarkToBasePositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToLigature: { - const MarkToLigaturePositioningSubtable *subtable = (const MarkToLigaturePositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToMark: { - const MarkToMarkPositioningSubtable *subtable = (const MarkToMarkPositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstContext: { - const ContextualPositioningSubtable *subtable = (const ContextualPositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -158,7 +158,7 @@ le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *l case gpstChainedContext: { - const ChainingContextualPositioningSubtable *subtable = (const ChainingContextualPositioningSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -166,7 +166,7 @@ le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *l case gpstExtension: { - const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable; + LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); break; diff --git a/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.h b/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.h index 6001f2c9863..3e46e415d20 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.h +++ b/jdk/src/share/native/sun/font/layout/GlyphPosnLookupProc.h @@ -51,7 +51,7 @@ U_NAMESPACE_BEGIN class GlyphPositioningLookupProcessor : public LookupProcessor { public: - GlyphPositioningLookupProcessor(const GlyphPositioningTableHeader *glyphPositioningTableHeader, + GlyphPositioningLookupProcessor(const LEReferenceTo &glyphPositioningTableHeader, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, @@ -61,7 +61,7 @@ public: virtual ~GlyphPositioningLookupProcessor(); - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, + virtual le_uint32 applySubtable(const LEReferenceTo &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; protected: diff --git a/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp b/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp index 850b7829318..d7b65aa8660 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp @@ -51,7 +51,7 @@ U_NAMESPACE_BEGIN GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor( - const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader, + const LEReferenceTo &glyphSubstitutionTableHeader, LETag scriptTag, LETag languageTag, const LEGlyphFilter *filter, @@ -60,7 +60,7 @@ GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor( le_bool featureOrder, LEErrorCode& success) : LookupProcessor( - (char *) glyphSubstitutionTableHeader, + glyphSubstitutionTableHeader, SWAPW(glyphSubstitutionTableHeader->scriptListOffset), SWAPW(glyphSubstitutionTableHeader->featureListOffset), SWAPW(glyphSubstitutionTableHeader->lookupListOffset), @@ -73,7 +73,7 @@ GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor() { } -le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, +le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LEReferenceTo &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -89,39 +89,39 @@ le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable * case gsstSingle: { - const SingleSubstitutionSubtable *subtable = (const SingleSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstMultiple: { - const MultipleSubstitutionSubtable *subtable = (const MultipleSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, success, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstAlternate: { - const AlternateSubstitutionSubtable *subtable = (const AlternateSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstLigature: { - const LigatureSubstitutionSubtable *subtable = (const LigatureSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstContext: { - const ContextualSubstitutionSubtable *subtable = (const ContextualSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -129,7 +129,7 @@ le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable * case gsstChainingContext: { - const ChainingContextualSubstitutionSubtable *subtable = (const ChainingContextualSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -137,7 +137,7 @@ le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable * case gsstExtension: { - const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable; + const LEReferenceTo subtable(lookupSubtable, success); delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); break; diff --git a/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.h b/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.h index 154cc2b9236..11890482756 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.h +++ b/jdk/src/share/native/sun/font/layout/GlyphSubstLookupProc.h @@ -52,7 +52,7 @@ U_NAMESPACE_BEGIN class GlyphSubstitutionLookupProcessor : public LookupProcessor { public: - GlyphSubstitutionLookupProcessor(const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader, + GlyphSubstitutionLookupProcessor(const LEReferenceTo &glyphSubstitutionTableHeader, LETag scriptTag, LETag languageTag, const LEGlyphFilter *filter, @@ -63,7 +63,7 @@ public: virtual ~GlyphSubstitutionLookupProcessor(); - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, + virtual le_uint32 applySubtable(const LEReferenceTo &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; protected: diff --git a/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp b/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp index bd056b60260..b60cdc53efd 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp +++ b/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp @@ -42,11 +42,12 @@ U_NAMESPACE_BEGIN -le_int32 GlyphSubstitutionTableHeader::process(LEGlyphStorage &glyphStorage, +le_int32 GlyphSubstitutionTableHeader::process(const LEReferenceTo &base, + LEGlyphStorage &glyphStorage, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + const LEReferenceTo &glyphDefinitionTableHeader, const LEGlyphFilter *filter, const FeatureMap *featureMap, le_int32 featureMapCount, @@ -57,7 +58,7 @@ le_int32 GlyphSubstitutionTableHeader::process(LEGlyphStorage &glyphStorage, return 0; } - GlyphSubstitutionLookupProcessor processor(this, scriptTag, languageTag, filter, featureMap, featureMapCount, featureOrder, success); + GlyphSubstitutionLookupProcessor processor(base, scriptTag, languageTag, filter, featureMap, featureMapCount, featureOrder, success); return processor.process(glyphStorage, NULL, rightToLeft, glyphDefinitionTableHeader, NULL, success); } diff --git a/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.h b/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.h index 207747dd9a7..ad3624c70ce 100644 --- a/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.h +++ b/jdk/src/share/native/sun/font/layout/GlyphSubstitutionTables.h @@ -50,11 +50,12 @@ struct GlyphDefinitionTableHeader; struct GlyphSubstitutionTableHeader : public GlyphLookupTableHeader { - le_int32 process(LEGlyphStorage &glyphStorage, + le_int32 process(const LEReferenceTo &base, + LEGlyphStorage &glyphStorage, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + const LEReferenceTo &glyphDefinitionTableHeader, const LEGlyphFilter *filter, const FeatureMap *featureMap, le_int32 featureMapCount, diff --git a/jdk/src/share/native/sun/font/layout/HanLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/HanLayoutEngine.cpp index 5e799ef8339..05c46790cd5 100644 --- a/jdk/src/share/native/sun/font/layout/HanLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/HanLayoutEngine.cpp @@ -64,7 +64,7 @@ static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); #define features (loclFeatureMask) HanOpenTypeLayoutEngine::HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = featureMap; diff --git a/jdk/src/share/native/sun/font/layout/HanLayoutEngine.h b/jdk/src/share/native/sun/font/layout/HanLayoutEngine.h index 6dd726069a5..de8d5569a2b 100644 --- a/jdk/src/share/native/sun/font/layout/HanLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/HanLayoutEngine.h @@ -73,7 +73,7 @@ public: * @internal */ HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTablem, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTablem, LEErrorCode &success); /** diff --git a/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.cpp index adc30bd526d..ac5f081d9c7 100644 --- a/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.cpp @@ -209,7 +209,7 @@ static le_int32 getCharClass(LEUnicode ch, LEUnicode &lead, LEUnicode &vowel, LE } HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 /*languageCode*/, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, korLanguageCode, typoFlags, gsubTable, success) { fFeatureMap = featureMap; diff --git a/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.h b/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.h index e2a485e5f81..bf0f0f85360 100644 --- a/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/HangulLayoutEngine.h @@ -79,7 +79,7 @@ public: * @internal */ HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known diff --git a/jdk/src/share/native/sun/font/layout/ICUFeatures.h b/jdk/src/share/native/sun/font/layout/ICUFeatures.h index f32d8e2b869..9eb97553a2b 100644 --- a/jdk/src/share/native/sun/font/layout/ICUFeatures.h +++ b/jdk/src/share/native/sun/font/layout/ICUFeatures.h @@ -54,16 +54,21 @@ struct FeatureTable le_uint16 lookupCount; le_uint16 lookupListIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(FeatureTable, lookupListIndexArray) struct FeatureListTable { le_uint16 featureCount; FeatureRecord featureRecordArray[ANY_NUMBER]; - const FeatureTable *getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const; + LEReferenceTo getFeatureTable(const LETableReference &base, le_uint16 featureIndex, LETag *featureTag, LEErrorCode &success) const; - const FeatureTable *getFeatureTable(LETag featureTag) const; +#if 0 + const LEReferenceTo getFeatureTable(const LETableReference &base, LETag featureTag, LEErrorCode &success) const; +#endif }; +LE_VAR_ARRAY(FeatureListTable, featureRecordArray) + U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.cpp index 4d2c4180226..61ab8b3a321 100644 --- a/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.cpp @@ -50,7 +50,7 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicOpenTypeLayoutEngine) IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, le_bool version2, const LEReferenceTo &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success), fMPreFixups(NULL) { if ( version2 ) { diff --git a/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.h b/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.h index b443941bf99..3b33da7394b 100644 --- a/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/IndicLayoutEngine.h @@ -81,7 +81,7 @@ public: * @internal */ IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, le_bool version2, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp index a83c9566f5d..3ae26be484c 100644 --- a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp @@ -43,11 +43,14 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor) -IndicRearrangementProcessor::IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) + IndicRearrangementProcessor::IndicRearrangementProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor(morphSubtableHeader, success), + indicRearrangementSubtableHeader(morphSubtableHeader, success), + entryTable(stateTableHeader, success, (const IndicRearrangementStateEntry*)(&stateTableHeader->stHeader), + entryTableOffset, LE_UNBOUNDED_ARRAY), + int16Table(stateTableHeader, success, (const le_int16*)entryTable.getAlias(), 0, LE_UNBOUNDED_ARRAY) + { - indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader *) morphSubtableHeader; - entryTable = (const IndicRearrangementStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); } IndicRearrangementProcessor::~IndicRearrangementProcessor() @@ -62,7 +65,8 @@ void IndicRearrangementProcessor::beginStateTable() ByteOffset IndicRearrangementProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const IndicRearrangementStateEntry *entry = &entryTable[index]; + LEErrorCode success = LE_NO_ERROR; // todo- make a param? + const IndicRearrangementStateEntry *entry = entryTable.getAlias(index,success); ByteOffset newState = SWAPW(entry->newStateOffset); IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags); diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.h b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.h index 202d3b7b094..271c6167339 100644 --- a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.h +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor.h @@ -58,7 +58,7 @@ public: void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; - IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader); + IndicRearrangementProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~IndicRearrangementProcessor(); /** @@ -79,8 +79,9 @@ protected: le_int32 firstGlyph; le_int32 lastGlyph; - const IndicRearrangementStateEntry *entryTable; - const IndicRearrangementSubtableHeader *indicRearrangementSubtableHeader; + LEReferenceTo indicRearrangementSubtableHeader; + LEReferenceToArrayOf entryTable; + LEReferenceToArrayOf int16Table; }; diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp index 35d6e43ac6b..4d531b2a03d 100644 --- a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp @@ -43,11 +43,11 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2) -IndicRearrangementProcessor2::IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : StateTableProcessor2(morphSubtableHeader) +IndicRearrangementProcessor2::IndicRearrangementProcessor2( + const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), indicRearrangementSubtableHeader(morphSubtableHeader, success), + entryTable(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY) { - indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader2 *) morphSubtableHeader; - entryTable = (const IndicRearrangementStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); } IndicRearrangementProcessor2::~IndicRearrangementProcessor2() @@ -60,9 +60,11 @@ void IndicRearrangementProcessor2::beginStateTable() lastGlyph = 0; } -le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) { - const IndicRearrangementStateEntry2 *entry = &entryTable[index]; + const IndicRearrangementStateEntry2 *entry = entryTable.getAlias(index, success); + if (LE_FAILURE(success)) return 0; // TODO - what to return in bad state? le_uint16 newState = SWAPW(entry->newStateIndex); // index to the new state IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags); diff --git a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h index 3d83f21ce3b..f58ac9b71fc 100644 --- a/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h @@ -52,13 +52,13 @@ class IndicRearrangementProcessor2 : public StateTableProcessor2 public: virtual void beginStateTable(); - virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); virtual void endStateTable(); void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; - IndicRearrangementProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + IndicRearrangementProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~IndicRearrangementProcessor2(); /** @@ -79,8 +79,8 @@ protected: le_int32 firstGlyph; le_int32 lastGlyph; - const IndicRearrangementStateEntry2 *entryTable; - const IndicRearrangementSubtableHeader2 *indicRearrangementSubtableHeader; + LEReferenceToArrayOf entryTable; + LEReferenceTo indicRearrangementSubtableHeader; }; diff --git a/jdk/src/share/native/sun/font/layout/IndicReordering.cpp b/jdk/src/share/native/sun/font/layout/IndicReordering.cpp index 9bf3a2a5c65..7ebabe141d2 100644 --- a/jdk/src/share/native/sun/font/layout/IndicReordering.cpp +++ b/jdk/src/share/native/sun/font/layout/IndicReordering.cpp @@ -658,6 +658,11 @@ le_int32 IndicReordering::reorder(const LEUnicode *chars, le_int32 charCount, le MPreFixups *mpreFixups = NULL; const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode); + if(classTable==NULL) { + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } + if (classTable->scriptFlags & SF_MPRE_FIXUP) { mpreFixups = new MPreFixups(charCount); if (mpreFixups == NULL) { diff --git a/jdk/src/share/native/sun/font/layout/KernTable.cpp b/jdk/src/share/native/sun/font/layout/KernTable.cpp index 3a9987eb6b9..13ddd0f3b32 100644 --- a/jdk/src/share/native/sun/font/layout/KernTable.cpp +++ b/jdk/src/share/native/sun/font/layout/KernTable.cpp @@ -48,7 +48,7 @@ struct PairInfo { 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 @@ struct Subtable_0 { 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 @@ struct SubtableHeader { 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 @@ struct KernTableHeader { 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,21 +95,21 @@ struct KernTableHeader { * TODO: support multiple subtables * TODO: respect header flags */ -KernTable::KernTable(const LEFontInstance* font_, const void* tableData) - : pairs(0), font(font_) +KernTable::KernTable(const LETableReference& base, LEErrorCode &success) + : pairs(), pairsSwapped(NULL), fTable(base) { - const KernTableHeader* header = (const KernTableHeader*)tableData; - if (header == 0) { + if(LE_FAILURE(success) || (fTable.isEmpty())) { #if DEBUG fprintf(stderr, "no kern data\n"); #endif return; } + LEReferenceTo header(fTable, success); #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) { @@ -115,12 +118,17 @@ KernTable::KernTable(const LEFontInstance* font_, const void* tableData) } #endif - if (header->version == 0 && SWAPW(header->nTables) > 0) { - const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE); - if (subhead->version == 0) { + if(LE_FAILURE(success)) return; + + if (!header.isEmpty() && header->version == 0 && SWAPW(header->nTables) > 0) { + LEReferenceTo subhead(header, success, KERN_TABLE_HEADER_SIZE); + + if (LE_SUCCESS(success) && !subhead.isEmpty() && subhead->version == 0) { coverage = SWAPW(subhead->coverage); if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning - const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE); + LEReferenceTo table(subhead, success, KERN_SUBTABLE_HEADER_SIZE); + + if(table.isEmpty() || LE_FAILURE(success)) return; nPairs = SWAPW(table->nPairs); @@ -134,19 +142,31 @@ KernTable::KernTable(const LEFontInstance* font_, const void* tableData) rangeShift = (nPairs * KERN_PAIRINFO_SIZE) - searchRange; #endif - pairs = (PairInfo*)font->getKernPairs(); - if (pairs == NULL) { - char *pairData = (char*)table + KERN_SUBTABLE_0_HEADER_SIZE; - char *pptr = pairData; - pairs = (PairInfo*)(malloc(nPairs*sizeof(PairInfo))); - PairInfo *p = (PairInfo*)pairs; - for (int i = 0; i < nPairs; i++, pptr += KERN_PAIRINFO_SIZE, p++) { - memcpy(p, pptr, KERN_PAIRINFO_SIZE); + 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. + + 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); } - font->setKernPairs((void*)pairs); + 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, @@ -194,14 +214,17 @@ KernTable::KernTable(const LEFontInstance* font_, const void* tableData) * Process the glyph positions. The positions array has two floats for each * glyph, plus a trailing pair to mark the end of the last glyph. */ -void KernTable::process(LEGlyphStorage& storage) +void KernTable::process(LEGlyphStorage& storage, LEErrorCode &success) { - if (pairs) { - LEErrorCode success = LE_NO_ERROR; + if(LE_FAILURE(success)) return; + + if (pairsSwapped) { + success = LE_NO_ERROR; 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 @@ -209,7 +232,7 @@ void KernTable::process(LEGlyphStorage& storage) // so either I have to swap the element each time I examine it, or I have to swap // all the elements ahead of time and store them in the font - const PairInfo* p = pairs; + const PairInfo* p = pairsSwapped; const PairInfo* tp = (const PairInfo*)(p + (rangeShift/KERN_PAIRINFO_SIZE)); /* rangeshift is in original table bytes */ if (key > tp->key) { p = tp; @@ -225,7 +248,7 @@ void KernTable::process(LEGlyphStorage& storage) tp = (const PairInfo*)(p + (probe/KERN_PAIRINFO_SIZE)); le_uint32 tkey = tp->key; #if DEBUG - fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairs), tkey); + fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairsSwapped), tkey); #endif if (tkey <= key) { if (tkey == key) { @@ -240,10 +263,10 @@ void KernTable::process(LEGlyphStorage& storage) // device transform, or a faster way, such as moving the // entire kern table up to Java. LEPoint pt; - pt.fX = font->xUnitsToPoints(value); + pt.fX = fTable.getFont()->xUnitsToPoints(value); pt.fY = 0; - font->getKerningAdjustment(pt); + fTable.getFont()->getKerningAdjustment(pt); adjust += pt.fX; break; } diff --git a/jdk/src/share/native/sun/font/layout/KernTable.h b/jdk/src/share/native/sun/font/layout/KernTable.h index ac41ee7d712..1cc4f872d3b 100644 --- a/jdk/src/share/native/sun/font/layout/KernTable.h +++ b/jdk/src/share/native/sun/font/layout/KernTable.h @@ -26,7 +26,7 @@ /* * * - * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 2004-2013 - All Rights Reserved * */ @@ -38,6 +38,7 @@ #endif #include "LETypes.h" +#include "LETableReference.h" //#include "LEFontInstance.h" //#include "LEGlyphStorage.h" @@ -56,19 +57,20 @@ class U_LAYOUT_API KernTable private: le_uint16 coverage; le_uint16 nPairs; - const PairInfo* pairs; - const LEFontInstance* font; + LEReferenceToArrayOf pairs; + PairInfo *pairsSwapped; + const LETableReference &fTable; le_uint16 searchRange; le_uint16 entrySelector; le_uint16 rangeShift; public: - KernTable(const LEFontInstance* font, const void* tableData); + KernTable(const LETableReference &table, LEErrorCode &success); /* * Process the glyph positions. */ - void process(LEGlyphStorage& storage); + void process(LEGlyphStorage& storage, LEErrorCode &success); }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp index d1f0674ebf4..9fd448c5682 100644 --- a/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp @@ -43,7 +43,7 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(KhmerOpenTypeLayoutEngine) KhmerOpenTypeLayoutEngine::KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = KhmerReordering::getFeatureMap(fFeatureMapCount); diff --git a/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.h b/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.h index 602d8563a33..2652c74f463 100644 --- a/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/KhmerLayoutEngine.h @@ -83,7 +83,7 @@ public: * @internal */ KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known diff --git a/jdk/src/share/native/sun/font/layout/LEScripts.h b/jdk/src/share/native/sun/font/layout/LEScripts.h index beb3bbedc6e..804c8f64610 100644 --- a/jdk/src/share/native/sun/font/layout/LEScripts.h +++ b/jdk/src/share/native/sun/font/layout/LEScripts.h @@ -258,10 +258,11 @@ enum ScriptCodes { * @stable ICU 49 */ - khojScriptCode = 156, - tirhScriptCode = 157, + hluwScriptCode = 156, /* bump to match current ICU */ + khojScriptCode = 157, + tirhScriptCode = 158, - scriptCodeCount = 158 + scriptCodeCount = 159 }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/LETableReference.h b/jdk/src/share/native/sun/font/layout/LETableReference.h new file mode 100644 index 00000000000..dab52b664a8 --- /dev/null +++ b/jdk/src/share/native/sun/font/layout/LETableReference.h @@ -0,0 +1,442 @@ +/* + * 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 + */ +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); +#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; + } + + /** + * 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 LETableVarSizer { + public: + inline static size_t getSize(); +}; + +// base definition- could override for adjustments +template inline +size_t LETableVarSizer::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::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::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::getSize() { return 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 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::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer::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::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer::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::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer::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 { + return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success))); + } + + 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::getSize()*i; + } else { + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + } + return 0; + } + + LEReferenceToArrayOf &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") + } + +private: + le_uint32 fCount; +}; + + +template +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(0, LETableVarSizer::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::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::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LETableReference &parent, LEErrorCode &success) + : LETableReference(parent, 0, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success) + : LETableReference(font, tableTag, success) { + verifyLength(0, LETableVarSizer::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& operator=(const T* other) { + setRaw(other); + return *this; + } + + LEReferenceTo &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + /** + * roll forward by one size. + * same as addOffset(LETableVarSizer::getSize(),success) + */ + void addObject(LEErrorCode &success) { + addOffset(LETableVarSizer::getSize(), success); + } + void addObject(size_t count, LEErrorCode &success) { + addOffset(LETableVarSizer::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 diff --git a/jdk/src/share/native/sun/font/layout/LETypes.h b/jdk/src/share/native/sun/font/layout/LETypes.h index d3801fc2450..130f72fd742 100644 --- a/jdk/src/share/native/sun/font/layout/LETypes.h +++ b/jdk/src/share/native/sun/font/layout/LETypes.h @@ -354,12 +354,15 @@ typedef struct LEPoint LEPoint; /** * Max value representable by a uintptr */ -#ifndef UINTPTR_MAX + #ifndef UINT32_MAX -#define LE_UINTPTR_MAX 0xFFFFFFFFU +#define LE_UINT32_MAX 0xFFFFFFFFU #else -#define LE_UINTPTR_MAX UINT32_MAX +#define LE_UINT32_MAX UINT32_MAX #endif + +#ifndef UINTPTR_MAX +#define LE_UINTPTR_MAX LE_UINT32_MAX #else #define LE_UINTPTR_MAX UINTPTR_MAX #endif diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp index 1fadbf9f792..6690316f32d 100644 --- a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp @@ -147,21 +147,21 @@ CharSubstitutionFilter::~CharSubstitutionFilter() class CanonMarkFilter : public UMemory, public LEGlyphFilter { private: - const GlyphClassDefinitionTable *classDefTable; + const LEReferenceTo classDefTable; CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class public: - CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable); + CanonMarkFilter(const LEReferenceTo &gdefTable, LEErrorCode &success); virtual ~CanonMarkFilter(); virtual le_bool accept(LEGlyphID glyph) const; }; -CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable) +CanonMarkFilter::CanonMarkFilter(const LEReferenceTo &gdefTable, LEErrorCode &success) + : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) { - classDefTable = gdefTable->getMarkAttachClassDefinitionTable(); } CanonMarkFilter::~CanonMarkFilter() @@ -171,9 +171,10 @@ CanonMarkFilter::~CanonMarkFilter() le_bool CanonMarkFilter::accept(LEGlyphID glyph) const { - le_int32 glyphClass = classDefTable->getGlyphClass(glyph); - - return glyphClass != 0; + LEErrorCode success = LE_NO_ERROR; + le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); + if(LE_FAILURE(success)) return false; + return glyphClass != 0; } UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) @@ -262,20 +263,20 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off return count; } - const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; + LEReferenceTo canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); le_int32 i, dir = 1, out = 0, outCharCount = count; - if (canonGSUBTable->coversScript(scriptTag)) { + if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); if (substitutionFilter == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } - const LEUnicode *inChars = &chars[offset]; - LEUnicode *reordered = NULL; + const LEUnicode *inChars = &chars[offset]; + LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); @@ -285,20 +286,20 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off return 0; } - // This is the cheapest way to get mark reordering only for Hebrew. - // We could just do the mark reordering for all scripts, but most - // of them probably don't need it... - if (fScriptCode == hebrScriptCode) { - reordered = LE_NEW_ARRAY(LEUnicode, count); + // This is the cheapest way to get mark reordering only for Hebrew. + // We could just do the mark reordering for all scripts, but most + // of them probably don't need it... + if (fScriptCode == hebrScriptCode) { + reordered = LE_NEW_ARRAY(LEUnicode, count); - if (reordered == NULL) { - delete substitutionFilter; - success = LE_MEMORY_ALLOCATION_ERROR; - return 0; - } + if (reordered == NULL) { + delete substitutionFilter; + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } - CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); - inChars = reordered; + CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); + inChars = reordered; } fakeGlyphStorage.allocateAuxData(success); @@ -318,11 +319,11 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off fakeGlyphStorage.setAuxData(out, canonFeatures, success); } - if (reordered != NULL) { - LE_DELETE_ARRAY(reordered); - } + if (reordered != NULL) { + LE_DELETE_ARRAY(reordered); + } - outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); + outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); if (LE_FAILURE(success)) { delete substitutionFilter; @@ -423,16 +424,16 @@ void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset return; } - GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - CanonMarkFilter filter(gdefTable); + LEReferenceTo gdefTable((GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, + CanonShaping::glyphDefinitionTableLen); + CanonMarkFilter filter(gdefTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } // default is no adjustments @@ -517,9 +518,9 @@ void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); } -const void *LayoutEngine::getFontTable(LETag tableTag) const +const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const { - return fFontInstance->getFontTable(tableTag); + return fFontInstance->getFontTable(tableTag, length); } void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, @@ -566,7 +567,10 @@ le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_ void LayoutEngine::reset() { + if(fGlyphStorage!=NULL) { fGlyphStorage->reset(); + fGlyphStorage = NULL; + } } LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) @@ -585,19 +589,19 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan return NULL; } - const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag); + LEReferenceTo gsubTable(fontInstance,gsubTableTag,success); LayoutEngine *result = NULL; LETag scriptTag = 0x00000000; LETag languageTag = 0x00000000; - LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); + LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are // properly tested. - if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); - } - else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { + if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); + } + else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { switch (scriptCode) { case bengScriptCode: case devaScriptCode: @@ -633,10 +637,10 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan case janLanguageCode: case zhtLanguageCode: case zhsLanguageCode: - if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) { + if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; - } + } // note: falling through to default case. default: @@ -663,9 +667,9 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); } else { - const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - if (mortTable != NULL && SWAPL(mortTable->version)==0x00010000) { // mort - result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + LEReferenceTo mortTable(fontInstance, mortTableTag, success); + if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); } else { switch (scriptCode) { case bengScriptCode: diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.h b/jdk/src/share/native/sun/font/layout/LayoutEngine.h index 9293167dba6..2f5487f382d 100644 --- a/jdk/src/share/native/sun/font/layout/LayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.h @@ -280,12 +280,18 @@ protected: * some other way must override this method. * * @param tableTag - the four byte table tag. + * @param length - length to use * * @return the address of the table. * * @internal */ - virtual const void *getFontTable(LETag tableTag) const; + virtual const void *getFontTable(LETag tableTag, size_t &length) const; + + /** + * @deprecated + */ + virtual const void *getFontTable(LETag tableTag) const { size_t ignored; return getFontTable(tableTag, ignored); } /** * This method does character to glyph mapping. The default implementation diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp index 842b095e085..0014b95a515 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.cpp @@ -47,15 +47,15 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor) -LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) + LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) +: StateTableProcessor(morphSubtableHeader, success), ligatureSubstitutionHeader(morphSubtableHeader, success) { - ligatureSubstitutionHeader = (const LigatureSubstitutionHeader *) morphSubtableHeader; + if(LE_FAILURE(success)) return; ligatureActionTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureActionTableOffset); componentTableOffset = SWAPW(ligatureSubstitutionHeader->componentTableOffset); ligatureTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureTableOffset); - entryTable = (const LigatureSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + entryTable = LEReferenceToArrayOf(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); } LigatureSubstitutionProcessor::~LigatureSubstitutionProcessor() @@ -69,7 +69,9 @@ void LigatureSubstitutionProcessor::beginStateTable() ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const LigatureSubstitutionStateEntry *entry = &entryTable[index]; + LEErrorCode success = LE_NO_ERROR; + const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + ByteOffset newState = SWAPW(entry->newStateOffset); le_int16 flags = SWAPW(entry->flags); @@ -88,7 +90,7 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp ByteOffset actionOffset = flags & lsfActionOffsetMask; if (actionOffset != 0) { - const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + actionOffset); + LEReferenceTo ap(stHeader, success, actionOffset); LigatureActionEntry action; le_int32 offset, i = 0; le_int32 stack[nComponents]; @@ -97,7 +99,8 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp do { le_uint32 componentGlyph = componentStack[m--]; - action = SWAPL(*ap++); + action = SWAPL(*ap.getAlias()); + ap.addObject(success); // ap++ if (m < 0) { m = nComponents - 1; @@ -105,37 +108,33 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp 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)); + LEReferenceToArrayOf offsetTable(stHeader, success, 2 * SignExtend(offset, lafComponentOffsetMask), LE_UNBOUNDED_ARRAY); - // 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? + if(LE_FAILURE(success)) { 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(componentGlyph > glyphStorage.getGlyphCount()) { + LE_DEBUG_BAD_FONT("preposterous componentGlyph"); + currGlyph++; + return newState; // get out! bad font + } + i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success)); if (action & (lafLast | lafStore)) { - const TTGlyphID *ligatureOffset = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + i); - TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset); + LEReferenceTo ligatureOffset(stHeader, success, i); + TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias()); - 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; + 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); + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); } } #if LE_ASSERT_BAD_FONT @@ -146,11 +145,11 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyp } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items while (mm >= 0) { - if (++m >= nComponents) { - m = 0; - } + if (++m >= nComponents) { + m = 0; + } - componentStack[m] = stack[mm--]; + componentStack[m] = stack[mm--]; } } diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.h b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.h index 9629a3d3a3d..1765a71d674 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc.h +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc.h @@ -58,7 +58,7 @@ public: virtual void endStateTable(); - LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + LigatureSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~LigatureSubstitutionProcessor(); /** @@ -83,12 +83,12 @@ protected: ByteOffset componentTableOffset; ByteOffset ligatureTableOffset; - const LigatureSubstitutionStateEntry *entryTable; + LEReferenceToArrayOf entryTable; le_int32 componentStack[nComponents]; le_int16 m; - const LigatureSubstitutionHeader *ligatureSubstitutionHeader; + LEReferenceTo ligatureSubstitutionHeader; }; diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp index f36be1b26ad..5eacf1c5e0c 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp @@ -47,15 +47,18 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor2) -LigatureSubstitutionProcessor2::LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : StateTableProcessor2(morphSubtableHeader) +LigatureSubstitutionProcessor2::LigatureSubstitutionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), + ligActionOffset(0), + ligatureSubstitutionHeader(morphSubtableHeader, success), componentOffset(0), ligatureOffset(0), entryTable() { - ligatureSubstitutionHeader = (const LigatureSubstitutionHeader2 *) morphSubtableHeader; + if (LE_FAILURE(success)) return; + ligActionOffset = SWAPL(ligatureSubstitutionHeader->ligActionOffset); componentOffset = SWAPL(ligatureSubstitutionHeader->componentOffset); ligatureOffset = SWAPL(ligatureSubstitutionHeader->ligatureOffset); - entryTable = (const LigatureSubstitutionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + entryTable = LEReferenceToArrayOf(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); } LigatureSubstitutionProcessor2::~LigatureSubstitutionProcessor2() @@ -67,9 +70,11 @@ void LigatureSubstitutionProcessor2::beginStateTable() m = -1; } -le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) +le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success) { - const LigatureSubstitutionStateEntry2 *entry = &entryTable[index]; + const LigatureSubstitutionStateEntry2 *entry = entryTable.getAlias(index, success); + if(LE_FAILURE(success)) return 0; + le_uint16 nextStateIndex = SWAPW(entry->nextStateIndex); le_uint16 flags = SWAPW(entry->entryFlags); le_uint16 ligActionIndex = SWAPW(entry->ligActionIndex); @@ -81,7 +86,7 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp componentStack[m] = currGlyph; } else if ( m == -1) { // bad font- skip this glyph. - LE_DEBUG_BAD_FONT("m==-1") + //LE_DEBUG_BAD_FONT("m==-1 (componentCount went negative)") currGlyph+= dir; return nextStateIndex; } @@ -89,29 +94,25 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp ByteOffset actionOffset = flags & lsfPerformAction; if (actionOffset != 0) { - const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + ligActionOffset) + ligActionIndex; - const TTGlyphID *ligatureTable = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + ligatureOffset); + LEReferenceTo ap(stHeader, success, ligActionOffset); // byte offset + ap.addObject(ligActionIndex - 1, success); // index offset ( one before the actual start, because we will pre-increment) + LEReferenceToArrayOf ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); LigatureActionEntry action; le_int32 offset, i = 0; le_int32 stack[nComponents]; le_int16 mm = -1; - const le_uint16 *componentTable = (const le_uint16 *)((char *) &ligatureSubstitutionHeader->stHeader + componentOffset); - - const le_uint16 *tableEnd = (const le_uint16 *)((char *) &ligatureSubstitutionHeader + SWAPL(ligatureSubstitutionHeader->length)); - - // Check if the font is internally consistent - if(tableEnd < (const le_uint16*)&ligatureSubstitutionHeader // stated end wrapped around? - || componentTable > tableEnd) { // offset past end of stated length? + LEReferenceToArrayOf componentTable(stHeader, success, componentOffset, LE_UNBOUNDED_ARRAY); + if(LE_FAILURE(success)) { currGlyph+= dir; - LE_DEBUG_BAD_FONT("ligatureSubstHeader off end of table") return nextStateIndex; // get out! bad font } do { le_uint32 componentGlyph = componentStack[m--]; // pop off - action = SWAPL(*ap++); + ap.addObject(success); + action = SWAPL(*ap.getAlias()); if (m < 0) { m = nComponents - 1; @@ -124,10 +125,10 @@ le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyp currGlyph+= dir; return nextStateIndex; // get out! bad font } - i += SWAPW(componentTable[LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask))]); + i += SWAPW(componentTable(LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask)),success)); if (action & (lafLast | lafStore)) { - TTGlyphID ligatureGlyph = SWAPW(ligatureTable[i]); + TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success)); glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); if(mm==nComponents) { LE_DEBUG_BAD_FONT("exceeded nComponents"); diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h index 81ab8b56e8a..2edfa903d25 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.h @@ -54,11 +54,12 @@ class LigatureSubstitutionProcessor2 : public StateTableProcessor2 public: virtual void beginStateTable(); - virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index); + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success); virtual void endStateTable(); - LigatureSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + LigatureSubstitutionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~LigatureSubstitutionProcessor2(); /** @@ -83,12 +84,12 @@ protected: le_uint32 componentOffset; le_uint32 ligatureOffset; - const LigatureSubstitutionStateEntry2 *entryTable; + LEReferenceToArrayOf entryTable; le_int32 componentStack[nComponents]; le_int16 m; - const LigatureSubstitutionHeader2 *ligatureSubstitutionHeader; + const LEReferenceTo ligatureSubstitutionHeader; }; diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp b/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp index 0c173f3c7d5..46e808f2b6e 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp @@ -40,10 +40,10 @@ U_NAMESPACE_BEGIN -le_uint32 LigatureSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 LigatureSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { Offset ligSetTableOffset = SWAPW(ligSetTableOffsetArray[coverageIndex]); diff --git a/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.h b/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.h index 97a426b104a..0b577e56980 100644 --- a/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.h +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstSubtables.h @@ -50,6 +50,7 @@ struct LigatureSetTable le_uint16 ligatureCount; Offset ligatureTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureSetTable, ligatureTableOffsetArray) struct LigatureTable { @@ -57,14 +58,16 @@ struct LigatureTable le_uint16 compCount; TTGlyphID componentArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureTable, componentArray) struct LigatureSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 ligSetCount; Offset ligSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(LigatureSubstitutionSubtable, ligSetTableOffsetArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp index db672efb98b..fe7477db730 100644 --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp @@ -44,7 +44,7 @@ U_NAMESPACE_BEGIN -le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator, +le_uint32 LookupProcessor::applyLookupTable(const LEReferenceTo &lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -57,7 +57,7 @@ le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, Glyp le_uint32 delta; for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) { - const LookupSubtable *lookupSubtable = lookupTable->getLookupSubtable(subtable); + LEReferenceTo lookupSubtable = lookupTable->getLookupSubtable(lookupTable, subtable, success); delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success); @@ -72,7 +72,7 @@ le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, Glyp } le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, - le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + le_bool rightToLeft, const LEReferenceTo &glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -89,13 +89,13 @@ le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdj rightToLeft, 0, 0, glyphDefinitionTableHeader); le_int32 newGlyphCount = glyphCount; - for (le_uint16 order = 0; order < lookupOrderCount; order += 1) { + for (le_uint16 order = 0; order < lookupOrderCount && LE_SUCCESS(success); order += 1) { le_uint16 lookup = lookupOrderArray[order]; FeatureMask selectMask = lookupSelectArray[lookup]; if (selectMask != 0) { - const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup); - if (!lookupTable) { + const LEReferenceTo lookupTable = lookupListTable->getLookupTable(lookupListTable, lookup, success); + if (!lookupTable.isValid() ||LE_FAILURE(success) ) { continue; } le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); @@ -103,7 +103,7 @@ le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdj glyphIterator.reset(lookupFlags, selectMask); while (glyphIterator.findFeatureTag()) { - applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); + applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); // TODO if (LE_FAILURE(success)) { return 0; } @@ -123,8 +123,8 @@ le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIt return 0; } - const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex); - if (lookupTable == NULL) { + const LEReferenceTo lookupTable = lookupListTable->getLookupTable(lookupListTable, lookupTableIndex, success); + if (!lookupTable.isValid()) { success = LE_INTERNAL_ERROR; return 0; } @@ -135,33 +135,35 @@ le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIt return delta; } -le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order) +le_int32 LookupProcessor::selectLookups(const LEReferenceTo &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success) { - le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0; + le_uint16 lookupCount = featureTable.isValid()? SWAPW(featureTable->lookupCount) : 0; le_int32 store = order; - for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) { - le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]); - if (lookupListIndex >= lookupSelectCount) { - continue; - } + LEReferenceToArrayOf lookupListIndexArray(featureTable, success, featureTable->lookupListIndexArray, lookupCount); - lookupSelectArray[lookupListIndex] |= featureMask; - lookupOrderArray[store++] = lookupListIndex; + for (le_uint16 lookup = 0; LE_SUCCESS(success) && lookup < lookupCount; lookup += 1) { + le_uint16 lookupListIndex = SWAPW(lookupListIndexArray.getObject(lookup,success)); + if (lookupListIndex >= lookupSelectCount) { + continue; + } + + lookupSelectArray[lookupListIndex] |= featureMask; + lookupOrderArray[store++] = lookupListIndex; } return store - order; } -LookupProcessor::LookupProcessor(const char *baseAddress, +LookupProcessor::LookupProcessor(const LETableReference &baseAddress, Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures, LEErrorCode& success) - : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL), lookupSelectCount(0), - lookupOrderArray(NULL), lookupOrderCount(0) + : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0), + lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress) { - const ScriptListTable *scriptListTable = NULL; - const LangSysTable *langSysTable = NULL; + LEReferenceTo scriptListTable; + LEReferenceTo langSysTable; le_uint16 featureCount = 0; le_uint16 lookupListCount = 0; le_uint16 requiredFeatureIndex; @@ -171,29 +173,33 @@ LookupProcessor::LookupProcessor(const char *baseAddress, } if (scriptListOffset != 0) { - scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset); - langSysTable = scriptListTable->findLanguage(scriptTag, languageTag); + scriptListTable = LEReferenceTo(baseAddress, success, scriptListOffset); + langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success); - if (langSysTable != 0) { - featureCount = SWAPW(langSysTable->featureCount); - } + if (langSysTable.isValid() && LE_SUCCESS(success)) { + featureCount = SWAPW(langSysTable->featureCount); + } } if (featureListOffset != 0) { - featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset); + featureListTable = LEReferenceTo(baseAddress, success, featureListOffset); } if (lookupListOffset != 0) { - lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset); + lookupListTable = LEReferenceTo(baseAddress,success, lookupListOffset); + if(LE_SUCCESS(success) && lookupListTable.isValid()) { lookupListCount = SWAPW(lookupListTable->lookupCount); + } } - if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL || + if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() || featureCount == 0 || lookupListCount == 0) { return; } - requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex); + if(langSysTable.isValid()) { + requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex); + } lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount); if (lookupSelectArray == NULL) { @@ -209,34 +215,38 @@ LookupProcessor::LookupProcessor(const char *baseAddress, le_int32 count, order = 0; le_uint32 featureReferences = 0; - const FeatureTable *featureTable = NULL; + LEReferenceTo featureTable; LETag featureTag; - const FeatureTable *requiredFeatureTable = NULL; + LEReferenceTo requiredFeatureTable; LETag requiredFeatureTag = 0x00000000U; // Count the total number of lookups referenced by all features. This will // 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_uint32 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + if(featureListTable.isValid() && LE_SUCCESS(success)) { + LEReferenceToArrayOf featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); - if (!featureTable) { - continue; + for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) { + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success)); + + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); + if (!featureTable.isValid() || LE_FAILURE(success)) { + continue; } featureReferences += SWAPW(featureTable->lookupCount); + } } - if (!featureTable) { + if (!featureTable.isValid() || LE_FAILURE(success)) { success = LE_INTERNAL_ERROR; return; } if (requiredFeatureIndex != 0xFFFF) { - requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag); - featureReferences += SWAPW(featureTable->lookupCount); + requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success); + featureReferences += SWAPW(featureTable->lookupCount); } lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences); @@ -251,7 +261,7 @@ LookupProcessor::LookupProcessor(const char *baseAddress, // If this is the required feature, add its lookups if (requiredFeatureTag == fm.tag) { - count += selectLookups(requiredFeatureTable, fm.mask, order); + count += selectLookups(requiredFeatureTable, fm.mask, order, success); } if (orderFeatures) { @@ -261,7 +271,8 @@ LookupProcessor::LookupProcessor(const char *baseAddress, } for (le_uint16 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + LEReferenceToArrayOf featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success)); // don't add the required feature to the list more than once... // TODO: Do we need this check? (Spec. says required feature won't be in feature list...) @@ -269,10 +280,10 @@ LookupProcessor::LookupProcessor(const char *baseAddress, continue; } - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); if (featureTag == fm.tag) { - count += selectLookups(featureTable, fm.mask, order + count); + count += selectLookups(featureTable, fm.mask, order + count, success); } } @@ -281,9 +292,10 @@ LookupProcessor::LookupProcessor(const char *baseAddress, } order += count; - } else { - for (le_uint16 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + } else if(langSysTable.isValid()) { + LEReferenceToArrayOf featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); + for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) { + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success)); // don't add the required feature to the list more than once... // NOTE: This check is commented out because the spec. says that @@ -295,10 +307,10 @@ LookupProcessor::LookupProcessor(const char *baseAddress, } #endif - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); if (featureTag == fm.tag) { - order += selectLookups(featureTable, fm.mask, order); + order += selectLookups(featureTable, fm.mask, order, success); } } } diff --git a/jdk/src/share/native/sun/font/layout/LookupProcessor.h b/jdk/src/share/native/sun/font/layout/LookupProcessor.h index dc474c4f2bc..3ba03ef85f2 100644 --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.h +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.h @@ -41,6 +41,7 @@ #include "LETypes.h" #include "LEFontInstance.h" #include "OpenTypeTables.h" +#include "LETableReference.h" //#include "Lookups.h" //#include "Features.h" @@ -59,19 +60,21 @@ struct LookupTable; class LookupProcessor : public UMemory { public: le_int32 process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, - le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const; + le_bool rightToLeft, const LEReferenceTo &glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const; - le_uint32 applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; + le_uint32 applyLookupTable(const LEReferenceTo &lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; le_uint32 applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 subtableType, + virtual le_uint32 applySubtable(const LEReferenceTo &lookupSubtable, le_uint16 subtableType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const = 0; virtual ~LookupProcessor(); + const LETableReference &getReference() const { return fReference; } + protected: - LookupProcessor(const char *baseAddress, + LookupProcessor(const LETableReference &baseAddress, Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset, @@ -84,10 +87,10 @@ protected: LookupProcessor(); - le_int32 selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order); + le_int32 selectLookups(const LEReferenceTo &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success); - const LookupListTable *lookupListTable; - const FeatureListTable *featureListTable; + LEReferenceTo lookupListTable; + LEReferenceTo featureListTable; FeatureMask *lookupSelectArray; le_uint32 lookupSelectCount; @@ -95,6 +98,8 @@ protected: le_uint16 *lookupOrderArray; le_uint32 lookupOrderCount; + LETableReference fReference; + private: LookupProcessor(const LookupProcessor &other); // forbid copying of this class diff --git a/jdk/src/share/native/sun/font/layout/LookupTables.cpp b/jdk/src/share/native/sun/font/layout/LookupTables.cpp index 1c3acc151fe..6e7aa27957e 100644 --- a/jdk/src/share/native/sun/font/layout/LookupTables.cpp +++ b/jdk/src/share/native/sun/font/layout/LookupTables.cpp @@ -49,22 +49,26 @@ U_NAMESPACE_BEGIN of the derived classes, and implement it in the others by casting the "this" pointer to the type that has the implementation. */ -const LookupSegment *BinarySearchLookupTable::lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const +const LookupSegment *BinarySearchLookupTable::lookupSegment(const LETableReference &base, const LookupSegment *segments, LEGlyphID glyph, LEErrorCode &success) const { + le_int16 unity = SWAPW(unitSize); le_int16 probe = SWAPW(searchRange); le_int16 extra = SWAPW(rangeShift); TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); - const LookupSegment *entry = segments; - const LookupSegment *trial = (const LookupSegment *) ((char *) entry + extra); + LEReferenceTo entry(base, success, segments); + LEReferenceTo trial(entry, success, extra); + + if(LE_FAILURE(success)) return NULL; if (SWAPW(trial->lastGlyph) <= ttGlyph) { entry = trial; } - while (probe > unity) { + while (probe > unity && LE_SUCCESS(success)) { probe >>= 1; - trial = (const LookupSegment *) ((char *) entry + probe); + trial = entry; // copy + trial.addOffset(probe, success); if (SWAPW(trial->lastGlyph) <= ttGlyph) { entry = trial; @@ -72,28 +76,29 @@ const LookupSegment *BinarySearchLookupTable::lookupSegment(const LookupSegment } if (SWAPW(entry->firstGlyph) <= ttGlyph) { - return entry; + return entry.getAlias(); } return NULL; } -const LookupSingle *BinarySearchLookupTable::lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const +const LookupSingle *BinarySearchLookupTable::lookupSingle(const LETableReference &base, const LookupSingle *entries, LEGlyphID glyph, LEErrorCode &success) const { le_int16 unity = SWAPW(unitSize); le_int16 probe = SWAPW(searchRange); le_int16 extra = SWAPW(rangeShift); TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); - const LookupSingle *entry = entries; - const LookupSingle *trial = (const LookupSingle *) ((char *) entry + extra); + LEReferenceTo entry(base, success, entries); + LEReferenceTo trial(entry, success, extra); if (SWAPW(trial->glyph) <= ttGlyph) { entry = trial; } - while (probe > unity) { + while (probe > unity && LE_SUCCESS(success)) { probe >>= 1; - trial = (const LookupSingle *) ((char *) entry + probe); + trial = entry; + trial.addOffset(probe, success); if (SWAPW(trial->glyph) <= ttGlyph) { entry = trial; @@ -101,7 +106,7 @@ const LookupSingle *BinarySearchLookupTable::lookupSingle(const LookupSingle *en } if (SWAPW(entry->glyph) == ttGlyph) { - return entry; + return entry.getAlias(); } return NULL; diff --git a/jdk/src/share/native/sun/font/layout/LookupTables.h b/jdk/src/share/native/sun/font/layout/LookupTables.h index 7f6fccecad0..f15c7decace 100644 --- a/jdk/src/share/native/sun/font/layout/LookupTables.h +++ b/jdk/src/share/native/sun/font/layout/LookupTables.h @@ -39,6 +39,7 @@ #include "LETypes.h" #include "LayoutTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -79,30 +80,34 @@ struct BinarySearchLookupTable : LookupTable le_int16 entrySelector; le_int16 rangeShift; - const LookupSegment *lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const; + const LookupSegment *lookupSegment(const LETableReference &base, const LookupSegment *segments, LEGlyphID glyph, LEErrorCode &success) const; - const LookupSingle *lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const; + const LookupSingle *lookupSingle(const LETableReference &base, const LookupSingle *entries, LEGlyphID glyph, LEErrorCode &success) const; }; struct SimpleArrayLookupTable : LookupTable { LookupValue valueArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SimpleArrayLookupTable, valueArray) struct SegmentSingleLookupTable : BinarySearchLookupTable { LookupSegment segments[ANY_NUMBER]; }; +LE_VAR_ARRAY(SegmentSingleLookupTable, segments) struct SegmentArrayLookupTable : BinarySearchLookupTable { LookupSegment segments[ANY_NUMBER]; }; +LE_VAR_ARRAY(SegmentArrayLookupTable, segments) struct SingleTableLookupTable : BinarySearchLookupTable { LookupSingle entries[ANY_NUMBER]; }; +LE_VAR_ARRAY(SingleTableLookupTable, entries) struct TrimmedArrayLookupTable : LookupTable { @@ -110,6 +115,7 @@ struct TrimmedArrayLookupTable : LookupTable TTGlyphID glyphCount; LookupValue valueArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(TrimmedArrayLookupTable, valueArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/Lookups.cpp b/jdk/src/share/native/sun/font/layout/Lookups.cpp index f6b502be228..2c04cdfe44c 100644 --- a/jdk/src/share/native/sun/font/layout/Lookups.cpp +++ b/jdk/src/share/native/sun/font/layout/Lookups.cpp @@ -37,33 +37,35 @@ U_NAMESPACE_BEGIN -const LookupTable *LookupListTable::getLookupTable(le_uint16 lookupTableIndex) const +const LEReferenceTo LookupListTable::getLookupTable(const LEReferenceTo &base, le_uint16 lookupTableIndex, LEErrorCode &success) const { - if (lookupTableIndex >= SWAPW(lookupCount)) { - return 0; - } + LEReferenceToArrayOf lookupTableOffsetArrayRef(base, success, (const Offset*)&lookupTableOffsetArray, SWAPW(lookupCount)); - Offset lookupTableOffset = lookupTableOffsetArray[lookupTableIndex]; - - return (const LookupTable *) ((char *) this + SWAPW(lookupTableOffset)); + if(LE_FAILURE(success) || lookupTableIndex>lookupTableOffsetArrayRef.getCount()) { + return LEReferenceTo(); + } else { + return LEReferenceTo(base, success, SWAPW(lookupTableOffsetArrayRef.getObject(lookupTableIndex, success))); + } } -const LookupSubtable *LookupTable::getLookupSubtable(le_uint16 subtableIndex) const +const LEReferenceTo LookupTable::getLookupSubtable(const LEReferenceTo &base, le_uint16 subtableIndex, LEErrorCode &success) const { - if (subtableIndex >= SWAPW(subTableCount)) { - return 0; - } + LEReferenceToArrayOf subTableOffsetArrayRef(base, success, (const Offset*)&subTableOffsetArray, SWAPW(subTableCount)); - Offset subtableOffset = subTableOffsetArray[subtableIndex]; - - return (const LookupSubtable *) ((char *) this + SWAPW(subtableOffset)); + if(LE_FAILURE(success) || subtableIndex>subTableOffsetArrayRef.getCount()) { + return LEReferenceTo(); + } else { + return LEReferenceTo(base, success, SWAPW(subTableOffsetArrayRef.getObject(subtableIndex, success))); + } } -le_int32 LookupSubtable::getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const +le_int32 LookupSubtable::getGlyphCoverage(const LEReferenceTo &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const { - const CoverageTable *coverageTable = (const CoverageTable *) ((char *) this + SWAPW(tableOffset)); + const LEReferenceTo coverageTable(base, success, SWAPW(tableOffset)); - return coverageTable->getGlyphCoverage(glyphID); + if(LE_FAILURE(success)) return 0; + + return coverageTable->getGlyphCoverage(glyphID); } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/Lookups.h b/jdk/src/share/native/sun/font/layout/Lookups.h index 2ca6cabe8c1..ef71d997d49 100644 --- a/jdk/src/share/native/sun/font/layout/Lookups.h +++ b/jdk/src/share/native/sun/font/layout/Lookups.h @@ -58,9 +58,14 @@ struct LookupSubtable le_uint16 subtableFormat; Offset coverageTableOffset; - inline le_int32 getGlyphCoverage(LEGlyphID glyphID) const; + inline le_int32 getGlyphCoverage(const LEReferenceTo &base, LEGlyphID glyphID, LEErrorCode &success) const; - le_int32 getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const; + le_int32 getGlyphCoverage(const LEReferenceTo &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const; + + // convenience + inline le_int32 getGlyphCoverage(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + + inline le_int32 getGlyphCoverage(const LETableReference &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const; }; struct LookupTable @@ -70,20 +75,32 @@ struct LookupTable le_uint16 subTableCount; Offset subTableOffsetArray[ANY_NUMBER]; - const LookupSubtable *getLookupSubtable(le_uint16 subtableIndex) const; + const LEReferenceTo getLookupSubtable(const LEReferenceTo &base, le_uint16 subtableIndex, LEErrorCode &success) const; }; +LE_VAR_ARRAY(LookupTable, subTableOffsetArray) struct LookupListTable { le_uint16 lookupCount; Offset lookupTableOffsetArray[ANY_NUMBER]; - const LookupTable *getLookupTable(le_uint16 lookupTableIndex) const; + const LEReferenceTo getLookupTable(const LEReferenceTo &base, le_uint16 lookupTableIndex, LEErrorCode &success) const; }; +LE_VAR_ARRAY(LookupListTable, lookupTableOffsetArray) -inline le_int32 LookupSubtable::getGlyphCoverage(LEGlyphID glyphID) const +inline le_int32 LookupSubtable::getGlyphCoverage(const LEReferenceTo &base, LEGlyphID glyphID, LEErrorCode &success) const { - return getGlyphCoverage(coverageTableOffset, glyphID); + return getGlyphCoverage(base, coverageTableOffset, glyphID, success); +} + +inline le_int32 LookupSubtable::getGlyphCoverage(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo thisRef(base, success, this); + return getGlyphCoverage(thisRef, glyphID, success); +} + +inline le_int32 LookupSubtable::getGlyphCoverage(const LETableReference &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo thisRef(base, success, this); + return getGlyphCoverage(thisRef, tableOffset, glyphID, success); } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/MarkArrays.h b/jdk/src/share/native/sun/font/layout/MarkArrays.h index f4e19fd2743..badeb4f162e 100644 --- a/jdk/src/share/native/sun/font/layout/MarkArrays.h +++ b/jdk/src/share/native/sun/font/layout/MarkArrays.h @@ -57,6 +57,7 @@ struct MarkArray le_int32 getMarkClass(LEGlyphID glyphID, le_int32 coverageIndex, const LEFontInstance *fontInstance, LEPoint &anchor) const; }; +LE_VAR_ARRAY(MarkArray, markRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp b/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp index 45b78cf81fe..2878981b6be 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp @@ -51,10 +51,10 @@ LEGlyphID MarkToBasePositioningSubtable::findBaseGlyph(GlyphIterator *glyphItera return 0xFFFF; } -le_int32 MarkToBasePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToBasePositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -75,7 +75,7 @@ le_int32 MarkToBasePositioningSubtable::process(GlyphIterator *glyphIterator, co // FIXME: We probably don't want to find a base glyph before a previous ligature... GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/)); LEGlyphID baseGlyph = findBaseGlyph(&baseIterator); - le_int32 baseCoverage = getBaseCoverage((LEGlyphID) baseGlyph); + le_int32 baseCoverage = getBaseCoverage(base, (LEGlyphID) baseGlyph, success); const BaseArray *baseArray = (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 baseCount = SWAPW(baseArray->baseRecordCount); diff --git a/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h b/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h index 41b133ee50e..dcddb9d0eb2 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h +++ b/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h @@ -48,7 +48,7 @@ U_NAMESPACE_BEGIN struct MarkToBasePositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findBaseGlyph(GlyphIterator *glyphIterator) const; }; @@ -56,12 +56,14 @@ struct BaseRecord { Offset baseAnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(BaseRecord, baseAnchorTableOffsetArray) struct BaseArray { le_int16 baseRecordCount; BaseRecord baseRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(BaseArray, baseRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp b/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp index 346291e11ce..8e93e079a79 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp @@ -50,10 +50,10 @@ LEGlyphID MarkToLigaturePositioningSubtable::findLigatureGlyph(GlyphIterator *gl return 0xFFFF; } -le_int32 MarkToLigaturePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToLigaturePositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -74,7 +74,7 @@ le_int32 MarkToLigaturePositioningSubtable::process(GlyphIterator *glyphIterator // FIXME: we probably don't want to find a ligature before a previous base glyph... GlyphIterator ligatureIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreBaseGlyphs*/)); LEGlyphID ligatureGlyph = findLigatureGlyph(&ligatureIterator); - le_int32 ligatureCoverage = getBaseCoverage((LEGlyphID) ligatureGlyph); + le_int32 ligatureCoverage = getBaseCoverage(base, (LEGlyphID) ligatureGlyph, success); const LigatureArray *ligatureArray = (const LigatureArray *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 ligatureCount = SWAPW(ligatureArray->ligatureCount); diff --git a/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h b/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h index 9a501bd0b4e..27199257b6b 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h +++ b/jdk/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h @@ -48,7 +48,7 @@ U_NAMESPACE_BEGIN struct MarkToLigaturePositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findLigatureGlyph(GlyphIterator *glyphIterator) const; }; @@ -56,18 +56,21 @@ struct ComponentRecord { Offset ligatureAnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ComponentRecord, ligatureAnchorTableOffsetArray) struct LigatureAttachTable { le_uint16 componentCount; ComponentRecord componentRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureAttachTable, componentRecordArray) struct LigatureArray { le_uint16 ligatureCount; Offset ligatureAttachTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureArray, ligatureAttachTableOffsetArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp b/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp index 719484c1468..aa0bcd43c7c 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp @@ -51,10 +51,10 @@ LEGlyphID MarkToMarkPositioningSubtable::findMark2Glyph(GlyphIterator *glyphIter return 0xFFFF; } -le_int32 MarkToMarkPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToMarkPositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -74,7 +74,7 @@ le_int32 MarkToMarkPositioningSubtable::process(GlyphIterator *glyphIterator, co GlyphIterator mark2Iterator(*glyphIterator); LEGlyphID mark2Glyph = findMark2Glyph(&mark2Iterator); - le_int32 mark2Coverage = getBaseCoverage((LEGlyphID) mark2Glyph); + le_int32 mark2Coverage = getBaseCoverage(base, (LEGlyphID) mark2Glyph, success); const Mark2Array *mark2Array = (const Mark2Array *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 mark2Count = SWAPW(mark2Array->mark2RecordCount); diff --git a/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h b/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h index b4861965ba5..3ddfc499609 100644 --- a/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h +++ b/jdk/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h @@ -48,7 +48,7 @@ U_NAMESPACE_BEGIN struct MarkToMarkPositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findMark2Glyph(GlyphIterator *glyphIterator) const; }; @@ -56,12 +56,14 @@ struct Mark2Record { Offset mark2AnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Mark2Record, mark2AnchorTableOffsetArray) struct Mark2Array { le_uint16 mark2RecordCount; Mark2Record mark2RecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Mark2Array, mark2RecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/MorphTables.cpp b/jdk/src/share/native/sun/font/layout/MorphTables.cpp index 543110e68ed..17597a1ba01 100644 --- a/jdk/src/share/native/sun/font/layout/MorphTables.cpp +++ b/jdk/src/share/native/sun/font/layout/MorphTables.cpp @@ -44,61 +44,61 @@ U_NAMESPACE_BEGIN -void MorphTableHeader::process(LEGlyphStorage &glyphStorage) const +void MorphTableHeader::process(const LETableReference &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const { - const ChainHeader *chainHeader = chains; - le_uint32 chainCount = SWAPL(this->nChains); + le_uint32 chainCount = SWAPL(this->nChains); + LEReferenceTo chainHeader(base, success, chains); // moving header + LEReferenceToArrayOf chainHeaderArray(base, success, chains, chainCount); le_uint32 chain; - for (chain = 0; chain < chainCount; chain += 1) { + for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain += 1) { FeatureFlags defaultFlags = SWAPL(chainHeader->defaultFlags); le_uint32 chainLength = SWAPL(chainHeader->chainLength); le_int16 nFeatureEntries = SWAPW(chainHeader->nFeatureEntries); le_int16 nSubtables = SWAPW(chainHeader->nSubtables); - const MorphSubtableHeader *subtableHeader = - (const MorphSubtableHeader *)&chainHeader->featureTable[nFeatureEntries]; + LEReferenceTo subtableHeader = + LEReferenceTo(chainHeader,success, &(chainHeader->featureTable[nFeatureEntries])); le_int16 subtable; - for (subtable = 0; subtable < nSubtables; subtable += 1) { + for (subtable = 0; LE_SUCCESS(success) && (subtable < nSubtables); subtable += 1) { le_int16 length = SWAPW(subtableHeader->length); SubtableCoverage coverage = SWAPW(subtableHeader->coverage); FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); // should check coverage more carefully... - if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0) { - subtableHeader->process(glyphStorage); + if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0 && LE_SUCCESS(success)) { + subtableHeader->process(subtableHeader, glyphStorage, success); } - subtableHeader = (const MorphSubtableHeader *) ((char *)subtableHeader + length); + subtableHeader.addOffset(length, success); } - - chainHeader = (const ChainHeader *)((char *)chainHeader + chainLength); + chainHeader.addOffset(chainLength, success); } } -void MorphSubtableHeader::process(LEGlyphStorage &glyphStorage) const +void MorphSubtableHeader::process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const { SubtableProcessor *processor = NULL; switch (SWAPW(coverage) & scfTypeMask) { case mstIndicRearrangement: - processor = new IndicRearrangementProcessor(this); + processor = new IndicRearrangementProcessor(base, success); break; case mstContextualGlyphSubstitution: - processor = new ContextualGlyphSubstitutionProcessor(this); + processor = new ContextualGlyphSubstitutionProcessor(base, success); break; case mstLigatureSubstitution: - processor = new LigatureSubstitutionProcessor(this); + processor = new LigatureSubstitutionProcessor(base, success); break; case mstReservedUnused: break; case mstNonContextualGlyphSubstitution: - processor = NonContextualGlyphSubstitutionProcessor::createInstance(this); + processor = NonContextualGlyphSubstitutionProcessor::createInstance(base, success); break; /* @@ -112,8 +112,10 @@ void MorphSubtableHeader::process(LEGlyphStorage &glyphStorage) const } if (processor != NULL) { - processor->process(glyphStorage); - delete processor; + if(LE_SUCCESS(success)) { + processor->process(glyphStorage, success); + } + delete processor; } } diff --git a/jdk/src/share/native/sun/font/layout/MorphTables.h b/jdk/src/share/native/sun/font/layout/MorphTables.h index f58c1985a64..a6838703f0b 100644 --- a/jdk/src/share/native/sun/font/layout/MorphTables.h +++ b/jdk/src/share/native/sun/font/layout/MorphTables.h @@ -39,6 +39,7 @@ #include "LETypes.h" #include "LayoutTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -65,6 +66,7 @@ struct ChainHeader le_int16 nSubtables; FeatureTableEntry featureTable[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainHeader, featureTable) struct MorphTableHeader { @@ -72,8 +74,9 @@ struct MorphTableHeader le_uint32 nChains; ChainHeader chains[ANY_NUMBER]; - void process(LEGlyphStorage &glyphStorage) const; + void process(const LETableReference& base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; }; +LE_VAR_ARRAY(MorphTableHeader, chains) typedef le_int16 SubtableCoverage; typedef le_uint32 SubtableCoverage2; @@ -103,7 +106,7 @@ struct MorphSubtableHeader SubtableCoverage coverage; FeatureFlags subtableFeatures; - void process(LEGlyphStorage &glyphStorage) const; + void process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; }; enum SubtableCoverageFlags2 @@ -121,7 +124,7 @@ struct MorphSubtableHeader2 SubtableCoverage2 coverage; FeatureFlags subtableFeatures; - void process(LEGlyphStorage &glyphStorage) const; + void process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; }; struct ChainHeader2 @@ -132,6 +135,7 @@ struct ChainHeader2 le_uint32 nSubtables; FeatureTableEntry featureTable[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainHeader2, featureTable) struct MorphTableHeader2 { @@ -139,8 +143,9 @@ struct MorphTableHeader2 le_uint32 nChains; ChainHeader2 chains[ANY_NUMBER]; - void process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const; + void process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, le_int32 typoFlags, LEErrorCode &success) const; }; +LE_VAR_ARRAY(MorphTableHeader2, chains) /* * AAT Font Features diff --git a/jdk/src/share/native/sun/font/layout/MorphTables2.cpp b/jdk/src/share/native/sun/font/layout/MorphTables2.cpp index c9951a5f411..b75ca85a0ce 100644 --- a/jdk/src/share/native/sun/font/layout/MorphTables2.cpp +++ b/jdk/src/share/native/sun/font/layout/MorphTables2.cpp @@ -42,27 +42,40 @@ U_NAMESPACE_BEGIN -void MorphTableHeader2::process(LEGlyphStorage &glyphStorage, le_int32 typoFlags) const +void MorphTableHeader2::process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, + le_int32 typoFlags, LEErrorCode &success) const { - const ChainHeader2 *chainHeader = chains; - le_uint32 chainCount = SWAPL(this->nChains); - le_uint32 chain; + if(LE_FAILURE(success)) return; - for (chain = 0; chain < chainCount; chain++) { + le_uint32 chainCount = SWAPL(this->nChains); + LEReferenceTo chainHeader(base, success, &chains[0]); + /* chainHeader and subtableHeader are implemented as a moving pointer rather than an array dereference + * to (slightly) reduce code churn. However, must be careful to preincrement them the 2nd time through. + * We don't want to increment them at the end of the loop, as that would attempt to dereference + * out of range memory. + */ + le_uint32 chain; + + for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain++) { + if (chain>0) { + le_uint32 chainLength = SWAPL(chainHeader->chainLength); + chainHeader.addOffset(chainLength, success); // Don't increment the first time + } FeatureFlags flag = SWAPL(chainHeader->defaultFlags); - le_uint32 chainLength = SWAPL(chainHeader->chainLength); le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); - const MorphSubtableHeader2 *subtableHeader = - (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]; + LEReferenceTo subtableHeader(chainHeader, + success, (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]); le_uint32 subtable; + if(LE_FAILURE(success)) break; // malformed table if (typoFlags != 0) { le_uint32 featureEntry; - + LEReferenceToArrayOf featureTableRef(chainHeader, success, &chainHeader->featureTable[0], nFeatureEntries); + if(LE_FAILURE(success)) break; // Feature subtables for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { - FeatureTableEntry featureTableEntry = chains->featureTable[featureEntry]; + const FeatureTableEntry &featureTableEntry = featureTableRef(featureEntry, success); le_int16 featureType = SWAPW(featureTableEntry.featureType); le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); @@ -172,57 +185,63 @@ void MorphTableHeader2::process(LEGlyphStorage &glyphStorage, le_int32 typoFlags } } - for (subtable = 0; subtable < nSubtables; subtable++) { - le_uint32 length = SWAPL(subtableHeader->length); + for (subtable = 0; LE_SUCCESS(success) && subtable < nSubtables; subtable++) { + if(subtable>0) { + le_uint32 length = SWAPL(subtableHeader->length); + subtableHeader.addOffset(length, success); // Don't addOffset for the last entry. + } le_uint32 coverage = SWAPL(subtableHeader->coverage); FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); // should check coverage more carefully... if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { - subtableHeader->process(glyphStorage); + subtableHeader->process(subtableHeader, glyphStorage, success); } - subtableHeader = (const MorphSubtableHeader2 *) ((char *)subtableHeader + length); } - chainHeader = (const ChainHeader2 *)((char *)chainHeader + chainLength); } } -void MorphSubtableHeader2::process(LEGlyphStorage &glyphStorage) const +void MorphSubtableHeader2::process(const LEReferenceTo &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const { SubtableProcessor2 *processor = NULL; switch (SWAPL(coverage) & scfTypeMask2) { case mstIndicRearrangement: - processor = new IndicRearrangementProcessor2(this); + processor = new IndicRearrangementProcessor2(base, success); break; case mstContextualGlyphSubstitution: - processor = new ContextualGlyphSubstitutionProcessor2(this); + processor = new ContextualGlyphSubstitutionProcessor2(base, success); break; case mstLigatureSubstitution: - processor = new LigatureSubstitutionProcessor2(this); + processor = new LigatureSubstitutionProcessor2(base, success); break; case mstReservedUnused: break; case mstNonContextualGlyphSubstitution: - processor = NonContextualGlyphSubstitutionProcessor2::createInstance(this); + processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success); break; case mstContextualGlyphInsertion: - processor = new ContextualGlyphInsertionProcessor2(this); + processor = new ContextualGlyphInsertionProcessor2(base, success); break; default: - break; + return; + break; /*NOTREACHED*/ } if (processor != NULL) { - processor->process(glyphStorage); + processor->process(glyphStorage, success); delete processor; + } else { + if(LE_SUCCESS(success)) { + success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out. + } } } diff --git a/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp b/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp index e105e1eb688..9d72ca8a16c 100644 --- a/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp @@ -39,7 +39,7 @@ U_NAMESPACE_BEGIN -le_uint32 MultipleSubstitutionSubtable::process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const +le_uint32 MultipleSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const { if (LE_FAILURE(success)) { return 0; @@ -58,7 +58,7 @@ le_uint32 MultipleSubstitutionSubtable::process(GlyphIterator *glyphIterator, LE return 0; } - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); le_uint16 seqCount = SWAPW(sequenceCount); if (coverageIndex >= 0 && coverageIndex < seqCount) { diff --git a/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.h b/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.h index 5fe715ab7d5..55b809eef67 100644 --- a/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.h +++ b/jdk/src/share/native/sun/font/layout/MultipleSubstSubtables.h @@ -50,14 +50,16 @@ struct SequenceTable le_uint16 glyphCount; TTGlyphID substituteArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SequenceTable, substituteArray) struct MultipleSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 sequenceCount; Offset sequenceTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(MultipleSubstitutionSubtable, sequenceTableOffsetArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp index a7e655f67f9..f664fe8fbc6 100644 --- a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp @@ -47,8 +47,8 @@ NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor { } -NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : SubtableProcessor(morphSubtableHeader) +NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor(morphSubtableHeader, success) { } @@ -56,26 +56,27 @@ NonContextualGlyphSubstitutionProcessor::~NonContextualGlyphSubstitutionProcesso { } -SubtableProcessor *NonContextualGlyphSubstitutionProcessor::createInstance(const MorphSubtableHeader *morphSubtableHeader) +SubtableProcessor *NonContextualGlyphSubstitutionProcessor::createInstance(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; + LEReferenceTo header(morphSubtableHeader, success); - switch (SWAPW(header->table.format)) - { + if(LE_FAILURE(success)) return NULL; + + switch (SWAPW(header->table.format)) { case ltfSimpleArray: - return new SimpleArrayProcessor(morphSubtableHeader); + return new SimpleArrayProcessor(morphSubtableHeader, success); case ltfSegmentSingle: - return new SegmentSingleProcessor(morphSubtableHeader); + return new SegmentSingleProcessor(morphSubtableHeader, success); case ltfSegmentArray: - return new SegmentArrayProcessor(morphSubtableHeader); + return new SegmentArrayProcessor(morphSubtableHeader, success); case ltfSingleTable: - return new SingleTableProcessor(morphSubtableHeader); + return new SingleTableProcessor(morphSubtableHeader, success); case ltfTrimmedArray: - return new TrimmedArrayProcessor(morphSubtableHeader); + return new TrimmedArrayProcessor(morphSubtableHeader, success); default: return NULL; diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h index e8e05078ab2..9fa70cfe1a8 100644 --- a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h @@ -49,13 +49,13 @@ class LEGlyphStorage; class NonContextualGlyphSubstitutionProcessor : public SubtableProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; - static SubtableProcessor *createInstance(const MorphSubtableHeader *morphSubtableHeader); + static SubtableProcessor *createInstance(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); protected: NonContextualGlyphSubstitutionProcessor(); - NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + NonContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &status); virtual ~NonContextualGlyphSubstitutionProcessor(); diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp index 8c304912400..615633c017a 100644 --- a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp @@ -47,8 +47,9 @@ NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcesso { } -NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : SubtableProcessor2(morphSubtableHeader) +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2( + const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor2(morphSubtableHeader, success) { } @@ -56,26 +57,28 @@ NonContextualGlyphSubstitutionProcessor2::~NonContextualGlyphSubstitutionProcess { } -SubtableProcessor2 *NonContextualGlyphSubstitutionProcessor2::createInstance(const MorphSubtableHeader2 *morphSubtableHeader) +SubtableProcessor2 *NonContextualGlyphSubstitutionProcessor2::createInstance( + const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + const LEReferenceTo header(morphSubtableHeader, success); + if(LE_FAILURE(success)) return NULL; switch (SWAPW(header->table.format)) { case ltfSimpleArray: - return new SimpleArrayProcessor2(morphSubtableHeader); + return new SimpleArrayProcessor2(morphSubtableHeader, success); case ltfSegmentSingle: - return new SegmentSingleProcessor2(morphSubtableHeader); + return new SegmentSingleProcessor2(morphSubtableHeader, success); case ltfSegmentArray: - return new SegmentArrayProcessor2(morphSubtableHeader); + return new SegmentArrayProcessor2(morphSubtableHeader, success); case ltfSingleTable: - return new SingleTableProcessor2(morphSubtableHeader); + return new SingleTableProcessor2(morphSubtableHeader, success); case ltfTrimmedArray: - return new TrimmedArrayProcessor2(morphSubtableHeader); + return new TrimmedArrayProcessor2(morphSubtableHeader, success); default: return NULL; diff --git a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h index 6354bc92069..f2a815037cb 100644 --- a/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h +++ b/jdk/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h @@ -49,13 +49,13 @@ class LEGlyphStorage; class NonContextualGlyphSubstitutionProcessor2 : public SubtableProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; - static SubtableProcessor2 *createInstance(const MorphSubtableHeader2 *morphSubtableHeader); + static SubtableProcessor2 *createInstance(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); protected: NonContextualGlyphSubstitutionProcessor2(); - NonContextualGlyphSubstitutionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + NonContextualGlyphSubstitutionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~NonContextualGlyphSubstitutionProcessor2(); diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp index a561a135182..707fb21eceb 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp @@ -151,25 +151,21 @@ static const FeatureMap featureMap[] = static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures), fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE), - fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) + fGSUBTable(gsubTable), + fGDEFTable(fontInstance, LE_GDEF_TABLE_TAG, success), + fGPOSTable(fontInstance, LE_GPOS_TABLE_TAG, success), fSubstitutionFilter(NULL) { - static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG; - 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; + if (!fGPOSTable.isEmpty()&& !fGPOSTable->coversScript(fGPOSTable, fScriptTag, success)) { + fGPOSTable.clear(); // already loaded } } @@ -252,7 +248,7 @@ void OpenTypeLayoutEngine::reset() OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE), - fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) + fGSUBTable(), fGDEFTable(), fGPOSTable(), fSubstitutionFilter(NULL) { applyTypoFlags(); setScriptAndLanguageTags(); @@ -375,13 +371,13 @@ le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 return 0; } - if (fGSUBTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + if (fGSUBTable.isValid()) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable, fScriptTagV2, fLangSysTag, success)) { + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } else { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } } @@ -402,13 +398,13 @@ le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, l return 0; } - if (fGSUBTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + if (fGSUBTable.isValid()) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable,fScriptTagV2,fLangSysTag,success)) { + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } else { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } } @@ -488,7 +484,7 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 return; } - if (fGPOSTable != NULL) { + if (!fGPOSTable.isEmpty()) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; @@ -511,19 +507,20 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 } #endif - if (fGPOSTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + if (!fGPOSTable.isEmpty()) { + if (fScriptTagV2 != nullScriptTag && + fGPOSTable->coversScriptAndLanguage(fGPOSTable, fScriptTagV2,fLangSysTag,success)) { + fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, + fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } else { - fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, + fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } - } else if ( fTypoFlags & 0x1 ) { - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + } else if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } float xAdjust = 0, yAdjust = 0; diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h index 7a89df46a4a..8ec6d4c774a 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h @@ -35,6 +35,7 @@ #include "LEGlyphFilter.h" #include "LEFontInstance.h" #include "LayoutEngine.h" +#include "LETableReference.h" #include "GlyphSubstitutionTables.h" #include "GlyphDefinitionTables.h" @@ -88,7 +89,7 @@ public: * @internal */ OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known @@ -228,21 +229,21 @@ protected: * * @internal */ - const GlyphSubstitutionTableHeader *fGSUBTable; + LEReferenceTo fGSUBTable; /** * The address of the GDEF table. * * @internal */ - const GlyphDefinitionTableHeader *fGDEFTable; + LEReferenceTo fGDEFTable; /** * The address of the GPOS table. * * @internal */ - const GlyphPositioningTableHeader *fGPOSTable; + LEReferenceTo fGPOSTable; /** * An optional filter used to inhibit substitutions diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeTables.h b/jdk/src/share/native/sun/font/layout/OpenTypeTables.h index c4a4a68b75a..1570071f1f2 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeTables.h +++ b/jdk/src/share/native/sun/font/layout/OpenTypeTables.h @@ -38,6 +38,7 @@ */ #include "LETypes.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -50,7 +51,7 @@ typedef le_uint32 fixed32; #define LE_GLYPH_GROUP_MASK 0x00000001UL typedef le_uint32 FeatureMask; -#define SWAPT(atag) ((LETag) ((atag[0] << 24) + (atag[1] << 16) + (atag[2] << 8) + atag[3])) +#define SWAPT(atag) ((LETag) (((atag[0]) << 24) + ((atag[1]) << 16) + ((atag[2]) << 8) + (atag[3]))) struct TagAndOffsetRecord { diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp b/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp index 3b25aa280c9..f234e9484e2 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp +++ b/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp @@ -76,58 +76,74 @@ le_int8 OpenTypeUtilities::highBit(le_int32 value) return bit; } -Offset OpenTypeUtilities::getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount) + +Offset OpenTypeUtilities::getTagOffset(LETag tag, const LEReferenceToArrayOf &records, LEErrorCode &success) { - le_uint8 bit = highBit(recordCount); - le_int32 power = 1 << bit; - le_int32 extra = recordCount - power; - le_int32 probe = power; - le_int32 index = 0; + if(LE_FAILURE(success)) return 0; - if (SWAPT(records[extra].tag) <= tag) { - index = extra; + le_uint32 recordCount = records.getCount(); + le_uint8 bit = highBit(recordCount); + le_int32 power = 1 << bit; + le_int32 extra = recordCount - power; + le_int32 probe = power; + le_int32 index = 0; + + { + const ATag &aTag = records.getAlias(extra,success)->tag; + if (SWAPT(aTag) <= tag) { + index = extra; } + } - while (probe > (1 << 0)) { - probe >>= 1; + while (probe > (1 << 0) && LE_SUCCESS(success)) { + probe >>= 1; - if (SWAPT(records[index + probe].tag) <= tag) { - index += probe; - } + { + const ATag &aTag = records.getAlias(index+probe,success)->tag; + if (SWAPT(aTag) <= tag) { + index += probe; + } } + } - if (SWAPT(records[index].tag) == tag) { - return SWAPW(records[index].offset); + { + const ATag &aTag = records.getAlias(index,success)->tag; + if (SWAPT(aTag) == tag) { + return SWAPW(records.getAlias(index,success)->offset); } + } - return 0; + return 0; } -le_int32 OpenTypeUtilities::getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount) +le_int32 OpenTypeUtilities::getGlyphRangeIndex(TTGlyphID glyphID, const LEReferenceToArrayOf &records, LEErrorCode &success) { + if(LE_FAILURE(success)) return -1; + + le_uint32 recordCount = records.getCount(); le_uint8 bit = highBit(recordCount); le_int32 power = 1 << bit; le_int32 extra = recordCount - power; le_int32 probe = power; le_int32 range = 0; - if (recordCount == 0) { - return -1; - } + if (recordCount == 0) { + return -1; + } - if (SWAPW(records[extra].firstGlyph) <= glyphID) { + if (SWAPW(records(extra,success).firstGlyph) <= glyphID) { range = extra; } - while (probe > (1 << 0)) { + while (probe > (1 << 0) && LE_SUCCESS(success)) { probe >>= 1; - if (SWAPW(records[range + probe].firstGlyph) <= glyphID) { + if (SWAPW(records(range + probe,success).firstGlyph) <= glyphID) { range += probe; } } - if (SWAPW(records[range].firstGlyph) <= glyphID && SWAPW(records[range].lastGlyph) >= glyphID) { + if (SWAPW(records(range,success).firstGlyph) <= glyphID && SWAPW(records(range,success).lastGlyph) >= glyphID) { return range; } @@ -199,6 +215,38 @@ void OpenTypeUtilities::sort(le_uint16 *array, le_int32 count) } } - - U_NAMESPACE_END + +#if LE_ASSERT_BAD_FONT +#include + +static const char *letagToStr(LETag tag, char *str) { + str[0]= 0xFF & (tag>>24); + str[1]= 0xFF & (tag>>16); + str[2]= 0xFF & (tag>>8); + str[3]= 0xFF & (tag>>0); + str[4]= 0; + return str; +} + +U_CAPI void U_EXPORT2 _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len) { + char tagbuf[5]; + + fprintf(stderr, "%s:%d: LETableReference@0x%p: ", f, l, what); + fprintf(stderr, msg, ptr, len); + fprintf(stderr, "\n"); + + for(int depth=0;depth<10&&(what!=NULL);depth++) { + for(int i=0;iisValid()) { + fprintf(stderr, "(invalid)"); + } + fprintf(stderr, "@%p: tag (%s) font (0x%p), [0x%p+0x%lx]\n", what, letagToStr(what->getTag(), tagbuf), what->getFont(), + what->getAlias(), what->getLength()); + + what = what->getParent(); + } +} +#endif diff --git a/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.h b/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.h index 6f35c29079e..1965a6517ba 100644 --- a/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.h +++ b/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.h @@ -45,8 +45,17 @@ U_NAMESPACE_BEGIN class OpenTypeUtilities /* not : public UObject because all methods are static */ { public: static le_int8 highBit(le_int32 value); - static Offset getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount); - static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount); + static Offset getTagOffset(LETag tag, const LEReferenceToArrayOf &records, LEErrorCode &success); + /** + * @deprecated TODO remove + */ + static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount) { + LEErrorCode success = LE_NO_ERROR; + LETableReference recordRef0((const le_uint8*)records); + LEReferenceToArrayOf recordRef(recordRef0, success, (size_t)0, recordCount); + return getGlyphRangeIndex(glyphID, recordRef, success); + } + static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const LEReferenceToArrayOf &records, LEErrorCode &success); static le_int32 search(le_uint16 value, const le_uint16 array[], le_int32 count); static le_int32 search(le_uint32 value, const le_uint32 array[], le_int32 count); static void sort(le_uint16 *array, le_int32 count); diff --git a/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.cpp b/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.cpp index d5d4f1bf15b..f46c8f1028b 100644 --- a/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.cpp @@ -41,7 +41,7 @@ U_NAMESPACE_BEGIN -le_uint32 PairPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningSubtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { switch(SWAPW(subtableFormat)) { @@ -50,27 +50,32 @@ le_uint32 PairPositioningSubtable::process(GlyphIterator *glyphIterator, const L case 1: { - const PairPositioningFormat1Subtable *subtable = (const PairPositioningFormat1Subtable *) this; + const LEReferenceTo subtable(base, success, (const PairPositioningFormat1Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + if(LE_SUCCESS(success)) + return subtable->process(subtable, glyphIterator, fontInstance, success); + else + return 0; } case 2: { - const PairPositioningFormat2Subtable *subtable = (const PairPositioningFormat2Subtable *) this; + const LEReferenceTo subtable(base, success, (const PairPositioningFormat2Subtable *) this); - return subtable->process(glyphIterator, fontInstance); - } - - default: + if(LE_SUCCESS(success)) + return subtable->process(subtable, glyphIterator, fontInstance, success); + else return 0; } + default: + return 0; + } } -le_uint32 PairPositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningFormat1Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(firstGlyph); + le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); GlyphIterator tempIterator(*glyphIterator); if (coverageIndex >= 0 && glyphIterator->next()) { @@ -110,10 +115,10 @@ le_uint32 PairPositioningFormat1Subtable::process(GlyphIterator *glyphIterator, return 0; } -le_uint32 PairPositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(firstGlyph); + le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); GlyphIterator tempIterator(*glyphIterator); if (coverageIndex >= 0 && glyphIterator->next()) { diff --git a/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.h b/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.h index 10a7a0996df..0c66ce61dc5 100644 --- a/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.h +++ b/jdk/src/share/native/sun/font/layout/PairPositioningSubtables.h @@ -59,13 +59,14 @@ struct PairSetTable le_uint16 pairValueCount; PairValueRecord pairValueRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(PairSetTable, pairValueRecordArray) struct PairPositioningSubtable : GlyphPositioningSubtable { ValueFormat valueFormat1; ValueFormat valueFormat2; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct PairPositioningFormat1Subtable : PairPositioningSubtable @@ -73,12 +74,13 @@ struct PairPositioningFormat1Subtable : PairPositioningSubtable le_uint16 pairSetCount; Offset pairSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; private: const PairValueRecord *findPairValueRecord(TTGlyphID glyphID, const PairValueRecord *records, le_uint16 recordCount, le_uint16 recordSize) const; }; +LE_VAR_ARRAY(PairPositioningFormat1Subtable, pairSetTableOffsetArray) // NOTE: ValueRecord has a variable size struct Class2Record @@ -91,6 +93,7 @@ struct Class1Record { Class2Record class2RecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Class1Record, class2RecordArray) struct PairPositioningFormat2Subtable : PairPositioningSubtable { @@ -100,8 +103,9 @@ struct PairPositioningFormat2Subtable : PairPositioningSubtable le_uint16 class2Count; Class1Record class1RecordArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(PairPositioningFormat2Subtable, class1RecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.cpp b/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.cpp index bb8b65ba371..dc16ed288de 100644 --- a/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.cpp +++ b/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.cpp @@ -38,29 +38,33 @@ U_NAMESPACE_BEGIN -const LangSysTable *ScriptTable::findLanguage(LETag languageTag, le_bool exactMatch) const +LEReferenceTo ScriptTable::findLanguage(const LETableReference& base, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { le_uint16 count = SWAPW(langSysCount); Offset langSysTableOffset = exactMatch? 0 : SWAPW(defaultLangSysTableOffset); if (count > 0) { - Offset foundOffset = - OpenTypeUtilities::getTagOffset(languageTag, langSysRecordArray, count); + LEReferenceToArrayOf langSysRecords(base, success, langSysRecordArray, count); + Offset foundOffset = + OpenTypeUtilities::getTagOffset(languageTag, langSysRecords, success); - if (foundOffset != 0) { - langSysTableOffset = foundOffset; - } + if (foundOffset != 0 && LE_SUCCESS(success)) { + langSysTableOffset = foundOffset; + } } if (langSysTableOffset != 0) { - return (const LangSysTable *) ((char *)this + langSysTableOffset); + return LEReferenceTo(base, success, langSysTableOffset); } - return NULL; + return LEReferenceTo(); } -const ScriptTable *ScriptListTable::findScript(LETag scriptTag) const +LEReferenceTo ScriptListTable::findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const { + if (LE_FAILURE(success) ) { + return LEReferenceTo(); // get out + } /* * There are some fonts that have a large, bogus value for scriptCount. To try * and protect against this, we use the offset in the first scriptRecord, @@ -74,38 +78,53 @@ const ScriptTable *ScriptListTable::findScript(LETag scriptTag) const * to be unsorted. */ le_uint16 count = SWAPW(scriptCount); + + if (count == 0) { + return LEReferenceTo(); // no items, no search + } + + // attempt to construct a ref with at least one element + LEReferenceToArrayOf oneElementTable(base, success, &scriptRecordArray[0], 1); + + if( LE_FAILURE(success) ) { + return LEReferenceTo(); // couldn't even read the first record - bad font. + } + le_uint16 limit = ((SWAPW(scriptRecordArray[0].offset) - sizeof(ScriptListTable)) / sizeof(scriptRecordArray)) + ANY_NUMBER; Offset scriptTableOffset = 0; + if (count > limit) { // the scriptCount value is bogus; do a linear search // because limit may still be too large. - for(le_int32 s = 0; s < limit; s += 1) { - if (SWAPT(scriptRecordArray[s].tag) == scriptTag) { - scriptTableOffset = SWAPW(scriptRecordArray[s].offset); - break; - } + LEReferenceToArrayOf scriptRecordArrayRef(base, success, &scriptRecordArray[0], limit); + for(le_int32 s = 0; (s < limit)&&LE_SUCCESS(success); s += 1) { + if (SWAPT(scriptRecordArrayRef(s,success).tag) == scriptTag) { + scriptTableOffset = SWAPW(scriptRecordArrayRef(s,success).offset); + break; + } } } else { - scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArray, count); + LEReferenceToArrayOf scriptRecordArrayRef(base, success, &scriptRecordArray[0], count); + scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArrayRef, success); // TODO } if (scriptTableOffset != 0) { - return (const ScriptTable *) ((char *)this + scriptTableOffset); + return LEReferenceTo(base, success, scriptTableOffset); } - return NULL; + return LEReferenceTo(); } -const LangSysTable *ScriptListTable::findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const +LEReferenceTo ScriptListTable::findLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { - const ScriptTable *scriptTable = findScript(scriptTag); + const LEReferenceTo scriptTable = findScript(base, scriptTag, success); - if (scriptTable == 0) { - return NULL; - } + if (scriptTable.isEmpty()) { + return LEReferenceTo(); + } - return scriptTable->findLanguage(languageTag, exactMatch); + return scriptTable->findLanguage(scriptTable, languageTag, success, exactMatch).reparent(base); } U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.h b/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.h index fe89657f66b..21d5e39df9b 100644 --- a/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.h +++ b/jdk/src/share/native/sun/font/layout/ScriptAndLanguage.h @@ -51,6 +51,7 @@ struct LangSysTable le_uint16 featureCount; le_uint16 featureIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LangSysTable, featureIndexArray) struct ScriptTable { @@ -58,8 +59,9 @@ struct ScriptTable le_uint16 langSysCount; LangSysRecord langSysRecordArray[ANY_NUMBER]; - const LangSysTable *findLanguage(LETag languageTag, le_bool exactMatch = FALSE) const; + LEReferenceTo findLanguage(const LETableReference &base, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; +LE_VAR_ARRAY(ScriptTable, langSysRecordArray) typedef TagAndOffsetRecord ScriptRecord; @@ -68,9 +70,10 @@ struct ScriptListTable le_uint16 scriptCount; ScriptRecord scriptRecordArray[ANY_NUMBER]; - const ScriptTable *findScript(LETag scriptTag) const; - const LangSysTable *findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const; + LEReferenceTo findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const; + LEReferenceTo findLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; +LE_VAR_ARRAY(ScriptListTable, scriptRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp index d9064a11c12..ecc63cb67be 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp @@ -46,19 +46,18 @@ SegmentArrayProcessor::SegmentArrayProcessor() { } -SegmentArrayProcessor::SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SegmentArrayProcessor::SegmentArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table; + LEReferenceTo header(morphSubtableHeader, success); + segmentArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, (const SegmentArrayLookupTable*)&header->table); } SegmentArrayProcessor::~SegmentArrayProcessor() { } -void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage) +void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentArrayLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); @@ -66,17 +65,16 @@ void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage) for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segmentArrayLookupTable, segments, thisGlyph, success); if (lookupSegment != NULL) { TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); le_int16 offset = SWAPW(lookupSegment->value); if (offset != 0) { - TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); - TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); - - glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + LEReferenceToArrayOf glyphArray(subtableHeader, success, offset, LE_UNBOUNDED_ARRAY); + TTGlyphID newGlyph = SWAPW(glyphArray(LE_GET_GLYPH(thisGlyph) - firstGlyph, success)); + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } } diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.h b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.h index 488cceaeabb..4f2dbff70d4 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.h +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SegmentArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + SegmentArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentArrayProcessor(); @@ -74,7 +74,7 @@ private: SegmentArrayProcessor(); protected: - const SegmentArrayLookupTable *segmentArrayLookupTable; + LEReferenceTo segmentArrayLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp index e50fdf0604e..0a052217979 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp @@ -46,19 +46,18 @@ SegmentArrayProcessor2::SegmentArrayProcessor2() { } -SegmentArrayProcessor2::SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +SegmentArrayProcessor2::SegmentArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; - - segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table; + const LEReferenceTo header(morphSubtableHeader, success); + segmentArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, &header->table); // don't parent to 'header' as it is on the stack } SegmentArrayProcessor2::~SegmentArrayProcessor2() { } -void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage) +void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentArrayLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); @@ -66,14 +65,14 @@ void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage) for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segmentArrayLookupTable, segments, thisGlyph, success); if (lookupSegment != NULL) { TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); le_int16 offset = SWAPW(lookupSegment->value); if (offset != 0) { - TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); + TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader.getAliasTODO() + offset); TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); diff --git a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h index 71999b76a8a..8a4971d040d 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor2.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SegmentArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + SegmentArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentArrayProcessor2(); @@ -74,7 +74,7 @@ private: SegmentArrayProcessor2(); protected: - const SegmentArrayLookupTable *segmentArrayLookupTable; + LEReferenceTo segmentArrayLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp index 4f89a7e1f16..42866a5473d 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp @@ -46,29 +46,28 @@ SegmentSingleProcessor::SegmentSingleProcessor() { } -SegmentSingleProcessor::SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SegmentSingleProcessor::SegmentSingleProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table; + LEReferenceTo header(morphSubtableHeader, success); + segmentSingleLookupTable = LEReferenceTo(morphSubtableHeader, success, (const SegmentSingleLookupTable*)&header->table); } SegmentSingleProcessor::~SegmentSingleProcessor() { } -void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage) +void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentSingleLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; - for (glyph = 0; glyph < glyphCount; glyph += 1) { + for (glyph = 0; glyph < glyphCount && LE_SUCCESS(success); glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segmentSingleLookupTable, segments, thisGlyph, success); - if (lookupSegment != NULL) { + if (lookupSegment != NULL && LE_SUCCESS(success)) { TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.h b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.h index 99fea88f703..bb6df57130e 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.h +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SegmentSingleProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader); + SegmentSingleProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentSingleProcessor(); @@ -74,7 +74,7 @@ private: SegmentSingleProcessor(); protected: - const SegmentSingleLookupTable *segmentSingleLookupTable; + LEReferenceTo segmentSingleLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp index e571cce9b87..e1857cd4c5e 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp @@ -46,19 +46,19 @@ SegmentSingleProcessor2::SegmentSingleProcessor2() { } -SegmentSingleProcessor2::SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +SegmentSingleProcessor2::SegmentSingleProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + const LEReferenceTo header(morphSubtableHeader, success); - segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table; + segmentSingleLookupTable = LEReferenceTo(morphSubtableHeader, success, &header->table); } SegmentSingleProcessor2::~SegmentSingleProcessor2() { } -void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage) +void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentSingleLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); @@ -66,9 +66,9 @@ void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage) for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segmentSingleLookupTable, segments, thisGlyph, success); - if (lookupSegment != NULL) { + if (lookupSegment != NULL && LE_SUCCESS(success)) { TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); diff --git a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h index 00def985133..b104e95b568 100644 --- a/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/SegmentSingleProcessor2.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SegmentSingleProcessor2 : public NonContextualGlyphSubstitutionProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentSingleProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + SegmentSingleProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentSingleProcessor2(); @@ -74,7 +74,7 @@ private: SegmentSingleProcessor2(); protected: - const SegmentSingleLookupTable *segmentSingleLookupTable; + LEReferenceTo segmentSingleLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/ShapingTypeData.cpp b/jdk/src/share/native/sun/font/layout/ShapingTypeData.cpp index 06529907ba9..bfca62ca71b 100644 --- a/jdk/src/share/native/sun/font/layout/ShapingTypeData.cpp +++ b/jdk/src/share/native/sun/font/layout/ShapingTypeData.cpp @@ -122,4 +122,6 @@ const le_uint8 ArabicShaping::shapingTypeTable[] = { 0x00, 0x05, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x05, 0xFF, 0xF9, 0xFF, 0xFB, 0x00, 0x05 }; +const size_t ArabicShaping::shapingTypeTableLen = sizeof(shapingTypeTable)/sizeof(shapingTypeTable[0]); + U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp index c0db2ec3fbe..1aa71b002b6 100644 --- a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp @@ -46,29 +46,29 @@ SimpleArrayProcessor::SimpleArrayProcessor() { } -SimpleArrayProcessor::SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SimpleArrayProcessor::SimpleArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table; + LEReferenceTo header(morphSubtableHeader, success); + simpleArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, (const SimpleArrayLookupTable*)&header->table); } SimpleArrayProcessor::~SimpleArrayProcessor() { } -void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage) +void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; - for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEReferenceToArrayOf valueArray(simpleArrayLookupTable, success, (const LookupValue*)&simpleArrayLookupTable->valueArray, LE_UNBOUNDED_ARRAY); + + for (glyph = 0; LE_SUCCESS(success) && (glyph < glyphCount); glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { - TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); - - glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + TTGlyphID newGlyph = SWAPW(valueArray.getObject(LE_GET_GLYPH(thisGlyph),success)); + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } } diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.h b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.h index 8cb8e710497..ed4aabc4fcf 100644 --- a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.h +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SimpleArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + SimpleArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SimpleArrayProcessor(); @@ -74,7 +74,7 @@ private: SimpleArrayProcessor(); protected: - const SimpleArrayLookupTable *simpleArrayLookupTable; + LEReferenceTo simpleArrayLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp index fa15b71215e..292c0a22e55 100644 --- a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp @@ -46,27 +46,29 @@ SimpleArrayProcessor2::SimpleArrayProcessor2() { } -SimpleArrayProcessor2::SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +SimpleArrayProcessor2::SimpleArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + const LEReferenceTo header(morphSubtableHeader, success); - simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table; + simpleArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, &header->table); + valueArray = LEReferenceToArrayOf(morphSubtableHeader, success, &simpleArrayLookupTable->valueArray[0], LE_UNBOUNDED_ARRAY); } SimpleArrayProcessor2::~SimpleArrayProcessor2() { } -void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage) +void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if (LE_FAILURE(success)) return; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { - TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); + TTGlyphID newGlyph = SWAPW(valueArray(LE_GET_GLYPH(thisGlyph),success)); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } diff --git a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h index 94bbbad858c..8855bdfa74f 100644 --- a/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/SimpleArrayProcessor2.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SimpleArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SimpleArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + SimpleArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SimpleArrayProcessor2(); @@ -74,7 +74,8 @@ private: SimpleArrayProcessor2(); protected: - const SimpleArrayLookupTable *simpleArrayLookupTable; + LEReferenceTo simpleArrayLookupTable; + LEReferenceToArrayOf valueArray; }; diff --git a/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp b/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp index 5fc0b1dfb78..1e2d257a6f8 100644 --- a/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp @@ -40,7 +40,7 @@ U_NAMESPACE_BEGIN -le_uint32 SinglePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningSubtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { switch(SWAPW(subtableFormat)) { @@ -49,16 +49,16 @@ le_uint32 SinglePositioningSubtable::process(GlyphIterator *glyphIterator, const case 1: { - const SinglePositioningFormat1Subtable *subtable = (const SinglePositioningFormat1Subtable *) this; + const LEReferenceTo subtable(base, success, (const SinglePositioningFormat1Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + return subtable->process(subtable, glyphIterator, fontInstance, success); } case 2: { - const SinglePositioningFormat2Subtable *subtable = (const SinglePositioningFormat2Subtable *) this; + const LEReferenceTo subtable(base, success, (const SinglePositioningFormat2Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + return subtable->process(subtable, glyphIterator, fontInstance, success); } default: @@ -66,10 +66,10 @@ le_uint32 SinglePositioningSubtable::process(GlyphIterator *glyphIterator, const } } -le_uint32 SinglePositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningFormat1Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { valueRecord.adjustPosition(SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance); @@ -80,10 +80,10 @@ le_uint32 SinglePositioningFormat1Subtable::process(GlyphIterator *glyphIterator return 0; } -le_uint32 SinglePositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningFormat2Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int16 coverageIndex = (le_int16) getGlyphCoverage(glyph); + le_int16 coverageIndex = (le_int16) getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { valueRecordArray[0].adjustPosition(coverageIndex, SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance); diff --git a/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.h b/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.h index 7dc2c1d9d12..27205ec9b7a 100644 --- a/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.h +++ b/jdk/src/share/native/sun/font/layout/SinglePositioningSubtables.h @@ -48,7 +48,7 @@ U_NAMESPACE_BEGIN struct SinglePositioningSubtable : GlyphPositioningSubtable { - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct SinglePositioningFormat1Subtable : SinglePositioningSubtable @@ -56,7 +56,7 @@ struct SinglePositioningFormat1Subtable : SinglePositioningSubtable ValueFormat valueFormat; ValueRecord valueRecord; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct SinglePositioningFormat2Subtable : SinglePositioningSubtable @@ -65,8 +65,9 @@ struct SinglePositioningFormat2Subtable : SinglePositioningSubtable le_uint16 valueCount; ValueRecord valueRecordArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(SinglePositioningFormat2Subtable, valueRecordArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp b/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp index 9eb884ed810..681958cf5ea 100644 --- a/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp +++ b/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp @@ -39,7 +39,7 @@ U_NAMESPACE_BEGIN -le_uint32 SingleSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionSubtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { switch(SWAPW(subtableFormat)) { @@ -48,16 +48,16 @@ le_uint32 SingleSubstitutionSubtable::process(GlyphIterator *glyphIterator, cons case 1: { - const SingleSubstitutionFormat1Subtable *subtable = (const SingleSubstitutionFormat1Subtable *) this; + const LEReferenceTo subtable(base, success, (const SingleSubstitutionFormat1Subtable *) this); - return subtable->process(glyphIterator, filter); + return subtable->process(subtable, glyphIterator, success, filter); } case 2: { - const SingleSubstitutionFormat2Subtable *subtable = (const SingleSubstitutionFormat2Subtable *) this; + const LEReferenceTo subtable(base, success, (const SingleSubstitutionFormat2Subtable *) this); - return subtable->process(glyphIterator, filter); + return subtable->process(subtable, glyphIterator, success, filter); } default: @@ -65,10 +65,10 @@ le_uint32 SingleSubstitutionSubtable::process(GlyphIterator *glyphIterator, cons } } -le_uint32 SingleSubstitutionFormat1Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionFormat1Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { TTGlyphID substitute = ((TTGlyphID) LE_GET_GLYPH(glyph)) + SWAPW(deltaGlyphID); @@ -83,10 +83,10 @@ le_uint32 SingleSubstitutionFormat1Subtable::process(GlyphIterator *glyphIterato return 0; } -le_uint32 SingleSubstitutionFormat2Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionFormat2Subtable::process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { TTGlyphID substitute = SWAPW(substituteArray[coverageIndex]); diff --git a/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h b/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h index 5115e9c2a29..e1aa84fd027 100644 --- a/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h +++ b/jdk/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h @@ -47,14 +47,14 @@ U_NAMESPACE_BEGIN struct SingleSubstitutionSubtable : GlyphSubstitutionSubtable { - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; struct SingleSubstitutionFormat1Subtable : SingleSubstitutionSubtable { le_int16 deltaGlyphID; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; struct SingleSubstitutionFormat2Subtable : SingleSubstitutionSubtable @@ -62,8 +62,9 @@ struct SingleSubstitutionFormat2Subtable : SingleSubstitutionSubtable le_uint16 glyphCount; TTGlyphID substituteArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(SingleSubstitutionFormat2Subtable, substituteArray) U_NAMESPACE_END #endif diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor.cpp b/jdk/src/share/native/sun/font/layout/SingleTableProcessor.cpp index 49fdd1d3bd9..dd44276f4a4 100644 --- a/jdk/src/share/native/sun/font/layout/SingleTableProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor.cpp @@ -46,26 +46,25 @@ SingleTableProcessor::SingleTableProcessor() { } -SingleTableProcessor::SingleTableProcessor(const MorphSubtableHeader *moprhSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(moprhSubtableHeader) +SingleTableProcessor::SingleTableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) moprhSubtableHeader; - - singleTableLookupTable = (const SingleTableLookupTable *) &header->table; + LEReferenceTo header(morphSubtableHeader, success); + singleTableLookupTable = LEReferenceTo(morphSubtableHeader, success, (const SingleTableLookupTable*)&header->table); } SingleTableProcessor::~SingleTableProcessor() { } -void SingleTableProcessor::process(LEGlyphStorage &glyphStorage) +void SingleTableProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); for (glyph = 0; glyph < glyphCount; glyph += 1) { - const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(singleTableLookupTable, entries, glyphStorage[glyph], success); if (lookupSingle != NULL) { glyphStorage[glyph] = SWAPW(lookupSingle->value); diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor.h b/jdk/src/share/native/sun/font/layout/SingleTableProcessor.h index 19d8b0ba851..2d3595eb335 100644 --- a/jdk/src/share/native/sun/font/layout/SingleTableProcessor.h +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SingleTableProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SingleTableProcessor(const MorphSubtableHeader *morphSubtableHeader); + SingleTableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SingleTableProcessor(); @@ -74,7 +74,7 @@ private: SingleTableProcessor(); protected: - const SingleTableLookupTable *singleTableLookupTable; + LEReferenceTo singleTableLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp index dc0b8fc53c4..1e21ab5be26 100644 --- a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.cpp @@ -46,26 +46,27 @@ SingleTableProcessor2::SingleTableProcessor2() { } -SingleTableProcessor2::SingleTableProcessor2(const MorphSubtableHeader2 *moprhSubtableHeader) - : NonContextualGlyphSubstitutionProcessor2(moprhSubtableHeader) +SingleTableProcessor2::SingleTableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) moprhSubtableHeader; + const LEReferenceTo header(morphSubtableHeader, success); - singleTableLookupTable = (const SingleTableLookupTable *) &header->table; + singleTableLookupTable = LEReferenceTo(morphSubtableHeader, success, &header->table); } SingleTableProcessor2::~SingleTableProcessor2() { } -void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage) +void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if(LE_FAILURE(success)) return; const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); for (glyph = 0; glyph < glyphCount; glyph += 1) { - const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(singleTableLookupTable, entries, glyphStorage[glyph], success); if (lookupSingle != NULL) { glyphStorage[glyph] = SWAPW(lookupSingle->value); diff --git a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h index e52d819a4b0..3f2d5009ea7 100644 --- a/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/SingleTableProcessor2.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class SingleTableProcessor2 : public NonContextualGlyphSubstitutionProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SingleTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + SingleTableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~SingleTableProcessor2(); @@ -74,7 +74,7 @@ private: SingleTableProcessor2(); protected: - const SingleTableLookupTable *singleTableLookupTable; + LEReferenceTo singleTableLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp b/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp index 3146cc53210..0f135c70b2b 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp @@ -44,17 +44,18 @@ StateTableProcessor::StateTableProcessor() { } -StateTableProcessor::StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader) - : SubtableProcessor(morphSubtableHeader) +StateTableProcessor::StateTableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor(morphSubtableHeader, success), stateTableHeader(morphSubtableHeader, success), + stHeader(stateTableHeader, success, (const StateTableHeader*)&stateTableHeader->stHeader) { - stateTableHeader = (const MorphStateTableHeader *) morphSubtableHeader; - + if(LE_FAILURE(success)) return; stateSize = SWAPW(stateTableHeader->stHeader.stateSize); classTableOffset = SWAPW(stateTableHeader->stHeader.classTableOffset); stateArrayOffset = SWAPW(stateTableHeader->stHeader.stateArrayOffset); entryTableOffset = SWAPW(stateTableHeader->stHeader.entryTableOffset); - classTable = (const ClassTable *) ((char *) &stateTableHeader->stHeader + classTableOffset); + classTable = LEReferenceTo(stateTableHeader, success, ((char *) &stateTableHeader->stHeader + classTableOffset)); + if(LE_FAILURE(success)) return; firstGlyph = SWAPW(classTable->firstGlyph); lastGlyph = firstGlyph + SWAPW(classTable->nGlyphs); } @@ -63,9 +64,9 @@ StateTableProcessor::~StateTableProcessor() { } -void StateTableProcessor::process(LEGlyphStorage &glyphStorage) +void StateTableProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { - + if (LE_FAILURE(success)) return; LE_STATE_PATIENCE_INIT(); // Start at state 0 @@ -94,8 +95,8 @@ void StateTableProcessor::process(LEGlyphStorage &glyphStorage) } } - const EntryTableIndex *stateArray = (const EntryTableIndex *) ((char *) &stateTableHeader->stHeader + currentState); - EntryTableIndex entryTableIndex = stateArray[(le_uint8)classCode]; + LEReferenceToArrayOf stateArray(stHeader, success, currentState, LE_UNBOUNDED_ARRAY); + EntryTableIndex entryTableIndex = stateArray.getObject((le_uint8)classCode, success); LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); LE_STATE_PATIENCE_INCR(currGlyph); diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor.h b/jdk/src/share/native/sun/font/layout/StateTableProcessor.h index 43f75776c0a..2e8d7f606b5 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor.h +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor.h @@ -49,7 +49,7 @@ class LEGlyphStorage; class StateTableProcessor : public SubtableProcessor { public: - void process(LEGlyphStorage &glyphStorage); + void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); virtual void beginStateTable() = 0; @@ -58,7 +58,7 @@ public: virtual void endStateTable() = 0; protected: - StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader); + StateTableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~StateTableProcessor(); StateTableProcessor(); @@ -68,11 +68,12 @@ protected: ByteOffset stateArrayOffset; ByteOffset entryTableOffset; - const ClassTable *classTable; + LEReferenceTo classTable; TTGlyphID firstGlyph; TTGlyphID lastGlyph; - const MorphStateTableHeader *stateTableHeader; + LEReferenceTo stateTableHeader; + LEReferenceTo stHeader; // for convenience private: StateTableProcessor(const StateTableProcessor &other); // forbid copying of this class diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp index 5bd9c253012..e00a2d09d2e 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.cpp @@ -45,27 +45,33 @@ StateTableProcessor2::StateTableProcessor2() { } -StateTableProcessor2::StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : SubtableProcessor2(morphSubtableHeader) +StateTableProcessor2::StateTableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor2(morphSubtableHeader, success), stateTableHeader(morphSubtableHeader, success), + stHeader(stateTableHeader, success, (const StateTableHeader2*)&stateTableHeader->stHeader), + nClasses(0), classTableOffset(0), stateArrayOffset(0), entryTableOffset(0), classTable(), format(0), + stateArray() { - stateTableHeader = (const MorphStateTableHeader2 *) morphSubtableHeader; - nClasses = SWAPL(stateTableHeader->stHeader.nClasses); - classTableOffset = SWAPL(stateTableHeader->stHeader.classTableOffset); - stateArrayOffset = SWAPL(stateTableHeader->stHeader.stateArrayOffset); - entryTableOffset = SWAPL(stateTableHeader->stHeader.entryTableOffset); + if (LE_FAILURE(success)) { + return; + } + nClasses = SWAPL(stHeader->nClasses); + classTableOffset = SWAPL(stHeader->classTableOffset); + stateArrayOffset = SWAPL(stHeader->stateArrayOffset); + entryTableOffset = SWAPL(stHeader->entryTableOffset); - classTable = (LookupTable *) ((char *) &stateTableHeader->stHeader + classTableOffset); - format = SWAPW(classTable->format); + classTable = LEReferenceTo(stHeader, success, classTableOffset); + format = SWAPW(classTable->format); - stateArray = (const EntryTableIndex2 *) ((char *) &stateTableHeader->stHeader + stateArrayOffset); + stateArray = LEReferenceToArrayOf(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY); } StateTableProcessor2::~StateTableProcessor2() { } -void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) +void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if (LE_FAILURE(success)) return; // Start at state 0 // XXX: How do we know when to start at state 1? le_uint16 currentState = 0; @@ -85,9 +91,11 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) switch (format) { case ltfSimpleArray: { #ifdef TEST_FORMAT - SimpleArrayLookupTable *lookupTable0 = (SimpleArrayLookupTable *) classTable; + LEReferenceTo lookupTable0(classTable, success); + if(LE_FAILURE(success)) break; while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { - if(LE_STATE_PATIENCE_DECR()) { + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") break; // patience exceeded. } @@ -105,7 +113,7 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) classCode = SWAPW(lookupTable0->valueArray[gid]); } } - EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset LE_STATE_PATIENCE_INCR(currGlyph); @@ -114,10 +122,12 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) break; } case ltfSegmentSingle: { - SegmentSingleLookupTable *lookupTable2 = (SegmentSingleLookupTable *) classTable; + LEReferenceTo lookupTable2(classTable, success); + if(LE_FAILURE(success)) break; while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { - if(LE_STATE_PATIENCE_DECR()) { - LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") break; // patience exceeded. } LookupValue classCode = classCodeOOB; @@ -131,15 +141,16 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) if (glyphCode == 0xFFFF) { classCode = classCodeDEL; } else { - const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); - if (segment != NULL) { + const LookupSegment *segment = + lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success); + if (segment != NULL && LE_SUCCESS(success)) { classCode = SWAPW(segment->value); } } } - EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success)); LE_STATE_PATIENCE_CURR(le_int32, currGlyph); - currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); LE_STATE_PATIENCE_INCR(currGlyph); } break; @@ -149,9 +160,10 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) break; } case ltfSingleTable: { - SingleTableLookupTable *lookupTable6 = (SingleTableLookupTable *) classTable; + LEReferenceTo lookupTable6(classTable, success); while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { - if(LE_STATE_PATIENCE_DECR()) { + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") break; // patience exceeded. } @@ -170,21 +182,22 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) if (glyphCode == 0xFFFF) { classCode = classCodeDEL; } else { - const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success); if (segment != NULL) { classCode = SWAPW(segment->value); } } } - EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); LE_STATE_PATIENCE_CURR(le_int32, currGlyph); - currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); LE_STATE_PATIENCE_INCR(currGlyph); } break; } case ltfTrimmedArray: { - TrimmedArrayLookupTable *lookupTable8 = (TrimmedArrayLookupTable *) classTable; + LEReferenceTo lookupTable8(classTable, success); + if (LE_FAILURE(success)) break; TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); @@ -206,9 +219,9 @@ void StateTableProcessor2::process(LEGlyphStorage &glyphStorage) classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); } } - EntryTableIndex2 entryTableIndex = SWAPW(stateArray[classCode + currentState * nClasses]); + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); LE_STATE_PATIENCE_CURR(le_int32, currGlyph); - currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); LE_STATE_PATIENCE_INCR(currGlyph); } break; diff --git a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h index 5b5c6c18baf..db5056c94bb 100644 --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor2.h @@ -50,16 +50,16 @@ class LEGlyphStorage; class StateTableProcessor2 : public SubtableProcessor2 { public: - void process(LEGlyphStorage &glyphStorage); + void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); virtual void beginStateTable() = 0; - virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) = 0; + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success) = 0; virtual void endStateTable() = 0; protected: - StateTableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + StateTableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~StateTableProcessor2(); StateTableProcessor2(); @@ -71,9 +71,10 @@ protected: le_uint32 stateArrayOffset; le_uint32 entryTableOffset; - const LookupTable *classTable; - const EntryTableIndex2 *stateArray; - const MorphStateTableHeader2 *stateTableHeader; + LEReferenceTo classTable; + LEReferenceToArrayOf stateArray; + LEReferenceTo stateTableHeader; + LEReferenceTo stHeader; // for convenience private: StateTableProcessor2(const StateTableProcessor2 &other); // forbid copying of this class diff --git a/jdk/src/share/native/sun/font/layout/StateTables.h b/jdk/src/share/native/sun/font/layout/StateTables.h index 6c6fdced933..9ba6da51295 100644 --- a/jdk/src/share/native/sun/font/layout/StateTables.h +++ b/jdk/src/share/native/sun/font/layout/StateTables.h @@ -111,6 +111,7 @@ struct ClassTable le_uint16 nGlyphs; ClassCode classArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ClassTable, classArray) enum StateNumber { diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor.cpp b/jdk/src/share/native/sun/font/layout/SubtableProcessor.cpp index 1f46bf03b98..3de2856ba93 100644 --- a/jdk/src/share/native/sun/font/layout/SubtableProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor.cpp @@ -40,10 +40,10 @@ SubtableProcessor::SubtableProcessor() { } -SubtableProcessor::SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader) +SubtableProcessor::SubtableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : length(0), coverage(0), subtableFeatures(0L), subtableHeader(morphSubtableHeader) { - subtableHeader = morphSubtableHeader; - + if(LE_FAILURE(success)) return; length = SWAPW(subtableHeader->length); coverage = SWAPW(subtableHeader->coverage); subtableFeatures = SWAPL(subtableHeader->subtableFeatures); diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor.h b/jdk/src/share/native/sun/font/layout/SubtableProcessor.h index 190f7d96d10..a2d6b276730 100644 --- a/jdk/src/share/native/sun/font/layout/SubtableProcessor.h +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor.h @@ -46,11 +46,11 @@ class LEGlyphStorage; class SubtableProcessor : public UMemory { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; virtual ~SubtableProcessor(); protected: - SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader); + SubtableProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); SubtableProcessor(); @@ -58,7 +58,7 @@ protected: SubtableCoverage coverage; FeatureFlags subtableFeatures; - const MorphSubtableHeader *subtableHeader; + const LEReferenceTo subtableHeader; private: diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp index 30d1426679c..d7949bc9467 100644 --- a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.cpp @@ -40,13 +40,14 @@ SubtableProcessor2::SubtableProcessor2() { } -SubtableProcessor2::SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) +SubtableProcessor2::SubtableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : subtableHeader(morphSubtableHeader, success), length(0), coverage(0), subtableFeatures(0L) { - subtableHeader = morphSubtableHeader; + if(LE_FAILURE(success)) return; - length = SWAPL(subtableHeader->length); - coverage = SWAPL(subtableHeader->coverage); - subtableFeatures = SWAPL(subtableHeader->subtableFeatures); + length = SWAPL(subtableHeader->length); + coverage = SWAPL(subtableHeader->coverage); + subtableFeatures = SWAPL(subtableHeader->subtableFeatures); } SubtableProcessor2::~SubtableProcessor2() diff --git a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h index 13af854666a..42ef68b592b 100644 --- a/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/SubtableProcessor2.h @@ -46,11 +46,11 @@ class LEGlyphStorage; class SubtableProcessor2 : public UMemory { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; virtual ~SubtableProcessor2(); protected: - SubtableProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + SubtableProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); SubtableProcessor2(); @@ -58,7 +58,7 @@ protected: SubtableCoverage2 coverage; FeatureFlags subtableFeatures; - const MorphSubtableHeader2 *subtableHeader; + const LEReferenceTo subtableHeader; private: diff --git a/jdk/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp index 65177a6e94c..3422bb27089 100644 --- a/jdk/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp @@ -134,11 +134,10 @@ void ThaiLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 of return; } - if (fTypoFlags & 0x1) { /* kerning enabled */ - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } // default is no adjustments diff --git a/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp index 9f706548aae..b5b67e77310 100644 --- a/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp @@ -49,7 +49,7 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TibetanOpenTypeLayoutEngine) TibetanOpenTypeLayoutEngine::TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = TibetanReordering::getFeatureMap(fFeatureMapCount); diff --git a/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.h b/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.h index c40dcc3343f..834979c3e4c 100644 --- a/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.h +++ b/jdk/src/share/native/sun/font/layout/TibetanLayoutEngine.h @@ -83,7 +83,7 @@ public: * @internal */ TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp index b460a612e82..3f88981ad98 100644 --- a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp @@ -46,22 +46,28 @@ TrimmedArrayProcessor::TrimmedArrayProcessor() { } -TrimmedArrayProcessor::TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +TrimmedArrayProcessor::TrimmedArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success), firstGlyph(0), lastGlyph(0) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; + LEReferenceTo header(morphSubtableHeader, success); - trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table; - firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); - lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); + if(LE_FAILURE(success)) return; + + trimmedArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, (const TrimmedArrayLookupTable*)&header->table); + + if(LE_FAILURE(success)) return; + + firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); + lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); } TrimmedArrayProcessor::~TrimmedArrayProcessor() { } -void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage) +void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if(LE_FAILURE(success)) return; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.h b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.h index 5960827f865..1a406c8b9a3 100644 --- a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.h +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class TrimmedArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + TrimmedArrayProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~TrimmedArrayProcessor(); @@ -76,7 +76,7 @@ private: protected: TTGlyphID firstGlyph; TTGlyphID lastGlyph; - const TrimmedArrayLookupTable *trimmedArrayLookupTable; + LEReferenceTo trimmedArrayLookupTable; }; diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp index f32b216326a..45d14e12504 100644 --- a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp @@ -46,22 +46,24 @@ TrimmedArrayProcessor2::TrimmedArrayProcessor2() { } -TrimmedArrayProcessor2::TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader) +TrimmedArrayProcessor2::TrimmedArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader2 *header = (const NonContextualGlyphSubstitutionHeader2 *) morphSubtableHeader; + const LEReferenceTo header(morphSubtableHeader, success); - trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table; + trimmedArrayLookupTable = LEReferenceTo(morphSubtableHeader, success, &header->table); firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); + valueArray = LEReferenceToArrayOf(morphSubtableHeader, success, &trimmedArrayLookupTable->valueArray[0], LE_UNBOUNDED_ARRAY); } TrimmedArrayProcessor2::~TrimmedArrayProcessor2() { } -void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage) +void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if(LE_FAILURE(success)) return; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; @@ -70,7 +72,7 @@ void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage) TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { - TTGlyphID newGlyph = SWAPW(trimmedArrayLookupTable->valueArray[ttGlyph - firstGlyph]); + TTGlyphID newGlyph = SWAPW(valueArray(ttGlyph - firstGlyph, success)); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } diff --git a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h index 1ebe4187784..a3261d554d4 100644 --- a/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h +++ b/jdk/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h @@ -50,9 +50,9 @@ class LEGlyphStorage; class TrimmedArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - TrimmedArrayProcessor2(const MorphSubtableHeader2 *morphSubtableHeader); + TrimmedArrayProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success); virtual ~TrimmedArrayProcessor2(); @@ -76,8 +76,8 @@ private: protected: TTGlyphID firstGlyph; TTGlyphID lastGlyph; - const TrimmedArrayLookupTable *trimmedArrayLookupTable; - + LEReferenceTo trimmedArrayLookupTable; + LEReferenceToArrayOf valueArray; }; U_NAMESPACE_END diff --git a/jdk/src/share/native/sun/font/layout/ValueRecords.h b/jdk/src/share/native/sun/font/layout/ValueRecords.h index eb63e7d3f4d..ac89b8acdd5 100644 --- a/jdk/src/share/native/sun/font/layout/ValueRecords.h +++ b/jdk/src/share/native/sun/font/layout/ValueRecords.h @@ -64,6 +64,7 @@ private: static le_int16 getFieldCount(ValueFormat valueFormat); static le_int16 getFieldIndex(ValueFormat valueFormat, ValueRecordField field); }; +LE_VAR_ARRAY(ValueRecord, values) enum ValueRecordFields { diff --git a/jdk/src/share/native/sun/font/sunFont.c b/jdk/src/share/native/sun/font/sunFont.c index cfcc5ed75c0..95927b003d7 100644 --- a/jdk/src/share/native/sun/font/sunFont.c +++ b/jdk/src/share/native/sun/font/sunFont.c @@ -320,22 +320,20 @@ Java_sun_font_StrikeCache_getGlyphCacheDescription JNIEXPORT TTLayoutTableCache* newLayoutTableCache() { TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache)); if (ltc) { - ltc->gsub_len = -1; - ltc->gpos_len = -1; - ltc->gdef_len = -1; - ltc->mort_len = -1; - ltc->kern_len = -1; + int i; + for(i=0;ientries[i].len = -1; + } } return ltc; } JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) { if (ltc) { - if (ltc->gsub) free(ltc->gsub); - if (ltc->gpos) free(ltc->gpos); - if (ltc->gdef) free(ltc->gdef); - if (ltc->mort) free(ltc->mort); - if (ltc->kern) free(ltc->kern); + int i; + for(i=0;ientries[i].ptr) free (ltc->entries[i].ptr); + } if (ltc->kernPairs) free(ltc->kernPairs); free(ltc); } From ac95e3f1ed0b9069ca2c193ba6489c99996c5a08 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 5 Feb 2013 20:07:54 +0400 Subject: [PATCH 25/36] 8006790: Improve checking for windows Reviewed-by: art, mschoene --- jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java | 6 +++--- .../classes/sun/lwawt/macosx/CFileDialog.java | 4 ++-- .../sun/lwawt/macosx/CPrinterDialogPeer.java | 4 ++-- jdk/src/share/classes/java/awt/Window.java | 4 ++-- jdk/src/share/classes/java/awt/peer/WindowPeer.java | 13 ++++++------- jdk/src/share/classes/sun/awt/EmbeddedFrame.java | 4 ++-- .../solaris/classes/sun/awt/X11/XWindowPeer.java | 6 +++--- .../classes/sun/awt/windows/WFileDialogPeer.java | 4 ++-- .../classes/sun/awt/windows/WPrintDialogPeer.java | 4 ++-- .../classes/sun/awt/windows/WWindowPeer.java | 6 +++++- 10 files changed, 29 insertions(+), 26 deletions(-) diff --git a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java index d50335f7cd5..0a789c415b3 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -170,7 +170,7 @@ public class LWWindowPeer setTitle(((Dialog) getTarget()).getTitle()); } - setAlwaysOnTop(getTarget().isAlwaysOnTop()); + updateAlwaysOnTopState(); updateMinimumSize(); final Shape shape = getTarget().getShape(); @@ -357,8 +357,8 @@ public class LWWindowPeer } @Override - public void setAlwaysOnTop(boolean value) { - platformWindow.setAlwaysOnTop(value); + public void updateAlwaysOnTopState() { + platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop()); } @Override diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java index 359f6066364..29129394a37 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -180,7 +180,7 @@ class CFileDialog implements FileDialogPeer { } @Override - public void setAlwaysOnTop(boolean alwaysOnTop) { + public void updateAlwaysOnTopState() { } @Override diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java index 1ca65e7faae..8dfe7e1e51e 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -87,7 +87,7 @@ public class CPrinterDialogPeer extends LWWindowPeer { } // 1.6 peer method - public void setAlwaysOnTop(boolean value) { + public void updateAlwaysOnTopState() { // no-op, since we just show the native print dialog } diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 68b9af95a96..89270e27df1 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -2234,7 +2234,7 @@ public class Window extends Container implements Accessible { WindowPeer peer = (WindowPeer)this.peer; synchronized(getTreeLock()) { if (peer != null) { - peer.setAlwaysOnTop(alwaysOnTop); + peer.updateAlwaysOnTopState(); } } } diff --git a/jdk/src/share/classes/java/awt/peer/WindowPeer.java b/jdk/src/share/classes/java/awt/peer/WindowPeer.java index fca78b7eed4..b44bfa00da9 100644 --- a/jdk/src/share/classes/java/awt/peer/WindowPeer.java +++ b/jdk/src/share/classes/java/awt/peer/WindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -53,15 +53,14 @@ public interface WindowPeer extends ContainerPeer { void toBack(); /** - * Sets if the window should always stay on top of all other windows or - * not. - * - * @param alwaysOnTop if the window should always stay on top of all other - * windows or not + * Updates the window's always-on-top state. + * Sets if the window should always stay + * on top of all other windows or not. * + * @see Window#getAlwaysOnTop() * @see Window#setAlwaysOnTop(boolean) */ - void setAlwaysOnTop(boolean alwaysOnTop); + void updateAlwaysOnTopState(); /** * Updates the window's focusable state. diff --git a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java index 0ae1ec762df..fe8ad9a9a0f 100644 --- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java +++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -542,7 +542,7 @@ public abstract class EmbeddedFrame extends Frame public void toBack() {} public void updateFocusableWindowState() {} public void updateAlwaysOnTop() {} - public void setAlwaysOnTop(boolean alwaysOnTop) {} + public void updateAlwaysOnTopState() {} public Component getGlobalHeavyweightFocusOwner() { return null; } public void setBoundsPrivate(int x, int y, int width, int height) { setBounds(x, y, width, height, SET_BOUNDS); diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java index 4d867175597..0c230d6aa99 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -993,8 +993,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, XLayerProtocol.LAYER_NORMAL); } - public void setAlwaysOnTop(boolean alwaysOnTop) { - this.alwaysOnTop = alwaysOnTop; + public void updateAlwaysOnTopState() { + this.alwaysOnTop = ((Window) this.target).isAlwaysOnTop(); updateAlwaysOnTop(); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java b/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java index 11fe02f83d0..92ec5f337ee 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -237,7 +237,7 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { // unused methods. Overridden to disable this functionality as // it requires HWND which is not available for FileDialog - public void setAlwaysOnTop(boolean value) {} + public void updateAlwaysOnTopState() {} public void setDirectory(String dir) {} public void setFile(String file) {} public void setTitle(String title) {} diff --git a/jdk/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/jdk/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java index 988098eb648..ee116d46879 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -117,7 +117,7 @@ public class WPrintDialogPeer extends WWindowPeer implements DialogPeer { // unused methods. Overridden to disable this functionality as // it requires HWND which is not available for FileDialog void initialize() {} - public void setAlwaysOnTop(boolean b) {} + public void updateAlwaysOnTopState() {} public void setResizable(boolean resizable) {} public void hide() {} public void enable() {} diff --git a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java index 07f0c1c08f9..8b941c6f3c5 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -132,6 +132,10 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, } } + public void updateAlwaysOnTopState() { + setAlwaysOnTop(((Window)target).isAlwaysOnTop()); + } + public void updateFocusableWindowState() { setFocusableWindow(((Window)target).isFocusableWindow()); } From 2e810672ba3c9705755d2675c8c7ffb485ecc76b Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Wed, 27 Mar 2013 10:37:46 +0000 Subject: [PATCH 26/36] 8003445: Adjust JAX-WS to focus on API Reviewed-by: vinnie, ahgross, mgrebac --- jdk/src/share/lib/security/java.security-linux | 6 ++---- jdk/src/share/lib/security/java.security-macosx | 6 ++---- jdk/src/share/lib/security/java.security-solaris | 6 ++---- jdk/src/share/lib/security/java.security-windows | 6 ++---- jdk/test/Makefile | 2 +- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index 8fc53d73677..6c62e385159 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -155,8 +155,7 @@ package.access=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # @@ -179,8 +178,7 @@ package.definition=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 5a319fa5445..56188dc3f82 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -156,8 +156,7 @@ package.access=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal.,\ apple. @@ -181,8 +180,7 @@ package.definition=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal.,\ apple. diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 2a781cff75d..bf56b71cdb8 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -157,8 +157,7 @@ package.access=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # @@ -181,8 +180,7 @@ package.definition=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index a00f4628dd6..479788f2c9d 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -156,8 +156,7 @@ package.access=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # @@ -180,8 +179,7 @@ package.definition=sun.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.glassfish.,\ jdk.internal. # diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 69d5dac3d57..75e56458a14 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -514,7 +514,7 @@ jdk_other: $(call TestDirs, \ java/sql javax/sql \ javax/smartcardio \ javax/xml/soap \ - javax/xml/ws com/sun/internal/ws \ + javax/xml/ws com/sun/internal/ws com/sun/org/glassfish \ jdk/asm \ com/sun/org/apache/xerces \ com/sun/corba \ From dc574bf905d8c2ef1464ff1584d385576e9236f6 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Mon, 18 Feb 2013 13:02:09 -0800 Subject: [PATCH 27/36] 6657673: Issues with JAXP Reviewed-by: alanb, lancea, ahgross, mullan --- .../share/lib/security/java.security-linux | 36 +++++++++++++++++-- .../share/lib/security/java.security-macosx | 36 +++++++++++++++++-- .../share/lib/security/java.security-solaris | 36 +++++++++++++++++-- .../share/lib/security/java.security-windows | 36 +++++++++++++++++-- jdk/test/Makefile | 1 + 5 files changed, 137 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index 6c62e385159..afe07617e45 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -148,13 +148,29 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. @@ -171,13 +187,29 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 56188dc3f82..a403d9b2982 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -149,13 +149,29 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal.,\ apple. @@ -173,13 +189,29 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal.,\ apple. diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index bf56b71cdb8..9f2f75939dc 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -150,13 +150,29 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. @@ -173,13 +189,29 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index 479788f2c9d..9f092dd1cd2 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -149,13 +149,29 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. @@ -172,13 +188,29 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.bind.,\ com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.stream.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ jdk.internal. diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 75e56458a14..c09368dd8dd 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -513,6 +513,7 @@ jdk_other: $(call TestDirs, \ javax/script \ java/sql javax/sql \ javax/smartcardio \ + javax/xml/jaxp \ javax/xml/soap \ javax/xml/ws com/sun/internal/ws com/sun/org/glassfish \ jdk/asm \ From 33184bb4131df574b9ac4028429ccb8e0bb1323d Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 19 Feb 2013 12:06:28 +0400 Subject: [PATCH 28/36] 8007675: Improve color conversion Reviewed-by: prr, mschoene, jgodinez --- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 98 +++++++++-- .../sun/java2d/cmm/lcms/LCMSTransform.java | 160 +++++++++++------- 2 files changed, 181 insertions(+), 77 deletions(-) diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 3695a163211..9bb34f555c5 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -99,50 +99,75 @@ class LCMSImageLayout { int offset; Object dataArray; - private LCMSImageLayout(int np, int pixelType, int pixelSize) { + private int dataArrayLength; /* in bytes */ + + private LCMSImageLayout(int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this.pixelType = pixelType; width = np; height = 1; - nextRowOffset = np*pixelSize; + nextRowOffset = safeMult(pixelSize, np); offset = 0; } private LCMSImageLayout(int width, int height, int pixelType, - int pixelSize) { + int pixelSize) + throws ImageLayoutException + { this.pixelType = pixelType; this.width = width; this.height = height; - nextRowOffset = width*pixelSize; + nextRowOffset = safeMult(pixelSize, width); offset = 0; } - public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_BYTE; dataArray = data; + dataArrayLength = data.length; + + verify(); } - public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_SHORT; dataArray = data; + dataArrayLength = 2 * data.length; + + verify(); } - public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_INT; dataArray = data; + dataArrayLength = 4 * data.length; + + verify(); } public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException { this(np, pixelType, pixelSize); dataType = DT_DOUBLE; dataArray = data; + dataArrayLength = 8 * data.length; + + verify(); } - public LCMSImageLayout(BufferedImage image) { + public LCMSImageLayout(BufferedImage image) throws ImageLayoutException { ShortComponentRaster shortRaster; IntegerComponentRaster intRaster; ByteComponentRaster byteRaster; @@ -186,9 +211,13 @@ class LCMSImageLayout { case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_BGR: intRaster = (IntegerComponentRaster)image.getRaster(); - nextRowOffset = intRaster.getScanlineStride()*4; - offset = intRaster.getDataOffset(0)*4; + + nextRowOffset = safeMult(4, intRaster.getScanlineStride()); + + offset = safeMult(4, intRaster.getDataOffset(0)); + dataArray = intRaster.getDataStorage(); + dataArrayLength = 4 * intRaster.getDataStorage().length; dataType = DT_INT; break; @@ -199,6 +228,7 @@ class LCMSImageLayout { int firstBand = image.getSampleModel().getNumBands() - 1; offset = byteRaster.getDataOffset(firstBand); dataArray = byteRaster.getDataStorage(); + dataArrayLength = byteRaster.getDataStorage().length; dataType = DT_BYTE; break; @@ -207,17 +237,20 @@ class LCMSImageLayout { nextRowOffset = byteRaster.getScanlineStride(); offset = byteRaster.getDataOffset(0); dataArray = byteRaster.getDataStorage(); + dataArrayLength = byteRaster.getDataStorage().length; dataType = DT_BYTE; break; case BufferedImage.TYPE_USHORT_GRAY: shortRaster = (ShortComponentRaster)image.getRaster(); - nextRowOffset = shortRaster.getScanlineStride()*2; - offset = shortRaster.getDataOffset(0) * 2; + nextRowOffset = safeMult(2, shortRaster.getScanlineStride()); + offset = safeMult(2, shortRaster.getDataOffset(0)); dataArray = shortRaster.getDataStorage(); + dataArrayLength = 2 * shortRaster.getDataStorage().length; dataType = DT_SHORT; break; } + verify(); } public static boolean isSupported(BufferedImage image) { @@ -233,4 +266,45 @@ class LCMSImageLayout { } return false; } + + private void verify() throws ImageLayoutException { + + if (offset < 0 || offset >= dataArrayLength) { + throw new ImageLayoutException("Invalid image layout"); + } + + int lastPixelOffset = safeMult(nextRowOffset, (height - 1)); + + lastPixelOffset = safeAdd(lastPixelOffset, (width - 1)); + + int off = safeAdd(offset, lastPixelOffset); + + if (off < 0 || off >= dataArrayLength) { + throw new ImageLayoutException("Invalid image layout"); + } + } + + static int safeAdd(int a, int b) throws ImageLayoutException { + long res = a; + res += b; + if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { + throw new ImageLayoutException("Invalid image layout"); + } + return (int)res; + } + + static int safeMult(int a, int b) throws ImageLayoutException { + long res = a; + res *= b; + if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { + throw new ImageLayoutException("Invalid image layout"); + } + return (int)res; + } + + public static class ImageLayoutException extends Exception { + public ImageLayoutException(String message) { + super(message); + } + } } diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index aa9d0bf054f..9792248dea7 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -51,6 +51,7 @@ import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.ComponentSampleModel; import sun.java2d.cmm.*; import sun.java2d.cmm.lcms.*; +import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException; public class LCMSTransform implements ColorTransform { @@ -164,8 +165,12 @@ public class LCMSTransform implements ColorTransform { if (LCMSImageLayout.isSupported(src) && LCMSImageLayout.isSupported(dst)) { - doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); - return; + try { + doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); + return; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); + } } LCMSImageLayout srcIL, dstIL; Raster srcRas = src.getRaster(); @@ -223,14 +228,18 @@ public class LCMSTransform implements ColorTransform { } int idx; // TODO check for src npixels = dst npixels - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); + } // process each scanline for (int y = 0; y < h; y++) { // convert src scanline @@ -279,16 +288,19 @@ public class LCMSTransform implements ColorTransform { alpha = new float[w]; } int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); + } // process each scanline for (int y = 0; y < h; y++) { // convert src scanline @@ -397,16 +409,19 @@ public class LCMSTransform implements ColorTransform { short[] srcLine = new short[w * srcNumBands]; short[] dstLine = new short[w * dstNumBands]; int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -489,15 +504,18 @@ public class LCMSTransform implements ColorTransform { byte[] dstLine = new byte[w * dstNumBands]; int idx; // TODO check for src npixels = dst npixels - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); - + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -529,16 +547,20 @@ public class LCMSTransform implements ColorTransform { short[] srcLine = new short[w * srcNumBands]; short[] dstLine = new short[w * dstNumBands]; int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -579,19 +601,23 @@ public class LCMSTransform implements ColorTransform { dst = new short [(src.length/getNumInComponents())*getNumOutComponents()]; } - LCMSImageLayout srcIL = new LCMSImageLayout( - src, src.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + try { + LCMSImageLayout srcIL = new LCMSImageLayout( + src, src.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - LCMSImageLayout dstIL = new LCMSImageLayout( - dst, dst.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + LCMSImageLayout dstIL = new LCMSImageLayout( + dst, dst.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); - doTransform(srcIL, dstIL); + doTransform(srcIL, dstIL); - return dst; + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); + } } public byte[] colorConvert(byte[] src, byte[] dst) { @@ -599,18 +625,22 @@ public class LCMSTransform implements ColorTransform { dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()]; } - LCMSImageLayout srcIL = new LCMSImageLayout( - src, src.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + try { + LCMSImageLayout srcIL = new LCMSImageLayout( + src, src.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - LCMSImageLayout dstIL = new LCMSImageLayout( - dst, dst.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + LCMSImageLayout dstIL = new LCMSImageLayout( + dst, dst.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); - doTransform(srcIL, dstIL); + doTransform(srcIL, dstIL); - return dst; + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); + } } } From 10415b74b76f79f1acbaa4775446b2a116d66e89 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Thu, 7 Mar 2013 07:19:35 -0500 Subject: [PATCH 29/36] 8005432: Update access to JAX-WS Newly restricted the whole package com.sun.xml.internal; fix reviewed also by Alexander Fomin Reviewed-by: mullan, skoivu --- jdk/src/share/lib/security/java.security-linux | 10 ++-------- jdk/src/share/lib/security/java.security-macosx | 10 ++-------- jdk/src/share/lib/security/java.security-solaris | 10 ++-------- jdk/src/share/lib/security/java.security-windows | 10 ++-------- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index afe07617e45..8797a6819f0 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -146,10 +146,7 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ @@ -185,10 +182,7 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index a403d9b2982..3ed6a4fd5dc 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -147,10 +147,7 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ @@ -187,10 +184,7 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 9f2f75939dc..a88da32ca48 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -148,10 +148,7 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ @@ -187,10 +184,7 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index 9f092dd1cd2..ffaa58f9ab5 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -147,10 +147,7 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ @@ -186,10 +183,7 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.stream.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ From 23f643597be28dc0c53352a37d18a22045e2b1a2 Mon Sep 17 00:00:00 2001 From: Ragini Prasad Date: Wed, 27 Mar 2013 21:32:53 +0000 Subject: [PATCH 30/36] 8007406: Improve accessibility of AccessBridge Reviewed-by: skoivu, mullan, ptbrunet --- jdk/src/share/lib/security/java.security-windows | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index ffaa58f9ab5..e73e1065412 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -170,7 +170,8 @@ package.access=sun.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ - jdk.internal. + jdk.internal.\ + com.sun.java.accessibility. # # List of comma-separated packages that start with or equal this string @@ -206,7 +207,8 @@ package.definition=sun.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ - jdk.internal. + jdk.internal.\ + com.sun.java.accessibility. # # Determines whether this properties file can be appended to From a876e30cd4479d483c4f38312c9d8cd51d853be4 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 28 Mar 2013 09:50:40 +0000 Subject: [PATCH 31/36] 8010944: Incorrectly separated package list in java.security-windows Reviewed-by: mullan --- jdk/src/share/lib/security/java.security-windows | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index e73e1065412..3949ef2daa4 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -170,7 +170,7 @@ package.access=sun.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ - jdk.internal.\ + jdk.internal.,\ com.sun.java.accessibility. # @@ -207,7 +207,7 @@ package.definition=sun.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ - jdk.internal.\ + jdk.internal.,\ com.sun.java.accessibility. # From fbc6f854cd5739eb43029905bf9189b9bdfd912c Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 1 Mar 2013 04:45:12 +0400 Subject: [PATCH 32/36] 8008140: Better method handle resolution Reviewed-by: jrose, twisti, jdn --- .../java/lang/invoke/MethodHandles.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java index f4cad4deaa8..d443e4c4597 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java @@ -1237,6 +1237,30 @@ return mh1; checkMethod(refKind, refc, method); if (method.isMethodHandleInvoke()) return fakeMethodHandleInvoke(method); + + Class refcAsSuper; + if (refKind == REF_invokeSpecial && + refc != lookupClass() && + refc != (refcAsSuper = lookupClass().getSuperclass()) && + refc.isAssignableFrom(lookupClass())) { + assert(!method.getName().equals("")); // not this code path + // Per JVMS 6.5, desc. of invokespecial instruction: + // If the method is in a superclass of the LC, + // and if our original search was above LC.super, + // repeat the search (symbolic lookup) from LC.super. + // FIXME: MemberName.resolve should handle this instead. + MemberName m2 = new MemberName(refcAsSuper, + method.getName(), + method.getMethodType(), + REF_invokeSpecial); + m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull()); + if (m2 == null) throw new InternalError(method.toString()); + method = m2; + refc = refcAsSuper; + // redo basic checks + checkMethod(refKind, refc, method); + } + MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); mh = maybeBindCaller(method, mh, callerClass); mh = mh.setVarargs(method); From 12cfd3e1b4ed9097c960687dc3ff5732d85c6b98 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 16 Apr 2013 11:17:19 -0700 Subject: [PATCH 33/36] 8004518: Add in-place operations to Map 8010122: Add defaults for ConcurrentMap operations to Map Co-authored-by: Doug Lea Co-authored-by: Henry Jen Co-authored-by: Akhil Arora Co-authored-by: Peter Levart Reviewed-by: darcy, briangoetz, mduigou, dholmes, ulfzibis --- .../share/classes/java/util/Collections.java | 351 +++++++++- jdk/src/share/classes/java/util/HashMap.java | 276 +++++++- .../share/classes/java/util/Hashtable.java | 275 +++++++- jdk/src/share/classes/java/util/Map.java | 615 +++++++++++++++++- .../java/util/concurrent/ConcurrentMap.java | 37 +- jdk/test/java/util/Map/Defaults.java | 594 +++++++++++++++++ 6 files changed, 2097 insertions(+), 51 deletions(-) create mode 100644 jdk/test/java/util/Map/Defaults.java diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index b6bac484dac..ad36637452b 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -28,6 +28,9 @@ import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.IOException; import java.lang.reflect.Array; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; /** * This class consists exclusively of static methods that operate on or return @@ -264,8 +267,7 @@ public class Collections { } private static - int indexedBinarySearch(List> list, T key) - { + int indexedBinarySearch(List> list, T key) { int low = 0; int high = list.size()-1; @@ -441,21 +443,21 @@ public class Collections { /** * Randomly permutes the specified list using a default source of * randomness. All permutations occur with approximately equal - * likelihood.

+ * likelihood. * - * The hedge "approximately" is used in the foregoing description because + *

The hedge "approximately" is used in the foregoing description because * default source of randomness is only approximately an unbiased source * of independently chosen bits. If it were a perfect source of randomly * chosen bits, then the algorithm would choose permutations with perfect - * uniformity.

+ * uniformity. * - * This implementation traverses the list backwards, from the last element - * up to the second, repeatedly swapping a randomly selected element into - * the "current position". Elements are randomly selected from the + *

This implementation traverses the list backwards, from the last + * element up to the second, repeatedly swapping a randomly selected element + * into the "current position". Elements are randomly selected from the * portion of the list that runs from the first element to the current - * position, inclusive.

+ * position, inclusive. * - * This method runs in linear time. If the specified list does not + *

This method runs in linear time. If the specified list does not * implement the {@link RandomAccess} interface and is large, this * implementation dumps the specified list into an array before shuffling * it, and dumps the shuffled array back into the list. This avoids the @@ -469,9 +471,10 @@ public class Collections { public static void shuffle(List list) { Random rnd = r; if (rnd == null) - r = rnd = new Random(); + r = rnd = new Random(); // harmless race. shuffle(list, rnd); } + private static Random r; /** @@ -1391,6 +1394,67 @@ public class Collections { public int hashCode() {return m.hashCode();} public String toString() {return m.toString();} + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + // Safe cast as we don't change the value + return ((Map)m).getOrDefault(k, defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + m.forEach(action); + } + + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + /** * We need this class in addition to UnmodifiableSet as * Map.Entries themselves permit modification of the backing Map @@ -1590,9 +1654,9 @@ public class Collections { * * Failure to follow this advice may result in non-deterministic behavior. * - *

The returned collection does not pass the hashCode - * and equals operations through to the backing collection, but - * relies on Object's equals and hashCode methods. This is + *

The returned collection does not pass the {@code hashCode} + * and {@code equals} operations through to the backing collection, but + * relies on {@code Object}'s equals and hashCode methods. This is * necessary to preserve the contracts of these operations in the case * that the backing collection is a set or a list.

* @@ -2107,6 +2171,57 @@ public class Collections { public String toString() { synchronized (mutex) {return m.toString();} } + + // Override default methods in Map + @Override + public V getOrDefault(Object k, V defaultValue) { + synchronized (mutex) {return m.getOrDefault(k, defaultValue);} + } + @Override + public void forEach(BiConsumer action) { + synchronized (mutex) {m.forEach(action);} + } + @Override + public void replaceAll(BiFunction function) { + synchronized (mutex) {m.replaceAll(function);} + } + @Override + public V putIfAbsent(K key, V value) { + synchronized (mutex) {return m.putIfAbsent(key, value);} + } + @Override + public boolean remove(Object key, Object value) { + synchronized (mutex) {return m.remove(key, value);} + } + @Override + public boolean replace(K key, V oldValue, V newValue) { + synchronized (mutex) {return m.replace(key, oldValue, newValue);} + } + @Override + public V replace(K key, V value) { + synchronized (mutex) {return m.replace(key, value);} + } + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);} + } + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);} + } + @Override + public V compute(K key, + BiFunction remappingFunction) { + synchronized (mutex) {return m.compute(key, remappingFunction);} + } + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + synchronized (mutex) {return m.merge(key, value, remappingFunction);} + } + private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} } @@ -2326,6 +2441,8 @@ public class Collections { } public Iterator iterator() { + // JDK-6363904 - unwrapped iterator could be typecast to + // ListIterator with unsafe set() final Iterator it = c.iterator(); return new Iterator() { public boolean hasNext() { return it.hasNext(); } @@ -2652,7 +2769,7 @@ public class Collections { public List subList(int fromIndex, int toIndex) { return new CheckedRandomAccessList<>( - list.subList(fromIndex, toIndex), type); + list.subList(fromIndex, toIndex), type); } } @@ -2717,14 +2834,24 @@ public class Collections { throw new ClassCastException(badValueMsg(value)); } + private BiFunction typeCheck( + BiFunction func) { + Objects.requireNonNull(func); + return (k, v) -> { + V newValue = func.apply(k, v); + typeCheck(k, newValue); + return newValue; + }; + } + private String badKeyMsg(Object key) { return "Attempt to insert " + key.getClass() + - " key into map with key type " + keyType; + " key into map with key type " + keyType; } private String badValueMsg(Object value) { return "Attempt to insert " + value.getClass() + - " value into map with value type " + valueType; + " value into map with value type " + valueType; } CheckedMap(Map m, Class keyType, Class valueType) { @@ -2768,7 +2895,7 @@ public class Collections { Object v = e.getValue(); typeCheck(k, v); checked.add( - new AbstractMap.SimpleImmutableEntry<>((K) k, (V) v)); + new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v)); } for (Map.Entry e : checked) m.put(e.getKey(), e.getValue()); @@ -2782,6 +2909,74 @@ public class Collections { return entrySet; } + // Override default methods in Map + @Override + public void forEach(BiConsumer action) { + m.forEach(action); + } + + @Override + public void replaceAll(BiFunction function) { + m.replaceAll(typeCheck(function)); + } + + @Override + public V putIfAbsent(K key, V value) { + typeCheck(key, value); + return m.putIfAbsent(key, value); + } + + @Override + public boolean remove(Object key, Object value) { + return m.remove(key, value); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + typeCheck(key, newValue); + return m.replace(key, oldValue, newValue); + } + + @Override + public V replace(K key, V value) { + typeCheck(key, value); + return m.replace(key, value); + } + + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + Objects.requireNonNull(mappingFunction); + return m.computeIfAbsent(key, k -> { + V value = mappingFunction.apply(k); + typeCheck(k, value); + return value; + }); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + return m.computeIfPresent(key, typeCheck(remappingFunction)); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + return m.compute(key, typeCheck(remappingFunction)); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + return m.merge(key, value, (v1, v2) -> { + V newValue = remappingFunction.apply(v1, v2); + typeCheck(null, newValue); + return newValue; + }); + } + /** * We need this class in addition to CheckedSet as Map.Entry permits * modification of the backing Map via the setValue operation. This @@ -3456,6 +3651,67 @@ public class Collections { public int hashCode() {return 0;} + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + return defaultValue; + } + + @Override + public void forEach(BiConsumer action) { + Objects.requireNonNull(action); + } + + @Override + public void replaceAll(BiFunction function) { + Objects.requireNonNull(function); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + // Preserves singleton property private Object readResolve() { return EMPTY_MAP; @@ -3619,6 +3875,65 @@ public class Collections { return values; } + // Override default methods in Map + @Override + public V getOrDefault(Object key, V defaultValue) { + return eq(key, k) ? v : defaultValue; + } + + @Override + public void forEach(BiConsumer action) { + action.accept(k, v); + } + + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } } // Miscellaneous diff --git a/jdk/src/share/classes/java/util/HashMap.java b/jdk/src/share/classes/java/util/HashMap.java index d1ac0cf16fe..b40c5c92ffa 100644 --- a/jdk/src/share/classes/java/util/HashMap.java +++ b/jdk/src/share/classes/java/util/HashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -24,7 +24,11 @@ */ package java.util; + import java.io.*; +import java.util.function.Consumer; +import java.util.function.BiFunction; +import java.util.function.Function; /** * Hash table based implementation of the Map interface. This @@ -376,6 +380,13 @@ public class HashMap return null == entry ? null : entry.getValue(); } + @Override + public V getOrDefault(Object key, V defaultValue) { + Entry entry = getEntry(key); + + return (entry == null) ? defaultValue : entry.getValue(); + } + /** * Returns true if this map contains a mapping for the * specified key. @@ -603,6 +614,261 @@ public class HashMap return (e == null ? null : e.value); } + // optimized implementations of default methods in Map + + @Override + public V putIfAbsent(K key, V value) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry e = (Entry)table[i]; + for(; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + if(e.value != null) { + return e.value; + } + e.value = value; + modCount++; + e.recordAccess(this); + return null; + } + } + + modCount++; + addEntry(hash, key, value, i); + return null; + } + + @Override + public boolean remove(Object key, Object value) { + if (isEmpty()) { + return false; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry prev = (Entry)table[i]; + Entry e = prev; + + while (e != null) { + Entry next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + if (!Objects.equals(e.value, value)) { + return false; + } + modCount++; + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + return true; + } + prev = e; + e = next; + } + + return false; + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + if (isEmpty()) { + return false; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry e = (Entry)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) { + e.value = newValue; + e.recordAccess(this); + return true; + } + } + + return false; + } + + @Override + public V replace(K key, V value) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry e = (Entry)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + e.value = value; + e.recordAccess(this); + return oldValue; + } + } + + return null; + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry e = (Entry)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + return oldValue == null ? (e.value = mappingFunction.apply(key)) : oldValue; + } + } + + V newValue = mappingFunction.apply(key); + if (newValue != null) { + modCount++; + addEntry(hash, key, newValue, i); + } + + return newValue; + } + + @Override + public V computeIfPresent(K key, BiFunction remappingFunction) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry prev = (Entry)table[i]; + Entry e = prev; + + while (e != null) { + Entry next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + if (oldValue == null) + break; + V newValue = remappingFunction.apply(key, oldValue); + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + return newValue; + } + prev = e; + e = next; + } + + return null; + } + + @Override + public V compute(K key, BiFunction remappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry prev = (Entry)table[i]; + Entry e = prev; + + while (e != null) { + Entry next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != oldValue) { + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + } + return newValue; + } + prev = e; + e = next; + } + + V newValue = remappingFunction.apply(key, null); + if (newValue != null) { + modCount++; + addEntry(hash, key, newValue, i); + } + + return newValue; + } + + @Override + public V merge(K key, V value, BiFunction remappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry prev = (Entry)table[i]; + Entry e = prev; + + while (e != null) { + Entry next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + V newValue = remappingFunction.apply(oldValue, value); + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + return newValue; + } + prev = e; + e = next; + } + + if (value != null) { + modCount++; + addEntry(hash, key, value, i); + } + + return value; + } + + // end of optimized implementations of default methods in Map + /** * Removes and returns the entry associated with the specified key * in the HashMap. Returns null if the HashMap contains no mapping @@ -697,8 +963,8 @@ public class HashMap return containsNullValue(); Entry[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry e = tab[i] ; e != null ; e = e.next) + for (int i = 0; i < tab.length; i++) + for (Entry e = tab[i]; e != null; e = e.next) if (value.equals(e.value)) return true; return false; @@ -709,8 +975,8 @@ public class HashMap */ private boolean containsNullValue() { Entry[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry e = tab[i] ; e != null ; e = e.next) + for (int i = 0; i < tab.length; i++) + for (Entry e = tab[i]; e != null; e = e.next) if (e.value == null) return true; return false; diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index f973c3ac718..1e38fcaa43b 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -24,7 +24,11 @@ */ package java.util; + import java.io.*; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.BiFunction; /** * This class implements a hash table, which maps keys to values. Any @@ -455,6 +459,26 @@ public class Hashtable } } + private void addEntry(int hash, K key, V value, int index) { + modCount++; + + Entry tab[] = table; + if (count >= threshold) { + // Rehash the table if the threshold is exceeded + rehash(); + + tab = table; + hash = hash(key); + index = (hash & 0x7FFFFFFF) % tab.length; + } + + // Creates the new entry. + @SuppressWarnings("unchecked") + Entry e = (Entry) tab[index]; + tab[index] = new Entry<>(hash, key, value, e); + count++; + } + /** * Maps the specified key to the specified * value in this hashtable. Neither the key nor the @@ -492,21 +516,7 @@ public class Hashtable } } - modCount++; - if (count >= threshold) { - // Rehash the table if the threshold is exceeded - rehash(); - - tab = table; - hash = hash(key); - index = (hash & 0x7FFFFFFF) % tab.length; - } - - // Creates the new entry. - @SuppressWarnings("unchecked") - Entry e = (Entry)tab[index]; - tab[index] = new Entry<>(hash, key, value, e); - count++; + addEntry(hash, key, value, index); return null; } @@ -892,6 +902,239 @@ public class Hashtable return h; } + @Override + public synchronized V getOrDefault(Object key, V defaultValue) { + V result = get(key); + return (null == result) ? defaultValue : result; + } + + @Override + public synchronized void forEach(BiConsumer action) { + Objects.requireNonNull(action); // explicit check required in case + // table is empty. + Entry[] tab = table; + for (Entry entry : tab) { + while (entry != null) { + action.accept((K)entry.key, (V)entry.value); + entry = entry.next; + } + } + } + + @Override + public synchronized void replaceAll( + BiFunction function) { + Map.super.replaceAll(function); + } + + @Override + public synchronized V putIfAbsent(K key, V value) { + Objects.requireNonNull(value); + + // Makes sure the key is not already in the hashtable. + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry entry = (Entry)tab[index]; + for (; entry != null; entry = entry.next) { + if ((entry.hash == hash) && entry.key.equals(key)) { + V old = entry.value; + if (old == null) { + entry.value = value; + } + return old; + } + } + + addEntry(hash, key, value, index); + return null; + } + + @Override + public synchronized boolean remove(Object key, Object value) { + Objects.requireNonNull(value); + + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (Entry prev = null; e != null; prev = e, e = e.next) { + if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + e.value = null; + return true; + } + } + return false; + } + + @Override + public synchronized boolean replace(K key, V oldValue, V newValue) { + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (; e != null; e = e.next) { + if ((e.hash == hash) && e.key.equals(key)) { + if (e.value.equals(oldValue)) { + e.value = newValue; + return true; + } else { + return false; + } + } + } + return false; + } + + @Override + public synchronized V replace(K key, V value) { + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (; e != null; e = e.next) { + if ((e.hash == hash) && e.key.equals(key)) { + V oldValue = e.value; + e.value = value; + return oldValue; + } + } + return null; + } + + @Override + public synchronized V computeIfAbsent(K key, Function mappingFunction) { + Objects.requireNonNull(mappingFunction); + + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (; e != null; e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + // Hashtable not accept null value + return e.value; + } + } + + V newValue = mappingFunction.apply(key); + if (newValue != null) { + addEntry(hash, key, newValue, index); + } + + return newValue; + } + + @Override + public V computeIfPresent(K key, BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (Entry prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + V newValue = remappingFunction.apply(key, e.value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + return null; + } + + @Override + public V compute(K key, BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (Entry prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V newValue = remappingFunction.apply(key, e.value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + + V newValue = remappingFunction.apply(key, null); + if (newValue != null) { + addEntry(hash, key, newValue, index); + } + + return newValue; + } + + @Override + public V merge(K key, V value, BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry e = (Entry)tab[index]; + for (Entry prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + V newValue = remappingFunction.apply(e.value, value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + + if (value != null) { + addEntry(hash, key, value, index); + } + + return value; + } + /** * Save the state of the Hashtable to a stream (i.e., serialize it). * diff --git a/jdk/src/share/classes/java/util/Map.java b/jdk/src/share/classes/java/util/Map.java index 6615f56daa0..acb595d8f07 100644 --- a/jdk/src/share/classes/java/util/Map.java +++ b/jdk/src/share/classes/java/util/Map.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,6 +25,10 @@ package java.util; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + /** * An object that maps keys to values. A map cannot contain duplicate keys; * each key can map to at most one value. @@ -475,4 +479,613 @@ public interface Map { */ int hashCode(); + // Defaultable methods + + /** + * Returns the value to which the specified key is mapped, + * or {@code defaultValue} if this map contains no mapping + * for the key. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or + * {@code defaultValue} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys + * (optional) + */ + default V getOrDefault(Object key, V defaultValue) { + V v; + return (((v = get(key)) != null) || containsKey(key)) + ? v + : defaultValue; + } + + /** + * Performs the given action on each entry in this map, in the order entries + * are returned by an entry set iterator (which may be unspecified), until + * all entries have been processed or the action throws an {@code Exception}. + * Exceptions thrown by the action are relayed to the caller. + * + *

The default implementation should be overridden by implementations if + * they can provide a more performant implementation than an iterator-based + * one. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec The default implementation is equivalent to, for this + * {@code map}: + *

 {@code
+     * for ((Map.Entry entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }
+ * + * @param action The action to be performed for each entry + * @throws NullPointerException if the specified action is null + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void forEach(BiConsumer action) { + Objects.requireNonNull(action); + for (Map.Entry entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + throw new ConcurrentModificationException(ise); + } + action.accept(k, v); + } + } + + /** + * Replaces each entry's value with the result of invoking the given + * function on that entry, in the order entries are returned by an entry + * set iterator, until all entries have been processed or the function + * throws an exception. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + *

The default implementation is equivalent to, for this {@code map}: + *

 {@code
+     * for ((Map.Entry entry : map.entrySet())
+     *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+     * }
+ * + * @param function the function to apply to each entry + * @throws UnsupportedOperationException if the {@code set} operation + * is not supported by this map's entry set iterator. + * @throws ClassCastException if the class of a replacement value + * prevents it from being stored in this map + * @throws NullPointerException if the specified function is null, or the + * specified replacement value is null, and this map does not permit null + * values + * @throws ClassCastException if a replacement value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if function or a replacement value is null, + * and this map does not permit null keys or values + * (optional) + * @throws IllegalArgumentException if some property of a replacement value + * prevents it from being stored in this map + * (optional) + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void replaceAll(BiFunction function) { + Objects.requireNonNull(function); + for (Map.Entry entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + throw new ConcurrentModificationException(ise); + } + entry.setValue(function.apply(k, v)); + } + } + + /** + * If the specified key is not already associated with a value (or is mapped + * to {@code null}) associates it with the given value and returns + * {@code null}, else returns the current value. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code + * map}: + * + *

 {@code
+     * if (map.get(key) == null)
+     *     return map.put(key, value);
+     * else
+     *     return map.get(key);
+     * }
+ * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code 1} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (optional) + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * (optional) + * @throws ConcurrentModificationException if a modification of the map is + * detected during insertion of the value. + * @since 1.8 + */ + default V putIfAbsent(K key, V value) { + V v = get(key); + if (v == null) { + if (put(key, value) != null) { + throw new ConcurrentModificationException(); + } + } + + return v; + } + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.remove(key);
+     *     return true;
+     * } else
+     *     return false;
+     * }
+ * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return {@code true} if the value was removed + * @throws UnsupportedOperationException if the {@code remove} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (optional) + * @since 1.8 + */ + default boolean remove(Object key, Object value) { + Object curValue = get(key); + if (!Objects.equals(curValue, value) || + (curValue == null && !containsKey(key))) { + return false; + } + remove(key); + return true; + } + + /** + * Replaces the entry for the specified key only if currently + * mapped to the specified value. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.put(key, newValue);
+     *     return true;
+     * } else
+     *     return false;
+     * }
+ * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return {@code true} if the value was replaced + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of a specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if a specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of a specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default boolean replace(K key, V oldValue, V newValue) { + Object curValue = get(key); + if (!Objects.equals(curValue, oldValue) || + (curValue == null && !containsKey(key))) { + return false; + } + put(key, newValue); + return true; + } + + /** + * Replaces the entry for the specified key only if it is + * currently mapped to some value. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key)) {
+     *     return map.put(key, value);
+     * } else
+     *     return null;
+     * }
+ * + * @param key key with which the specified value is associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default V replace(K key, V value) { + return containsKey(key) ? put(key, value) : null; + } + + /** + * If the specified key is not already associated with a value (or + * is mapped to {@code null}), attempts to compute its value using + * the given mapping function and enters it into this map unless + * {@code null}. + * + *

If the function returns {@code null} no mapping is recorded. If + * the function itself throws an (unchecked) exception, the + * exception is rethrown, and no mapping is recorded. The most + * common usage is to construct a new object serving as an initial + * mapped value or memoized result, as in: + * + *

 {@code
+     * map.computeIfAbsent(key, k -> new Value(f(k)));
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to the following + * steps for this {@code map}, then returning the current value or + * {@code null} if now absent: + * + *

 {@code
+     * if (map.get(key) == null) {
+     *     V newValue = mappingFunction.apply(key);
+     *     if (newValue != null)
+     *         map.putIfAbsent(key, newValue);
+     * }
+     * }
+ * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * mappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V computeIfAbsent(K key, + Function mappingFunction) { + V v, newValue; + return ((v = get(key)) == null && + (newValue = mappingFunction.apply(key)) != null && + (v = putIfAbsent(key, newValue)) == null) ? newValue : v; + } + + /** + * If the value for the specified key is present and non-null, attempts to + * compute a new mapping given the key and its current mapped value. + * + *

If the function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception is + * rethrown, and the current mapping is left unchanged. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the + * following steps for this {@code map}, then returning the + * current value or {@code null} if now absent: + * + *

 {@code
+     * if (map.get(key) != null) {
+     *     V oldValue = map.get(key);
+     *     V newValue = remappingFunction.apply(key, oldValue);
+     *     if (newValue != null)
+     *         map.replace(key, oldValue, newValue);
+     *     else
+     *         map.remove(key, oldValue);
+     * }
+     * }
+ * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V computeIfPresent(K key, + BiFunction remappingFunction) { + V oldValue; + while ((oldValue = get(key)) != null) { + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) + return null; + } + return oldValue; + } + + /** + * Attempts to compute a mapping for the specified key and its + * current mapped value (or {@code null} if there is no current + * mapping). For example, to either create or append a {@code + * String msg} to a value mapping: + * + *
 {@code
+     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}
+ * (Method {@link #merge merge()} is often simpler to use for such purposes.) + * + *

If the function returns {@code null}, the mapping is removed (or + * remains absent if initially absent). If the function itself throws an + * (unchecked) exception, the exception is rethrown, and the current mapping + * is left unchanged. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the following + * steps for this {@code map}, then returning the current value or + * {@code null} if absent: + * + *

 {@code
+     * V oldValue = map.get(key);
+     * V newValue = remappingFunction.apply(key, oldValue);
+     * if (oldValue != null ) {
+     *    if (newValue != null)
+     *       map.replace(key, oldValue, newValue);
+     *    else
+     *       map.remove(key, oldValue);
+     * } else {
+     *    if (newValue != null)
+     *       map.putIfAbsent(key, newValue);
+     *    else
+     *       return null;
+     * }
+     * }
+ * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V compute(K key, + BiFunction remappingFunction) { + V oldValue = get(key); + for (;;) { + V newValue = remappingFunction.apply(key, oldValue); + if (oldValue != null) { + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) { + return null; + } + oldValue = get(key); + } else { + if (newValue != null) { + if ((oldValue = putIfAbsent(key, newValue)) == null) + return newValue; + } else { + return null; + } + } + } + } + + /** + * If the specified key is not already associated with a value or is + * associated with null, associates it with the given value. + * Otherwise, replaces the value with the results of the given + * remapping function, or removes if the result is {@code null}. This + * method may be of use when combining multiple mapped values for a key. + * For example, to either create or append a {@code String msg} to a + * value mapping: + * + *
 {@code
+     * map.merge(key, msg, String::concat)
+     * }
+ * + *

If the function returns {@code null}, the mapping is removed (or + * remains absent if initially absent). If the function itself throws an + * (unchecked) exception, the exception is rethrown, and the current mapping + * is left unchanged. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the + * following steps for this {@code map}, then returning the + * current value or {@code null} if absent: + * + *

 {@code
+     * V oldValue = map.get(key);
+     * V newValue = (oldValue == null) ? value :
+     *              remappingFunction.apply(oldValue, value);
+     * if (newValue == null)
+     *     map.remove(key, oldValue);
+     * else if (oldValue == null)
+     *     map.putIfAbsent(key, newValue);
+     * else
+     *     map.replace(key, oldValue, newValue);
+     * }
+ * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param value the value to use if absent + * @param remappingFunction the function to recompute a value if present + * @return the new value associated with the specified key, or null if none + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @since 1.8 + */ + default V merge(K key, V value, + BiFunction remappingFunction) { + V oldValue = get(key); + for (;;) { + if (oldValue != null) { + V newValue = remappingFunction.apply(oldValue, value); + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) { + return null; + } + oldValue = get(key); + } else { + if (value == null) { + return null; + } + + if ((oldValue = putIfAbsent(key, value)) == null) { + return value; + } + } + } + } } diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java index a725db6e674..fee5689db89 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java @@ -38,7 +38,7 @@ import java.util.Map; /** * A {@link java.util.Map} providing additional atomic - * putIfAbsent, remove, and replace methods. + * {@code putIfAbsent}, {@code remove}, and {@code replace} methods. * *

Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a @@ -57,6 +57,21 @@ import java.util.Map; * @param the type of mapped values */ public interface ConcurrentMap extends Map { + + /** + * {@inheritDoc} + * + * @implNote This implementation assumes that the ConcurrentMap cannot + * contain null values and get() returning null unambiguously means the key + * is absent. Implementations which support null values must override this + * default implementation. + */ + @Override + default V getOrDefault(Object key, V defaultValue) { + V v; + return ((v = get(key)) != null) ? v : defaultValue; + } + /** * If the specified key is not already associated * with a value, associate it with the given value. @@ -91,7 +106,7 @@ public interface ConcurrentMap extends Map { * Removes the entry for a key only if currently mapped to a given value. * This is equivalent to *

 {@code
-     * if (map.containsKey(key) && map.get(key).equals(value)) {
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
      *   map.remove(key);
      *   return true;
      * } else
@@ -101,8 +116,8 @@ public interface ConcurrentMap extends Map {
      *
      * @param key key with which the specified value is associated
      * @param value value expected to be associated with the specified key
-     * @return true if the value was removed
-     * @throws UnsupportedOperationException if the remove operation
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this map
      * @throws ClassCastException if the key or value is of an inappropriate
      *         type for this map
@@ -117,7 +132,7 @@ public interface ConcurrentMap extends Map {
      * Replaces the entry for a key only if currently mapped to a given value.
      * This is equivalent to
      *  
 {@code
-     * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
+     * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
      *   map.put(key, newValue);
      *   return true;
      * } else
@@ -128,8 +143,8 @@ public interface ConcurrentMap extends Map {
      * @param key key with which the specified value is associated
      * @param oldValue value expected to be associated with the specified key
      * @param newValue value to be associated with the specified key
-     * @return true if the value was replaced
-     * @throws UnsupportedOperationException if the put operation
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
      *         is not supported by this map
      * @throws ClassCastException if the class of a specified key or value
      *         prevents it from being stored in this map
@@ -154,11 +169,11 @@ public interface ConcurrentMap extends Map {
      * @param key key with which the specified value is associated
      * @param value value to be associated with the specified key
      * @return the previous value associated with the specified key, or
-     *         null if there was no mapping for the key.
-     *         (A null return can also indicate that the map
-     *         previously associated null with the key,
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
      *         if the implementation supports null values.)
-     * @throws UnsupportedOperationException if the put operation
+     * @throws UnsupportedOperationException if the {@code put} operation
      *         is not supported by this map
      * @throws ClassCastException if the class of the specified key or value
      *         prevents it from being stored in this map
diff --git a/jdk/test/java/util/Map/Defaults.java b/jdk/test/java/util/Map/Defaults.java
new file mode 100644
index 00000000000..92a2cb30b69
--- /dev/null
+++ b/jdk/test/java/util/Map/Defaults.java
@@ -0,0 +1,594 @@
+/*
+ * 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 8010122 8004518
+ * @summary Test Map default methods
+ * @author Mike Duigou
+ * @run testng Defaults
+ */
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.function.Supplier;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.fail;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+
+public class Defaults {
+
+    @Test(dataProvider = "Nulls Map")
+    public void testGetOrDefaultNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), "values should match");
+    }
+
+    @Test(dataProvider = "Map")
+    public void testGetOrDefault(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]), "expected key missing");
+        assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
+        assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
+        assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
+        assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testPutIfAbsentNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
+        assertTrue(map.containsKey(null), "null key absent");
+        assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
+        assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value");
+        assertTrue(map.containsKey(null), "null key absent");
+        assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
+        assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
+
+        assertFalse(map.containsKey(null), description + ": key present after remove");
+        assertNull(map.putIfAbsent(null, null), "previous not null");
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
+        assertSame(map.get(null), EXTRA_VALUE, "value not expected");
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testPutIfAbsent(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object expected = map.get(KEYS[1]);
+        assertTrue(null == expected || expected == VALUES[1]);
+        assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected);
+        assertSame(map.get(KEYS[1]), expected);
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null);
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+    }
+
+    @Test(dataProvider = "Nulls Map")
+    public void testForEach(String description, Map map) {
+        IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
+
+        map.forEach((k, v) -> {
+            int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
+            assertNull(EACH_KEY[idx]);
+            EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
+            assertSame(v, map.get(k));
+        });
+
+        assertEquals(KEYS, EACH_KEY);
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public static void testRemoveNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertFalse(map.remove(null, EXTRA_VALUE), description);
+        assertTrue(map.containsKey(null));
+        assertNull(map.get(null));
+        assertTrue(map.remove(null, null));
+        assertFalse(map.containsKey(null));
+        assertNull(map.get(null));
+        assertFalse(map.remove(null, null));
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public static void testRemove(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object expected = map.get(KEYS[1]);
+        assertTrue(null == expected || expected == VALUES[1]);
+        assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description);
+        assertSame(map.get(KEYS[1]), expected);
+        assertTrue(map.remove(KEYS[1], expected));
+        assertNull(map.get(KEYS[1]));
+        assertFalse(map.remove(KEYS[1], expected));
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testReplaceKVNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertSame(map.replace(null, EXTRA_VALUE), null);
+        assertSame(map.get(null), EXTRA_VALUE);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testReplaceKV(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object expected = map.get(KEYS[1]);
+        assertTrue(null == expected || expected == VALUES[1]);
+        assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
+        assertSame(map.get(KEYS[1]), EXTRA_VALUE);
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertNull(map.get(EXTRA_KEY));
+        assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+        assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
+        assertSame(map.get(EXTRA_KEY), expected);
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testReplaceKVVNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
+        assertNull(map.get(null));
+        assertTrue(map.replace(null, null, EXTRA_VALUE));
+        assertSame(map.get(null), EXTRA_VALUE);
+        assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
+        assertSame(map.get(null), EXTRA_VALUE);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testReplaceKVV(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object expected = map.get(KEYS[1]);
+        assertTrue(null == expected || expected == VALUES[1]);
+        assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
+        assertSame(map.get(KEYS[1]), expected);
+        assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
+        assertSame(map.get(KEYS[1]), EXTRA_VALUE);
+        assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
+        assertSame(map.get(KEYS[1]), EXTRA_VALUE);
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertNull(map.get(EXTRA_KEY));
+        assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
+        assertTrue(map.containsKey(EXTRA_KEY));
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+        assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testComputeIfAbsentNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description);
+        assertSame(map.get(null), EXTRA_VALUE, description);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testComputeIfAbsent(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object expected = map.get(KEYS[1]);
+        assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
+        expected = (null == expected) ? EXTRA_VALUE : expected;
+        assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
+        assertSame(map.get(KEYS[1]), expected, description);
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testComputeIfPresentNulls(String description, Map map) {
+        assertTrue(map.containsKey(null));
+        assertNull(map.get(null));
+        assertSame(map.computeIfPresent(null, (k, v) -> {
+            fail();
+            return EXTRA_VALUE;
+        }), null, description);
+        assertTrue(map.containsKey(null));
+        assertSame(map.get(null), null, description);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testComputeIfPresent(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object value = map.get(KEYS[1]);
+        assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
+        Object expected = (null == value) ? null : EXTRA_VALUE;
+        assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
+            assertSame(v, value);
+            return EXTRA_VALUE;
+        }), expected, description);
+        assertSame(map.get(KEYS[1]), expected, description);
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
+            fail();
+            return EXTRA_VALUE;
+        }), null);
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.get(EXTRA_KEY), null);
+    }
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testComputeNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertSame(map.compute(null, (k, v) -> {
+            assertSame(k, null);
+            assertNull(v);
+            return EXTRA_VALUE;
+        }), EXTRA_VALUE, description);
+        assertTrue(map.containsKey(null));
+        assertSame(map.get(null), EXTRA_VALUE, description);
+        assertSame(map.remove(null), EXTRA_VALUE, "removed value not expected");
+        assertFalse(map.containsKey(null), "null key present");
+        assertSame(map.compute(null, (k, v) -> {
+            assertSame(k, null);
+            assertNull(v);
+            return null;
+        }), null, description);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testCompute(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object value = map.get(KEYS[1]);
+        assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
+        assertSame(map.compute(KEYS[1], (k, v) -> {
+            assertSame(k, KEYS[1]);
+            assertSame(v, value);
+            return EXTRA_VALUE;
+        }), EXTRA_VALUE, description);
+        assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
+        assertNull(map.compute(KEYS[1], (k, v) -> {
+            assertSame(v, EXTRA_VALUE);
+            return null;
+        }), description);
+        assertFalse(map.containsKey(KEYS[1]));
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.compute(EXTRA_KEY, (k, v) -> {
+            assertNull(v);
+            return EXTRA_VALUE;
+        }), EXTRA_VALUE);
+        assertTrue(map.containsKey(EXTRA_KEY));
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+    }
+
+
+    @Test(dataProvider = "R/W Nulls Map")
+    public void testMergeNulls(String description, Map map) {
+        assertTrue(map.containsKey(null), "null key absent");
+        assertNull(map.get(null), "value not null");
+        assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> {
+            assertNull(v);
+            assertSame(vv, EXTRA_VALUE);
+            return vv;
+        }), EXTRA_VALUE, description);
+        assertTrue(map.containsKey(null));
+        assertSame(map.get(null), EXTRA_VALUE, description);
+    }
+
+    @Test(dataProvider = "R/W Map")
+    public void testMerge(String description, Map map) {
+        assertTrue(map.containsKey(KEYS[1]));
+        Object value = map.get(KEYS[1]);
+        assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
+        assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
+            assertSame(v, value);
+            assertSame(vv, EXTRA_VALUE);
+            return vv;
+        }), EXTRA_VALUE, description);
+        assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
+        assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
+            assertSame(v, EXTRA_VALUE);
+            assertSame(vv, EXTRA_VALUE);
+            return null;
+        }), description);
+        assertFalse(map.containsKey(KEYS[1]));
+
+        assertFalse(map.containsKey(EXTRA_KEY));
+        assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> {
+            assertNull(v);
+            assertSame(vv, EXTRA_VALUE);
+            return EXTRA_VALUE;
+        }), EXTRA_VALUE);
+        assertTrue(map.containsKey(EXTRA_KEY));
+        assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
+    }
+
+    enum IntegerEnum {
+
+        e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
+        e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
+        e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
+        e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
+        e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
+        e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
+        e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
+        e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
+        e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
+        e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
+        EXTRA_KEY;
+        public static final int SIZE = values().length;
+    };
+    private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
+    /**
+     * Realized keys ensure that there is always a hard ref to all test objects.
+     */
+    private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
+    /**
+     * Realized values ensure that there is always a hard ref to all test
+     * objects.
+     */
+    private static final String[] VALUES = new String[TEST_SIZE];
+
+    static {
+        IntegerEnum[] keys = IntegerEnum.values();
+        for (int each = 0; each < TEST_SIZE; each++) {
+            KEYS[each] = keys[each];
+            VALUES[each] = String.valueOf(each);
+        }
+    }
+    private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
+    private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
+
+    @DataProvider(name = "Map", parallel = true)
+    public static Iterator allNullsMapProvider() {
+        return makeAllMaps().iterator();
+    }
+
+    @DataProvider(name = "Nulls Map", parallel = true)
+    public static Iterator allMapProvider() {
+        return makeRWMaps(true).iterator();
+    }
+
+    @DataProvider(name = "R/W Map", parallel = true)
+    public static Iterator rwMapProvider() {
+        return makeRWMapsNoNulls().iterator();
+    }
+
+    @DataProvider(name = "R/W Nulls Map", parallel = true)
+    public static Iterator rwNullsMapProvider() {
+        return makeRWMaps(true).iterator();
+    }
+
+    private static Collection makeAllMapsNoNulls() {
+        Collection all = new ArrayList<>();
+
+        all.addAll(makeRWMaps(false));
+        all.addAll(makeRWNoNullsMaps());
+        all.addAll(makeROMaps(false));
+
+        return all;
+    }
+
+    private static Collection makeRWMapsNoNulls() {
+        Collection all = new ArrayList<>();
+
+        all.addAll(makeRWMaps(false));
+        all.addAll(makeRWNoNullsMaps());
+
+        return all;
+    }
+
+    private static Collection makeAllMaps() {
+        Collection all = new ArrayList<>();
+
+        all.addAll(makeROMaps(false));
+        all.addAll(makeRWMaps(false));
+        all.addAll(makeRWNoNullsMaps());
+        all.addAll(makeRWMaps(true));
+        all.addAll(makeROMaps(true));
+
+        return all;
+    }
+
+    private static Collection makeAllRWMaps() {
+        Collection all = new ArrayList<>();
+
+        all.addAll(makeRWMaps(false));
+        all.addAll(makeRWNoNullsMaps());
+        all.addAll(makeRWMaps(true));
+
+        return all;
+    }
+
+    private static Collection makeRWMaps(boolean nulls) {
+        return Arrays.asList(
+            new Object[]{"HashMap", makeMap(HashMap::new, nulls)},
+            new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nulls)},
+            new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nulls)},
+            new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nulls)},
+            new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nulls), IntegerEnum.class, String.class)},
+            new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nulls))},
+            new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nulls)});
+    }
+
+    private static Collection makeRWNoNullsMaps() {
+        return Arrays.asList(
+            // null hostile
+            new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false)},
+            new Object[]{"Hashtable", makeMap(Hashtable::new, false)},
+            new Object[]{"TreeMap", makeMap(TreeMap::new, false)},
+            new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false)},
+            new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false)},
+            new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false), IntegerEnum.class, String.class)},
+            new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false))},
+            new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false)});
+    }
+
+    private static Collection makeROMaps(boolean nulls) {
+        return Arrays.asList(new Object[][]{
+            new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls))}
+        });
+    }
+
+    private static Map makeMap(Supplier> supplier, boolean nulls) {
+        Map result = supplier.get();
+
+        for (int each = 0; each < TEST_SIZE; each++) {
+            if (nulls) {
+                result.put((each == 0) ? null : KEYS[each], null);
+            } else {
+                result.put(KEYS[each], VALUES[each]);
+            }
+        }
+
+        return result;
+    }
+
+    public interface Thrower {
+
+        public void run() throws T;
+    }
+
+    public static  void assertThrows(Thrower thrower, Class throwable) {
+        assertThrows(thrower, throwable, null);
+    }
+
+    public static  void assertThrows(Thrower thrower, Class throwable, String message) {
+        Throwable result;
+        try {
+            thrower.run();
+            result = null;
+        } catch (Throwable caught) {
+            result = caught;
+        }
+
+        assertInstance(result, throwable,
+            (null != message)
+            ? message
+            : "Failed to throw " + throwable.getCanonicalName());
+    }
+
+    public static  void assertInstance(T actual, Class expected) {
+        assertInstance(expected.isInstance(actual), null);
+    }
+
+    public static  void assertInstance(T actual, Class expected, String message) {
+        assertTrue(expected.isInstance(actual), message);
+    }
+
+    /**
+     * A simple mutable map implementation that provides only default
+     * implementations of all methods. ie. none of the Map interface default
+     * methods have overridden implementations.
+     *
+     * @param  Type of keys
+     * @param  Type of values
+     */
+    public static class ExtendsAbstractMap, K, V> extends AbstractMap {
+
+        protected final M map;
+
+        public ExtendsAbstractMap() { this( (M) new HashMap()); }
+
+        protected ExtendsAbstractMap(M map) { this.map = map; }
+
+        public Set> entrySet() {
+            return new AbstractSet>() {
+                public int size() {
+                    return map.size();
+                }
+
+                public Iterator> iterator() {
+                    final Iterator> source = map.entrySet().iterator();
+                    return new Iterator>() {
+                       public boolean hasNext() { return source.hasNext(); }
+                       public Map.Entry next() { return source.next(); }
+                       public void remove() { source.remove(); }
+                    };
+                }
+
+                public boolean add(Map.Entry e) {
+                    return map.entrySet().add(e);
+                }
+            };
+        }
+
+        public V put(K key, V value) {
+            return map.put(key, value);
+        }
+    }
+
+    /**
+     * A simple mutable concurrent map implementation that provides only default
+     * implementations of all methods. ie. none of the ConcurrentMap interface
+     * default methods have overridden implementations.
+     *
+     * @param  Type of keys
+     * @param  Type of values
+     */
+    public static class ImplementsConcurrentMap extends ExtendsAbstractMap, K, V> implements ConcurrentMap {
+        public ImplementsConcurrentMap() { super(new ConcurrentHashMap()); }
+
+        // ConcurrentMap reabstracts these methods
+
+        public V replace(K k, V v) { return map.replace(k, v); };
+
+        public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); };
+
+        public boolean remove(Object k, Object v) { return map.remove(k, v); }
+
+        public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); }
+    }
+}

From dfcf6055a75dc3dbe35503674e7b61e266e59046 Mon Sep 17 00:00:00 2001
From: Weijun Wang 
Date: Wed, 17 Apr 2013 10:15:33 +0800
Subject: [PATCH 34/36] 8011124: Make KerberosTime immutable

Reviewed-by: xuelei
---
 .../classes/sun/security/krb5/KrbApReq.java   |  12 +-
 .../sun/security/krb5/KrbAppMessage.java      |  14 +-
 .../classes/sun/security/krb5/KrbCred.java    |   2 +-
 .../classes/sun/security/krb5/KrbTgsReq.java  |   3 +-
 .../security/krb5/internal/KerberosTime.java  | 202 ++++++------------
 .../security/krb5/internal/KrbCredInfo.java   |  12 +-
 .../security/krb5/internal/LastReqEntry.java  |   2 +-
 .../security/krb5/internal/PAEncTSEnc.java    |   2 +-
 .../krb5/internal/ccache/Credentials.java     |  42 ++--
 jdk/test/sun/security/krb5/MicroTime.java     |   6 +-
 10 files changed, 110 insertions(+), 187 deletions(-)

diff --git a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
index 535bb0dc52f..2bc01f693f5 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
@@ -204,7 +204,7 @@ public class KrbApReq {
         int usage)
         throws KrbException, IOException {
 
-        ctime = new KerberosTime(KerberosTime.NOW);
+        ctime = KerberosTime.now();
         init(options,
              tgs_creds.ticket,
              tgs_creds.key,
@@ -287,14 +287,14 @@ public class KrbApReq {
         authenticator = new Authenticator(temp2);
         ctime = authenticator.ctime;
         cusec = authenticator.cusec;
-        authenticator.ctime.setMicroSeconds(authenticator.cusec);
+        authenticator.ctime =
+                authenticator.ctime.withMicroSeconds(authenticator.cusec);
 
         if (!authenticator.cname.equals(enc_ticketPart.cname)) {
             throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);
         }
 
-        KerberosTime currTime = new KerberosTime(KerberosTime.NOW);
-        if (!authenticator.ctime.inClockSkew(currTime))
+        if (!authenticator.ctime.inClockSkew())
             throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
 
         // start to check if it is a replay attack.
@@ -304,7 +304,7 @@ public class KrbApReq {
         if (table.get(time, authenticator.cname.toString()) != null) {
             throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
         } else {
-            table.put(client, time, currTime.getTime());
+            table.put(client, time, System.currentTimeMillis());
         }
 
         if (initiator != null) {
@@ -329,7 +329,7 @@ public class KrbApReq {
         // else
         //    save authenticator to check for later
 
-        KerberosTime now = new KerberosTime(KerberosTime.NOW);
+        KerberosTime now = KerberosTime.now();
 
         if ((enc_ticketPart.starttime != null &&
              enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java b/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
index cf19cf98242..47aa1681a1a 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
@@ -71,12 +71,18 @@ abstract class KrbAppMessage {
         }
 
         if (packetTimestamp != null) {
-            packetTimestamp.setMicroSeconds(packetUsec);
-            if (!packetTimestamp.inClockSkew())
+            if (packetUsec != null) {
+                packetTimestamp =
+                    packetTimestamp.withMicroSeconds(packetUsec.intValue());
+            }
+            if (!packetTimestamp.inClockSkew()) {
                 throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
-        } else
-            if (timestampRequired)
+            }
+        } else {
+            if (timestampRequired) {
                 throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
+            }
+        }
 
         // XXX check replay cache
         // if (rcache.repeated(packetTimestamp, packetUsec, packetSAddress))
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbCred.java b/jdk/src/share/classes/sun/security/krb5/KrbCred.java
index 9a131811959..64dada1d35e 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbCred.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbCred.java
@@ -103,7 +103,7 @@ public class KrbCred {
                                                delegatedCreds.renewTill, tgService,
                                                delegatedCreds.cAddr);
 
-        timeStamp = new KerberosTime(KerberosTime.NOW);
+        timeStamp = KerberosTime.now();
         KrbCredInfo[] credInfos = {credInfo};
         EncKrbCredPart encPart =
             new EncKrbCredPart(credInfos,
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java b/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
index 9cd84c6d9a4..32263b53770 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
@@ -147,8 +147,7 @@ public class KrbTgsReq {
 
         princName = cname;
         servName = sname;
-        ctime = new KerberosTime(KerberosTime.NOW);
-
+        ctime = KerberosTime.now();
 
         // check if they are valid arguments. The optional fields
         // should be  consistent with settings in KDCOptions.
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
index ce141419f83..3beaac873ce 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
@@ -30,18 +30,20 @@
 
 package sun.security.krb5.internal;
 
-import java.util.TimeZone;
-import sun.security.util.*;
+import sun.security.krb5.Asn1Exception;
 import sun.security.krb5.Config;
 import sun.security.krb5.KrbException;
-import sun.security.krb5.Asn1Exception;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Calendar;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+
 import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
 
 /**
- * Implements the ASN.1 KerberosTime type.
+ * Implements the ASN.1 KerberosTime type. This is an immutable class.
  *
  * 
  * KerberosTime    ::= GeneralizedTime -- with no fractional seconds
@@ -62,55 +64,38 @@ import java.io.IOException;
  * same class can be used as a precise timestamp in Authenticator etc.
  */
 
-public class KerberosTime implements Cloneable {
+public class KerberosTime {
 
-    private long kerberosTime; // milliseconds since epoch, a Date.getTime() value
-    private int  microSeconds; // the last three digits of the microsecond value
+    private final long kerberosTime; // milliseconds since epoch, Date.getTime()
+    private final int  microSeconds; // last 3 digits of the real microsecond
 
     // The time when this class is loaded. Used in setNow()
     private static long initMilli = System.currentTimeMillis();
     private static long initMicro = System.nanoTime() / 1000;
 
-    private static long syncTime;
     private static boolean DEBUG = Krb5.DEBUG;
 
-    public static final boolean NOW = true;
-    public static final boolean UNADJUSTED_NOW = false;
-
-    public KerberosTime(long time) {
-        kerberosTime = time;
-    }
-
+    // Do not make this public. It's a little confusing that micro
+    // is only the last 3 digits of microsecond.
     private KerberosTime(long time, int micro) {
         kerberosTime = time;
         microSeconds = micro;
     }
 
-    public Object clone() {
-        return new KerberosTime(kerberosTime, microSeconds);
+    /**
+     * Creates a KerberosTime object from milliseconds since epoch.
+     */
+    public KerberosTime(long time) {
+        this(time, 0);
     }
 
     // This constructor is used in the native code
     // src/windows/native/sun/security/krb5/NativeCreds.c
     public KerberosTime(String time) throws Asn1Exception {
-        kerberosTime = toKerberosTime(time);
-    }
-
-    /**
-     * Constructs a KerberosTime object.
-     * @param encoding a DER-encoded data.
-     * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
-     * @exception IOException if an I/O error occurs while reading encoded data.
-     */
-    public KerberosTime(DerValue encoding) throws Asn1Exception, IOException {
-        GregorianCalendar calendar = new GregorianCalendar();
-        Date temp = encoding.getGeneralizedTime();
-        kerberosTime = temp.getTime();
+        this(toKerberosTime(time), 0);
     }
 
     private static long toKerberosTime(String time) throws Asn1Exception {
-        // this method only used by KerberosTime class.
-
         // ASN.1 GeneralizedTime format:
 
         // "19700101000000Z"
@@ -133,30 +118,34 @@ public class KerberosTime implements Cloneable {
                      Integer.parseInt(time.substring(8, 10)),
                      Integer.parseInt(time.substring(10, 12)),
                      Integer.parseInt(time.substring(12, 14)));
-
-        //The Date constructor assumes the setting are local relative
-        //and converts the time to UTC before storing it.  Since we
-        //want the internal representation to correspond to local
-        //and not UTC time we subtract the UTC time offset.
-        return (calendar.getTime().getTime());
-
-    }
-
-    // should be moved to sun.security.krb5.util class
-    public static String zeroPad(String s, int length) {
-        StringBuffer temp = new StringBuffer(s);
-        while (temp.length() < length)
-            temp.insert(0, '0');
-        return temp.toString();
+        return calendar.getTimeInMillis();
     }
 
+    /**
+     * Creates a KerberosTime object from a Date object.
+     */
     public KerberosTime(Date time) {
-        kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
+        this(time.getTime(), 0);
     }
 
-    public KerberosTime(boolean initToNow) {
-        if (initToNow) {
-            setNow();
+    /**
+     * Creates a KerberosTime object for now. It uses System.nanoTime()
+     * to get a more precise time than "new Date()".
+     */
+    public static KerberosTime now() {
+        long newMilli = System.currentTimeMillis();
+        long newMicro = System.nanoTime() / 1000;
+        long microElapsed = newMicro - initMicro;
+        long calcMilli = initMilli + microElapsed/1000;
+        if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
+            if (DEBUG) {
+                System.out.println("System time adjusted");
+            }
+            initMilli = newMilli;
+            initMicro = newMicro;
+            return new KerberosTime(newMilli, 0);
+        } else {
+            return new KerberosTime(calcMilli, (int)(microElapsed % 1000));
         }
     }
 
@@ -169,13 +158,13 @@ public class KerberosTime implements Cloneable {
         calendar.clear();
 
         calendar.setTimeInMillis(kerberosTime);
-        return zeroPad(Integer.toString(calendar.get(Calendar.YEAR)), 4) +
-            zeroPad(Integer.toString(calendar.get(Calendar.MONTH) + 1), 2) +
-            zeroPad(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), 2) +
-            zeroPad(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)), 2) +
-            zeroPad(Integer.toString(calendar.get(Calendar.MINUTE)), 2) +
-            zeroPad(Integer.toString(calendar.get(Calendar.SECOND)), 2) + 'Z';
-
+        return String.format("%04d%02d%02d%02d%02d%02dZ",
+                calendar.get(Calendar.YEAR),
+                calendar.get(Calendar.MONTH) + 1,
+                calendar.get(Calendar.DAY_OF_MONTH),
+                calendar.get(Calendar.HOUR_OF_DAY),
+                calendar.get(Calendar.MINUTE),
+                calendar.get(Calendar.SECOND));
     }
 
     /**
@@ -194,40 +183,8 @@ public class KerberosTime implements Cloneable {
         return kerberosTime;
     }
 
-
-    public void setTime(Date time) {
-        kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
-        microSeconds = 0;
-    }
-
-    public void setTime(long time) {
-        kerberosTime = time;
-        microSeconds = 0;
-    }
-
     public Date toDate() {
-        Date temp = new Date(kerberosTime);
-        temp.setTime(temp.getTime());
-        return temp;
-    }
-
-    public void setNow() {
-        long newMilli = System.currentTimeMillis();
-        long newMicro = System.nanoTime() / 1000;
-        long microElapsed = newMicro - initMicro;
-        long calcMilli = initMilli + microElapsed/1000;
-        if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
-            if (DEBUG) {
-                System.out.println("System time adjusted");
-            }
-            initMilli = newMilli;
-            initMicro = newMicro;
-            setTime(newMilli);
-            microSeconds = 0;
-        } else {
-            setTime(calcMilli);
-            microSeconds = (int)(microElapsed % 1000);
-        }
+        return new Date(kerberosTime);
     }
 
     public int getMicroSeconds() {
@@ -235,45 +192,25 @@ public class KerberosTime implements Cloneable {
         return temp_long.intValue() + microSeconds;
     }
 
-    public void setMicroSeconds(int usec) {
-        microSeconds = usec % 1000;
-        Integer temp_int = new Integer(usec);
-        long temp_long = temp_int.longValue() / 1000L;
-        kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
+    /**
+     * Returns a new KerberosTime object with the original seconds
+     * and the given microseconds.
+     */
+    public KerberosTime withMicroSeconds(int usec) {
+        return new KerberosTime(
+                kerberosTime - kerberosTime%1000L + usec/1000L,
+                usec%1000);
     }
 
-    public void setMicroSeconds(Integer usec) {
-        if (usec != null) {
-            microSeconds = usec.intValue() % 1000;
-            long temp_long = usec.longValue() / 1000L;
-            kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
-        }
-    }
-
-    public boolean inClockSkew(int clockSkew) {
-        KerberosTime now = new KerberosTime(KerberosTime.NOW);
-
-        if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
-            clockSkew * 1000L)
-            return false;
-        return true;
+    private boolean inClockSkew(int clockSkew) {
+        return java.lang.Math.abs(kerberosTime - System.currentTimeMillis())
+                <= clockSkew * 1000L;
     }
 
     public boolean inClockSkew() {
         return inClockSkew(getDefaultSkew());
     }
 
-    public boolean inClockSkew(int clockSkew, KerberosTime now) {
-        if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
-            clockSkew * 1000L)
-            return false;
-        return true;
-    }
-
-    public boolean inClockSkew(KerberosTime time) {
-        return inClockSkew(getDefaultSkew(), time);
-    }
-
     public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {
         if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)
             return true;
@@ -317,24 +254,22 @@ public class KerberosTime implements Cloneable {
         return temp_long.intValue();
     }
 
-    public void setSeconds(int sec) {
-        Integer temp_int = new Integer(sec);
-        kerberosTime = temp_int.longValue() * 1000L;
-    }
-
     /**
      * Parse (unmarshal) a kerberostime from a DER input stream.  This form
      * parsing might be used when expanding a value which is part of
      * a constructed sequence and uses explicitly tagged type.
      *
      * @exception Asn1Exception on error.
-     * @param data the Der input stream value, which contains one or more marshaled value.
+     * @param data the Der input stream value, which contains
+     *             one or more marshaled value.
      * @param explicitTag tag number.
      * @param optional indicates if this data field is optional
      * @return an instance of KerberosTime.
      *
      */
-    public static KerberosTime parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException {
+    public static KerberosTime parse(
+            DerInputStream data, byte explicitTag, boolean optional)
+            throws Asn1Exception, IOException {
         if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))
             return null;
         DerValue der = data.getDerValue();
@@ -343,7 +278,8 @@ public class KerberosTime implements Cloneable {
         }
         else {
             DerValue subDer = der.getData().getDerValue();
-            return new KerberosTime(subDer);
+            Date temp = subDer.getGeneralizedTime();
+            return new KerberosTime(temp.getTime(), 0);
         }
     }
 
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java b/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
index 4acf451cc6c..18fa7412fac 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
@@ -187,14 +187,10 @@ public class KrbCredInfo {
             kcred.pname = (PrincipalName)pname.clone();
         if (flags != null)
             kcred.flags = (TicketFlags)flags.clone();
-        if (authtime != null)
-            kcred.authtime = (KerberosTime)authtime.clone();
-        if (starttime != null)
-            kcred.starttime = (KerberosTime)starttime.clone();
-        if (endtime != null)
-            kcred.endtime = (KerberosTime)endtime.clone();
-        if (renewTill != null)
-            kcred.renewTill = (KerberosTime)renewTill.clone();
+        kcred.authtime = authtime;
+        kcred.starttime = starttime;
+        kcred.endtime = endtime;
+        kcred.renewTill = renewTill;
         if (sname != null)
             kcred.sname = (PrincipalName)sname.clone();
         if (caddr != null)
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java b/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
index fa4ae0a5e11..396d3b8df03 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
@@ -90,7 +90,7 @@ public class LastReqEntry {
     public Object clone() {
         LastReqEntry newEntry = new LastReqEntry();
         newEntry.lrType = lrType;
-        newEntry.lrValue = (KerberosTime)lrValue.clone();
+        newEntry.lrValue = lrValue;
         return newEntry;
     }
 }
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java b/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
index e5f2f755be9..83375647046 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
@@ -65,7 +65,7 @@ public class PAEncTSEnc {
     }
 
     public PAEncTSEnc() {
-        KerberosTime now = new KerberosTime(KerberosTime.NOW);
+        KerberosTime now = KerberosTime.now();
         pATimeStamp = now;
         pAUSec = new Integer(now.getMicroSeconds());
     }
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java
index f27a1588ec3..7128545a25a 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java
@@ -68,14 +68,11 @@ public class Credentials {
         sname = (PrincipalName) new_sname.clone();
         key = (EncryptionKey) new_key.clone();
 
-        authtime = (KerberosTime) new_authtime.clone();
-        if (new_starttime != null) {
-            starttime = (KerberosTime) new_starttime.clone();
-        }
-        endtime = (KerberosTime) new_endtime.clone();
-        if (new_renewTill != null) {
-            renewTill = (KerberosTime) new_renewTill.clone();
-        }
+        authtime = new_authtime;
+        starttime = new_starttime;
+        endtime = new_endtime;
+        renewTill = new_renewTill;
+
         if (new_caddr != null) {
             caddr = (HostAddresses) new_caddr.clone();
         }
@@ -104,14 +101,11 @@ public class Credentials {
         ticket = (Ticket) kdcRep.ticket.clone();
         key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
         flags = (TicketFlags) kdcRep.encKDCRepPart.flags.clone();
-        authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone();
-        if (kdcRep.encKDCRepPart.starttime != null) {
-            starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone();
-        }
-        endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone();
-        if (kdcRep.encKDCRepPart.renewTill != null) {
-            renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone();
-        }
+        authtime = kdcRep.encKDCRepPart.authtime;
+        starttime = kdcRep.encKDCRepPart.starttime;
+        endtime = kdcRep.encKDCRepPart.endtime;
+        renewTill = kdcRep.encKDCRepPart.renewTill;
+
         sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
         caddr = (HostAddresses) kdcRep.encKDCRepPart.caddr.clone();
         secondTicket = (Ticket) new_secondTicket.clone();
@@ -128,18 +122,10 @@ public class Credentials {
         sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
         cname = (PrincipalName) kdcRep.cname.clone();
         key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
-        authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone();
-        if (kdcRep.encKDCRepPart.starttime != null) {
-            starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone();
-        } else {
-            starttime = null;
-        }
-        endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone();
-        if (kdcRep.encKDCRepPart.renewTill != null) {
-            renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone();
-        } else {
-            renewTill = null;
-        }
+        authtime = kdcRep.encKDCRepPart.authtime;
+        starttime = kdcRep.encKDCRepPart.starttime;
+        endtime = kdcRep.encKDCRepPart.endtime;
+        renewTill = kdcRep.encKDCRepPart.renewTill;
         // if (kdcRep.msgType == Krb5.KRB_AS_REP) {
         //    isEncInSKey = false;
         //    secondTicket = null;
diff --git a/jdk/test/sun/security/krb5/MicroTime.java b/jdk/test/sun/security/krb5/MicroTime.java
index 6bbf8b8e974..e22f330df32 100644
--- a/jdk/test/sun/security/krb5/MicroTime.java
+++ b/jdk/test/sun/security/krb5/MicroTime.java
@@ -22,7 +22,7 @@
  */
 /*
  * @test
- * @bug 6882687
+ * @bug 6882687 8011124
  * @summary KerberosTime too imprecise
  */
 
@@ -32,11 +32,11 @@ public class MicroTime {
     public static void main(String[] args) throws Exception {
         // We count how many different KerberosTime values
         // can be acquired within one second.
-        KerberosTime t1 = new KerberosTime(true);
+        KerberosTime t1 = KerberosTime.now();
         KerberosTime last = t1;
         int count = 0;
         while (true) {
-            KerberosTime t2 = new KerberosTime(true);
+            KerberosTime t2 = KerberosTime.now();
             if (t2.getTime() - t1.getTime() > 1000) break;
             if (!last.equals(t2)) {
                 last = t2;

From 176ed8d94c997a2880d06882358304125b93e43a Mon Sep 17 00:00:00 2001
From: Mandy Chung <mchung@openjdk.org>
Date: Tue, 16 Apr 2013 21:39:52 -0700
Subject: [PATCH 35/36] 8010117: Annotate jdk caller sensitive methods with
 @sun.reflect.CallerSensitive

Reviewed-by: jrose, alanb, twisti
---
 jdk/make/java/java/FILES_c.gmk                |   1 -
 jdk/make/java/java/mapfile-vers               |   2 -
 jdk/make/java/java/reorder-i586               |   1 -
 jdk/make/java/java/reorder-sparc              |   1 -
 jdk/make/java/java/reorder-sparcv9            |   1 -
 jdk/makefiles/mapfiles/libjava/mapfile-vers   |   2 -
 jdk/makefiles/mapfiles/libjava/reorder-sparc  |   1 -
 .../mapfiles/libjava/reorder-sparcv9          |   1 -
 jdk/makefiles/mapfiles/libjava/reorder-x86    |   1 -
 jdk/src/share/classes/java/lang/Class.java    | 141 ++++++------
 .../share/classes/java/lang/ClassLoader.java  |  47 ++--
 jdk/src/share/classes/java/lang/Package.java  |   8 +-
 jdk/src/share/classes/java/lang/Runtime.java  |   8 +-
 .../classes/java/lang/SecurityManager.java    |   3 +-
 jdk/src/share/classes/java/lang/System.java   |  13 +-
 jdk/src/share/classes/java/lang/Thread.java   |   9 +-
 .../java/lang/invoke/BoundMethodHandle.java   |   4 +-
 .../classes/java/lang/invoke/MemberName.java  |  13 +-
 .../java/lang/invoke/MethodHandleImpl.java    |   8 +-
 .../java/lang/invoke/MethodHandleNatives.java | 121 +---------
 .../java/lang/invoke/MethodHandleProxies.java |   5 +-
 .../java/lang/invoke/MethodHandles.java       | 169 ++++++++------
 .../java/lang/reflect/Constructor.java        |   5 +-
 .../classes/java/lang/reflect/Field.java      | 147 ++++++++++--
 .../classes/java/lang/reflect/Method.java     |   5 +-
 .../classes/java/lang/reflect/Proxy.java      |  51 +++--
 .../java/security/AccessController.java       |  36 +--
 .../share/classes/java/sql/DriverManager.java |  68 +++---
 .../classes/java/util/ResourceBundle.java     |  33 ++-
 .../atomic/AtomicIntegerFieldUpdater.java     |  13 +-
 .../atomic/AtomicLongFieldUpdater.java        |  17 +-
 .../atomic/AtomicReferenceFieldUpdater.java   |  13 +-
 .../classes/java/util/logging/Logger.java     |  13 +-
 .../javax/script/ScriptEngineManager.java     |  13 +-
 jdk/src/share/classes/sun/misc/Unsafe.java    |  10 +-
 .../sun/reflect/CallerSensitive.java}         |  22 +-
 .../share/classes/sun/reflect/Reflection.java |  38 ++-
 jdk/src/share/javavm/export/jvm.h             |  17 +-
 jdk/src/share/native/java/lang/ClassLoader.c  |  18 --
 .../share/native/java/lang/SecurityManager.c  |   1 -
 jdk/src/share/native/sun/reflect/Reflection.c |   4 +-
 jdk/test/Makefile                             |   2 +-
 .../CallerSensitiveFinder.java                | 216 ++++++++++++++++++
 .../reflect/CallerSensitive/MethodFinder.java | 201 ++++++++++++++++
 .../MissingCallerSensitive.java               |  65 ++++++
 .../reflect/Reflection/GetCallerClass.java    |  37 +++
 .../Reflection/GetCallerClassTest.java        | 113 +++++++++
 .../reflect/Reflection/GetCallerClassTest.sh  |  68 ++++++
 48 files changed, 1267 insertions(+), 519 deletions(-)
 rename jdk/src/share/{native/java/lang/ResourceBundle.c => classes/sun/reflect/CallerSensitive.java} (70%)
 create mode 100644 jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java
 create mode 100644 jdk/test/sun/reflect/CallerSensitive/MethodFinder.java
 create mode 100644 jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java
 create mode 100644 jdk/test/sun/reflect/Reflection/GetCallerClass.java
 create mode 100644 jdk/test/sun/reflect/Reflection/GetCallerClassTest.java
 create mode 100644 jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh

diff --git a/jdk/make/java/java/FILES_c.gmk b/jdk/make/java/java/FILES_c.gmk
index 617780a42af..d01b0c29563 100644
--- a/jdk/make/java/java/FILES_c.gmk
+++ b/jdk/make/java/java/FILES_c.gmk
@@ -48,7 +48,6 @@ FILES_c = \
 	Proxy.c \
 	RandomAccessFile.c \
 	RandomAccessFile_md.c \
-	ResourceBundle.c \
 	Runtime.c \
 	SecurityManager.c \
 	Shutdown.c \
diff --git a/jdk/make/java/java/mapfile-vers b/jdk/make/java/java/mapfile-vers
index dc20bed7b9e..ca33582de6b 100644
--- a/jdk/make/java/java/mapfile-vers
+++ b/jdk/make/java/java/mapfile-vers
@@ -134,7 +134,6 @@ SUNWprivate_1.1 {
 		Java_java_lang_ClassLoader_00024NativeLibrary_load;
 		Java_java_lang_ClassLoader_00024NativeLibrary_unload;
 		Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
-		Java_java_lang_ClassLoader_getCaller; 
 		Java_java_lang_ClassLoader_registerNatives;
 		Java_java_lang_Compiler_registerNatives;
 		Java_java_lang_Double_longBitsToDouble;
@@ -233,7 +232,6 @@ SUNWprivate_1.1 {
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_getStackAccessControlContext;
 		Java_java_security_AccessController_getInheritedAccessControlContext;
-		Java_java_util_ResourceBundle_getClassContext;
 		Java_java_util_TimeZone_getSystemTimeZoneID;
 		Java_java_util_TimeZone_getSystemGMTOffsetID;
 		Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
diff --git a/jdk/make/java/java/reorder-i586 b/jdk/make/java/java/reorder-i586
index fc3202a8439..86fd4a53c3e 100644
--- a/jdk/make/java/java/reorder-i586
+++ b/jdk/make/java/java/reorder-i586
@@ -73,7 +73,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/make/java/java/reorder-sparc b/jdk/make/java/java/reorder-sparc
index 090f0001da2..6293ec799a7 100644
--- a/jdk/make/java/java/reorder-sparc
+++ b/jdk/make/java/java/reorder-sparc
@@ -78,7 +78,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/make/java/java/reorder-sparcv9 b/jdk/make/java/java/reorder-sparcv9
index b20b45ab960..29a530d8096 100644
--- a/jdk/make/java/java/reorder-sparcv9
+++ b/jdk/make/java/java/reorder-sparcv9
@@ -74,7 +74,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/makefiles/mapfiles/libjava/mapfile-vers b/jdk/makefiles/mapfiles/libjava/mapfile-vers
index dc20bed7b9e..ca33582de6b 100644
--- a/jdk/makefiles/mapfiles/libjava/mapfile-vers
+++ b/jdk/makefiles/mapfiles/libjava/mapfile-vers
@@ -134,7 +134,6 @@ SUNWprivate_1.1 {
 		Java_java_lang_ClassLoader_00024NativeLibrary_load;
 		Java_java_lang_ClassLoader_00024NativeLibrary_unload;
 		Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
-		Java_java_lang_ClassLoader_getCaller; 
 		Java_java_lang_ClassLoader_registerNatives;
 		Java_java_lang_Compiler_registerNatives;
 		Java_java_lang_Double_longBitsToDouble;
@@ -233,7 +232,6 @@ SUNWprivate_1.1 {
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_getStackAccessControlContext;
 		Java_java_security_AccessController_getInheritedAccessControlContext;
-		Java_java_util_ResourceBundle_getClassContext;
 		Java_java_util_TimeZone_getSystemTimeZoneID;
 		Java_java_util_TimeZone_getSystemGMTOffsetID;
 		Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
diff --git a/jdk/makefiles/mapfiles/libjava/reorder-sparc b/jdk/makefiles/mapfiles/libjava/reorder-sparc
index 32f9aaf2d8e..b64537e3edd 100644
--- a/jdk/makefiles/mapfiles/libjava/reorder-sparc
+++ b/jdk/makefiles/mapfiles/libjava/reorder-sparc
@@ -78,7 +78,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/makefiles/mapfiles/libjava/reorder-sparcv9 b/jdk/makefiles/mapfiles/libjava/reorder-sparcv9
index d64cb957793..8e6d249a440 100644
--- a/jdk/makefiles/mapfiles/libjava/reorder-sparcv9
+++ b/jdk/makefiles/mapfiles/libjava/reorder-sparcv9
@@ -74,7 +74,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/makefiles/mapfiles/libjava/reorder-x86 b/jdk/makefiles/mapfiles/libjava/reorder-x86
index deb78fb9799..ff4836f4612 100644
--- a/jdk/makefiles/mapfiles/libjava/reorder-x86
+++ b/jdk/makefiles/mapfiles/libjava/reorder-x86
@@ -73,7 +73,6 @@ text: .text%writeBytes;
 # Test Sleep
 # Test IntToString
 # Test LoadToolkit
-text: .text%Java_java_util_ResourceBundle_getClassContext;
 text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 text: .text%JNU_GetEnv;
 text: .text%Java_java_io_UnixFileSystem_checkAccess;
diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java
index 5fd388d657d..5593f2b4898 100644
--- a/jdk/src/share/classes/java/lang/Class.java
+++ b/jdk/src/share/classes/java/lang/Class.java
@@ -53,6 +53,7 @@ import java.util.Map;
 import java.util.HashMap;
 import java.util.Objects;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
 import sun.reflect.ConstantPool;
 import sun.reflect.Reflection;
 import sun.reflect.ReflectionFactory;
@@ -250,9 +251,11 @@ public final class Class<T> implements java.io.Serializable,
      *            by this method fails
      * @exception ClassNotFoundException if the class cannot be located
      */
+    @CallerSensitive
     public static Class<?> forName(String className)
                 throws ClassNotFoundException {
-        return forName0(className, true, ClassLoader.getCallerClassLoader());
+        return forName0(className, true,
+                        ClassLoader.getClassLoader(Reflection.getCallerClass()));
     }
 
 
@@ -317,6 +320,7 @@ public final class Class<T> implements java.io.Serializable,
      * @see       java.lang.ClassLoader
      * @since     1.2
      */
+    @CallerSensitive
     public static Class<?> forName(String name, boolean initialize,
                                    ClassLoader loader)
         throws ClassNotFoundException
@@ -324,7 +328,7 @@ public final class Class<T> implements java.io.Serializable,
         if (sun.misc.VM.isSystemDomainLoader(loader)) {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                ClassLoader ccl = ClassLoader.getCallerClassLoader();
+                ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
                 if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                     sm.checkPermission(
                         SecurityConstants.GET_CLASSLOADER_PERMISSION);
@@ -386,18 +390,14 @@ public final class Class<T> implements java.io.Serializable,
      *             </ul>
      *
      */
+    @CallerSensitive
     public T newInstance()
         throws InstantiationException, IllegalAccessException
     {
         if (System.getSecurityManager() != null) {
-            checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
+            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
         }
-        return newInstance0();
-    }
 
-    private T newInstance0()
-        throws InstantiationException, IllegalAccessException
-    {
         // NOTE: the following code may not be strictly correct under
         // the current Java memory model.
 
@@ -432,7 +432,7 @@ public final class Class<T> implements java.io.Serializable,
         // Security check (same as in java.lang.reflect.Constructor)
         int modifiers = tmpConstructor.getModifiers();
         if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
-            Class<?> caller = Reflection.getCallerClass(3);
+            Class<?> caller = Reflection.getCallerClass();
             if (newInstanceCallerCache != caller) {
                 Reflection.ensureMemberAccess(caller, this, null, modifiers);
                 newInstanceCallerCache = caller;
@@ -674,16 +674,14 @@ public final class Class<T> implements java.io.Serializable,
      * @see SecurityManager#checkPermission
      * @see java.lang.RuntimePermission
      */
+    @CallerSensitive
     public ClassLoader getClassLoader() {
         ClassLoader cl = getClassLoader0();
         if (cl == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
         }
         return cl;
     }
@@ -1392,11 +1390,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Class<?>[] getClasses() {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
 
         // Privileged so this implementation can look at DECLARED classes,
         // something the caller might not have privilege to do.  The code here
@@ -1467,11 +1463,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field[] getFields() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyFields(privateGetPublicFields(null));
     }
 
@@ -1518,11 +1512,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method[] getMethods() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyMethods(privateGetPublicMethods());
     }
 
@@ -1567,11 +1559,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<?>[] getConstructors() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return copyConstructors(privateGetDeclaredConstructors(true));
     }
 
@@ -1625,12 +1615,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field getField(String name)
         throws NoSuchFieldException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         Field field = getField0(name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -1710,12 +1698,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method getMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         Method method = getMethod0(name, parameterTypes);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
@@ -1764,12 +1750,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<T> getConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         return getConstructor0(parameterTypes, Member.PUBLIC);
     }
 
@@ -1807,11 +1791,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Class<?>[] getDeclaredClasses() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
         return getDeclaredClasses0();
     }
 
@@ -1851,11 +1833,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field[] getDeclaredFields() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyFields(privateGetDeclaredFields(false));
     }
 
@@ -1899,11 +1879,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method[] getDeclaredMethods() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyMethods(privateGetDeclaredMethods(false));
     }
 
@@ -1944,11 +1922,9 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return copyConstructors(privateGetDeclaredConstructors(false));
     }
 
@@ -1987,12 +1963,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Field getDeclaredField(String name)
         throws NoSuchFieldException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Field field = searchFields(privateGetDeclaredFields(false), name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -2042,12 +2016,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
@@ -2092,12 +2064,10 @@ public final class Class<T> implements java.io.Serializable,
      *
      * @since JDK1.1
      */
+    @CallerSensitive
     public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
-        // be very careful not to change the stack depth of this
-        // checkMemberAccess call for security reasons
-        // see java.lang.SecurityManager.checkMemberAccess
-        checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
+        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         return getConstructor0(parameterTypes, Member.DECLARED);
     }
 
@@ -2255,23 +2225,40 @@ public final class Class<T> implements java.io.Serializable,
      */
     static native Class<?> getPrimitiveClass(String name);
 
+    private static boolean isCheckMemberAccessOverridden(SecurityManager smgr) {
+        if (smgr.getClass() == SecurityManager.class) return false;
+
+        Class<?>[] paramTypes = new Class<?>[] {Class.class, int.class};
+        return smgr.getClass().getMethod0("checkMemberAccess", paramTypes).
+                getDeclaringClass() != SecurityManager.class;
+    }
 
     /*
      * Check if client is allowed to access members.  If access is denied,
      * throw a SecurityException.
      *
-     * Be very careful not to change the stack depth of this checkMemberAccess
-     * call for security reasons.
-     * See java.lang.SecurityManager.checkMemberAccess.
-     *
      * <p> Default policy: allow all clients access with normal Java access
      * control.
      */
-    private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) {
-        SecurityManager s = System.getSecurityManager();
+    private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {
+        final SecurityManager s = System.getSecurityManager();
         if (s != null) {
-            s.checkMemberAccess(this, which);
-            ClassLoader cl = getClassLoader0();
+            final ClassLoader ccl = ClassLoader.getClassLoader(caller);
+            final ClassLoader cl = getClassLoader0();
+            if (!isCheckMemberAccessOverridden(s)) {
+                // Inlined SecurityManager.checkMemberAccess
+                if (which != Member.PUBLIC) {
+                    if (ccl != cl) {
+                        s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+                    }
+                }
+            } else {
+                // Don't refactor; otherwise break the stack depth for
+                // checkMemberAccess of subclasses of SecurityManager as specified.
+                s.checkMemberAccess(this, which);
+            }
+
+
             if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
                 String name = this.getName();
                 int i = name.lastIndexOf('.');
diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java
index c41280d3c79..8d0205f54f1 100644
--- a/jdk/src/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java
@@ -55,6 +55,7 @@ import sun.misc.CompoundEnumeration;
 import sun.misc.Resource;
 import sun.misc.URLClassPath;
 import sun.misc.VM;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
@@ -1159,11 +1160,6 @@ public abstract class ClassLoader {
         return java.util.Collections.emptyEnumeration();
     }
 
-    // index 0: java.lang.ClassLoader.class
-    // index 1: the immediate caller of index 0.
-    // index 2: the immediate caller of index 1.
-    private static native Class<? extends ClassLoader> getCaller(int index);
-
     /**
      * Registers the caller as parallel capable.</p>
      * The registration succeeds if and only if all of the following
@@ -1179,8 +1175,11 @@ public abstract class ClassLoader {
      *
      * @since   1.7
      */
+    @CallerSensitive
     protected static boolean registerAsParallelCapable() {
-        return ParallelLoaders.register(getCaller(1));
+        Class<? extends ClassLoader> callerClass =
+            Reflection.getCallerClass().asSubclass(ClassLoader.class);
+        return ParallelLoaders.register(callerClass);
     }
 
     /**
@@ -1340,15 +1339,13 @@ public abstract class ClassLoader {
      *
      * @since  1.2
      */
+    @CallerSensitive
     public final ClassLoader getParent() {
         if (parent == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = getCallerClassLoader();
-            if (needsClassLoaderPermissionCheck(ccl, this)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            checkClassLoaderPermission(this, Reflection.getCallerClass());
         }
         return parent;
     }
@@ -1408,6 +1405,7 @@ public abstract class ClassLoader {
      *
      * @revised  1.4
      */
+    @CallerSensitive
     public static ClassLoader getSystemClassLoader() {
         initSystemClassLoader();
         if (scl == null) {
@@ -1415,10 +1413,7 @@ public abstract class ClassLoader {
         }
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = getCallerClassLoader();
-            if (needsClassLoaderPermissionCheck(ccl, scl)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            checkClassLoaderPermission(scl, Reflection.getCallerClass());
         }
         return scl;
     }
@@ -1471,8 +1466,8 @@ public abstract class ClassLoader {
     // class loader 'from' is same as class loader 'to' or an ancestor
     // of 'to'.  The class loader in a system domain can access
     // any class loader.
-    static boolean needsClassLoaderPermissionCheck(ClassLoader from,
-                                                   ClassLoader to)
+    private static boolean needsClassLoaderPermissionCheck(ClassLoader from,
+                                                           ClassLoader to)
     {
         if (from == to)
             return false;
@@ -1483,13 +1478,8 @@ public abstract class ClassLoader {
         return !to.isAncestor(from);
     }
 
-    // Returns the invoker's class loader, or null if none.
-    // NOTE: This must always be invoked when there is exactly one intervening
-    // frame from the core libraries on the stack between this method's
-    // invocation and the desired invoker.
-    static ClassLoader getCallerClassLoader() {
-        // NOTE use of more generic Reflection.getCallerClass()
-        Class<?> caller = Reflection.getCallerClass(3);
+    // Returns the class's class loader, or null if none.
+    static ClassLoader getClassLoader(Class<?> caller) {
         // This can be null if the VM is requesting it
         if (caller == null) {
             return null;
@@ -1498,6 +1488,17 @@ public abstract class ClassLoader {
         return caller.getClassLoader0();
     }
 
+    static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // caller can be null if the VM is requesting it
+            ClassLoader ccl = getClassLoader(caller);
+            if (needsClassLoaderPermissionCheck(ccl, cl)) {
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            }
+        }
+    }
+
     // The class loader for the system
     // @GuardedBy("ClassLoader.class")
     private static ClassLoader scl;
diff --git a/jdk/src/share/classes/java/lang/Package.java b/jdk/src/share/classes/java/lang/Package.java
index 7d1d38db64d..d22e3ece462 100644
--- a/jdk/src/share/classes/java/lang/Package.java
+++ b/jdk/src/share/classes/java/lang/Package.java
@@ -49,6 +49,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 
 import sun.net.www.ParseUtil;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 import java.lang.annotation.Annotation;
 
@@ -273,8 +275,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
      * @return the package of the requested name. It may be null if no package
      *          information is available from the archive or codebase.
      */
+    @CallerSensitive
     public static Package getPackage(String name) {
-        ClassLoader l = ClassLoader.getCallerClassLoader();
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
         if (l != null) {
             return l.getPackage(name);
         } else {
@@ -294,8 +297,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
      * @return a new array of packages known to the callers {@code ClassLoader}
      * instance.  An zero length array is returned if none are known.
      */
+    @CallerSensitive
     public static Package[] getPackages() {
-        ClassLoader l = ClassLoader.getCallerClassLoader();
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
         if (l != null) {
             return l.getPackages();
         } else {
diff --git a/jdk/src/share/classes/java/lang/Runtime.java b/jdk/src/share/classes/java/lang/Runtime.java
index ada915dbb60..6275e2859d0 100644
--- a/jdk/src/share/classes/java/lang/Runtime.java
+++ b/jdk/src/share/classes/java/lang/Runtime.java
@@ -27,6 +27,8 @@ package java.lang;
 
 import java.io.*;
 import java.util.StringTokenizer;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * Every Java application has a single instance of class
@@ -790,8 +792,9 @@ public class Runtime {
      * @see        java.lang.SecurityException
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public void load(String filename) {
-        load0(System.getCallerClass(), filename);
+        load0(Reflection.getCallerClass(), filename);
     }
 
     synchronized void load0(Class<?> fromClass, String filename) {
@@ -850,8 +853,9 @@ public class Runtime {
      * @see        java.lang.SecurityException
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public void loadLibrary(String libname) {
-        loadLibrary0(System.getCallerClass(), libname);
+        loadLibrary0(Reflection.getCallerClass(), libname);
     }
 
     synchronized void loadLibrary0(Class<?> fromClass, String libname) {
diff --git a/jdk/src/share/classes/java/lang/SecurityManager.java b/jdk/src/share/classes/java/lang/SecurityManager.java
index 31664dc6cb2..ca187630528 100644
--- a/jdk/src/share/classes/java/lang/SecurityManager.java
+++ b/jdk/src/share/classes/java/lang/SecurityManager.java
@@ -36,10 +36,10 @@ import java.net.SocketPermission;
 import java.net.NetPermission;
 import java.util.Hashtable;
 import java.net.InetAddress;
-import java.lang.reflect.Member;
 import java.lang.reflect.*;
 import java.net.URL;
 
+import sun.reflect.CallerSensitive;
 import sun.security.util.SecurityConstants;
 
 /**
@@ -1679,6 +1679,7 @@ class SecurityManager {
      * @since JDK1.1
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @CallerSensitive
     public void checkMemberAccess(Class<?> clazz, int which) {
         if (clazz == null) {
             throw new NullPointerException("class can't be null");
diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java
index 9d1663ae819..c7f69f5e496 100644
--- a/jdk/src/share/classes/java/lang/System.java
+++ b/jdk/src/share/classes/java/lang/System.java
@@ -35,6 +35,7 @@ import java.security.AllPermission;
 import java.nio.channels.Channel;
 import java.nio.channels.spi.SelectorProvider;
 import sun.nio.ch.Interruptible;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 import sun.reflect.annotation.AnnotationType;
@@ -1072,8 +1073,9 @@ public final class System {
      * @see        java.lang.Runtime#load(java.lang.String)
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public static void load(String filename) {
-        Runtime.getRuntime().load0(getCallerClass(), filename);
+        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
     }
 
     /**
@@ -1107,8 +1109,9 @@ public final class System {
      * @see        java.lang.Runtime#loadLibrary(java.lang.String)
      * @see        java.lang.SecurityManager#checkLink(java.lang.String)
      */
+    @CallerSensitive
     public static void loadLibrary(String libname) {
-        Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
+        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
     }
 
     /**
@@ -1245,10 +1248,4 @@ public final class System {
             }
         });
     }
-
-    /* returns the class of the caller. */
-    static Class<?> getCallerClass() {
-        // NOTE use of more generic Reflection.getCallerClass()
-        return Reflection.getCallerClass(3);
-    }
 }
diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java
index 8aab573ded7..e418f1f9a93 100644
--- a/jdk/src/share/classes/java/lang/Thread.java
+++ b/jdk/src/share/classes/java/lang/Thread.java
@@ -37,6 +37,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.LockSupport;
 import sun.nio.ch.Interruptible;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
 
@@ -1443,15 +1445,14 @@ class Thread implements Runnable {
      *
      * @since 1.2
      */
+    @CallerSensitive
     public ClassLoader getContextClassLoader() {
         if (contextClassLoader == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) {
-                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-            }
+            ClassLoader.checkClassLoaderPermission(contextClassLoader,
+                                                   Reflection.getCallerClass());
         }
         return contextClassLoader;
     }
diff --git a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
index 9bbc09c32ce..846920a59a9 100644
--- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
@@ -709,7 +709,9 @@ import jdk.internal.org.objectweb.asm.Type;
             InvokerBytecodeGenerator.maybeDump(className, classFile);
             Class<? extends BoundMethodHandle> bmhClass =
                 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
-                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
+                UNSAFE.defineClass(className, classFile, 0, classFile.length,
+                                   BoundMethodHandle.class.getClassLoader(), null)
+                    .asSubclass(BoundMethodHandle.class);
             UNSAFE.ensureClassInitialized(bmhClass);
 
             return bmhClass;
diff --git a/jdk/src/share/classes/java/lang/invoke/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java
index da8edae1153..59096015acc 100644
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java
@@ -391,10 +391,11 @@ import java.util.Objects;
 
     // private flags, not part of RECOGNIZED_MODIFIERS:
     static final int
-            IS_METHOD      = MN_IS_METHOD,      // method (not constructor)
-            IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
-            IS_FIELD       = MN_IS_FIELD,       // field
-            IS_TYPE        = MN_IS_TYPE;        // nested type
+            IS_METHOD        = MN_IS_METHOD,        // method (not constructor)
+            IS_CONSTRUCTOR   = MN_IS_CONSTRUCTOR,   // constructor
+            IS_FIELD         = MN_IS_FIELD,         // field
+            IS_TYPE          = MN_IS_TYPE,          // nested type
+            CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
 
     static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
     static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
@@ -430,6 +431,10 @@ import java.util.Objects;
     public boolean isPackage() {
         return !testAnyFlags(ALL_ACCESS);
     }
+    /** Query whether this member has a CallerSensitive annotation. */
+    public boolean isCallerSensitive() {
+        return testAllFlags(CALLER_SENSITIVE);
+    }
 
     /** Utility method to query whether this member is accessible from a given lookup class. */
     public boolean isAccessibleFrom(Class<?> lookupClass) {
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
index a18a7a484a8..8efbda80614 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -34,6 +34,8 @@ import sun.invoke.empty.Empty;
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyType;
 import sun.invoke.util.Wrapper;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import static java.lang.invoke.LambdaForm.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@@ -891,9 +893,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
             }
         }
 
+        @CallerSensitive
         private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
-            final int FRAME_COUNT_ARG = 2;  // [0] Reflection [1] BindCaller [2] Expected
-            Class<?> actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG);
+            // This method is called via MH_checkCallerClass and so it's
+            // correct to ask for the immediate caller here.
+            Class<?> actual = Reflection.getCallerClass();
             if (actual != expected && actual != expected2)
                 throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
                                         +(expected == expected2 ? "" : ", or else "+expected2.getName()));
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
index db072126e1f..06e61a7dd8b 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
@@ -26,7 +26,6 @@
 package java.lang.invoke;
 
 import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandleStatics.*;
@@ -34,7 +33,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
 
 /**
  * The JVM interface for the method handles package is all here.
- * This is an interface internal and private to an implemetantion of JSR 292.
+ * This is an interface internal and private to an implementation of JSR 292.
  * <em>This class is not part of the JSR 292 standard.</em>
  * @author jrose
  */
@@ -101,6 +100,7 @@ class MethodHandleNatives {
                 MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
                 MN_IS_FIELD            = 0x00040000, // field
                 MN_IS_TYPE             = 0x00080000, // nested type
+                MN_CALLER_SENSITIVE    = 0x00100000, // @CallerSensitive annotation detected
                 MN_REFERENCE_KIND_SHIFT = 24, // refKind
                 MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
                 // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
@@ -391,129 +391,24 @@ class MethodHandleNatives {
      * I.e., does it call Reflection.getCallerClass or a similer method
      * to ask about the identity of its caller?
      */
-    // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive.
     static boolean isCallerSensitive(MemberName mem) {
         if (!mem.isInvocable())  return false;  // fields are not caller sensitive
+
+        return mem.isCallerSensitive() || canBeCalledVirtual(mem);
+    }
+
+    static boolean canBeCalledVirtual(MemberName mem) {
+        assert(mem.isInvocable());
         Class<?> defc = mem.getDeclaringClass();
         switch (mem.getName()) {
-        case "doPrivileged":
-        case "doPrivilegedWithCombiner":
-            return defc == java.security.AccessController.class;
         case "checkMemberAccess":
             return canBeCalledVirtual(mem, java.lang.SecurityManager.class);
-        case "getUnsafe":
-            return defc == sun.misc.Unsafe.class;
-        case "lookup":
-            return defc == java.lang.invoke.MethodHandles.class;
-        case "findStatic":
-        case "findVirtual":
-        case "findConstructor":
-        case "findSpecial":
-        case "findGetter":
-        case "findSetter":
-        case "findStaticGetter":
-        case "findStaticSetter":
-        case "bind":
-        case "unreflect":
-        case "unreflectSpecial":
-        case "unreflectConstructor":
-        case "unreflectGetter":
-        case "unreflectSetter":
-            return defc == java.lang.invoke.MethodHandles.Lookup.class;
-        case "invoke":
-            return defc == java.lang.reflect.Method.class;
-        case "get":
-        case "getBoolean":
-        case "getByte":
-        case "getChar":
-        case "getShort":
-        case "getInt":
-        case "getLong":
-        case "getFloat":
-        case "getDouble":
-        case "set":
-        case "setBoolean":
-        case "setByte":
-        case "setChar":
-        case "setShort":
-        case "setInt":
-        case "setLong":
-        case "setFloat":
-        case "setDouble":
-            return defc == java.lang.reflect.Field.class;
-        case "newInstance":
-            if (defc == java.lang.reflect.Constructor.class)  return true;
-            if (defc == java.lang.Class.class)  return true;
-            break;
-        case "forName":
-        case "getClassLoader":
-        case "getClasses":
-        case "getFields":
-        case "getMethods":
-        case "getConstructors":
-        case "getDeclaredClasses":
-        case "getDeclaredFields":
-        case "getDeclaredMethods":
-        case "getDeclaredConstructors":
-        case "getField":
-        case "getMethod":
-        case "getConstructor":
-        case "getDeclaredField":
-        case "getDeclaredMethod":
-        case "getDeclaredConstructor":
-            return defc == java.lang.Class.class;
-        case "getConnection":
-        case "getDriver":
-        case "getDrivers":
-        case "deregisterDriver":
-            return defc == getClass("java.sql.DriverManager");
-        case "newUpdater":
-            if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class)  return true;
-            if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class)  return true;
-            if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class)  return true;
-            break;
         case "getContextClassLoader":
             return canBeCalledVirtual(mem, java.lang.Thread.class);
-        case "getPackage":
-        case "getPackages":
-            return defc == java.lang.Package.class;
-        case "getParent":
-        case "getSystemClassLoader":
-            return defc == java.lang.ClassLoader.class;
-        case "load":
-        case "loadLibrary":
-            if (defc == java.lang.Runtime.class)  return true;
-            if (defc == java.lang.System.class)  return true;
-            break;
-        case "getCallerClass":
-            if (defc == sun.reflect.Reflection.class)  return true;
-            if (defc == java.lang.System.class)  return true;
-            break;
-        case "getCallerClassLoader":
-            return defc == java.lang.ClassLoader.class;
-        case "registerAsParallelCapable":
-            return canBeCalledVirtual(mem, java.lang.ClassLoader.class);
-        case "getProxyClass":
-        case "newProxyInstance":
-            return defc == java.lang.reflect.Proxy.class;
-        case "asInterfaceInstance":
-            return defc == java.lang.invoke.MethodHandleProxies.class;
-        case "getBundle":
-        case "clearCache":
-            return defc == java.util.ResourceBundle.class;
         }
         return false;
     }
 
-    // avoid static dependency to a class in other modules
-    private static Class<?> getClass(String cn) {
-        try {
-            return Class.forName(cn, false,
-                                 MethodHandleNatives.class.getClassLoader());
-        } catch (ClassNotFoundException e) {
-            throw new InternalError(e);
-        }
-    }
     static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
         Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
         if (symbolicRefClass == definingClass)  return true;
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
index ade1630dcfb..641f2eeea51 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
@@ -30,6 +30,7 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import sun.invoke.WrapperInstance;
 import java.util.ArrayList;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 
@@ -137,14 +138,14 @@ public class MethodHandleProxies {
     // entry points, must be covered by hand-written or automatically
     // generated adapter classes.
     //
+    @CallerSensitive
     public static
     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
         if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
             throw new IllegalArgumentException("not a public interface: "+intfc.getName());
         final MethodHandle mh;
         if (System.getSecurityManager() != null) {
-            final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller
-            final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
+            final Class<?> caller = Reflection.getCallerClass();
             final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
             ReflectUtil.checkProxyPackageAccess(ccl, intfc);
             mh = ccl != null ? bindCaller(target, caller) : target;
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
index d443e4c4597..fa3cb607855 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -26,13 +26,17 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import sun.invoke.util.ValueConversions;
-import sun.invoke.util.VerifyAccess;
-import sun.invoke.util.Wrapper;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 
@@ -65,8 +69,9 @@ public class MethodHandles {
      * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
      * Do not store it in place where untrusted code can access it.
      */
+    @CallerSensitive
     public static Lookup lookup() {
-        return new Lookup();
+        return new Lookup(Reflection.getCallerClass());
     }
 
     /**
@@ -416,18 +421,11 @@ public class MethodHandles {
          * for method handle creation.
          * Must be called by from a method in this package,
          * which in turn is called by a method not in this package.
-         * <p>
-         * Also, don't make it private, lest javac interpose
-         * an access$N method.
          */
-        Lookup() {
-            this(getCallerClassAtEntryPoint(false), ALL_MODES);
-            // make sure we haven't accidentally picked up a privileged class:
-            checkUnprivilegedlookupClass(lookupClass);
-        }
-
         Lookup(Class<?> lookupClass) {
             this(lookupClass, ALL_MODES);
+            // make sure we haven't accidentally picked up a privileged class:
+            checkUnprivilegedlookupClass(lookupClass);
         }
 
         private Lookup(Class<?> lookupClass, int allowedModes) {
@@ -554,20 +552,6 @@ public class MethodHandles {
             }
         }
 
-        /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */
-        private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) {
-            final int CALLER_DEPTH = 4;
-            //  Stack for the constructor entry point (inSubroutine=false):
-            // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
-            // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
-            //  The stack is slightly different for a subroutine of a Lookup.find* method:
-            // 2: Lookup.*, 3: Lookup.find*.*, 4: caller
-            // Note:  This should be the only use of getCallerClass in this file.
-            assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
-            assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
-            return Reflection.getCallerClass(CALLER_DEPTH);
-        }
-
         /**
          * Produces a method handle for a static method.
          * The type of the method handle will be that of the method.
@@ -594,12 +578,14 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
-            return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return getDirectMethod(REF_invokeStatic, refc, method,
+                                   findBoundCallerClass(method, callerClass));
         }
 
         /**
@@ -645,6 +631,7 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             if (refc == MethodHandle.class) {
                 MethodHandle mh = findVirtualForMH(name, type);
@@ -652,9 +639,10 @@ public class MethodHandles {
             }
             byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
             MemberName method = resolveOrFail(refKind, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);
-            return getDirectMethod(refKind, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return getDirectMethod(refKind, refc, method,
+                                   findBoundCallerClass(method, callerClass));
         }
         private MethodHandle findVirtualForMH(String name, MethodType type) {
             // these names require special lookups because of the implicit MethodType argument
@@ -691,10 +679,11 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             String name = "<init>";
             MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
-            checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, ctor, Reflection.getCallerClass());
             return getDirectConstructor(refc, ctor);
         }
 
@@ -732,14 +721,16 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
             checkSpecialCaller(specialCaller);
             Lookup specialLookup = this.in(specialCaller);
             MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);
-            return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
+                                                 findBoundCallerClass(method, callerClass));
         }
 
         /**
@@ -759,9 +750,10 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getField, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_getField, refc, field);
         }
 
@@ -782,9 +774,10 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putField, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_putField, refc, field);
         }
 
@@ -804,9 +797,10 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_getStatic, refc, field);
         }
 
@@ -826,9 +820,10 @@ public class MethodHandles {
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
-            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            checkSecurityManager(refc, field, Reflection.getCallerClass());
             return getDirectField(REF_putStatic, refc, field);
         }
 
@@ -878,12 +873,14 @@ return mh1;
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
-            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
-            MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
+            Class<?> callerClass = Reflection.getCallerClass();
+            checkSecurityManager(refc, method, callerClass);
+            MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
+                                                        findBoundCallerClass(method, callerClass));
             return mh.bindReceiver(receiver).setVarargs(method);
         }
 
@@ -908,13 +905,14 @@ return mh1;
          *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if the argument is null
          */
+        @CallerSensitive
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
             MemberName method = new MemberName(m);
             byte refKind = method.getReferenceKind();
             if (refKind == REF_invokeSpecial)
                 refKind = REF_invokeVirtual;
             assert(method.isMethod());
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
+            Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
         }
@@ -940,12 +938,13 @@ return mh1;
          *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if any argument is null
          */
+        @CallerSensitive
         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
             checkSpecialCaller(specialCaller);
             Lookup specialLookup = this.in(specialCaller);
             MemberName method = new MemberName(m, true);
             assert(method.isMethod());
-            Class<?> callerClass = findBoundCallerClass(method);  // stack walk magic: do not refactor
+            Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
             // ignore m.isAccessible:  this is a new kind of access
             return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
         }
@@ -1050,20 +1049,35 @@ return mh1;
          * If this lookup object has private access, then the caller class is the lookupClass.
          * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
          * This is the same caller class as is used by checkSecurityManager.
-         * This function performs stack walk magic: do not refactor it.
          */
-        Class<?> findBoundCallerClass(MemberName m) {
+        Class<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) {
             Class<?> callerClass = null;
             if (MethodHandleNatives.isCallerSensitive(m)) {
                 // Do not refactor this to a more "logical" place, since it is stack walk magic.
                 // Note that this is the same expression as in Step 2 below in checkSecurityManager.
                 callerClass = ((allowedModes & PRIVATE) != 0
                                ? lookupClass  // for strong access modes, no extra check
-                               // next line does stack walk magic; do not refactor:
-                               : getCallerClassAtEntryPoint(true));
+                               : callerAtEntryPoint);
             }
             return callerClass;
         }
+
+        /**
+         * Determine whether a security manager has an overridden
+         * SecurityManager.checkMemberAccess method.
+         */
+        private boolean isCheckMemberAccessOverridden(SecurityManager sm) {
+            final Class<? extends SecurityManager> cls = sm.getClass();
+            if (cls == SecurityManager.class) return false;
+
+            try {
+                return cls.getMethod("checkMemberAccess", Class.class, int.class).
+                    getDeclaringClass() != SecurityManager.class;
+            } catch (NoSuchMethodException e) {
+                throw new InternalError("should not reach here");
+            }
+        }
+
         /**
          * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
          * Determines a trustable caller class to compare with refc, the symbolic reference class.
@@ -1071,46 +1085,55 @@ return mh1;
          * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
          * This function performs stack walk magic: do not refactor it.
          */
-        void checkSecurityManager(Class<?> refc, MemberName m) {
+        void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) {
             SecurityManager smgr = System.getSecurityManager();
             if (smgr == null)  return;
             if (allowedModes == TRUSTED)  return;
+
+            final boolean overridden = isCheckMemberAccessOverridden(smgr);
             // Step 1:
-            smgr.checkMemberAccess(refc, Member.PUBLIC);
+            {
+                // Default policy is to allow Member.PUBLIC; no need to check
+                // permission if SecurityManager is the default implementation
+                final int which = Member.PUBLIC;
+                final Class<?> clazz = refc;
+                if (overridden) {
+                    // Don't refactor; otherwise break the stack depth for
+                    // checkMemberAccess of subclasses of SecurityManager as specified.
+                    smgr.checkMemberAccess(clazz, which);
+                }
+            }
+
             // Step 2:
             Class<?> callerClass = ((allowedModes & PRIVATE) != 0
                                     ? lookupClass  // for strong access modes, no extra check
-                                    // next line does stack walk magic; do not refactor:
-                                    : getCallerClassAtEntryPoint(true));
+                                    : caller);
             if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
                 (callerClass != lookupClass &&
                  !VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
                 smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
+
             // Step 3:
             if (m.isPublic()) return;
             Class<?> defc = m.getDeclaringClass();
-            smgr.checkMemberAccess(defc, Member.DECLARED);  // STACK WALK HERE
+            {
+                // Inline SecurityManager.checkMemberAccess
+                final int which = Member.DECLARED;
+                final Class<?> clazz = defc;
+                if (!overridden) {
+                    if (caller.getClassLoader() != clazz.getClassLoader()) {
+                        smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+                    }
+                } else {
+                    // Don't refactor; otherwise break the stack depth for
+                    // checkMemberAccess of subclasses of SecurityManager as specified.
+                    smgr.checkMemberAccess(clazz, which);
+                }
+            }
+
             // Step 4:
             if (defc != refc)
                 smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
-
-            // Comment from SM.checkMemberAccess, where which=DECLARED:
-            /*
-             * stack depth of 4 should be the caller of one of the
-             * methods in java.lang.Class that invoke checkMember
-             * access. The stack should look like:
-             *
-             * someCaller                        [3]
-             * java.lang.Class.someReflectionAPI [2]
-             * java.lang.Class.checkMemberAccess [1]
-             * SecurityManager.checkMemberAccess [0]
-             *
-             */
-            // For us it is this stack:
-            // someCaller                        [3]
-            // Lookup.findSomeMember             [2]
-            // Lookup.checkSecurityManager       [1]
-            // SecurityManager.checkMemberAccess [0]
         }
 
         void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java
index 14a515fe949..0ed60dc375b 100644
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.ConstructorAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.ConstructorRepository;
@@ -392,14 +393,14 @@ public final class Constructor<T> extends Executable {
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public T newInstance(Object ... initargs)
         throws InstantiationException, IllegalAccessException,
                IllegalArgumentException, InvocationTargetException
     {
         if (!override) {
             if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(2);
-
+                Class<?> caller = Reflection.getCallerClass();
                 checkAccess(caller, clazz, null, modifiers);
             }
         }
diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java
index bd2b9ef929f..a25223f68c1 100644
--- a/jdk/src/share/classes/java/lang/reflect/Field.java
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.FieldAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.FieldRepository;
@@ -376,9 +377,16 @@ class Field extends AccessibleObject implements Member {
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public Object get(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).get(obj);
     }
 
@@ -404,9 +412,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public boolean getBoolean(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getBoolean(obj);
     }
 
@@ -432,9 +447,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public byte getByte(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getByte(obj);
     }
 
@@ -462,9 +484,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see Field#get
      */
+    @CallerSensitive
     public char getChar(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getChar(obj);
     }
 
@@ -492,9 +521,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public short getShort(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getShort(obj);
     }
 
@@ -522,9 +558,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public int getInt(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getInt(obj);
     }
 
@@ -552,9 +595,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public long getLong(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getLong(obj);
     }
 
@@ -582,9 +632,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see Field#get
      */
+    @CallerSensitive
     public float getFloat(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getFloat(obj);
     }
 
@@ -612,9 +669,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#get
      */
+    @CallerSensitive
     public double getDouble(Object obj)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         return getFieldAccessor(obj).getDouble(obj);
     }
 
@@ -684,9 +748,16 @@ class Field extends AccessibleObject implements Member {
      * @exception ExceptionInInitializerError if the initialization provoked
      *              by this method fails.
      */
+    @CallerSensitive
     public void set(Object obj, Object value)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).set(obj, value);
     }
 
@@ -714,9 +785,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setBoolean(Object obj, boolean z)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setBoolean(obj, z);
     }
 
@@ -744,9 +822,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setByte(Object obj, byte b)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setByte(obj, b);
     }
 
@@ -774,9 +859,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setChar(Object obj, char c)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setChar(obj, c);
     }
 
@@ -804,9 +896,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setShort(Object obj, short s)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setShort(obj, s);
     }
 
@@ -834,9 +933,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setInt(Object obj, int i)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setInt(obj, i);
     }
 
@@ -864,9 +970,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setLong(Object obj, long l)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setLong(obj, l);
     }
 
@@ -894,9 +1007,16 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setFloat(Object obj, float f)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setFloat(obj, f);
     }
 
@@ -924,20 +1044,26 @@ class Field extends AccessibleObject implements Member {
      *              by this method fails.
      * @see       Field#set
      */
+    @CallerSensitive
     public void setDouble(Object obj, double d)
         throws IllegalArgumentException, IllegalAccessException
     {
+        if (!override) {
+            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+                Class<?> caller = Reflection.getCallerClass();
+                checkAccess(caller, clazz, obj, modifiers);
+            }
+        }
         getFieldAccessor(obj).setDouble(obj, d);
     }
 
-    // Convenience routine which performs security checks
+    // security check is done before calling this method
     private FieldAccessor getFieldAccessor(Object obj)
         throws IllegalAccessException
     {
-        doSecurityCheck(obj);
         boolean ov = override;
-        FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor;
-        return (a != null)? a : acquireFieldAccessor(ov);
+        FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
+        return (a != null) ? a : acquireFieldAccessor(ov);
     }
 
     // NOTE that there is no synchronization used here. It is correct
@@ -982,19 +1108,6 @@ class Field extends AccessibleObject implements Member {
         }
     }
 
-    // NOTE: be very careful if you change the stack depth of this
-    // routine. The depth of the "getCallerClass" call is hardwired so
-    // that the compiler can have an easier time if this gets inlined.
-    private void doSecurityCheck(Object obj) throws IllegalAccessException {
-        if (!override) {
-            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(4);
-
-                checkAccess(caller, clazz, obj, modifiers);
-            }
-        }
-    }
-
     /**
      * @throws NullPointerException {@inheritDoc}
      * @since 1.5
diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java
index 1caddd6f522..7c7abe43dff 100644
--- a/jdk/src/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import sun.reflect.CallerSensitive;
 import sun.reflect.MethodAccessor;
 import sun.reflect.Reflection;
 import sun.reflect.generics.repository.MethodRepository;
@@ -472,14 +473,14 @@ public final class Method extends Executable {
      * @exception ExceptionInInitializerError if the initialization
      * provoked by this method fails.
      */
+    @CallerSensitive
     public Object invoke(Object obj, Object... args)
         throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException
     {
         if (!override) {
             if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
-                Class<?> caller = Reflection.getCallerClass(1);
-
+                Class<?> caller = Reflection.getCallerClass();
                 checkAccess(caller, clazz, obj, modifiers);
             }
         }
diff --git a/jdk/src/share/classes/java/lang/reflect/Proxy.java b/jdk/src/share/classes/java/lang/reflect/Proxy.java
index e946ba3226d..2dd06020b26 100644
--- a/jdk/src/share/classes/java/lang/reflect/Proxy.java
+++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java
@@ -39,6 +39,8 @@ import java.util.Set;
 import java.util.List;
 import java.util.WeakHashMap;
 import sun.misc.ProxyGenerator;
+import sun.misc.VM;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.util.SecurityConstants;
@@ -408,28 +410,21 @@ public class Proxy implements java.io.Serializable {
      * @throws  NullPointerException if the {@code interfaces} array
      *          argument or any of its elements are {@code null}
      */
+    @CallerSensitive
     public static Class<?> getProxyClass(ClassLoader loader,
                                          Class<?>... interfaces)
         throws IllegalArgumentException
-    {
-        return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
-    }
-
-    private static void checkProxyLoader(ClassLoader ccl,
-                                         ClassLoader loader)
     {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            if (loader == null && ccl != null) {
-                if (!ProxyAccessHelper.allowNullLoader) {
-                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
-                }
-            }
+            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
         }
+
+        return getProxyClass0(loader, interfaces);
     }
 
     /*
-     * Generate a proxy class (caller-sensitive).
+     * Check permissions required to create a Proxy class.
      *
      * To define a proxy class, it performs the access checks as in
      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
@@ -446,17 +441,28 @@ public class Proxy implements java.io.Serializable {
      * will throw IllegalAccessError when the generated proxy class is
      * being defined via the defineClass0 method.
      */
-    private static Class<?> getProxyClass0(ClassLoader loader,
-                                           Class<?>... interfaces) {
+    private static void checkProxyAccess(Class<?> caller,
+                                         ClassLoader loader,
+                                         Class<?>... interfaces)
+    {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
-            final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
-            final ClassLoader ccl = caller.getClassLoader();
-            checkProxyLoader(ccl, loader);
+            ClassLoader ccl = caller.getClassLoader();
+            if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
+                if (!ProxyAccessHelper.allowNullLoader) {
+                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+                }
+            }
             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
         }
+    }
 
+    /**
+     * Generate a proxy class.  Must call the checkProxyAccess method
+     * to perform permission checks before calling this.
+     */
+    private static Class<?> getProxyClass0(ClassLoader loader,
+                                           Class<?>... interfaces) {
         if (interfaces.length > 65535) {
             throw new IllegalArgumentException("interface limit exceeded");
         }
@@ -698,6 +704,7 @@ public class Proxy implements java.io.Serializable {
      *          if the invocation handler, {@code h}, is
      *          {@code null}
      */
+    @CallerSensitive
     public static Object newProxyInstance(ClassLoader loader,
                                           Class<?>[] interfaces,
                                           InvocationHandler h)
@@ -707,10 +714,15 @@ public class Proxy implements java.io.Serializable {
             throw new NullPointerException();
         }
 
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
+        }
+
         /*
          * Look up or generate the designated proxy class.
          */
-        Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
+        Class<?> cl = getProxyClass0(loader, interfaces);
 
         /*
          * Invoke its constructor with the designated invocation handler.
@@ -718,7 +730,6 @@ public class Proxy implements java.io.Serializable {
         try {
             final Constructor<?> cons = cl.getConstructor(constructorParams);
             final InvocationHandler ih = h;
-            SecurityManager sm = System.getSecurityManager();
             if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                 // create proxy instance with doPrivilege as the proxy class may
                 // implement non-public interfaces that requires a special permission
diff --git a/jdk/src/share/classes/java/security/AccessController.java b/jdk/src/share/classes/java/security/AccessController.java
index 4e790ffc8da..e7fbe737a8e 100644
--- a/jdk/src/share/classes/java/security/AccessController.java
+++ b/jdk/src/share/classes/java/security/AccessController.java
@@ -26,6 +26,8 @@
 package java.security;
 
 import sun.security.util.Debug;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * <p> The AccessController class is used for access control operations
@@ -264,6 +266,7 @@ public final class AccessController {
      * @see java.security.DomainCombiner
      */
 
+    @CallerSensitive
     public static native <T> T doPrivileged(PrivilegedAction<T> action);
 
     /**
@@ -288,14 +291,15 @@ public final class AccessController {
      *
      * @since 1.6
      */
+    @CallerSensitive
     public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
-
         AccessControlContext acc = getStackAccessControlContext();
         if (acc == null) {
             return AccessController.doPrivileged(action);
         }
         DomainCombiner dc = acc.getAssignedCombiner();
-        return AccessController.doPrivileged(action, preserveCombiner(dc));
+        return AccessController.doPrivileged(action,
+                                             preserveCombiner(dc, Reflection.getCallerClass()));
     }
 
 
@@ -326,6 +330,7 @@ public final class AccessController {
      * @see #doPrivileged(PrivilegedAction)
      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
      */
+    @CallerSensitive
     public static native <T> T doPrivileged(PrivilegedAction<T> action,
                                             AccessControlContext context);
 
@@ -353,6 +358,7 @@ public final class AccessController {
      * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
      * @see java.security.DomainCombiner
      */
+    @CallerSensitive
     public static native <T> T
         doPrivileged(PrivilegedExceptionAction<T> action)
         throws PrivilegedActionException;
@@ -383,34 +389,29 @@ public final class AccessController {
      *
      * @since 1.6
      */
-    public static <T> T doPrivilegedWithCombiner
-        (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
-
+    @CallerSensitive
+    public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action)
+        throws PrivilegedActionException
+    {
         AccessControlContext acc = getStackAccessControlContext();
         if (acc == null) {
             return AccessController.doPrivileged(action);
         }
         DomainCombiner dc = acc.getAssignedCombiner();
-        return AccessController.doPrivileged(action, preserveCombiner(dc));
+        return AccessController.doPrivileged(action,
+                                             preserveCombiner(dc, Reflection.getCallerClass()));
     }
 
     /**
      * preserve the combiner across the doPrivileged call
      */
-    private static AccessControlContext preserveCombiner
-                                        (DomainCombiner combiner) {
-
-        /**
-         * callerClass[0] = Reflection.getCallerClass
-         * callerClass[1] = AccessController.preserveCombiner
-         * callerClass[2] = AccessController.doPrivileged
-         * callerClass[3] = caller
-         */
-        final Class<?> callerClass = sun.reflect.Reflection.getCallerClass(3);
+    private static AccessControlContext preserveCombiner(DomainCombiner combiner,
+                                                         Class<?> caller)
+    {
         ProtectionDomain callerPd = doPrivileged
             (new PrivilegedAction<ProtectionDomain>() {
             public ProtectionDomain run() {
-                return callerClass.getProtectionDomain();
+                return caller.getProtectionDomain();
             }
         });
 
@@ -455,6 +456,7 @@ public final class AccessController {
      * @see #doPrivileged(PrivilegedAction)
      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
      */
+    @CallerSensitive
     public static native <T> T
         doPrivileged(PrivilegedExceptionAction<T> action,
                      AccessControlContext context)
diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java
index a97595da5d1..b0d8decf40b 100644
--- a/jdk/src/share/classes/java/sql/DriverManager.java
+++ b/jdk/src/share/classes/java/sql/DriverManager.java
@@ -30,6 +30,7 @@ import java.util.ServiceLoader;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.concurrent.CopyOnWriteArrayList;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 
 
@@ -192,14 +193,11 @@ public class DriverManager {
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url,
         java.util.Properties info) throws SQLException {
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -226,14 +224,11 @@ public class DriverManager {
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url,
         String user, String password) throws SQLException {
         java.util.Properties info = new java.util.Properties();
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
         if (user != null) {
             info.put("user", user);
         }
@@ -241,7 +236,7 @@ public class DriverManager {
             info.put("password", password);
         }
 
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -259,16 +254,12 @@ public class DriverManager {
      * has been exceeded and has at least tried to cancel the
      * current database connection attempt
      */
+    @CallerSensitive
     public static Connection getConnection(String url)
         throws SQLException {
 
         java.util.Properties info = new java.util.Properties();
-
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
-        return (getConnection(url, info, callerCL));
+        return (getConnection(url, info, Reflection.getCallerClass()));
     }
 
     /**
@@ -282,21 +273,20 @@ public class DriverManager {
      * that can connect to the given URL
      * @exception SQLException if a database access error occurs
      */
+    @CallerSensitive
     public static Driver getDriver(String url)
         throws SQLException {
 
         println("DriverManager.getDriver(\"" + url + "\")");
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
+        Class<?> callerClass = Reflection.getCallerClass();
 
         // Walk through the loaded registeredDrivers attempting to locate someone
         // who understands the given URL.
         for (DriverInfo aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if(isDriverAllowed(aDriver.driver, callerCL)) {
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
                 try {
                     if(aDriver.driver.acceptsURL(url)) {
                         // Success!
@@ -350,20 +340,18 @@ public class DriverManager {
      * @param driver the JDBC Driver to drop
      * @exception SQLException if a database access error occurs
      */
+    @CallerSensitive
     public static synchronized void deregisterDriver(Driver driver)
         throws SQLException {
         if (driver == null) {
             return;
         }
 
-        // Gets the classloader of the code that called this method,
-        // may be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
         println("DriverManager.deregisterDriver: " + driver);
 
         DriverInfo aDriver = new DriverInfo(driver);
         if(registeredDrivers.contains(aDriver)) {
-            if (isDriverAllowed(driver, callerCL)) {
+            if (isDriverAllowed(driver, Reflection.getCallerClass())) {
                  registeredDrivers.remove(aDriver);
             } else {
                 // If the caller does not have permission to load the driver then
@@ -384,18 +372,17 @@ public class DriverManager {
      *
      * @return the list of JDBC Drivers loaded by the caller's class loader
      */
+    @CallerSensitive
     public static java.util.Enumeration<Driver> getDrivers() {
         java.util.Vector<Driver> result = new java.util.Vector<>();
 
-        // Gets the classloader of the code that called this method, may
-        // be null.
-        ClassLoader callerCL = DriverManager.getCallerClassLoader();
+        Class<?> callerClass = Reflection.getCallerClass();
 
         // Walk through the loaded registeredDrivers.
         for(DriverInfo aDriver : registeredDrivers) {
             // If the caller does not have permission to load the driver then
             // skip it.
-            if(isDriverAllowed(aDriver.driver, callerCL)) {
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
                 result.addElement(aDriver.driver);
             } else {
                 println("    skipping: " + aDriver.getClass().getName());
@@ -493,17 +480,13 @@ public class DriverManager {
 
     //------------------------------------------------------------------------
 
-    // Internal method used to get the caller's class loader.
-    // Replaces the call to the native method
-    private static ClassLoader getCallerClassLoader() {
-        Class<?> cc = Reflection.getCallerClass(3);
-        ClassLoader cl = (cc != null) ? cc.getClassLoader() : null;
-        return cl;
-    }
-
-
     // Indicates whether the class object that would be created if the code calling
     // DriverManager is accessible.
+    private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
+        return isDriverAllowed(driver, callerCL);
+    }
+
     private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
         boolean result = false;
         if(driver != null) {
@@ -586,18 +569,19 @@ public class DriverManager {
 
     //  Worker method called by the public getConnection() methods.
     private static Connection getConnection(
-        String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
+        String url, java.util.Properties info, Class<?> caller) throws SQLException {
         /*
          * When callerCl is null, we should check the application's
          * (which is invoking this class indirectly)
          * classloader, so that the JDBC driver class outside rt.jar
          * can be loaded from here.
          */
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
         synchronized(DriverManager.class) {
-          // synchronize loading of the correct classloader.
-          if(callerCL == null) {
-              callerCL = Thread.currentThread().getContextClassLoader();
-           }
+            // synchronize loading of the correct classloader.
+            if (callerCL == null) {
+                callerCL = Thread.currentThread().getContextClassLoader();
+            }
         }
 
         if(url == null) {
diff --git a/jdk/src/share/classes/java/util/ResourceBundle.java b/jdk/src/share/classes/java/util/ResourceBundle.java
index 6d341dc304e..0d52daa9c48 100644
--- a/jdk/src/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/share/classes/java/util/ResourceBundle.java
@@ -57,6 +57,8 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.jar.JarEntry;
 import java.util.spi.ResourceBundleControlProvider;
 
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
 
@@ -440,14 +442,10 @@ public abstract class ResourceBundle {
 
     /*
      * Automatic determination of the ClassLoader to be used to load
-     * resources on behalf of the client.  N.B. The client is getLoader's
-     * caller's caller.
+     * resources on behalf of the client.
      */
-    private static ClassLoader getLoader() {
-        Class<?>[] stack = getClassContext();
-        /* Magic number 2 identifies our caller's caller */
-        Class<?> c = stack[2];
-        ClassLoader cl = (c == null) ? null : c.getClassLoader();
+    private static ClassLoader getLoader(Class<?> caller) {
+        ClassLoader cl = caller == null ? null : caller.getClassLoader();
         if (cl == null) {
             // When the caller's loader is the boot class loader, cl is null
             // here. In that case, ClassLoader.getSystemClassLoader() may
@@ -461,8 +459,6 @@ public abstract class ResourceBundle {
         return cl;
     }
 
-    private static native Class<?>[] getClassContext();
-
     /**
      * A wrapper of ClassLoader.getSystemClassLoader().
      */
@@ -746,11 +742,11 @@ public abstract class ResourceBundle {
      *     if no resource bundle for the specified base name can be found
      * @return a resource bundle for the given base name and the default locale
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName)
     {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              getDefaultControl(baseName));
     }
 
@@ -788,11 +784,11 @@ public abstract class ResourceBundle {
      *        needed.
      * @since 1.6
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
                                                  Control control) {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -817,12 +813,12 @@ public abstract class ResourceBundle {
      *        if no resource bundle for the specified base name can be found
      * @return a resource bundle for the given base name and locale
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
                                                  Locale locale)
     {
         return getBundleImpl(baseName, locale,
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              getDefaultControl(baseName));
     }
 
@@ -863,11 +859,11 @@ public abstract class ResourceBundle {
      *        needed.
      * @since 1.6
      */
+    @CallerSensitive
     public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
                                                  Control control) {
         return getBundleImpl(baseName, targetLocale,
-                             /* must determine loader here, else we break stack invariant */
-                             getLoader(),
+                             getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -1721,8 +1717,9 @@ public abstract class ResourceBundle {
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
+    @CallerSensitive
     public static final void clearCache() {
-        clearCache(getLoader());
+        clearCache(getLoader(Reflection.getCallerClass()));
     }
 
     /**
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index 4a8d1df5a63..e761b6ec73d 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
 import java.util.function.IntUnaryOperator;
 import java.util.function.IntBinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -77,8 +80,9 @@ public abstract class AtomicIntegerFieldUpdater<T> {
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
-        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
+        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
     }
 
     /**
@@ -365,9 +369,11 @@ public abstract class AtomicIntegerFieldUpdater<T> {
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) {
+        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
+                                      final String fieldName,
+                                      final Class<?> caller)
+        {
             final Field field;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -376,7 +382,6 @@ public abstract class AtomicIntegerFieldUpdater<T> {
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index e5c6e8a0044..7ac0e73d601 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
 import java.util.function.LongUnaryOperator;
 import java.util.function.LongBinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -77,11 +80,13 @@ public abstract class AtomicLongFieldUpdater<T> {
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
+        Class<?> caller = Reflection.getCallerClass();
         if (AtomicLong.VM_SUPPORTS_LONG_CAS)
-            return new CASUpdater<U>(tclass, fieldName);
+            return new CASUpdater<U>(tclass, fieldName, caller);
         else
-            return new LockedUpdater<U>(tclass, fieldName);
+            return new LockedUpdater<U>(tclass, fieldName, caller);
     }
 
     /**
@@ -365,9 +370,8 @@ public abstract class AtomicLongFieldUpdater<T> {
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        CASUpdater(final Class<T> tclass, final String fieldName) {
+        CASUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) {
             final Field field;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -376,7 +380,6 @@ public abstract class AtomicLongFieldUpdater<T> {
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
@@ -490,9 +493,8 @@ public abstract class AtomicLongFieldUpdater<T> {
         private final Class<T> tclass;
         private final Class<?> cclass;
 
-        LockedUpdater(final Class<T> tclass, final String fieldName) {
+        LockedUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) {
             Field field = null;
-            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = AccessController.doPrivileged(
@@ -501,7 +503,6 @@ public abstract class AtomicLongFieldUpdater<T> {
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 933e5e4fc92..2cd0e1df369 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
 import java.util.function.UnaryOperator;
 import java.util.function.BinaryOperator;
 import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.security.AccessController;
@@ -96,10 +99,12 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
      * or the field is inaccessible to the caller according to Java language
      * access control
      */
+    @CallerSensitive
     public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
         return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
                                                         vclass,
-                                                        fieldName);
+                                                        fieldName,
+                                                        Reflection.getCallerClass());
     }
 
     /**
@@ -297,10 +302,11 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
 
         AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
                                         Class<V> vclass,
-                                        final String fieldName) {
+                                        final String fieldName,
+                                        final Class<?> caller)
+        {
             final Field field;
             final Class<?> fieldClass;
-            final Class<?> caller;
             final int modifiers;
             try {
                 field = AccessController.doPrivileged(
@@ -309,7 +315,6 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
                             return tclass.getDeclaredField(fieldName);
                         }
                     });
-                caller = sun.reflect.Reflection.getCallerClass(3);
                 modifiers = field.getModifiers();
                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                     caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java
index c8f8fae0702..20bba2671b6 100644
--- a/jdk/src/share/classes/java/util/logging/Logger.java
+++ b/jdk/src/share/classes/java/util/logging/Logger.java
@@ -36,6 +36,8 @@ import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
 
 /**
  * A Logger object is used to log messages for a specific
@@ -333,13 +335,10 @@ public class Logger {
         }
     }
 
-    private static Logger demandLogger(String name, String resourceBundleName) {
+    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
         LogManager manager = LogManager.getLogManager();
         SecurityManager sm = System.getSecurityManager();
         if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
-            // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller
-            final int SKIP_FRAMES = 3;
-            Class<?> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES);
             if (caller.getClassLoader() == null) {
                 return manager.demandSystemLogger(name, resourceBundleName);
             }
@@ -377,6 +376,7 @@ public class Logger {
 
     // Synchronization is not required here. All synchronization for
     // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
     public static Logger getLogger(String name) {
         // This method is intentionally not a wrapper around a call
         // to getLogger(name, resourceBundleName). If it were then
@@ -388,7 +388,7 @@ public class Logger {
         // would throw an IllegalArgumentException in the second call
         // because the wrapper would result in an attempt to replace
         // the existing "resourceBundleForFoo" with null.
-        return demandLogger(name, null);
+        return demandLogger(name, null, Reflection.getCallerClass());
     }
 
     /**
@@ -434,8 +434,9 @@ public class Logger {
 
     // Synchronization is not required here. All synchronization for
     // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
     public static Logger getLogger(String name, String resourceBundleName) {
-        Logger result = demandLogger(name, resourceBundleName);
+        Logger result = demandLogger(name, resourceBundleName, Reflection.getCallerClass());
 
         // MissingResourceException or IllegalArgumentException can be
         // thrown by setupResourceInfo().
diff --git a/jdk/src/share/classes/javax/script/ScriptEngineManager.java b/jdk/src/share/classes/javax/script/ScriptEngineManager.java
index 480c69a605c..7ce42d89298 100644
--- a/jdk/src/share/classes/javax/script/ScriptEngineManager.java
+++ b/jdk/src/share/classes/javax/script/ScriptEngineManager.java
@@ -28,6 +28,7 @@ import java.util.*;
 import java.security.*;
 import java.util.ServiceLoader;
 import java.util.ServiceConfigurationError;
+import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
 
@@ -60,9 +61,10 @@ public class ScriptEngineManager  {
      *
      * @see java.lang.Thread#getContextClassLoader
      */
+    @CallerSensitive
     public ScriptEngineManager() {
         ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
-        if (canCallerAccessLoader(ctxtLoader)) {
+        if (canCallerAccessLoader(ctxtLoader, Reflection.getCallerClass())) {
             if (DEBUG) System.out.println("using " + ctxtLoader);
             init(ctxtLoader);
         } else {
@@ -419,10 +421,10 @@ public class ScriptEngineManager  {
     /** Global bindings associated with script engines created by this manager. */
     private Bindings globalScope;
 
-    private boolean canCallerAccessLoader(ClassLoader loader) {
+    private boolean canCallerAccessLoader(ClassLoader loader, Class<?> caller) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            ClassLoader callerLoader = getCallerClassLoader();
+            ClassLoader callerLoader = getClassLoader(caller);
             if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) {
                 if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
                     try {
@@ -438,10 +440,9 @@ public class ScriptEngineManager  {
         return true;
     }
 
-    // Note that this code is same as ClassLoader.getCallerClassLoader().
+    // Note that this code is same as ClassLoader.getClassLoader().
     // But, that method is package private and hence we can't call here.
-    private ClassLoader getCallerClassLoader() {
-        Class<?> caller = Reflection.getCallerClass(3);
+    private ClassLoader getClassLoader(Class<?> caller) {
         if (caller == null) {
             return null;
         }
diff --git a/jdk/src/share/classes/sun/misc/Unsafe.java b/jdk/src/share/classes/sun/misc/Unsafe.java
index 8f45c867de0..25fb99e2639 100644
--- a/jdk/src/share/classes/sun/misc/Unsafe.java
+++ b/jdk/src/share/classes/sun/misc/Unsafe.java
@@ -28,6 +28,9 @@ package sun.misc;
 import java.security.*;
 import java.lang.reflect.*;
 
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
 
 /**
  * A collection of methods for performing low-level, unsafe operations.
@@ -80,9 +83,10 @@ public final class Unsafe {
      *             <code>checkPropertiesAccess</code> method doesn't allow
      *             access to the system properties.
      */
+    @CallerSensitive
     public static Unsafe getUnsafe() {
-        Class<?> cc = sun.reflect.Reflection.getCallerClass(2);
-        if (!VM.isSystemDomainLoader(cc.getClassLoader()))
+        Class<?> caller = Reflection.getCallerClass();
+        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
             throw new SecurityException("Unsafe");
         return theUnsafe;
     }
@@ -817,8 +821,6 @@ public final class Unsafe {
                                        ClassLoader loader,
                                        ProtectionDomain protectionDomain);
 
-    public native Class<?> defineClass(String name, byte[] b, int off, int len);
-
     /**
      * Define a class but do not make it known to the class loader or system dictionary.
      * <p>
diff --git a/jdk/src/share/native/java/lang/ResourceBundle.c b/jdk/src/share/classes/sun/reflect/CallerSensitive.java
similarity index 70%
rename from jdk/src/share/native/java/lang/ResourceBundle.c
rename to jdk/src/share/classes/sun/reflect/CallerSensitive.java
index 8914eb374ff..19e47cdd5ea 100644
--- a/jdk/src/share/native/java/lang/ResourceBundle.c
+++ b/jdk/src/share/classes/sun/reflect/CallerSensitive.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,13 +23,19 @@
  * questions.
  */
 
-#include "jni.h"
-#include "jvm.h"
+package sun.reflect;
 
-#include "java_util_ResourceBundle.h"
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
 
-JNIEXPORT jobjectArray JNICALL
-Java_java_util_ResourceBundle_getClassContext(JNIEnv *env, jobject this)
-{
-    return JVM_GetClassContext(env);
+/**
+ * A method annotated @CallerSensitive is sensitive to its calling class,
+ * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
+ * or via some equivalent.
+ *
+ * @author John R. Rose
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({CONSTRUCTOR, METHOD})
+public @interface CallerSensitive {
 }
diff --git a/jdk/src/share/classes/sun/reflect/Reflection.java b/jdk/src/share/classes/sun/reflect/Reflection.java
index fb559826969..274705fc249 100644
--- a/jdk/src/share/classes/sun/reflect/Reflection.java
+++ b/jdk/src/share/classes/sun/reflect/Reflection.java
@@ -51,16 +51,11 @@ public class Reflection {
         methodFilterMap = new HashMap<>();
     }
 
-    /** Returns the class of the method <code>realFramesToSkip</code>
-        frames up the stack (zero-based), ignoring frames associated
-        with java.lang.reflect.Method.invoke() and its implementation.
-        The first frame is that associated with this method, so
-        <code>getCallerClass(0)</code> returns the Class object for
-        sun.reflect.Reflection. Frames associated with
-        java.lang.reflect.Method.invoke() and its implementation are
-        completely ignored and do not count toward the number of "real"
-        frames skipped. */
-    public static native Class<?> getCallerClass(int realFramesToSkip);
+    /** Returns the class of the caller of the method calling this method,
+        ignoring frames associated with java.lang.reflect.Method.invoke()
+        and its implementation. */
+    @CallerSensitive
+    public static native Class<?> getCallerClass();
 
     /** Retrieves the access flags written to the class file. For
         inner classes these flags may differ from those returned by
@@ -321,4 +316,27 @@ public class Reflection {
         }
         return newMembers;
     }
+
+    /**
+     * Tests if the given method is caller-sensitive and the declaring class
+     * is defined by either the bootstrap class loader or extension class loader.
+     */
+    public static boolean isCallerSensitive(Method m) {
+        final ClassLoader loader = m.getDeclaringClass().getClassLoader();
+        if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader))  {
+            return m.isAnnotationPresent(CallerSensitive.class);
+        }
+        return false;
+    }
+
+    private static boolean isExtClassLoader(ClassLoader loader) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        while (cl != null) {
+            if (cl.getParent() == null && cl == loader) {
+                return true;
+            }
+            cl = cl.getParent();
+        }
+        return false;
+    }
 }
diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h
index 44b0be576d4..f10019a92ec 100644
--- a/jdk/src/share/javavm/export/jvm.h
+++ b/jdk/src/share/javavm/export/jvm.h
@@ -350,16 +350,21 @@ JVM_NewMultiArray(JNIEnv *env, jclass eltClass, jintArray dim);
 /*
  * java.lang.Class and java.lang.ClassLoader
  */
+
+#define JVM_DEPTH -1
+
 /*
- * Returns the class in which the code invoking the native method
- * belongs.
+ * Returns the immediate caller class of the native method invoking
+ * JVM_GetCallerClass.  The Method.invoke and other frames due to
+ * reflection machinery are skipped.
  *
- * Note that in JDK 1.1, native methods did not create a frame.
- * In 1.2, they do. Therefore native methods like Class.forName
- * can no longer look at the current frame for the caller class.
+ * The depth parameter must be -1 (JVM_DEPTH). The caller is expected
+ * to be marked with sun.reflect.CallerSensitive.  The JVM will throw
+ * an error if it is not marked propertly.
  */
 JNIEXPORT jclass JNICALL
-JVM_GetCallerClass(JNIEnv *env, int n);
+JVM_GetCallerClass(JNIEnv *env, int depth);
+
 
 /*
  * Find primitive classes
diff --git a/jdk/src/share/native/java/lang/ClassLoader.c b/jdk/src/share/native/java/lang/ClassLoader.c
index 776b2dd24e7..f6d0583990c 100644
--- a/jdk/src/share/native/java/lang/ClassLoader.c
+++ b/jdk/src/share/native/java/lang/ClassLoader.c
@@ -492,24 +492,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_find
     (*env)->ReleaseStringUTFChars(env, name, cname);
     return res;
 }
-
-JNIEXPORT jobject JNICALL
-Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index)
-{
-    jobjectArray jcallerStack;
-    int len;
-
-    jcallerStack = JVM_GetClassContext(env);
-    if ((*env)->ExceptionCheck(env)) {
-        return NULL;
-    }
-    len = (*env)->GetArrayLength(env, jcallerStack);
-    if (index < len) {
-        return (*env)->GetObjectArrayElement(env, jcallerStack, index);
-    }
-    return NULL;
-}
-
 /*
  * Class:     java_lang_ClassLoader_NativeLibrary
  * Method:    findBuiltinLib
diff --git a/jdk/src/share/native/java/lang/SecurityManager.c b/jdk/src/share/native/java/lang/SecurityManager.c
index 397e30bb99a..a815df5300f 100644
--- a/jdk/src/share/native/java/lang/SecurityManager.c
+++ b/jdk/src/share/native/java/lang/SecurityManager.c
@@ -29,7 +29,6 @@
 
 #include "java_lang_SecurityManager.h"
 #include "java_lang_ClassLoader.h"
-#include "java_util_ResourceBundle.h"
 
 /*
  * Make sure a security manager instance is initialized.
diff --git a/jdk/src/share/native/sun/reflect/Reflection.c b/jdk/src/share/native/sun/reflect/Reflection.c
index 5a92d9ef385..46cfa570e1c 100644
--- a/jdk/src/share/native/sun/reflect/Reflection.c
+++ b/jdk/src/share/native/sun/reflect/Reflection.c
@@ -27,9 +27,9 @@
 #include "sun_reflect_Reflection.h"
 
 JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass
-(JNIEnv *env, jclass unused, jint depth)
+(JNIEnv *env, jclass unused)
 {
-    return JVM_GetCallerClass(env, depth);
+    return JVM_GetCallerClass(env, JVM_DEPTH); // JVM_DEPTH is only the expected value
 }
 
 JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags
diff --git a/jdk/test/Makefile b/jdk/test/Makefile
index bd3a8d3b23a..289e208ee9d 100644
--- a/jdk/test/Makefile
+++ b/jdk/test/Makefile
@@ -478,7 +478,7 @@ jdk_io: $(call TestDirs, java/io)
 # Stable agentvm testruns (minus items from PROBLEM_LIST)
 JDK_ALL_TARGETS += jdk_lang
 JDK_DEFAULT_TARGETS += jdk_lang
-jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc vm)
+jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc sun/reflect vm)
 	$(call RunAgentvmBatch)
 
 # Stable othervm testruns (minus items from PROBLEM_LIST)
diff --git a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java
new file mode 100644
index 00000000000..8dbb23503fc
--- /dev/null
+++ b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.jdeps.ClassFileReader;
+import static com.sun.tools.classfile.ConstantPool.*;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+
+/*
+ * @test
+ * @bug 8010117
+ * @summary Verify if CallerSensitive methods are annotated with
+ *          sun.reflect.CallerSensitive annotation
+ * @build CallerSensitiveFinder MethodFinder
+ * @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder
+ */
+public class CallerSensitiveFinder extends MethodFinder {
+    private static int numThreads = 3;
+    private static boolean verbose = false;
+    public static void main(String[] args) throws Exception {
+        List<Path> classes = new ArrayList<>();
+        String testclasses = System.getProperty("test.classes", ".");
+        int i = 0;
+        while (i < args.length) {
+            String arg = args[i++];
+            if (arg.equals("-v")) {
+                verbose = true;
+            } else {
+                Path p = Paths.get(testclasses, arg);
+                if (!p.toFile().exists()) {
+                    throw new IllegalArgumentException(arg + " does not exist");
+                }
+                classes.add(p);
+            }
+        }
+        if (classes.isEmpty()) {
+            classes.addAll(PlatformClassPath.getJREClasses());
+        }
+        final String method = "sun/reflect/Reflection.getCallerClass";
+        CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method);
+
+        List<String> errors = csfinder.run(classes);
+        if (!errors.isEmpty()) {
+            throw new RuntimeException(errors.size() +
+                    " caller-sensitive methods are missing @CallerSensitive annotation");
+        }
+    }
+
+    private final List<String> csMethodsMissingAnnotation = new ArrayList<>();
+    public CallerSensitiveFinder(String... methods) {
+        super(methods);
+    }
+
+    public List<String> run(List<Path> classes) throws IOException, InterruptedException,
+            ExecutionException, ConstantPoolException
+    {
+        ExecutorService pool = Executors.newFixedThreadPool(numThreads);
+        for (Path path : classes) {
+            ClassFileReader reader = ClassFileReader.newInstance(path.toFile());
+            for (ClassFile cf : reader.getClassFiles()) {
+                String classFileName = cf.getName();
+                // for each ClassFile
+                //    parse constant pool to find matching method refs
+                //      parse each method (caller)
+                //      - visit and find method references matching the given method name
+                pool.submit(getTask(cf));
+            }
+        }
+        waitForCompletion();
+        pool.shutdown();
+        return csMethodsMissingAnnotation;
+    }
+
+    private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;";
+    private static boolean isCallerSensitive(Method m, ConstantPool cp)
+            throws ConstantPoolException
+    {
+        RuntimeAnnotations_attribute attr =
+            (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations);
+        int index = 0;
+        if (attr != null) {
+            for (int i = 0; i < attr.annotations.length; i++) {
+                Annotation ann = attr.annotations[i];
+                String annType = cp.getUTF8Value(ann.type_index);
+                if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void referenceFound(ClassFile cf, Method m, Set<Integer> refs)
+            throws ConstantPoolException
+    {
+        String name = String.format("%s#%s %s", cf.getName(),
+                                    m.getName(cf.constant_pool),
+                                    m.descriptor.getValue(cf.constant_pool));
+        if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) {
+            csMethodsMissingAnnotation.add(name);
+            System.err.println("Missing @CallerSensitive: " + name);
+        } else {
+            if (verbose) {
+                System.out.format("@CS  %s%n", name);
+            }
+        }
+    }
+
+    private final List<FutureTask<String>> tasks = new ArrayList<FutureTask<String>>();
+    private FutureTask<String> getTask(final ClassFile cf) {
+        FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
+            public String call() throws Exception {
+                return parse(cf);
+            }
+        });
+        tasks.add(task);
+        return task;
+    }
+
+    private void waitForCompletion() throws InterruptedException, ExecutionException {
+        for (FutureTask<String> t : tasks) {
+            String s = t.get();
+        }
+        System.out.println("Parsed " + tasks.size() + " classfiles");
+    }
+
+    static class PlatformClassPath {
+        static List<Path> getJREClasses() throws IOException {
+            List<Path> result = new ArrayList<Path>();
+            Path home = Paths.get(System.getProperty("java.home"));
+
+            if (home.endsWith("jre")) {
+                // jar files in <javahome>/jre/lib
+                // skip <javahome>/lib
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else if (home.resolve("lib").toFile().exists()) {
+                // either a JRE or a jdk build image
+                File classes = home.resolve("classes").toFile();
+                if (classes.exists() && classes.isDirectory()) {
+                    // jdk build outputdir
+                    result.add(classes.toPath());
+                }
+                // add other JAR files
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else {
+                throw new RuntimeException("\"" + home + "\" not a JDK home");
+            }
+            return result;
+        }
+
+        static List<Path> addJarFiles(final Path root) throws IOException {
+            final List<Path> result = new ArrayList<Path>();
+            final Path ext = root.resolve("ext");
+            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+                        throws IOException {
+                    if (dir.equals(root) || dir.equals(ext)) {
+                        return FileVisitResult.CONTINUE;
+                    } else {
+                        // skip other cobundled JAR files
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                        throws IOException {
+                    File f = file.toFile();
+                    String fn = f.getName();
+                    // parse alt-rt.jar as well
+                    if (fn.endsWith(".jar") && !fn.equals("jfxrt.jar")) {
+                        result.add(file);
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+            return result;
+        }
+    }
+}
diff --git a/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java b/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java
new file mode 100644
index 00000000000..8ea78866dae
--- /dev/null
+++ b/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+import java.util.*;
+import com.sun.tools.classfile.*;
+import static com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.Instruction.TypeKind;
+
+/**
+ * MethodFinder utility class to find references to the given methods.
+ */
+public abstract class MethodFinder {
+    final List<String> methods;
+    public MethodFinder(String... methods) {
+        this.methods = Arrays.asList(methods);
+    }
+
+    /**
+     * A callback method will be invoked when a method referencing
+     * any of the lookup methods.
+     *
+     * @param cf ClassFile
+     * @param m Method
+     * @param refs Set of constant pool indices that reference the methods
+     *             matching the given lookup method names
+     */
+    public abstract void referenceFound(ClassFile cf, Method m, Set<Integer> refs)
+            throws ConstantPoolException;
+
+    public String parse(ClassFile cf) throws ConstantPoolException {
+        List<Integer> cprefs = new ArrayList<Integer>();
+        int index = 1;
+        for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) {
+            if (cpInfo.accept(cpVisitor, null)) {
+                cprefs.add(index);
+            }
+            index += cpInfo.size();
+        }
+
+        if (!cprefs.isEmpty()) {
+            for (Method m : cf.methods) {
+                Set<Integer> refs = new HashSet<Integer>();
+                Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code);
+                if (c_attr != null) {
+                    for (Instruction instr : c_attr.getInstructions()) {
+                        int idx = instr.accept(codeVisitor, cprefs);
+                        if (idx > 0) {
+                            refs.add(idx);
+                        }
+                    }
+                }
+                if (refs.size() > 0) {
+                    referenceFound(cf, m, refs);
+                }
+            }
+        }
+        return cprefs.isEmpty() ? "" : cf.getName();
+    }
+
+    private ConstantPool.Visitor<Boolean,Void> cpVisitor =
+            new ConstantPool.Visitor<Boolean,Void>()
+    {
+        private boolean matches(CPRefInfo info) {
+            try {
+                CONSTANT_NameAndType_info nat = info.getNameAndTypeInfo();
+                return matches(info.getClassName(), nat.getName(), nat.getType());
+            } catch (ConstantPoolException ex) {
+                return false;
+            }
+        }
+
+        private boolean matches(String cn, String name, String type) {
+            return methods.contains(cn + "." + name);
+        }
+
+        public Boolean visitClass(CONSTANT_Class_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
+            return matches(info);
+        }
+
+        public Boolean visitMethodref(CONSTANT_Methodref_info info, Void p) {
+            return matches(info);
+        }
+
+        public Boolean visitDouble(CONSTANT_Double_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitFieldref(CONSTANT_Fieldref_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitFloat(CONSTANT_Float_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInteger(CONSTANT_Integer_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitLong(CONSTANT_Long_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitMethodType(CONSTANT_MethodType_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitString(CONSTANT_String_info info, Void p) {
+            return false;
+        }
+
+        public Boolean visitUtf8(CONSTANT_Utf8_info info, Void p) {
+            return false;
+        }
+    };
+
+    private Instruction.KindVisitor<Integer, List<Integer>> codeVisitor =
+            new Instruction.KindVisitor<Integer, List<Integer>>()
+    {
+        public Integer visitNoOperands(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitArrayType(Instruction instr, TypeKind kind, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitBranch(Instruction instr, int offset, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitConstantPoolRef(Instruction instr, int index, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitLocal(Instruction instr, int index, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLocalAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitValue(Instruction instr, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitUnknown(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+    };
+}
+
diff --git a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java
new file mode 100644
index 00000000000..c60a8d0eca5
--- /dev/null
+++ b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java
@@ -0,0 +1,65 @@
+/*
+ * 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 8010117
+ * @summary Test CallerSensitiveFinder to find missing annotation
+ * @compile -XDignore.symbol.file MissingCallerSensitive.java
+ * @build CallerSensitiveFinder MethodFinder
+ * @run main MissingCallerSensitive
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+public class MissingCallerSensitive {
+    public static void main(String[] args) throws Exception {
+        String testclasses = System.getProperty("test.classes", ".");
+        List<Path> classes = new ArrayList<>();
+        classes.add(Paths.get(testclasses, "MissingCallerSensitive.class"));
+
+        final String method = "sun/reflect/Reflection.getCallerClass";
+        CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method);
+        List<String> errors = csfinder.run(classes);
+        if (errors.size() != 1) {
+            throw new RuntimeException("Unexpected number of methods found: " + errors.size());
+        }
+        String m = errors.get(0);
+        if (!m.startsWith("MissingCallerSensitive#missingCallerSensitiveAnnotation")) {
+            throw new RuntimeException("Unexpected method missing annotation: " + m);
+        }
+    }
+
+    @sun.reflect.CallerSensitive
+    public ClassLoader getCallerLoader() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+
+    public ClassLoader missingCallerSensitiveAnnotation() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+}
diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClass.java b/jdk/test/sun/reflect/Reflection/GetCallerClass.java
new file mode 100644
index 00000000000..8c822a5f517
--- /dev/null
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClass.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package boot;
+
+public class GetCallerClass {
+    @sun.reflect.CallerSensitive
+    public ClassLoader getCallerLoader() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+
+    public ClassLoader missingCallerSensitiveAnnotation() {
+        Class<?> c = sun.reflect.Reflection.getCallerClass();
+        return c.getClassLoader();
+    }
+}
diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java
new file mode 100644
index 00000000000..3e96f4b0a70
--- /dev/null
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+import boot.GetCallerClass;
+import java.lang.reflect.*;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+public class GetCallerClassTest {
+    private final GetCallerClass gcc;   // boot.GetCallerClass is in bootclasspath
+    GetCallerClassTest() {
+        this.gcc = new GetCallerClass();
+    }
+
+    public static void main(String[] args) throws Exception {
+        GetCallerClassTest gcct = new GetCallerClassTest();
+        // ensure methods are annotated with @CallerSensitive
+        ensureAnnotationPresent(boot.GetCallerClass.class, "getCallerLoader", true);
+        ensureAnnotationPresent(GetCallerClassTest.class, "testNonSystemMethod", false);
+        // call Reflection.getCallerClass from bootclasspath with and without @CS
+        gcct.testCallerSensitiveMethods();
+        // call Reflection.getCallerClass from classpath with @CS
+        gcct.testNonSystemMethod();
+    }
+
+    private static void ensureAnnotationPresent(Class<?> c, String name, boolean cs)
+        throws NoSuchMethodException
+    {
+        Method m = c.getDeclaredMethod(name);
+        if (!m.isAnnotationPresent(CallerSensitive.class)) {
+            throw new RuntimeException("@CallerSensitive not present in method " + m);
+        }
+        if (Reflection.isCallerSensitive(m) != cs) {
+            throw new RuntimeException("Unexpected: isCallerSensitive returns " +
+                Reflection.isCallerSensitive(m));
+        }
+    }
+
+    private void testCallerSensitiveMethods() {
+        try {
+            ClassLoader cl = gcc.getCallerLoader();
+            if (cl != GetCallerClassTest.class.getClassLoader()) {
+                throw new RuntimeException("mismatched class loader");
+            }
+            gcc.missingCallerSensitiveAnnotation();
+            throw new RuntimeException("getCallerLoader not marked with @CallerSensitive");
+        } catch (InternalError e) {
+            StackTraceElement[] stackTrace = e.getStackTrace();
+            checkStackTrace(stackTrace, e);
+            if (!stackTrace[1].getClassName().equals(GetCallerClass.class.getName()) ||
+                !stackTrace[1].getMethodName().equals("missingCallerSensitiveAnnotation")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[2].getMethodName().equals("testCallerSensitiveMethods")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            System.out.println("Expected error: " + e.getMessage());
+        }
+    }
+
+    @CallerSensitive
+    private void testNonSystemMethod() {
+        try {
+            Class<?> c = Reflection.getCallerClass();
+            throw new RuntimeException("@CallerSensitive testNonSystemMethods not supported");
+        } catch (InternalError e) {
+            StackTraceElement[] stackTrace = e.getStackTrace();
+            checkStackTrace(stackTrace, e);
+            if (!stackTrace[1].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[1].getMethodName().equals("testNonSystemMethod")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) ||
+                !stackTrace[2].getMethodName().equals("main")) {
+                throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+            }
+            System.out.println("Expected error: " + e.getMessage());
+        }
+    }
+
+    private void checkStackTrace(StackTraceElement[] stackTrace, Error e) {
+        if (stackTrace.length < 3) {
+            throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+        }
+
+        if (!stackTrace[0].getClassName().equals("sun.reflect.Reflection") ||
+            !stackTrace[0].getMethodName().equals("getCallerClass")) {
+            throw new RuntimeException("Unexpected error: " + e.getMessage(), e);
+        }
+
+    }
+}
diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh
new file mode 100644
index 00000000000..b6337096320
--- /dev/null
+++ b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh
@@ -0,0 +1,68 @@
+#
+# 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 8010117
+# @summary Test if the VM enforces sun.reflect.Reflection.getCallerClass 
+#          be called by methods annotated with sun.reflect.CallerSensitive
+#
+# @run shell GetCallerClassTest.sh
+
+if [ "${TESTSRC}" = "" ]
+then
+  echo "TESTSRC not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTSRC=${TESTSRC}"
+if [ "${TESTJAVA}" = "" ]
+then
+  echo "TESTJAVA not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+echo "TESTJAVA=${TESTJAVA}"
+if [ "${COMPILEJAVA}" = "" ]
+then
+  COMPILEJAVA="${TESTJAVA}"
+fi
+echo "COMPILEJAVA=${COMPILEJAVA}"
+if [ "${TESTCLASSES}" = "" ]
+then
+  echo "TESTCLASSES not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+BCP=${TESTCLASSES}/bcp
+rm -rf ${BCP}
+mkdir ${BCP}
+
+# Compile GetCallerClass in bootclasspath
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
+     -XDignore.symbol.file \
+     -d ${BCP} ${TESTSRC}/GetCallerClass.java  || exit 1
+
+${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \
+     -XDignore.symbol.file -Xbootclasspath/a:${BCP} \
+     -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java  || exit 2
+
+${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \
+     -cp ${TESTCLASSES} GetCallerClassTest || exit 3

From fc3e45929e225e9c7ecdd3070718dc912acbb069 Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang <yhuang@openjdk.org>
Date: Tue, 16 Apr 2013 22:28:47 -0700
Subject: [PATCH 36/36] 8011977: ISO 4217 Amendment Number 155

Reviewed-by: naoto
---
 jdk/src/share/classes/java/util/CurrencyData.properties | 6 +++---
 jdk/test/java/util/Currency/tablea1.txt                 | 8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/jdk/src/share/classes/java/util/CurrencyData.properties b/jdk/src/share/classes/java/util/CurrencyData.properties
index 198558d05a3..4783af39505 100644
--- a/jdk/src/share/classes/java/util/CurrencyData.properties
+++ b/jdk/src/share/classes/java/util/CurrencyData.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 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
@@ -28,7 +28,7 @@ formatVersion=1
 # Version of the currency code information in this class.
 # It is a serial number that accompanies with each amendment.
 
-dataVersion=154
+dataVersion=155
 
 # List of all valid ISO 4217 currency codes.
 # To ensure compatibility, do not remove codes.
@@ -585,7 +585,7 @@ ZW=ZWL
 minor0=\
     ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
     GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
-    TPE-TRL-VND-VUV-XAF-XOF-XPF
+    TPE-TRL-UGX-VND-VUV-XAF-XOF-XPF
 minor1=
 minor3=\
     BHD-IQD-JOD-KWD-LYD-OMR-TND
diff --git a/jdk/test/java/util/Currency/tablea1.txt b/jdk/test/java/util/Currency/tablea1.txt
index ea142da7d33..40af4631257 100644
--- a/jdk/test/java/util/Currency/tablea1.txt
+++ b/jdk/test/java/util/Currency/tablea1.txt
@@ -1,12 +1,12 @@
 #
 #
-# Amendments up until ISO 4217 AMENDMENT NUMBER 154
-#   (As of 31 August 2012)
+# Amendments up until ISO 4217 AMENDMENT NUMBER 155
+#   (As of 11 April 2013)
 #
 
 # Version
 FILEVERSION=1
-DATAVERSION=154
+DATAVERSION=155
 
 # ISO 4217 currency data
 AF	AFN	971	2
@@ -256,7 +256,7 @@ TR	TRY	949	2
 TM	TMT	934	2
 TC	USD	840	2
 TV	AUD	36	2
-UG	UGX	800	2
+UG	UGX	800	0
 UA	UAH	980	2
 AE	AED	784	2
 GB	GBP	826	2