OpenJDK / jdk7u / jdk7u-dev / jdk
changeset 5972:90c9f1577a0b
8007918: Better image writing
Reviewed-by: prr, jgodinez
author | bae |
---|---|
date | Tue, 26 Feb 2013 01:27:17 +0400 |
parents | d868fe7c7618 |
children | f9fda42383a2 |
files | src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java src/share/native/sun/awt/image/jpeg/imageioJPEG.c |
diffstat | 2 files changed, 131 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Tue Feb 26 00:15:17 2013 +0400 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Tue Feb 26 01:27:17 2013 +0400 @@ -178,8 +178,7 @@ static { java.security.AccessController.doPrivileged( new sun.security.action.LoadLibraryAction("jpeg")); - initWriterIDs(ImageOutputStream.class, - JPEGQTable.class, + initWriterIDs(JPEGQTable.class, JPEGHuffmanTable.class); } @@ -195,11 +194,13 @@ 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(); } @@ -354,6 +355,8 @@ ImageWriteParam param) throws IOException { setThreadLock(); try { + cbLock.check(); + writeOnThread(streamMetadata, image, param); } finally { clearThreadLock(); @@ -1077,13 +1080,18 @@ haveMetadata, restartInterval); - if (aborted) { - processWriteAborted(); - } else { - processImageComplete(); + cbLock.lock(); + try { + if (aborted) { + processWriteAborted(); + } else { + processImageComplete(); + } + + ios.flush(); + } finally { + cbLock.unlock(); } - - ios.flush(); currentImage++; // After a successful write } @@ -1091,6 +1099,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + prepareWriteSequenceOnThread(streamMetadata); } finally { clearThreadLock(); @@ -1170,6 +1180,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1183,6 +1195,8 @@ public void endWriteSequence() throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1195,6 +1209,10 @@ 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 { @@ -1218,6 +1236,8 @@ public void reset() { setThreadLock(); try { + cbLock.check(); + super.reset(); } finally { clearThreadLock(); @@ -1227,6 +1247,8 @@ public void dispose() { setThreadLock(); try { + cbLock.check(); + if (structPointer != 0) { disposerRecord.dispose(); structPointer = 0; @@ -1246,13 +1268,18 @@ * 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)); } /** @@ -1269,21 +1296,41 @@ * 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 @@ -1610,16 +1657,14 @@ ////////////// 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 <code>true</code> if the write was aborted. @@ -1744,7 +1789,12 @@ } 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(); + } } } @@ -1772,6 +1822,25 @@ } } + /** + * 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; @@ -1806,4 +1875,34 @@ 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 + } + } }
--- a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Tue Feb 26 00:15:17 2013 +0400 +++ b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Tue Feb 26 01:27:17 2013 +0400 @@ -66,7 +66,7 @@ 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 @@ (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, sb->bufferLength); @@ -2327,7 +2327,7 @@ (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, datacount); @@ -2365,13 +2365,12 @@ 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 @@ 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 @@ 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