4924727: reader.abort() method does not work when called inside imageStarted for PNG

Reviewed-by: prr, serb, bpb
This commit is contained in:
Jayathirth D V 2016-09-12 12:07:56 +05:30
parent b68b46b14f
commit a99b7ce759
8 changed files with 326 additions and 92 deletions

View File

@ -42,6 +42,7 @@ SUNWprivate_1.1 {
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetReader;
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_disposeReader;
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetLibraryState;
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_clearNativeReadAbortFlag;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter;
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, 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
@ -749,6 +749,10 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
checkIndex(imageIndex);
clearAbortRequest();
processImageStarted(imageIndex);
if (abortRequested()) {
processReadAborted();
return bi;
}
if (param == null)
param = getDefaultReadParam();
@ -1005,9 +1009,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
@ -1015,6 +1016,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
@ -1051,9 +1055,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
@ -1067,6 +1068,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
@ -1087,9 +1091,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
@ -1097,6 +1098,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
@ -1133,9 +1137,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
@ -1149,6 +1150,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
@ -1168,9 +1172,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
@ -1178,6 +1179,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
@ -1200,9 +1204,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@ -1216,6 +1217,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
@ -1235,9 +1239,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int j = isBottomUp ? (height -1) * width * 3 : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(bdata, j, lineStride);
iis.skipBytes(padding);
j += isBottomUp ? -lineStride : lineStride;
@ -1245,6 +1246,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
@ -1267,9 +1271,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.read(buf, 0, lineLength);
for (int i = 0, m = 3 * sourceRegion.x;
i < destinationRegion.width; i++, m += 3 * scaleX) {
@ -1285,6 +1286,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
@ -1302,10 +1306,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(sdata, j, width);
iis.skipBytes(padding);
@ -1314,6 +1314,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
short[] buf = new short[lineLength];
@ -1336,9 +1339,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.readFully(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@ -1352,6 +1352,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
@ -1361,15 +1364,15 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
if (abortRequested()) {
break;
}
iis.readFully(idata, j, width);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
int[] buf = new int[width];
@ -1392,9 +1395,6 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
if (abortRequested())
break;
iis.readFully(buf, 0, width);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
@ -1408,6 +1408,9 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -456,6 +456,9 @@ public class GIFImageReader extends ImageReader {
// Update IIOReadProgressListeners
++rowsDone;
processImageProgress(100.0F*rowsDone/height);
if (abortRequested()) {
return;
}
if (decodeThisRow) {
outputRow();
@ -860,7 +863,6 @@ public class GIFImageReader extends ImageReader {
throw new IndexOutOfBoundsException("imageIndex out of bounds!");
}
clearAbortRequest();
readMetadata();
// A null ImageReadParam means we use the default
@ -903,8 +905,13 @@ public class GIFImageReader extends ImageReader {
(streamY - sourceRegion.y)/sourceYSubsampling;
computeDecodeThisRow();
clearAbortRequest();
// Inform IIOReadProgressListeners of start of image
processImageStarted(imageIndex);
if (abortRequested()) {
processReadAborted();
return theImage;
}
startPass(0);
this.rowBuf = new byte[width];
@ -947,7 +954,7 @@ public class GIFImageReader extends ImageReader {
int codeSize = initCodeSize + 1;
int codeMask = (1 << codeSize) - 1;
while (!abortRequested()) {
do {
code = getCode(codeSize, codeMask);
if (code == clearCode) {
@ -1005,7 +1012,7 @@ public class GIFImageReader extends ImageReader {
outputPixels(string, len);
oldCode = code;
}
} while (!abortRequested());
processReadAborted();
return theImage;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -1327,28 +1327,32 @@ public class JPEGImageReader extends ImageReader {
System.out.println("callbackUpdates is " + callbackUpdates);
}
// Finally, we are ready to read
/*
* All the Jpeg processing happens in native, we should clear
* abortFlag of imageIODataStruct in imageioJPEG.c. And we need to
* clear abortFlag because if in previous read() if we had called
* reader.abort() that will continue to be valid for present call also.
*/
clearNativeReadAbortFlag(structPointer);
processImageStarted(currentImage);
boolean aborted = false;
// Note that getData disables acceleration on buffer, but it is
// just a 1-line intermediate data transfer buffer that will not
// affect the acceleration of the resulting image.
aborted = readImage(structPointer,
buffer.getData(),
numRasterBands,
srcBands,
bandSizes,
srcROI.x, srcROI.y,
srcROI.width, srcROI.height,
periodX, periodY,
abbrevQTables,
abbrevDCHuffmanTables,
abbrevACHuffmanTables,
minProgressivePass, maxProgressivePass,
callbackUpdates);
/*
* Note that getData disables acceleration on buffer, but it is
* just a 1-line intermediate data transfer buffer that will not
* affect the acceleration of the resulting image.
*/
boolean aborted = readImage(structPointer,
buffer.getData(),
numRasterBands,
srcBands,
bandSizes,
srcROI.x, srcROI.y,
srcROI.width, srcROI.height,
periodX, periodY,
abbrevQTables,
abbrevDCHuffmanTables,
abbrevACHuffmanTables,
minProgressivePass, maxProgressivePass,
callbackUpdates);
if (aborted) {
processReadAborted();
@ -1513,6 +1517,12 @@ public class JPEGImageReader extends ImageReader {
int maxProgressivePass,
boolean wantUpdates);
/*
* We should call clearNativeReadAbortFlag() before we start reading
* jpeg image as image processing happens at native side.
*/
private native void clearNativeReadAbortFlag(long structPointer);
public void abort() {
setThreadLock();
try {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -937,12 +937,6 @@ public class PNGImageReader extends ImageReader {
for (int srcY = 0; srcY < passHeight; srcY++) {
// Skip filter byte and the remaining row bytes
pixelStream.skipBytes(1 + bytesPerRow);
// If read has been aborted, just return
// processReadAborted will be called later
if (abortRequested()) {
return;
}
}
}
@ -996,6 +990,13 @@ public class PNGImageReader extends ImageReader {
for (int srcY = 0; srcY < passHeight; srcY++) {
// Update count of pixels read
updateImageProgress(passWidth);
/*
* If read has been aborted, just return
* processReadAborted will be called later
*/
if (abortRequested()) {
return;
}
// Skip filter byte and the remaining row bytes
pixelStream.skipBytes(1 + bytesPerRow);
}
@ -1105,7 +1106,13 @@ public class PNGImageReader extends ImageReader {
for (int srcY = 0; srcY < passHeight; srcY++) {
// Update count of pixels read
updateImageProgress(passWidth);
/*
* If read has been aborted, just return
* processReadAborted will be called later
*/
if (abortRequested()) {
return;
}
// Read the filter type byte and a row of data
int filter = pixelStream.read();
try {
@ -1195,12 +1202,6 @@ public class PNGImageReader extends ImageReader {
updateWidth, 1,
updateXStep, updateYStep,
destinationBands);
// If read has been aborted, just return
// processReadAborted will be called later
if (abortRequested()) {
return;
}
}
}
@ -1215,8 +1216,6 @@ public class PNGImageReader extends ImageReader {
this.pixelsDone = 0;
this.totalPixels = width*height;
clearAbortRequest();
if (metadata.IHDR_interlaceMethod == 0) {
decodePass(0, 0, 0, 1, 1, width, height);
} else {
@ -1241,8 +1240,10 @@ public class PNGImageReader extends ImageReader {
(height + ybump)/YSubsampling);
}
// If read has been aborted, just return
// processReadAborted will be called later
/*
* If read has been aborted, just return
* processReadAborted will be called later
*/
if (abortRequested()) {
return;
}
@ -1332,13 +1333,19 @@ public class PNGImageReader extends ImageReader {
inputBandsForColorType[colorType],
theImage.getSampleModel().getNumBands());
clearAbortRequest();
processImageStarted(0);
decodeImage();
if (abortRequested()) {
processReadAborted();
} else {
processImageComplete();
decodeImage();
if (abortRequested()) {
processReadAborted();
} else {
processImageComplete();
}
}
} catch (IOException e) {
throw new IIOException("Error reading PNG image data", e);
} finally {

View File

@ -1131,8 +1131,12 @@ public class TIFFImageReader extends ImageReader {
pixelsToRead = destRegion.width * destRegion.height;
pixelsRead = 0;
clearAbortRequest();
processImageStarted(imageIndex);
processImageProgress(0.0f);
if (abortRequested()) {
processReadAborted();
return theImage;
}
tilesAcross = (width + tileOrStripWidth - 1) / tileOrStripWidth;
tilesDown = (height + tileOrStripHeight - 1) / tileOrStripHeight;
@ -1286,6 +1290,10 @@ public class TIFFImageReader extends ImageReader {
}
reportProgress();
if (abortRequested()) {
processReadAborted();
return theImage;
}
}
}
} else {
@ -1294,16 +1302,14 @@ public class TIFFImageReader extends ImageReader {
decodeTile(ti, tj, -1);
reportProgress();
if (abortRequested()) {
processReadAborted();
return theImage;
}
}
}
}
if (abortRequested()) {
processReadAborted();
} else {
processImageComplete();
}
processImageComplete();
return theImage;
}

View File

@ -2161,6 +2161,25 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
return data->abortFlag;
}
JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_clearNativeReadAbortFlag
(JNIEnv *env,
jobject this,
jlong ptr) {
imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr);
if (data == NULL) {
JNU_ThrowByName(env,
"java/lang/IllegalStateException",
"Attempting to use reader after dispose()");
return;
}
data->abortFlag = JNI_FALSE;
}
JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_abortRead
(JNIEnv *env,

View File

@ -0,0 +1,181 @@
/*
* Copyright (c) 2016, 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 4924727
* @summary Test verifies that if we call ImageReader.abort() in
* IIOReadProgressListener.imageStarted() or
* IIOReadProgressListener.imageProgress() are we
* calling IIOReadProgressListener.readAborted() for all readers.
* @run main ReadAbortTest
*/
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.stream.ImageInputStream;
import java.awt.Color;
import java.awt.Graphics2D;
import java.nio.file.Files;
public class ReadAbortTest implements IIOReadProgressListener {
ImageReader reader = null;
ImageInputStream iis = null;
BufferedImage bimg = null;
File file;
boolean startAbort = false;
boolean startAborted = false;
boolean progressAbort = false;
boolean progressAborted = false;
Color srccolor = Color.red;
int width = 100;
int heght = 100;
public ReadAbortTest(String format) throws Exception {
try {
System.out.println("Test for format " + format);
bimg = new BufferedImage(width, heght,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimg.createGraphics();
g.setColor(srccolor);
g.fillRect(0, 0, width, heght);
g.dispose();
file = File.createTempFile("src_", "." + format, new File("."));
ImageIO.write(bimg, format, file);
ImageInputStream iis = ImageIO.createImageInputStream(file);
Iterator iter = ImageIO.getImageReaders(iis);
while (iter.hasNext()) {
reader = (ImageReader) iter.next();
break;
}
reader.setInput(iis);
reader.addIIOReadProgressListener(this);
// Abort reading in IIOReadProgressListener.imageStarted().
startAbort = true;
bimg = reader.read(0);
startAbort = false;
// Abort reading in IIOReadProgressListener.imageProgress().
progressAbort = true;
bimg = reader.read(0);
progressAbort = false;
iis.close();
/*
* All abort requests from imageStarted,imageProgress and
* imageComplete from IIOReadProgressListener should be reached
* otherwise throw RuntimeException.
*/
if (!(startAborted
&& progressAborted)) {
throw new RuntimeException("All IIOReadProgressListener abort"
+ " requests are not processed for format "
+ format);
}
} catch (Exception e) {
throw e;
} finally {
Files.delete(file.toPath());
}
}
/*
* Abstract methods that we need to implement from
* IIOReadProgressListener, and relevant for this test case.
*/
@Override
public void imageStarted(ImageReader source, int imageIndex) {
System.out.println("imageStarted called");
if (startAbort) {
source.abort();
}
}
@Override
public void imageProgress(ImageReader source, float percentageDone) {
System.out.println("imageProgress called");
if (progressAbort) {
source.abort();
}
}
@Override
public void readAborted(ImageReader source) {
System.out.println("readAborted called");
// Verify IIOReadProgressListener.imageStarted() abort request.
if (startAbort) {
System.out.println("imageStarted aborted ");
startAborted = true;
}
// Verify IIOReadProgressListener.imageProgress() abort request.
if (progressAbort) {
System.out.println("imageProgress aborted ");
progressAborted = true;
}
}
public static void main(String args[]) throws Exception {
final String[] formats = {"bmp", "png", "gif", "jpg", "tif"};
for (String format : formats) {
new ReadAbortTest(format);
}
}
/*
* Remaining abstract methods that we need to implement from
* IIOReadProgressListener, but not relevant for this test case.
*/
@Override
public void imageComplete(ImageReader source) {
}
@Override
public void sequenceStarted(ImageReader reader, int i) {
}
@Override
public void sequenceComplete(ImageReader reader) {
}
@Override
public void thumbnailStarted(ImageReader reader, int i, int i1) {
}
@Override
public void thumbnailProgress(ImageReader reader, float f) {
}
@Override
public void thumbnailComplete(ImageReader reader) {
}
}