Bug 568641 - [GTK] IAE in GC.drawImage when switching screen DPI
- Image.getBounds now takes into account if we are using cairo auto
scaling
- Image.init(ImageData) & Image.initNative now scale the width and
height of the Image
object to user coordinate (100% scale factor). Note that the cairo
surface is still being initalized to the full dimensions given and the
device_scale is set appropriately to reflect that as well.
Change-Id: Ia8724098e7711772919dba49c25e27ffe3e09d5f
Signed-off-by: Paul D'Pong <sdamrong@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java
index b68d3b3..22e26bf 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java
@@ -823,18 +823,25 @@
void createFromPixbuf(int type, long pixbuf) {
this.type = type;
- boolean hasAlpha = GDK.gdk_pixbuf_get_has_alpha(pixbuf);
- int width = this.width = GDK.gdk_pixbuf_get_width(pixbuf);
- int height = this.height = GDK.gdk_pixbuf_get_height(pixbuf);
+
+ int pixbufWidth = GDK.gdk_pixbuf_get_width(pixbuf);
+ int pixbufHeight = GDK.gdk_pixbuf_get_height(pixbuf);
+
+ // Scale dimensions of Image object to 100% scale factor
+ double scaleFactor = DPIUtil.getDeviceZoom() / 100f;
+ this.width = pixbufWidth / (int) scaleFactor;
+ this.height = pixbufHeight / (int) scaleFactor;
+
int stride = GDK.gdk_pixbuf_get_rowstride(pixbuf);
long pixels = GDK.gdk_pixbuf_get_pixels(pixbuf);
+ boolean hasAlpha = GDK.gdk_pixbuf_get_has_alpha(pixbuf);
int format = hasAlpha ? Cairo.CAIRO_FORMAT_ARGB32 : Cairo.CAIRO_FORMAT_RGB24;
- surface = Cairo.cairo_image_surface_create(format, width, height);
+
+ // Initialize surface with dimensions received from the pixbuf and set device_scale appropriately
+ surface = Cairo.cairo_image_surface_create(format, pixbufWidth, pixbufHeight);
if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- if (DPIUtil.useCairoAutoScale()) {
- double scaleFactor = DPIUtil.getDeviceZoom() / 100f;
- Cairo.cairo_surface_set_device_scale(surface, scaleFactor, scaleFactor);
- }
+ if (DPIUtil.useCairoAutoScale()) Cairo.cairo_surface_set_device_scale(surface, scaleFactor, scaleFactor);
+
long data = Cairo.cairo_image_surface_get_data(surface);
int cairoStride = Cairo.cairo_image_surface_get_stride(surface);
int oa = 0, or = 0, og = 0, ob = 0;
@@ -845,10 +852,10 @@
}
byte[] line = new byte[stride];
if (hasAlpha) {
- alphaData = new byte[width * height];
- for (int y = 0, alphaOffset = 0; y < height; y++) {
+ alphaData = new byte[pixbufWidth * pixbufHeight];
+ for (int y = 0, alphaOffset = 0; y < pixbufHeight; y++) {
C.memmove(line, pixels + (y * stride), stride);
- for (int x = 0, offset = 0; x < width; x++, offset += 4) {
+ for (int x = 0, offset = 0; x < pixbufWidth; x++, offset += 4) {
int a = line[offset + 3] & 0xFF;
int r = ((line[offset + 0] & 0xFF) * a) + 128;
r = (r + (r >> 8)) >> 8;
@@ -866,9 +873,9 @@
}
} else {
byte[] cairoLine = new byte[cairoStride];
- for (int y = 0; y < height; y++) {
+ for (int y = 0; y < pixbufHeight; y++) {
C.memmove(line, pixels + (y * stride), stride);
- for (int x = 0, offset = 0, cairoOffset = 0; x < width; x++, offset += 3, cairoOffset += 4) {
+ for (int x = 0, offset = 0, cairoOffset = 0; x < pixbufWidth; x++, offset += 3, cairoOffset += 4) {
int r = line[offset + 0] & 0xFF;
int g = line[offset + 1] & 0xFF;
int b = line[offset + 2] & 0xFF;
@@ -1010,7 +1017,7 @@
*/
public Rectangle getBounds() {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
- return DPIUtil.autoScaleBounds(getBoundsInPixels(), 100, currentDeviceZoom);
+ return DPIUtil.autoScaleDown(getBoundsInPixels());
}
/**
@@ -1292,20 +1299,29 @@
void init(ImageData image) {
if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- int width = this.width = image.width;
- int height = this.height = image.height;
+
PaletteData palette = image.palette;
if (!(((image.depth == 1 || image.depth == 2 || image.depth == 4 || image.depth == 8) && !palette.isDirect) ||
- ((image.depth == 8) || (image.depth == 16 || image.depth == 24 || image.depth == 32) && palette.isDirect)))
- SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
+ ((image.depth == 8) || (image.depth == 16 || image.depth == 24 || image.depth == 32) && palette.isDirect))) {
+ SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+
+ int imageDataWidth = image.width;
+ int imageDataHeight = image.height;
+
+ // Scale dimensions of Image object to 100% scale factor
+ double scaleFactor = DPIUtil.getDeviceZoom() / 100f;
+ this.width = imageDataWidth / (int) scaleFactor;
+ this.height = imageDataHeight / (int) scaleFactor;
+
boolean hasAlpha = image.transparentPixel != -1 || image.alpha != -1 || image.maskData != null || image.alphaData != null;
int format = hasAlpha ? Cairo.CAIRO_FORMAT_ARGB32 : Cairo.CAIRO_FORMAT_RGB24;
- surface = Cairo.cairo_image_surface_create(format, width, height);
+
+ // Initialize surface with dimensions received from the ImageData and set device_scale appropriately
+ surface = Cairo.cairo_image_surface_create(format, imageDataWidth, imageDataHeight);
if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- if (DPIUtil.useCairoAutoScale()) {
- double scaleFactor = DPIUtil.getDeviceZoom() / 100f;
- Cairo.cairo_surface_set_device_scale(surface, scaleFactor, scaleFactor);
- }
+ if (DPIUtil.useCairoAutoScale()) Cairo.cairo_surface_set_device_scale(surface, scaleFactor, scaleFactor);
+
int stride = Cairo.cairo_image_surface_get_stride(surface);
long data = Cairo.cairo_image_surface_get_data(surface);
int oa = 0, or = 0, og = 0, ob = 0;
@@ -1325,12 +1341,12 @@
}
byte[] buffer = image.data;
if (!palette.isDirect || image.depth != destDepth || stride != image.bytesPerLine || palette.redMask != redMask || palette.greenMask != greenMask || palette.blueMask != blueMask || destOrder != image.getByteOrder()) {
- buffer = new byte[stride * height];
+ buffer = new byte[stride * imageDataHeight];
if (palette.isDirect) {
ImageData.blit(ImageData.BLIT_SRC,
- image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
+ image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, imageDataWidth, imageDataHeight, palette.redMask, palette.greenMask, palette.blueMask,
ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
- buffer, destDepth, stride, destOrder, 0, 0, width, height, redMask, greenMask, blueMask,
+ buffer, destDepth, stride, destOrder, 0, 0, imageDataWidth, imageDataHeight, redMask, greenMask, blueMask,
false, false);
} else {
RGB[] rgbs = palette.getRGBs();
@@ -1346,9 +1362,9 @@
srcBlues[i] = (byte)rgb.blue;
}
ImageData.blit(ImageData.BLIT_SRC,
- image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
+ image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, imageDataWidth, imageDataHeight, srcReds, srcGreens, srcBlues,
ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
- buffer, destDepth, stride, destOrder, 0, 0, width, height, redMask, greenMask, blueMask,
+ buffer, destDepth, stride, destOrder, 0, 0, imageDataWidth, imageDataHeight, redMask, greenMask, blueMask,
false, false);
}
}
@@ -1369,8 +1385,8 @@
}
}
ImageData mask = image.getTransparencyMask();
- for (int y = 0, offset = 0; y < height; y++) {
- for (int x=0; x<width; x++, offset += 4) {
+ for (int y = 0, offset = 0; y < imageDataHeight; y++) {
+ for (int x=0; x<imageDataWidth; x++, offset += 4) {
int alpha = mask.getPixel(x, y) == 0 ? 0 : 0xff;
/* pre-multiplied alpha */
int r = ((buffer[offset + or] & 0xFF) * alpha) + 128;
@@ -1392,8 +1408,8 @@
System.arraycopy(image.alphaData, 0, this.alphaData, 0, alphaData.length);
}
if (this.alpha != -1) {
- for (int y = 0, offset = 0; y < height; y++) {
- for (int x=0; x<width; x++, offset += 4) {
+ for (int y = 0, offset = 0; y < imageDataHeight; y++) {
+ for (int x=0; x<imageDataWidth; x++, offset += 4) {
int alpha = this.alpha;
/* pre-multiplied alpha */
int r = ((buffer[offset + or] & 0xFF) * alpha) + 128;
@@ -1409,9 +1425,9 @@
}
}
} else if (this.alphaData != null) {
- for (int y = 0, offset = 0; y < height; y++) {
- for (int x=0; x<width; x++, offset += 4) {
- int alpha = alphaData [y*width+x] & 0xFF;
+ for (int y = 0, offset = 0; y < imageDataHeight; y++) {
+ for (int x=0; x<imageDataWidth; x++, offset += 4) {
+ int alpha = alphaData [y*imageDataWidth+x] & 0xFF;
/* pre-multiplied alpha */
int r = ((buffer[offset + or] & 0xFF) * alpha) + 128;
r = (r + (r >> 8)) >> 8;
@@ -1427,7 +1443,7 @@
}
}
}
- C.memmove(data, buffer, stride * height);
+ C.memmove(data, buffer, stride * imageDataHeight);
Cairo.cairo_surface_mark_dirty(surface);
}