Bug 545032: [GTK] Implement native ImageLoader

Most ImageData's created on GTK have an RGB byte order, however some
exceptions do exist. Specifically, ImageData's created from JFace's
CompositeImageDescriptor can have a BGR byte order. Because of
this, it's necessary to check the PaletteData in ImageLoader.save().

If the PaletteData indicates a negative blue shift, we are dealing with
BGR byte ordering and must adjust the offsets accordingly.

Revert some smaller changes from the original ImageLoader patch, as they
are not needed (causes the white background on breadcrumb icons).

Verified with the relevant bug snippets, JUnits, and with the JDT icons
in a child Eclipse.

Change-Id: I8d6e1cea4c1559689e42dedf334c550435cd7533
Signed-off-by: Eric Williams <ericwill@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
index 58a8649..ae4a103 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
@@ -667,7 +667,7 @@
 			surface = Cairo.cairo_image_surface_create(Cairo.CAIRO_FORMAT_RGB24, 10, 10);
 		} else {
 			gdkResource = GDK.gdk_get_default_root_window();
-			surface = GDK.gdk_window_create_similar_surface(gdkResource, Cairo.CAIRO_CONTENT_COLOR_ALPHA, 10, 10);
+			surface = GDK.gdk_window_create_similar_surface(gdkResource, Cairo.CAIRO_CONTENT_COLOR, 10, 10);
 		}
 		Cairo.cairo_surface_get_device_scale(surface, sx, sy);
 		DPIUtil.setUseCairoAutoScale((sx[0]*100) == scaleFactor);
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 da7ed3a..d865552 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
@@ -1252,7 +1252,7 @@
 	if (GTK.GTK4) {
 		surface = Cairo.cairo_image_surface_create(Cairo.CAIRO_FORMAT_RGB24, width, height);
 	} else {
-		surface = GDK.gdk_window_create_similar_surface(GDK.gdk_get_default_root_window(), Cairo.CAIRO_CONTENT_COLOR_ALPHA, width, height);
+		surface = GDK.gdk_window_create_similar_surface(GDK.gdk_get_default_root_window(), Cairo.CAIRO_CONTENT_COLOR, width, height);
 	}
 	if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES);
 	// When we create a blank image we need to set it to 100 in GTK3 as we draw using 100% scale.
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
index a6612be..248ccf1 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
@@ -469,11 +469,25 @@
 	int bytes_per_pixel = imgData.bytesPerLine / width; // n_channels for original ImageData (width * height * bytes_per_pixel) = imgData.length
 
 	/*
-	 * Destination offsets, ImageData data provided is in RGBA format.
-	 *
+	 * Destination offsets, GdkPixbuf data is stored in RGBA format.
 	 */
-	int da, dr, dg, db;
-	da = 3; dr = 0; dg = 1; db = 2;
+	int da = 3; int dr = 0; int dg = 1; int db = 2;
+
+	/*
+	 * ImageData offsets. These can vary depending on how the ImageData.data
+	 * field was populated. In most cases it will be RGB format, so this case
+	 * is assumed (blue shift is 0).
+	 *
+	 * If blue is negatively shifted, then we are dealing with BGR byte ordering, so
+	 * adjust the offsets accordingly.
+	 */
+	int or = 0; int og = 1; int ob = 2;
+	PaletteData palette = imgData.palette;
+	if (palette.isDirect && palette.blueShift < 0) {
+		or = 2;
+		og = 1;
+		ob = 0;
+	}
 
 	if (has_alpha && bytes_per_pixel == 3) {
 		bytes_per_pixel = 4;
@@ -487,10 +501,9 @@
 		for (int y = 0, offset = 0, new_offset = 0, alphaOffset = 0; y < height; y++) {
 			for (int x = 0; x < width; x++, offset += n_channels, new_offset += bytes_per_pixel) {
 				byte a = imgData.alphaData[alphaOffset++];
-				// ImageData data is stored in RGBA format
-				byte r = imgData.data[offset + alpha_offset + 0];
-				byte g = imgData.data[offset + alpha_offset + 1];
-				byte b = imgData.data[offset + alpha_offset + 2];
+				byte r = imgData.data[offset + alpha_offset + or];
+				byte g = imgData.data[offset + alpha_offset + og];
+				byte b = imgData.data[offset + alpha_offset + ob];
 
 				// GdkPixbuf expects RGBA format
 				srcData[new_offset + db] = b;
@@ -502,9 +515,9 @@
 	} else {
 		for (int y = 0, offset = 0, new_offset = 0; y < height; y++) {
 			for (int x = 0; x < width; x++, offset += n_channels, new_offset += bytes_per_pixel) {
-				byte r = imgData.data[offset + alpha_offset + 0];
-				byte g = imgData.data[offset + alpha_offset + 1];
-				byte b = imgData.data[offset + alpha_offset + 2];
+				byte r = imgData.data[offset + alpha_offset + or];
+				byte g = imgData.data[offset + alpha_offset + og];
+				byte b = imgData.data[offset + alpha_offset + ob];
 				byte a = (byte) 255;
 
 				srcData[new_offset + db] = b;
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java
index 5100bde..875e8a7 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java
@@ -200,7 +200,6 @@
 		 */
 		if (SwtTestUtil.isGTK) {
 			imageDepth = 32;
-
 		} else {
 			imageDepth = 24;
 		}