--- a/src/gui/image/qpixmap_x11.cpp Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/image/qpixmap_x11.cpp Wed Aug 18 10:37:55 2010 +0300
@@ -1250,10 +1250,8 @@
pengine = 0;
if (!X11) {
-#ifndef QT_NO_DEBUG
- qWarning("~QX11PixmapData(): QPixmap objects must be destroyed before the QApplication"
- " object, otherwise the native pixmap object will be leaked.");
-#endif
+ // At this point, the X server will already have freed our resources,
+ // so there is nothing to do.
return;
}
@@ -1460,6 +1458,105 @@
}
}
+struct QXImageWrapper
+{
+ XImage *xi;
+};
+
+bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ // ARGB32_Premultiplied
+ if (picture && depth() == 32)
+ return true;
+
+ Visual *visual = (Visual *)xinfo.visual();
+
+ // RGB32
+ if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000
+ && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
+ return true;
+
+ // RGB16
+ if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800
+ && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
+ return true;
+
+ return false;
+}
+
+QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ QImage::Format format = QImage::Format_ARGB32_Premultiplied;
+ if (depth() == 24)
+ format = QImage::Format_RGB32;
+ else if (depth() == 16)
+ format = QImage::Format_RGB16;
+
+ QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format);
+ // take ownership
+ image.data_ptr()->own_data = true;
+ xi->data = 0;
+
+ // we may have to swap the byte order
+ if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
+ || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
+ {
+ for (int i=0; i < image.height(); i++) {
+ if (depth() == 16) {
+ ushort *p = (ushort*)image.scanLine(i);
+ ushort *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
+ p++;
+ }
+ } else {
+ uint *p = (uint*)image.scanLine(i);
+ uint *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ }
+ }
+ }
+
+ // fix-up alpha channel
+ if (format == QImage::Format_RGB32) {
+ QRgb *p = (QRgb *)image.bits();
+ for (int y = 0; y < xi->height; ++y) {
+ for (int x = 0; x < xi->width; ++x)
+ p[x] |= 0xff000000;
+ p += xi->bytes_per_line / 4;
+ }
+ }
+
+ XDestroyImage(xi);
+ return image;
+}
+
+QImage QX11PixmapData::toImage(const QRect &rect) const
+{
+ QXImageWrapper xiWrapper;
+ xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(),
+ AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap);
+
+ Q_CHECK_PTR(xiWrapper.xi);
+ if (!xiWrapper.xi)
+ return QImage();
+
+ if (canTakeQImageFromXImage(xiWrapper))
+ return takeQImageFromXImage(xiWrapper);
+
+ QImage image = toImage(xiWrapper, rect);
+ qSafeXDestroyImage(xiWrapper.xi);
+ return image;
+}
+
/*!
Converts the pixmap to a QImage. Returns a null image if the
conversion fails.
@@ -1477,6 +1574,13 @@
QImage QX11PixmapData::toImage() const
{
+ return toImage(QRect(0, 0, w, h));
+}
+
+QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const
+{
+ XImage *xi = xiWrapper.xi;
+
int d = depth();
Visual *visual = (Visual *)xinfo.visual();
bool trucol = (visual->c_class >= TrueColor) && d > 1;
@@ -1494,59 +1598,21 @@
format = QImage::Format_RGB32;
}
- XImage *xi = XGetImage(X11->display, hd, 0, 0, w, h, AllPlanes,
- (d == 1) ? XYPixmap : ZPixmap);
-
- Q_CHECK_PTR(xi);
- if (!xi)
- return QImage();
-
- if (picture && depth() == 32) {
- QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
- memcpy(image.bits(), xi->data, xi->bytes_per_line * xi->height);
-
- // we may have to swap the byte order
- if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
- || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
- {
- for (int i=0; i < image.height(); i++) {
- uint *p = (uint*)image.scanLine(i);
- uint *end = p + image.width();
- if ((xi->byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
- || (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
- while (p < end) {
- *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
- | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
- p++;
- }
- } else if (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- while (p < end) {
- *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff)
- | ((*p ) & 0xff00ff00);
- p++;
- }
- }
- }
- }
-
- // throw away image data
- qSafeXDestroyImage(xi);
-
- return image;
- }
-
if (d == 1 && xi->bitmap_bit_order == LSBFirst)
format = QImage::Format_MonoLSB;
if (x11_mask && format == QImage::Format_RGB32)
format = QImage::Format_ARGB32;
- QImage image(w, h, format);
+ QImage image(xi->width, xi->height, format);
if (image.isNull()) // could not create image
return image;
QImage alpha;
if (x11_mask) {
- alpha = mask().toImage();
+ if (rect.contains(QRect(0, 0, w, h)))
+ alpha = mask().toImage();
+ else
+ alpha = mask().toImage().copy(rect);
}
bool ale = alpha.format() == QImage::Format_MonoLSB;
@@ -1589,11 +1655,11 @@
if (bppc > 8 && xi->byte_order == LSBFirst)
bppc++;
- for (int y = 0; y < h; ++y) {
+ for (int y = 0; y < xi->height; ++y) {
uchar* asrc = x11_mask ? alpha.scanLine(y) : 0;
dst = (QRgb *)image.scanLine(y);
src = (uchar *)xi->data + xi->bytes_per_line*y;
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
switch (bppc) {
case 8:
pixel = *src++;
@@ -1623,8 +1689,8 @@
src += 4;
break;
default: // should not really happen
- x = w; // leave loop
- y = h;
+ x = xi->width; // leave loop
+ y = xi->height;
pixel = 0; // eliminate compiler warning
qWarning("QPixmap::convertToImage: Invalid depth %d", bppc);
}
@@ -1662,7 +1728,7 @@
} else if (xi->bits_per_pixel == d) { // compatible depth
char *xidata = xi->data; // copy each scanline
int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
- for (int y=0; y<h; y++) {
+ for (int y=0; y<xi->height; y++) {
memcpy(image.scanLine(y), xidata, bpl);
xidata += xi->bytes_per_line;
}
@@ -1688,17 +1754,17 @@
bpl = image.bytesPerLine();
if (x11_mask) { // which pixels are used?
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
uchar* asrc = alpha.scanLine(i);
p = image.scanLine(i);
if (ale) {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (asrc[x >> 3] & (1 << (x & 7)))
use[*p] = 1;
++p;
}
} else {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (asrc[x >> 3] & (0x80 >> (x & 7)))
use[*p] = 1;
++p;
@@ -1706,7 +1772,7 @@
}
}
} else {
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
p = image.scanLine(i);
end = p + bpl;
while (p < end)
@@ -1718,7 +1784,7 @@
if (use[i])
pix[i] = ncols++;
}
- for (int i = 0; i < h; i++) { // translate pixels
+ for (int i = 0; i < xi->height; i++) { // translate pixels
p = image.scanLine(i);
end = p + bpl;
while (p < end) {
@@ -1738,17 +1804,17 @@
// use first pixel in image (as good as any).
trans = image.scanLine(0)[0];
}
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
uchar* asrc = alpha.scanLine(i);
p = image.scanLine(i);
if (ale) {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (!(asrc[x >> 3] & (1 << (x & 7))))
*p = trans;
++p;
}
} else {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
*p = trans;
++p;
@@ -1766,8 +1832,6 @@
}
}
- qSafeXDestroyImage(xi);
-
return image;
}