Blob Blame History Raw
From b56dbaf5b3247bd8e87e4e856ad845593755c10c Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Samuel=20R=C3=B8dal?= <samuel.rodal@nokia.com>
Date: Wed, 28 Sep 2011 15:22:56 +0200
Subject: [PATCH] Fixed broken window surface flush when depth is 24 and bpp is not 32.

Some X servers use a compact representation of 24 depth visuals. In that
case we can't use the shared memory or XPutImage paths, as Qt's RGB32
does not match the internal memory layout.

Also fixed QPixmap::fromImage() to work in this case to prevent the red
and blue channels from being swapped.

Task-number: QTBUG-21754
Reviewed-by: Alberto Mardegan
---
 src/gui/image/qnativeimage.cpp             |   12 ++++++------
 src/gui/image/qpixmap_x11.cpp              |   18 +++++++++++++-----
 src/gui/kernel/qapplication_x11.cpp        |    6 ++++++
 src/gui/kernel/qt_x11_p.h                  |    2 ++
 src/gui/painting/qwindowsurface_raster.cpp |    5 +++--
 5 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/src/gui/image/qnativeimage.cpp b/src/gui/image/qnativeimage.cpp
index aebcbaf..e1382dd 100644
--- a/src/gui/image/qnativeimage.cpp
+++ b/src/gui/image/qnativeimage.cpp
@@ -153,7 +153,12 @@ QImage::Format QNativeImage::systemFormat()
 QNativeImage::QNativeImage(int width, int height, QImage::Format format,bool /* isTextBuffer */, QWidget *widget)
     : xshmimg(0), xshmpm(0)
 {
-    if (!X11->use_mitshm) {
+    QX11Info info = widget->x11Info();
+
+    int dd = info.depth();
+    Visual *vis = (Visual*) info.visual();
+
+    if (!X11->use_mitshm || format != QImage::Format_RGB16 && X11->bppForDepth.value(dd) != 32) {
         image = QImage(width, height, format);
         // follow good coding practice and set xshminfo attributes, though values not used in this case
         xshminfo.readOnly = true;
@@ -163,11 +168,6 @@ QNativeImage::QNativeImage(int width, int height, QImage::Format format,bool /*
         return;
     }
 
-    QX11Info info = widget->x11Info();
-
-    int dd = info.depth();
-    Visual *vis = (Visual*) info.visual();
-
     xshmimg = XShmCreateImage(X11->display, vis, dd, ZPixmap, 0, &xshminfo, width, height);
     if (!xshmimg) {
         qWarning("QNativeImage: Unable to create shared XImage.");
diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp
index 77c2a2a..0e1401c 100644
--- a/src/gui/image/qpixmap_x11.cpp
+++ b/src/gui/image/qpixmap_x11.cpp
@@ -897,12 +897,20 @@ void QX11PixmapData::fromImage(const QImage &img,
                     }
                     )
                     break;
-            case BPP24_888:                        // 24 bit MSB
+            case BPP24_888:
                 CYCLE(
-                    for (int x=0; x<w; x++) {
-                        *dst++ = qRed  (*p);
-                        *dst++ = qGreen(*p);
-                        *dst++ = qBlue (*p++);
+                    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+                        for (int x=0; x<w; x++) {
+                            *dst++ = qRed  (*p);
+                            *dst++ = qGreen(*p);
+                            *dst++ = qBlue (*p++);
+                        }
+                    } else {
+                        for (int x=0; x<w; x++) {
+                            *dst++ = qBlue (*p);
+                            *dst++ = qGreen(*p);
+                            *dst++ = qRed  (*p++);
+                        }
                     }
                     )
                     break;
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index ef8e2b8..408e9ac 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -1896,6 +1896,12 @@ void qt_init(QApplicationPrivate *priv, int,
         X11->defaultScreen = DefaultScreen(X11->display);
         X11->screenCount = ScreenCount(X11->display);
 
+        int formatCount = 0;
+        XPixmapFormatValues *values = XListPixmapFormats(X11->display, &formatCount);
+        for (int i = 0; i < formatCount; ++i)
+            X11->bppForDepth[values[i].depth] = values[i].bits_per_pixel;
+        XFree(values);
+
         X11->screens = new QX11InfoData[X11->screenCount];
         X11->argbVisuals = new Visual *[X11->screenCount];
         X11->argbColormaps = new Colormap[X11->screenCount];
diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h
index 72acaf3..fe4a631 100644
--- a/src/gui/kernel/qt_x11_p.h
+++ b/src/gui/kernel/qt_x11_p.h
@@ -54,6 +54,7 @@
 //
 
 #include "QtGui/qwindowdefs.h"
+#include "QtCore/qhash.h"
 #include "QtCore/qlist.h"
 #include "QtCore/qvariant.h"
 
@@ -467,6 +468,7 @@ struct QX11Data
     Colormap *argbColormaps;
     int screenCount;
     int defaultScreen;
+    QHash<int, int> bppForDepth;
 
     Time time;
     Time userTime;
diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp
index 15ff044..2a25bff 100644
--- a/src/gui/painting/qwindowsurface_raster.cpp
+++ b/src/gui/painting/qwindowsurface_raster.cpp
@@ -254,8 +254,9 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi
     } else
 #endif
     {
+        int depth = widget->x11Info().depth();
         const QImage &src = d->image->image;
-        if (src.format() != QImage::Format_RGB32 || widget->x11Info().depth() < 24) {
+        if (src.format() != QImage::Format_RGB32 || depth < 24 || X11->bppForDepth.value(depth) != 32) {
             Q_ASSERT(src.depth() >= 16);
             const QImage sub_src(src.scanLine(br.y()) + br.x() * (uint(src.depth()) / 8),
                                  br.width(), br.height(), src.bytesPerLine(), src.format());
@@ -267,7 +268,7 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi
         } else {
             // qpaintengine_x11.cpp
             extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth);
-            qt_x11_drawImage(br, wpos, src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth());
+            qt_x11_drawImage(br, wpos, src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), depth);
         }
     }
 
-- 
1.6.1