1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include <QGuiApplication>
41
42 #include <private/qdrawhelper_p.h>
43 #include <private/qimage_p.h>
44 #include <private/qimagepixmapcleanuphooks_p.h>
45
46 #include "qxcbnativepainting.h"
47 #include "qpixmap_x11_p.h"
48 #include "qcolormap_x11_p.h"
49 #include "qpaintengine_x11_p.h"
50
51 QT_BEGIN_NAMESPACE
52
53 #if QT_POINTER_SIZE == 8 // 64-bit versions
54
PREMUL(uint x)55 Q_ALWAYS_INLINE uint PREMUL(uint x) {
56 uint a = x >> 24;
57 quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
58 t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
59 t &= 0x000000ff00ff00ff;
60 return (uint(t)) | (uint(t >> 24)) | (a << 24);
61 }
62
63 #else // 32-bit versions
64
65 Q_ALWAYS_INLINE uint PREMUL(uint x) {
66 uint a = x >> 24;
67 uint t = (x & 0xff00ff) * a;
68 t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
69 t &= 0xff00ff;
70
71 x = ((x >> 8) & 0xff) * a;
72 x = (x + ((x >> 8) & 0xff) + 0x80);
73 x &= 0xff00;
74 x |= t | (a << 24);
75 return x;
76 }
77 #endif
78
79
80
81 struct QXImageWrapper
82 {
83 XImage *xi;
84 };
85
qt_toX11Pixmap(const QImage & image)86 QPixmap qt_toX11Pixmap(const QImage &image)
87 {
88 QPlatformPixmap *data =
89 new QX11PlatformPixmap(image.depth() == 1
90 ? QPlatformPixmap::BitmapType
91 : QPlatformPixmap::PixmapType);
92
93 data->fromImage(image, Qt::AutoColor);
94
95 return QPixmap(data);
96 }
97
qt_toX11Pixmap(const QPixmap & pixmap)98 QPixmap qt_toX11Pixmap(const QPixmap &pixmap)
99 {
100 if (pixmap.isNull())
101 return QPixmap();
102
103 if (QPixmap(pixmap).data_ptr()->classId() == QPlatformPixmap::X11Class)
104 return pixmap;
105
106 return qt_toX11Pixmap(pixmap.toImage());
107 }
108
109 // For thread-safety:
110 // image->data does not belong to X11, so we must free it ourselves.
111
qSafeXDestroyImage(XImage * x)112 inline static void qSafeXDestroyImage(XImage *x)
113 {
114 if (x->data) {
115 free(x->data);
116 x->data = 0;
117 }
118 XDestroyImage(x);
119 }
120
mask_to_bitmap(int screen) const121 QBitmap QX11PlatformPixmap::mask_to_bitmap(int screen) const
122 {
123 if (!x11_mask)
124 return QBitmap();
125 qt_x11SetDefaultScreen(screen);
126 QBitmap bm(w, h);
127 QX11PlatformPixmap *that = qt_x11Pixmap(bm);
128 const QXcbX11Info *x = that->x11_info();
129 GC gc = XCreateGC(x->display(), that->handle(), 0, 0);
130 XCopyArea(x->display(), x11_mask, that->handle(), gc, 0, 0,
131 that->width(), that->height(), 0, 0);
132 XFreeGC(x->display(), gc);
133 return bm;
134 }
135
bitmapFromImage(const QImage & image)136 void QX11PlatformPixmap::bitmapFromImage(const QImage &image)
137 {
138 w = image.width();
139 h = image.height();
140 d = 1;
141 is_null = (w <= 0 || h <= 0);
142 hd = createBitmapFromImage(image);
143 #if QT_CONFIG(xrender)
144 if (X11->use_xrender)
145 picture = XRenderCreatePicture(xinfo.display(), hd,
146 XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0);
147 #endif // QT_CONFIG(xrender)
148 }
149
canTakeQImageFromXImage(const QXImageWrapper & xiWrapper) const150 bool QX11PlatformPixmap::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const
151 {
152 XImage *xi = xiWrapper.xi;
153
154 if (xi->format != ZPixmap)
155 return false;
156
157 // ARGB32_Premultiplied
158 if (picture && depth() == 32)
159 return true;
160
161 // RGB32
162 if (depth() == 24 && xi->bits_per_pixel == 32 && xi->red_mask == 0xff0000
163 && xi->green_mask == 0xff00 && xi->blue_mask == 0xff)
164 return true;
165
166 // RGB16
167 if (depth() == 16 && xi->bits_per_pixel == 16 && xi->red_mask == 0xf800
168 && xi->green_mask == 0x7e0 && xi->blue_mask == 0x1f)
169 return true;
170
171 return false;
172 }
173
takeQImageFromXImage(const QXImageWrapper & xiWrapper) const174 QImage QX11PlatformPixmap::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const
175 {
176 XImage *xi = xiWrapper.xi;
177
178 QImage::Format format = QImage::Format_ARGB32_Premultiplied;
179 if (depth() == 24)
180 format = QImage::Format_RGB32;
181 else if (depth() == 16)
182 format = QImage::Format_RGB16;
183
184 QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format);
185 image.setDevicePixelRatio(devicePixelRatio());
186 // take ownership
187 image.data_ptr()->own_data = true;
188 xi->data = 0;
189
190 // we may have to swap the byte order
191 if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
192 || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
193 {
194 for (int i=0; i < image.height(); i++) {
195 if (depth() == 16) {
196 ushort *p = (ushort*)image.scanLine(i);
197 ushort *end = p + image.width();
198 while (p < end) {
199 *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
200 p++;
201 }
202 } else {
203 uint *p = (uint*)image.scanLine(i);
204 uint *end = p + image.width();
205 while (p < end) {
206 *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
207 | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
208 p++;
209 }
210 }
211 }
212 }
213
214 // fix-up alpha channel
215 if (format == QImage::Format_RGB32) {
216 QRgb *p = (QRgb *)image.bits();
217 for (int y = 0; y < xi->height; ++y) {
218 for (int x = 0; x < xi->width; ++x)
219 p[x] |= 0xff000000;
220 p += xi->bytes_per_line / 4;
221 }
222 }
223
224 XDestroyImage(xi);
225 return image;
226 }
227
bitmap_to_mask(const QBitmap & bitmap,int screen)228 XID QX11PlatformPixmap::bitmap_to_mask(const QBitmap &bitmap, int screen)
229 {
230 if (bitmap.isNull())
231 return 0;
232 QBitmap bm = bitmap;
233 qt_x11SetScreen(bm, screen);
234
235 QX11PlatformPixmap *that = qt_x11Pixmap(bm);
236 const QXcbX11Info *x = that->x11_info();
237 Pixmap mask = XCreatePixmap(x->display(), RootWindow(x->display(), screen),
238 that->width(), that->height(), 1);
239 GC gc = XCreateGC(x->display(), mask, 0, 0);
240 XCopyArea(x->display(), that->handle(), mask, gc, 0, 0,
241 that->width(), that->height(), 0, 0);
242 XFreeGC(x->display(), gc);
243 return mask;
244 }
245
qt_x11Handle(const QPixmap & pixmap)246 Drawable qt_x11Handle(const QPixmap &pixmap)
247 {
248 if (pixmap.isNull())
249 return XNone;
250
251 if (pixmap.handle()->classId() != QPlatformPixmap::X11Class)
252 return XNone;
253
254 return static_cast<const QX11PlatformPixmap *>(pixmap.handle())->handle();
255 }
256
257
258 /*****************************************************************************
259 Internal functions
260 *****************************************************************************/
261
262 //extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp
263
264 // Returns position of highest bit set or -1 if none
highest_bit(uint v)265 static int highest_bit(uint v)
266 {
267 int i;
268 uint b = (uint)1 << 31;
269 for (i=31; ((b & v) == 0) && i>=0; i--)
270 b >>= 1;
271 return i;
272 }
273
274 // Counts the number of bits set in 'v'
n_bits(uint v)275 static uint n_bits(uint v)
276 {
277 int i = 0;
278 while (v) {
279 v = v & (v - 1);
280 i++;
281 }
282 return i;
283 }
284
285 static uint *red_scale_table = 0;
286 static uint *green_scale_table = 0;
287 static uint *blue_scale_table = 0;
288
cleanup_scale_tables()289 static void cleanup_scale_tables()
290 {
291 delete[] red_scale_table;
292 delete[] green_scale_table;
293 delete[] blue_scale_table;
294 }
295
296 /*
297 Could do smart bitshifting, but the "obvious" algorithm only works for
298 nBits >= 4. This is more robust.
299 */
build_scale_table(uint ** table,uint nBits)300 static void build_scale_table(uint **table, uint nBits)
301 {
302 if (nBits > 7) {
303 qWarning("build_scale_table: internal error, nBits = %i", nBits);
304 return;
305 }
306 if (!*table) {
307 static bool firstTable = true;
308 if (firstTable) {
309 qAddPostRoutine(cleanup_scale_tables);
310 firstTable = false;
311 }
312 *table = new uint[256];
313 }
314 int maxVal = (1 << nBits) - 1;
315 int valShift = 8 - nBits;
316 int i;
317 for (i = 0 ; i < maxVal + 1 ; i++)
318 (*table)[i << valShift] = i*255/maxVal;
319 }
320
321 static int defaultScreen = -1;
322
qt_x11SetDefaultScreen(int screen)323 int qt_x11SetDefaultScreen(int screen)
324 {
325 int old = defaultScreen;
326 defaultScreen = screen;
327 return old;
328 }
329
qt_x11SetScreen(QPixmap & pixmap,int screen)330 void qt_x11SetScreen(QPixmap &pixmap, int screen)
331 {
332 if (pixmap.paintingActive()) {
333 qWarning("qt_x11SetScreen(): Cannot change screens during painting");
334 return;
335 }
336
337 if (pixmap.isNull())
338 return;
339
340 if (pixmap.handle()->classId() != QPlatformPixmap::X11Class)
341 return;
342
343 if (screen < 0)
344 screen = QXcbX11Info::appScreen();
345
346 QX11PlatformPixmap *pm = static_cast<QX11PlatformPixmap *>(pixmap.handle());
347 if (screen == pm->xinfo.screen())
348 return; // nothing to do
349
350 if (pixmap.isNull()) {
351 pm->xinfo = QXcbX11Info::fromScreen(screen);
352 return;
353 }
354
355 #if 0
356 qDebug("qt_x11SetScreen for %p from %d to %d. Size is %d/%d", pm, pm->xinfo.screen(), screen, pm->width(), pm->height());
357 #endif
358
359 qt_x11SetDefaultScreen(screen);
360 pixmap = qt_toX11Pixmap(pixmap.toImage());
361 }
362
363 /*****************************************************************************
364 QPixmap member functions
365 *****************************************************************************/
366
367 QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0);
368 int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0;
369
QX11PlatformPixmap(PixelType pixelType)370 QX11PlatformPixmap::QX11PlatformPixmap(PixelType pixelType)
371 : QPlatformPixmap(pixelType, X11Class), hd(0),
372 flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(0),
373 dpr(1.0), pengine(0)
374 {}
375
~QX11PlatformPixmap()376 QX11PlatformPixmap::~QX11PlatformPixmap()
377 {
378 // Cleanup hooks have to be called before the handles are freed
379 if (is_cached) {
380 QImagePixmapCleanupHooks::executePlatformPixmapDestructionHooks(this);
381 is_cached = false;
382 }
383
384 release();
385 }
386
createCompatiblePlatformPixmap() const387 QPlatformPixmap *QX11PlatformPixmap::createCompatiblePlatformPixmap() const
388 {
389 QX11PlatformPixmap *p = new QX11PlatformPixmap(pixelType());
390 p->setDevicePixelRatio(devicePixelRatio());
391 return p;
392 }
393
resize(int width,int height)394 void QX11PlatformPixmap::resize(int width, int height)
395 {
396 setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
397
398 w = width;
399 h = height;
400 is_null = (w <= 0 || h <= 0);
401
402 if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) {
403 xinfo = QXcbX11Info::fromScreen(defaultScreen);
404 }
405
406 int dd = xinfo.depth();
407
408 if (qt_x11_preferred_pixmap_depth)
409 dd = qt_x11_preferred_pixmap_depth;
410
411 bool make_null = w <= 0 || h <= 0; // create null pixmap
412 d = (pixelType() == BitmapType ? 1 : dd);
413 if (make_null || d == 0) {
414 w = 0;
415 h = 0;
416 is_null = true;
417 hd = 0;
418 picture = 0;
419 d = 0;
420 if (!make_null)
421 qWarning("QPixmap: Invalid pixmap parameters");
422 return;
423 }
424 hd = XCreatePixmap(xinfo.display(),
425 RootWindow(xinfo.display(), xinfo.screen()),
426 w, h, d);
427 #if QT_CONFIG(xrender)
428 if (X11->use_xrender) {
429 XRenderPictFormat *format = d == 1
430 ? XRenderFindStandardFormat(xinfo.display(), PictStandardA1)
431 : XRenderFindVisualFormat(xinfo.display(), (Visual *) xinfo.visual());
432 picture = XRenderCreatePicture(xinfo.display(), hd, format, 0, 0);
433 }
434 #endif // QT_CONFIG(xrender)
435 }
436
437 struct QX11AlphaDetector
438 {
hasAlphaQX11AlphaDetector439 bool hasAlpha() const {
440 if (checked)
441 return has;
442 // Will implicitly also check format and return quickly for opaque types...
443 checked = true;
444 has = image->isNull() ? false : const_cast<QImage *>(image)->data_ptr()->checkForAlphaPixels();
445 return has;
446 }
447
hasXRenderAndAlphaQX11AlphaDetector448 bool hasXRenderAndAlpha() const {
449 if (!X11->use_xrender)
450 return false;
451 return hasAlpha();
452 }
453
QX11AlphaDetectorQX11AlphaDetector454 QX11AlphaDetector(const QImage *i, Qt::ImageConversionFlags flags)
455 : image(i), checked(false), has(false)
456 {
457 if (flags & Qt::NoOpaqueDetection) {
458 checked = true;
459 has = image->hasAlphaChannel();
460 }
461 }
462
463 const QImage *image;
464 mutable bool checked;
465 mutable bool has;
466 };
467
fromImage(const QImage & img,Qt::ImageConversionFlags flags)468 void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
469 {
470 setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
471
472 w = img.width();
473 h = img.height();
474 d = img.depth();
475 is_null = (w <= 0 || h <= 0);
476 setDevicePixelRatio(img.devicePixelRatio());
477
478 if (is_null) {
479 w = h = 0;
480 return;
481 }
482
483 if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) {
484 xinfo = QXcbX11Info::fromScreen(defaultScreen);
485 }
486
487 if (pixelType() == BitmapType) {
488 bitmapFromImage(img);
489 return;
490 }
491
492 if (uint(w) >= 32768 || uint(h) >= 32768) {
493 w = h = 0;
494 is_null = true;
495 return;
496 }
497
498 QX11AlphaDetector alphaCheck(&img, flags);
499 int dd = alphaCheck.hasXRenderAndAlpha() ? 32 : xinfo.depth();
500
501 if (qt_x11_preferred_pixmap_depth)
502 dd = qt_x11_preferred_pixmap_depth;
503
504 QImage image = img;
505
506 // must be monochrome
507 if (dd == 1 || (flags & Qt::ColorMode_Mask) == Qt::MonoOnly) {
508 if (d != 1) {
509 // dither
510 image = image.convertToFormat(QImage::Format_MonoLSB, flags);
511 d = 1;
512 }
513 } else { // can be both
514 bool conv8 = false;
515 if (d > 8 && dd <= 8) { // convert to 8 bit
516 if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither)
517 flags = (flags & ~Qt::DitherMode_Mask)
518 | Qt::PreferDither;
519 conv8 = true;
520 } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) {
521 conv8 = (d == 1); // native depth wanted
522 } else if (d == 1) {
523 if (image.colorCount() == 2) {
524 QRgb c0 = image.color(0); // Auto: convert to best
525 QRgb c1 = image.color(1);
526 conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255);
527 } else {
528 // eg. 1-color monochrome images (they do exist).
529 conv8 = true;
530 }
531 }
532 if (conv8) {
533 image = image.convertToFormat(QImage::Format_Indexed8, flags);
534 d = 8;
535 }
536 }
537
538 if (d == 1 || image.format() > QImage::Format_ARGB32_Premultiplied) {
539 QImage::Format fmt = QImage::Format_RGB32;
540 if (alphaCheck.hasXRenderAndAlpha() && d > 1)
541 fmt = QImage::Format_ARGB32_Premultiplied;
542 image = image.convertToFormat(fmt, flags);
543 fromImage(image, Qt::AutoColor);
544 return;
545 }
546
547 Display *dpy = xinfo.display();
548 Visual *visual = (Visual *)xinfo.visual();
549 XImage *xi = 0;
550 bool trucol = (visual->c_class >= TrueColor);
551 size_t nbytes = image.sizeInBytes();
552 uchar *newbits= 0;
553
554 #if QT_CONFIG(xrender)
555 if (alphaCheck.hasXRenderAndAlpha()) {
556 const QImage &cimage = image;
557
558 d = 32;
559
560 if (QXcbX11Info::appDepth() != d) {
561 xinfo.setDepth(d);
562 }
563
564 hd = XCreatePixmap(dpy, RootWindow(dpy, xinfo.screen()), w, h, d);
565 picture = XRenderCreatePicture(dpy, hd,
566 XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0);
567
568 xi = XCreateImage(dpy, visual, d, ZPixmap, 0, 0, w, h, 32, 0);
569 Q_CHECK_PTR(xi);
570 newbits = (uchar *)malloc(xi->bytes_per_line*h);
571 Q_CHECK_PTR(newbits);
572 xi->data = (char *)newbits;
573
574 switch (cimage.format()) {
575 case QImage::Format_Indexed8: {
576 QVector<QRgb> colorTable = cimage.colorTable();
577 uint *xidata = (uint *)xi->data;
578 for (int y = 0; y < h; ++y) {
579 const uchar *p = cimage.scanLine(y);
580 for (int x = 0; x < w; ++x) {
581 const QRgb rgb = colorTable[p[x]];
582 const int a = qAlpha(rgb);
583 if (a == 0xff)
584 *xidata = rgb;
585 else
586 // RENDER expects premultiplied alpha
587 *xidata = qRgba(qt_div_255(qRed(rgb) * a),
588 qt_div_255(qGreen(rgb) * a),
589 qt_div_255(qBlue(rgb) * a),
590 a);
591 ++xidata;
592 }
593 }
594 }
595 break;
596 case QImage::Format_RGB32: {
597 uint *xidata = (uint *)xi->data;
598 for (int y = 0; y < h; ++y) {
599 const QRgb *p = (const QRgb *) cimage.scanLine(y);
600 for (int x = 0; x < w; ++x)
601 *xidata++ = p[x] | 0xff000000;
602 }
603 }
604 break;
605 case QImage::Format_ARGB32: {
606 uint *xidata = (uint *)xi->data;
607 for (int y = 0; y < h; ++y) {
608 const QRgb *p = (const QRgb *) cimage.scanLine(y);
609 for (int x = 0; x < w; ++x) {
610 const QRgb rgb = p[x];
611 const int a = qAlpha(rgb);
612 if (a == 0xff)
613 *xidata = rgb;
614 else
615 // RENDER expects premultiplied alpha
616 *xidata = qRgba(qt_div_255(qRed(rgb) * a),
617 qt_div_255(qGreen(rgb) * a),
618 qt_div_255(qBlue(rgb) * a),
619 a);
620 ++xidata;
621 }
622 }
623
624 }
625 break;
626 case QImage::Format_ARGB32_Premultiplied: {
627 uint *xidata = (uint *)xi->data;
628 for (int y = 0; y < h; ++y) {
629 const QRgb *p = (const QRgb *) cimage.scanLine(y);
630 memcpy(xidata, p, w*sizeof(QRgb));
631 xidata += w;
632 }
633 }
634 break;
635 default:
636 Q_ASSERT(false);
637 }
638
639 if ((xi->byte_order == MSBFirst) != (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
640 uint *xidata = (uint *)xi->data;
641 uint *xiend = xidata + w*h;
642 while (xidata < xiend) {
643 *xidata = (*xidata >> 24)
644 | ((*xidata >> 8) & 0xff00)
645 | ((*xidata << 8) & 0xff0000)
646 | (*xidata << 24);
647 ++xidata;
648 }
649 }
650
651 GC gc = XCreateGC(dpy, hd, 0, 0);
652 XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h);
653 XFreeGC(dpy, gc);
654
655 qSafeXDestroyImage(xi);
656
657 return;
658 }
659 #endif // QT_CONFIG(xrender)
660
661 if (trucol) { // truecolor display
662 if (image.format() == QImage::Format_ARGB32_Premultiplied)
663 image = image.convertToFormat(QImage::Format_ARGB32);
664
665 const QImage &cimage = image;
666 QRgb pix[256]; // pixel translation table
667 const bool d8 = (d == 8);
668 const uint red_mask = (uint)visual->red_mask;
669 const uint green_mask = (uint)visual->green_mask;
670 const uint blue_mask = (uint)visual->blue_mask;
671 const int red_shift = highest_bit(red_mask) - 7;
672 const int green_shift = highest_bit(green_mask) - 7;
673 const int blue_shift = highest_bit(blue_mask) - 7;
674 const uint rbits = highest_bit(red_mask) - lowest_bit(red_mask) + 1;
675 const uint gbits = highest_bit(green_mask) - lowest_bit(green_mask) + 1;
676 const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1;
677
678 if (d8) { // setup pixel translation
679 QVector<QRgb> ctable = cimage.colorTable();
680 for (int i=0; i < cimage.colorCount(); i++) {
681 int r = qRed (ctable[i]);
682 int g = qGreen(ctable[i]);
683 int b = qBlue (ctable[i]);
684 r = red_shift > 0 ? r << red_shift : r >> -red_shift;
685 g = green_shift > 0 ? g << green_shift : g >> -green_shift;
686 b = blue_shift > 0 ? b << blue_shift : b >> -blue_shift;
687 pix[i] = (b & blue_mask) | (g & green_mask) | (r & red_mask)
688 | ~(blue_mask | green_mask | red_mask);
689 }
690 }
691
692 xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0);
693 Q_CHECK_PTR(xi);
694 newbits = (uchar *)malloc(xi->bytes_per_line*h);
695 Q_CHECK_PTR(newbits);
696 if (!newbits) // no memory
697 return;
698 int bppc = xi->bits_per_pixel;
699
700 bool contig_bits = n_bits(red_mask) == rbits &&
701 n_bits(green_mask) == gbits &&
702 n_bits(blue_mask) == bbits;
703 bool dither_tc =
704 // Want it?
705 (flags & Qt::Dither_Mask) != Qt::ThresholdDither &&
706 (flags & Qt::DitherMode_Mask) != Qt::AvoidDither &&
707 // Need it?
708 bppc < 24 && !d8 &&
709 // Can do it? (Contiguous bits?)
710 contig_bits;
711
712 static bool init=false;
713 static int D[16][16];
714 if (dither_tc && !init) {
715 // I also contributed this code to XV - WWA.
716 /*
717 The dither matrix, D, is obtained with this formula:
718
719 D2 = [0 2]
720 [3 1]
721
722
723 D2*n = [4*Dn 4*Dn+2*Un]
724 [4*Dn+3*Un 4*Dn+1*Un]
725 */
726 int n,i,j;
727 init=1;
728
729 /* Set D2 */
730 D[0][0]=0;
731 D[1][0]=2;
732 D[0][1]=3;
733 D[1][1]=1;
734
735 /* Expand using recursive definition given above */
736 for (n=2; n<16; n*=2) {
737 for (i=0; i<n; i++) {
738 for (j=0; j<n; j++) {
739 D[i][j]*=4;
740 D[i+n][j]=D[i][j]+2;
741 D[i][j+n]=D[i][j]+3;
742 D[i+n][j+n]=D[i][j]+1;
743 }
744 }
745 }
746 init=true;
747 }
748
749 enum { BPP8,
750 BPP16_565, BPP16_555,
751 BPP16_MSB, BPP16_LSB,
752 BPP24_888,
753 BPP24_MSB, BPP24_LSB,
754 BPP32_8888,
755 BPP32_MSB, BPP32_LSB
756 } mode = BPP8;
757
758 bool same_msb_lsb = (xi->byte_order == MSBFirst) == (QSysInfo::ByteOrder == QSysInfo::BigEndian);
759
760 if (bppc == 8) // 8 bit
761 mode = BPP8;
762 else if (bppc == 16) { // 16 bit MSB/LSB
763 if (red_shift == 8 && green_shift == 3 && blue_shift == -3 && !d8 && same_msb_lsb)
764 mode = BPP16_565;
765 else if (red_shift == 7 && green_shift == 2 && blue_shift == -3 && !d8 && same_msb_lsb)
766 mode = BPP16_555;
767 else
768 mode = (xi->byte_order == LSBFirst) ? BPP16_LSB : BPP16_MSB;
769 } else if (bppc == 24) { // 24 bit MSB/LSB
770 if (red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb)
771 mode = BPP24_888;
772 else
773 mode = (xi->byte_order == LSBFirst) ? BPP24_LSB : BPP24_MSB;
774 } else if (bppc == 32) { // 32 bit MSB/LSB
775 if (red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb)
776 mode = BPP32_8888;
777 else
778 mode = (xi->byte_order == LSBFirst) ? BPP32_LSB : BPP32_MSB;
779 } else
780 qFatal("Logic error 3");
781
782 #define GET_PIXEL \
783 uint pixel; \
784 if (d8) pixel = pix[*src++]; \
785 else { \
786 int r = qRed (*p); \
787 int g = qGreen(*p); \
788 int b = qBlue (*p++); \
789 r = red_shift > 0 \
790 ? r << red_shift : r >> -red_shift; \
791 g = green_shift > 0 \
792 ? g << green_shift : g >> -green_shift; \
793 b = blue_shift > 0 \
794 ? b << blue_shift : b >> -blue_shift; \
795 pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask) \
796 | ~(blue_mask | green_mask | red_mask); \
797 }
798
799 #define GET_PIXEL_DITHER_TC \
800 int r = qRed (*p); \
801 int g = qGreen(*p); \
802 int b = qBlue (*p++); \
803 const int thres = D[x%16][y%16]; \
804 if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
805 > thres) \
806 r += (1<<(8-rbits)); \
807 if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
808 > thres) \
809 g += (1<<(8-gbits)); \
810 if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
811 > thres) \
812 b += (1<<(8-bbits)); \
813 r = red_shift > 0 \
814 ? r << red_shift : r >> -red_shift; \
815 g = green_shift > 0 \
816 ? g << green_shift : g >> -green_shift; \
817 b = blue_shift > 0 \
818 ? b << blue_shift : b >> -blue_shift; \
819 uint pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask);
820
821 // again, optimized case
822 // can't be optimized that much :(
823 #define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask, \
824 rbits,gbits,bbits) \
825 const int thres = D[x%16][y%16]; \
826 int r = qRed (*p); \
827 if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
828 > thres) \
829 r += (1<<(8-rbits)); \
830 int g = qGreen(*p); \
831 if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
832 > thres) \
833 g += (1<<(8-gbits)); \
834 int b = qBlue (*p++); \
835 if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
836 > thres) \
837 b += (1<<(8-bbits)); \
838 uint pixel = ((r red_shift) & red_mask) \
839 | ((g green_shift) & green_mask) \
840 | ((b blue_shift) & blue_mask);
841
842 #define CYCLE(body) \
843 for (int y=0; y<h; y++) { \
844 const uchar* src = cimage.scanLine(y); \
845 uchar* dst = newbits + xi->bytes_per_line*y; \
846 const QRgb* p = (const QRgb *)src; \
847 body \
848 }
849
850 if (dither_tc) {
851 switch (mode) {
852 case BPP16_565:
853 CYCLE(
854 quint16* dst16 = (quint16*)dst;
855 for (int x=0; x<w; x++) {
856 GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5)
857 *dst16++ = pixel;
858 }
859 )
860 break;
861 case BPP16_555:
862 CYCLE(
863 quint16* dst16 = (quint16*)dst;
864 for (int x=0; x<w; x++) {
865 GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5)
866 *dst16++ = pixel;
867 }
868 )
869 break;
870 case BPP16_MSB: // 16 bit MSB
871 CYCLE(
872 for (int x=0; x<w; x++) {
873 GET_PIXEL_DITHER_TC
874 *dst++ = (pixel >> 8);
875 *dst++ = pixel;
876 }
877 )
878 break;
879 case BPP16_LSB: // 16 bit LSB
880 CYCLE(
881 for (int x=0; x<w; x++) {
882 GET_PIXEL_DITHER_TC
883 *dst++ = pixel;
884 *dst++ = pixel >> 8;
885 }
886 )
887 break;
888 default:
889 qFatal("Logic error");
890 }
891 } else {
892 switch (mode) {
893 case BPP8: // 8 bit
894 CYCLE(
895 Q_UNUSED(p);
896 for (int x=0; x<w; x++)
897 *dst++ = pix[*src++];
898 )
899 break;
900 case BPP16_565:
901 CYCLE(
902 quint16* dst16 = (quint16*)dst;
903 for (int x = 0; x < w; x++) {
904 *dst16++ = ((*p >> 8) & 0xf800)
905 | ((*p >> 5) & 0x7e0)
906 | ((*p >> 3) & 0x1f);
907 ++p;
908 }
909 )
910 break;
911 case BPP16_555:
912 CYCLE(
913 quint16* dst16 = (quint16*)dst;
914 for (int x=0; x<w; x++) {
915 *dst16++ = ((*p >> 9) & 0x7c00)
916 | ((*p >> 6) & 0x3e0)
917 | ((*p >> 3) & 0x1f);
918 ++p;
919 }
920 )
921 break;
922 case BPP16_MSB: // 16 bit MSB
923 CYCLE(
924 for (int x=0; x<w; x++) {
925 GET_PIXEL
926 *dst++ = (pixel >> 8);
927 *dst++ = pixel;
928 }
929 )
930 break;
931 case BPP16_LSB: // 16 bit LSB
932 CYCLE(
933 for (int x=0; x<w; x++) {
934 GET_PIXEL
935 *dst++ = pixel;
936 *dst++ = pixel >> 8;
937 }
938 )
939 break;
940 case BPP24_888:
941 CYCLE(
942 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
943 for (int x=0; x<w; x++) {
944 *dst++ = qRed (*p);
945 *dst++ = qGreen(*p);
946 *dst++ = qBlue (*p++);
947 }
948 } else {
949 for (int x=0; x<w; x++) {
950 *dst++ = qBlue (*p);
951 *dst++ = qGreen(*p);
952 *dst++ = qRed (*p++);
953 }
954 }
955 )
956 break;
957 case BPP24_MSB: // 24 bit MSB
958 CYCLE(
959 for (int x=0; x<w; x++) {
960 GET_PIXEL
961 *dst++ = pixel >> 16;
962 *dst++ = pixel >> 8;
963 *dst++ = pixel;
964 }
965 )
966 break;
967 case BPP24_LSB: // 24 bit LSB
968 CYCLE(
969 for (int x=0; x<w; x++) {
970 GET_PIXEL
971 *dst++ = pixel;
972 *dst++ = pixel >> 8;
973 *dst++ = pixel >> 16;
974 }
975 )
976 break;
977 case BPP32_8888:
978 CYCLE(
979 memcpy(dst, p, w * 4);
980 )
981 break;
982 case BPP32_MSB: // 32 bit MSB
983 CYCLE(
984 for (int x=0; x<w; x++) {
985 GET_PIXEL
986 *dst++ = pixel >> 24;
987 *dst++ = pixel >> 16;
988 *dst++ = pixel >> 8;
989 *dst++ = pixel;
990 }
991 )
992 break;
993 case BPP32_LSB: // 32 bit LSB
994 CYCLE(
995 for (int x=0; x<w; x++) {
996 GET_PIXEL
997 *dst++ = pixel;
998 *dst++ = pixel >> 8;
999 *dst++ = pixel >> 16;
1000 *dst++ = pixel >> 24;
1001 }
1002 )
1003 break;
1004 default:
1005 qFatal("Logic error 2");
1006 }
1007 }
1008 xi->data = (char *)newbits;
1009 }
1010
1011 if (d == 8 && !trucol) { // 8 bit pixmap
1012 int pop[256]; // pixel popularity
1013
1014 if (image.colorCount() == 0)
1015 image.setColorCount(1);
1016
1017 const QImage &cimage = image;
1018 memset(pop, 0, sizeof(int)*256); // reset popularity array
1019 for (int i = 0; i < h; i++) { // for each scanline...
1020 const uchar* p = cimage.scanLine(i);
1021 const uchar *end = p + w;
1022 while (p < end) // compute popularity
1023 pop[*p++]++;
1024 }
1025
1026 newbits = (uchar *)malloc(nbytes); // copy image into newbits
1027 Q_CHECK_PTR(newbits);
1028 if (!newbits) // no memory
1029 return;
1030 uchar* p = newbits;
1031 memcpy(p, cimage.bits(), nbytes); // copy image data into newbits
1032
1033 /*
1034 * The code below picks the most important colors. It is based on the
1035 * diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley.
1036 */
1037
1038 struct PIX { // pixel sort element
1039 uchar r,g,b,n; // color + pad
1040 int use; // popularity
1041 int index; // index in colormap
1042 int mindist;
1043 };
1044 int ncols = 0;
1045 for (int i=0; i< cimage.colorCount(); i++) { // compute number of colors
1046 if (pop[i] > 0)
1047 ncols++;
1048 }
1049 for (int i = cimage.colorCount(); i < 256; i++) // ignore out-of-range pixels
1050 pop[i] = 0;
1051
1052 // works since we make sure above to have at least
1053 // one color in the image
1054 if (ncols == 0)
1055 ncols = 1;
1056
1057 PIX pixarr[256]; // pixel array
1058 PIX pixarr_sorted[256]; // pixel array (sorted)
1059 memset(pixarr, 0, ncols*sizeof(PIX));
1060 PIX *px = &pixarr[0];
1061 int maxpop = 0;
1062 int maxpix = 0;
1063 uint j = 0;
1064 QVector<QRgb> ctable = cimage.colorTable();
1065 for (int i = 0; i < 256; i++) { // init pixel array
1066 if (pop[i] > 0) {
1067 px->r = qRed (ctable[i]);
1068 px->g = qGreen(ctable[i]);
1069 px->b = qBlue (ctable[i]);
1070 px->n = 0;
1071 px->use = pop[i];
1072 if (pop[i] > maxpop) { // select most popular entry
1073 maxpop = pop[i];
1074 maxpix = j;
1075 }
1076 px->index = i;
1077 px->mindist = 1000000;
1078 px++;
1079 j++;
1080 }
1081 }
1082 pixarr_sorted[0] = pixarr[maxpix];
1083 pixarr[maxpix].use = 0;
1084
1085 for (int i = 1; i < ncols; i++) { // sort pixels
1086 int minpix = -1, mindist = -1;
1087 px = &pixarr_sorted[i-1];
1088 int r = px->r;
1089 int g = px->g;
1090 int b = px->b;
1091 int dist;
1092 if ((i & 1) || i<10) { // sort on max distance
1093 for (int j=0; j<ncols; j++) {
1094 px = &pixarr[j];
1095 if (px->use) {
1096 dist = (px->r - r)*(px->r - r) +
1097 (px->g - g)*(px->g - g) +
1098 (px->b - b)*(px->b - b);
1099 if (px->mindist > dist)
1100 px->mindist = dist;
1101 if (px->mindist > mindist) {
1102 mindist = px->mindist;
1103 minpix = j;
1104 }
1105 }
1106 }
1107 } else { // sort on max popularity
1108 for (int j=0; j<ncols; j++) {
1109 px = &pixarr[j];
1110 if (px->use) {
1111 dist = (px->r - r)*(px->r - r) +
1112 (px->g - g)*(px->g - g) +
1113 (px->b - b)*(px->b - b);
1114 if (px->mindist > dist)
1115 px->mindist = dist;
1116 if (px->use > mindist) {
1117 mindist = px->use;
1118 minpix = j;
1119 }
1120 }
1121 }
1122 }
1123 pixarr_sorted[i] = pixarr[minpix];
1124 pixarr[minpix].use = 0;
1125 }
1126
1127 QXcbColormap cmap = QXcbColormap::instance(xinfo.screen());
1128 uint pix[256]; // pixel translation table
1129 px = &pixarr_sorted[0];
1130 for (int i = 0; i < ncols; i++) { // allocate colors
1131 QColor c(px->r, px->g, px->b);
1132 pix[px->index] = cmap.pixel(c);
1133 px++;
1134 }
1135
1136 p = newbits;
1137 for (size_t i = 0; i < nbytes; i++) { // translate pixels
1138 *p = pix[*p];
1139 p++;
1140 }
1141 }
1142
1143 if (!xi) { // X image not created
1144 xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0);
1145 if (xi->bits_per_pixel == 16) { // convert 8 bpp ==> 16 bpp
1146 ushort *p2;
1147 int p2inc = xi->bytes_per_line/sizeof(ushort);
1148 ushort *newerbits = (ushort *)malloc(xi->bytes_per_line * h);
1149 Q_CHECK_PTR(newerbits);
1150 if (!newerbits) // no memory
1151 return;
1152 uchar* p = newbits;
1153 for (int y = 0; y < h; y++) { // OOPS: Do right byte order!!
1154 p2 = newerbits + p2inc*y;
1155 for (int x = 0; x < w; x++)
1156 *p2++ = *p++;
1157 }
1158 free(newbits);
1159 newbits = (uchar *)newerbits;
1160 } else if (xi->bits_per_pixel != 8) {
1161 qWarning("QPixmap::fromImage: Display not supported "
1162 "(bpp=%d)", xi->bits_per_pixel);
1163 }
1164 xi->data = (char *)newbits;
1165 }
1166
1167 hd = XCreatePixmap(dpy,
1168 RootWindow(dpy, xinfo.screen()),
1169 w, h, dd);
1170
1171 GC gc = XCreateGC(dpy, hd, 0, 0);
1172 XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h);
1173 XFreeGC(dpy, gc);
1174
1175 qSafeXDestroyImage(xi);
1176 d = dd;
1177
1178 #if QT_CONFIG(xrender)
1179 if (X11->use_xrender) {
1180 XRenderPictFormat *format = d == 1
1181 ? XRenderFindStandardFormat(dpy, PictStandardA1)
1182 : XRenderFindVisualFormat(dpy, (Visual *)xinfo.visual());
1183 picture = XRenderCreatePicture(dpy, hd, format, 0, 0);
1184 }
1185 #endif
1186
1187 if (alphaCheck.hasAlpha()) {
1188 QBitmap m = QBitmap::fromImage(image.createAlphaMask(flags));
1189 setMask(m);
1190 }
1191 }
1192
copy(const QPlatformPixmap * data,const QRect & rect)1193 void QX11PlatformPixmap::copy(const QPlatformPixmap *data, const QRect &rect)
1194 {
1195 if (data->pixelType() == BitmapType) {
1196 fromImage(data->toImage().copy(rect), Qt::AutoColor);
1197 return;
1198 }
1199
1200 const QX11PlatformPixmap *x11Data = static_cast<const QX11PlatformPixmap*>(data);
1201
1202 setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
1203
1204 flags &= ~Uninitialized;
1205 xinfo = x11Data->xinfo;
1206 d = x11Data->d;
1207 w = rect.width();
1208 h = rect.height();
1209 is_null = (w <= 0 || h <= 0);
1210 hd = XCreatePixmap(xinfo.display(),
1211 RootWindow(xinfo.display(), x11Data->xinfo.screen()),
1212 w, h, d);
1213 #if QT_CONFIG(xrender)
1214 if (X11->use_xrender) {
1215 XRenderPictFormat *format = d == 32
1216 ? XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32)
1217 : XRenderFindVisualFormat(xinfo.display(), (Visual *)xinfo.visual());
1218 picture = XRenderCreatePicture(xinfo.display(), hd, format, 0, 0);
1219 }
1220 #endif // QT_CONFIG(xrender)
1221 if (x11Data->x11_mask) {
1222 x11_mask = XCreatePixmap(xinfo.display(), hd, w, h, 1);
1223 #if QT_CONFIG(xrender)
1224 if (X11->use_xrender) {
1225 mask_picture = XRenderCreatePicture(xinfo.display(), x11_mask,
1226 XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0);
1227 XRenderPictureAttributes attrs;
1228 attrs.alpha_map = x11Data->mask_picture;
1229 XRenderChangePicture(xinfo.display(), x11Data->picture, CPAlphaMap, &attrs);
1230 }
1231 #endif
1232 }
1233
1234 #if QT_CONFIG(xrender)
1235 if (x11Data->picture && x11Data->d == 32) {
1236 XRenderComposite(xinfo.display(), PictOpSrc,
1237 x11Data->picture, 0, picture,
1238 rect.x(), rect.y(), 0, 0, 0, 0, w, h);
1239 } else
1240 #endif
1241 {
1242 GC gc = XCreateGC(xinfo.display(), hd, 0, 0);
1243 XCopyArea(xinfo.display(), x11Data->hd, hd, gc,
1244 rect.x(), rect.y(), w, h, 0, 0);
1245 if (x11Data->x11_mask) {
1246 GC monogc = XCreateGC(xinfo.display(), x11_mask, 0, 0);
1247 XCopyArea(xinfo.display(), x11Data->x11_mask, x11_mask, monogc,
1248 rect.x(), rect.y(), w, h, 0, 0);
1249 XFreeGC(xinfo.display(), monogc);
1250 }
1251 XFreeGC(xinfo.display(), gc);
1252 }
1253 }
1254
scroll(int dx,int dy,const QRect & rect)1255 bool QX11PlatformPixmap::scroll(int dx, int dy, const QRect &rect)
1256 {
1257 GC gc = XCreateGC(xinfo.display(), hd, 0, 0);
1258 XCopyArea(xinfo.display(), hd, hd, gc,
1259 rect.left(), rect.top(), rect.width(), rect.height(),
1260 rect.left() + dx, rect.top() + dy);
1261 XFreeGC(xinfo.display(), gc);
1262 return true;
1263 }
1264
metric(QPaintDevice::PaintDeviceMetric metric) const1265 int QX11PlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
1266 {
1267 switch (metric) {
1268 case QPaintDevice::PdmDevicePixelRatio:
1269 return devicePixelRatio();
1270 break;
1271 case QPaintDevice::PdmDevicePixelRatioScaled:
1272 return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
1273 break;
1274 case QPaintDevice::PdmWidth:
1275 return w;
1276 case QPaintDevice::PdmHeight:
1277 return h;
1278 case QPaintDevice::PdmNumColors:
1279 return 1 << d;
1280 case QPaintDevice::PdmDepth:
1281 return d;
1282 case QPaintDevice::PdmWidthMM: {
1283 const int screen = xinfo.screen();
1284 const int mm = DisplayWidthMM(xinfo.display(), screen) * w
1285 / DisplayWidth(xinfo.display(), screen);
1286 return mm;
1287 }
1288 case QPaintDevice::PdmHeightMM: {
1289 const int screen = xinfo.screen();
1290 const int mm = (DisplayHeightMM(xinfo.display(), screen) * h)
1291 / DisplayHeight(xinfo.display(), screen);
1292 return mm;
1293 }
1294 case QPaintDevice::PdmDpiX:
1295 case QPaintDevice::PdmPhysicalDpiX:
1296 return QXcbX11Info::appDpiX(xinfo.screen());
1297 case QPaintDevice::PdmDpiY:
1298 case QPaintDevice::PdmPhysicalDpiY:
1299 return QXcbX11Info::appDpiY(xinfo.screen());
1300 default:
1301 qWarning("QX11PlatformPixmap::metric(): Invalid metric");
1302 return 0;
1303 }
1304 }
1305
fill(const QColor & fillColor)1306 void QX11PlatformPixmap::fill(const QColor &fillColor)
1307 {
1308 if (fillColor.alpha() != 255) {
1309 #if QT_CONFIG(xrender)
1310 if (X11->use_xrender) {
1311 if (!picture || d != 32)
1312 convertToARGB32(/*preserveContents = */false);
1313
1314 ::Picture src = X11->getSolidFill(xinfo.screen(), fillColor);
1315 XRenderComposite(xinfo.display(), PictOpSrc, src, 0, picture,
1316 0, 0, width(), height(),
1317 0, 0, width(), height());
1318 } else
1319 #endif
1320 {
1321 QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
1322 im.fill(PREMUL(fillColor.rgba()));
1323 release();
1324 fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
1325 }
1326 return;
1327 }
1328
1329 GC gc = XCreateGC(xinfo.display(), hd, 0, 0);
1330 if (depth() == 1) {
1331 XSetForeground(xinfo.display(), gc, qGray(fillColor.rgb()) > 127 ? 0 : 1);
1332 } else if (X11->use_xrender && d >= 24) {
1333 XSetForeground(xinfo.display(), gc, fillColor.rgba());
1334 } else {
1335 XSetForeground(xinfo.display(), gc,
1336 QXcbColormap::instance(xinfo.screen()).pixel(fillColor));
1337 }
1338 XFillRectangle(xinfo.display(), hd, gc, 0, 0, width(), height());
1339 XFreeGC(xinfo.display(), gc);
1340 }
1341
mask() const1342 QBitmap QX11PlatformPixmap::mask() const
1343 {
1344 QBitmap mask;
1345 #if QT_CONFIG(xrender)
1346 if (picture && d == 32) {
1347 // #### slow - there must be a better way..
1348 mask = QBitmap::fromImage(toImage().createAlphaMask());
1349 } else
1350 #endif
1351 if (d == 1) {
1352 QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this);
1353 mask = QPixmap(that);
1354 } else {
1355 mask = mask_to_bitmap(xinfo.screen());
1356 }
1357 return mask;
1358 }
1359
setMask(const QBitmap & newmask)1360 void QX11PlatformPixmap::setMask(const QBitmap &newmask)
1361 {
1362 if (newmask.isNull()) { // clear mask
1363 #if QT_CONFIG(xrender)
1364 if (picture && d == 32) {
1365 QX11PlatformPixmap newData(pixelType());
1366 newData.resize(w, h);
1367 newData.fill(Qt::black);
1368 XRenderComposite(xinfo.display(), PictOpOver,
1369 picture, 0, newData.picture,
1370 0, 0, 0, 0, 0, 0, w, h);
1371 release();
1372 *this = newData;
1373 // the new QX11PlatformPixmap object isn't referenced yet, so
1374 // ref it
1375 ref.ref();
1376
1377 // the below is to make sure the QX11PlatformPixmap destructor
1378 // doesn't delete our newly created render picture
1379 newData.hd = 0;
1380 newData.x11_mask = 0;
1381 newData.picture = 0;
1382 newData.mask_picture = 0;
1383 newData.hd2 = 0;
1384 } else
1385 #endif
1386 if (x11_mask) {
1387 #if QT_CONFIG(xrender)
1388 if (picture) {
1389 XRenderPictureAttributes attrs;
1390 attrs.alpha_map = 0;
1391 XRenderChangePicture(xinfo.display(), picture, CPAlphaMap,
1392 &attrs);
1393 }
1394 if (mask_picture)
1395 XRenderFreePicture(xinfo.display(), mask_picture);
1396 mask_picture = 0;
1397 #endif
1398 XFreePixmap(xinfo.display(), x11_mask);
1399 x11_mask = 0;
1400 }
1401 return;
1402 }
1403
1404 #if QT_CONFIG(xrender)
1405 if (picture && d == 32) {
1406 XRenderComposite(xinfo.display(), PictOpSrc,
1407 picture, qt_x11Pixmap(newmask)->x11PictureHandle(),
1408 picture, 0, 0, 0, 0, 0, 0, w, h);
1409 } else
1410 #endif
1411 if (depth() == 1) {
1412 XGCValues vals;
1413 vals.function = GXand;
1414 GC gc = XCreateGC(xinfo.display(), hd, GCFunction, &vals);
1415 XCopyArea(xinfo.display(), qt_x11Pixmap(newmask)->handle(), hd, gc, 0, 0,
1416 width(), height(), 0, 0);
1417 XFreeGC(xinfo.display(), gc);
1418 } else {
1419 // ##### should or the masks together
1420 if (x11_mask) {
1421 XFreePixmap(xinfo.display(), x11_mask);
1422 #if QT_CONFIG(xrender)
1423 if (mask_picture)
1424 XRenderFreePicture(xinfo.display(), mask_picture);
1425 #endif
1426 }
1427 x11_mask = QX11PlatformPixmap::bitmap_to_mask(newmask, xinfo.screen());
1428 #if QT_CONFIG(xrender)
1429 if (picture) {
1430 mask_picture = XRenderCreatePicture(xinfo.display(), x11_mask,
1431 XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0);
1432 XRenderPictureAttributes attrs;
1433 attrs.alpha_map = mask_picture;
1434 XRenderChangePicture(xinfo.display(), picture, CPAlphaMap, &attrs);
1435 }
1436 #endif
1437 }
1438 }
1439
hasAlphaChannel() const1440 bool QX11PlatformPixmap::hasAlphaChannel() const
1441 {
1442 if (picture && d == 32)
1443 return true;
1444
1445 if (x11_mask && d == 1)
1446 return true;
1447
1448 return false;
1449 }
1450
transformed(const QTransform & transform,Qt::TransformationMode mode) const1451 QPixmap QX11PlatformPixmap::transformed(const QTransform &transform, Qt::TransformationMode mode) const
1452 {
1453 if (mode == Qt::SmoothTransformation || transform.type() >= QTransform::TxProject) {
1454 QImage image = toImage();
1455 return QPixmap::fromImage(image.transformed(transform, mode));
1456 }
1457
1458 uint w = 0;
1459 uint h = 0; // size of target pixmap
1460 uint ws, hs; // size of source pixmap
1461 uchar *dptr; // data in target pixmap
1462 uint dbpl, dbytes; // bytes per line/bytes total
1463 uchar *sptr; // data in original pixmap
1464 int sbpl; // bytes per line in original
1465 int bpp; // bits per pixel
1466 bool depth1 = depth() == 1;
1467 Display *dpy = xinfo.display();
1468
1469 ws = width();
1470 hs = height();
1471
1472 QTransform mat(transform.m11(), transform.m12(), transform.m13(),
1473 transform.m21(), transform.m22(), transform.m23(),
1474 0., 0., 1);
1475 bool complex_xform = false;
1476 qreal scaledWidth;
1477 qreal scaledHeight;
1478
1479 if (mat.type() <= QTransform::TxScale) {
1480 scaledHeight = qAbs(mat.m22()) * hs + 0.9999;
1481 scaledWidth = qAbs(mat.m11()) * ws + 0.9999;
1482 h = qAbs(int(scaledHeight));
1483 w = qAbs(int(scaledWidth));
1484 } else { // rotation or shearing
1485 QPolygonF a(QRectF(0, 0, ws, hs));
1486 a = mat.map(a);
1487 QRect r = a.boundingRect().toAlignedRect();
1488 w = r.width();
1489 h = r.height();
1490 scaledWidth = w;
1491 scaledHeight = h;
1492 complex_xform = true;
1493 }
1494 mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix
1495
1496 bool invertible;
1497 mat = mat.inverted(&invertible); // invert matrix
1498
1499 if (h == 0 || w == 0 || !invertible
1500 || qAbs(scaledWidth) >= 32768 || qAbs(scaledHeight) >= 32768 )
1501 // error, return null pixmap
1502 return QPixmap();
1503
1504 XImage *xi = XGetImage(xinfo.display(), handle(), 0, 0, ws, hs, AllPlanes,
1505 depth1 ? XYPixmap : ZPixmap);
1506
1507 if (!xi)
1508 return QPixmap();
1509
1510 sbpl = xi->bytes_per_line;
1511 sptr = (uchar *)xi->data;
1512 bpp = xi->bits_per_pixel;
1513
1514 if (depth1)
1515 dbpl = (w+7)/8;
1516 else
1517 dbpl = ((w*bpp+31)/32)*4;
1518 dbytes = dbpl*h;
1519
1520 dptr = (uchar *)malloc(dbytes); // create buffer for bits
1521 Q_CHECK_PTR(dptr);
1522 if (depth1) // fill with zeros
1523 memset(dptr, 0, dbytes);
1524 else if (bpp == 8) // fill with background color
1525 memset(dptr, WhitePixel(xinfo.display(), xinfo.screen()), dbytes);
1526 else
1527 memset(dptr, 0, dbytes);
1528
1529 // #define QT_DEBUG_XIMAGE
1530 #if defined(QT_DEBUG_XIMAGE)
1531 qDebug("----IMAGE--INFO--------------");
1532 qDebug("width............. %d", xi->width);
1533 qDebug("height............ %d", xi->height);
1534 qDebug("xoffset........... %d", xi->xoffset);
1535 qDebug("format............ %d", xi->format);
1536 qDebug("byte order........ %d", xi->byte_order);
1537 qDebug("bitmap unit....... %d", xi->bitmap_unit);
1538 qDebug("bitmap bit order.. %d", xi->bitmap_bit_order);
1539 qDebug("depth............. %d", xi->depth);
1540 qDebug("bytes per line.... %d", xi->bytes_per_line);
1541 qDebug("bits per pixel.... %d", xi->bits_per_pixel);
1542 #endif
1543
1544 int type;
1545 if (xi->bitmap_bit_order == MSBFirst)
1546 type = QT_XFORM_TYPE_MSBFIRST;
1547 else
1548 type = QT_XFORM_TYPE_LSBFIRST;
1549 int xbpl, p_inc;
1550 if (depth1) {
1551 xbpl = (w+7)/8;
1552 p_inc = dbpl - xbpl;
1553 } else {
1554 xbpl = (w*bpp)/8;
1555 p_inc = dbpl - xbpl;
1556 }
1557
1558 if (!qt_xForm_helper(mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs)){
1559 qWarning("QPixmap::transform: display not supported (bpp=%d)",bpp);
1560 QPixmap pm;
1561 free(dptr);
1562 return pm;
1563 }
1564
1565 qSafeXDestroyImage(xi);
1566
1567 if (depth1) { // mono bitmap
1568 QBitmap bm = QBitmap::fromData(QSize(w, h), dptr,
1569 BitmapBitOrder(xinfo.display()) == MSBFirst
1570 ? QImage::Format_Mono
1571 : QImage::Format_MonoLSB);
1572 free(dptr);
1573 return bm;
1574 } else { // color pixmap
1575 QX11PlatformPixmap *x11Data = new QX11PlatformPixmap(QPlatformPixmap::PixmapType);
1576 QPixmap pm(x11Data);
1577 x11Data->flags &= ~QX11PlatformPixmap::Uninitialized;
1578 x11Data->xinfo = xinfo;
1579 x11Data->d = d;
1580 x11Data->w = w;
1581 x11Data->h = h;
1582 x11Data->is_null = (w <= 0 || h <= 0);
1583 x11Data->hd = XCreatePixmap(xinfo.display(),
1584 RootWindow(xinfo.display(), xinfo.screen()),
1585 w, h, d);
1586 x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
1587
1588 #if QT_CONFIG(xrender)
1589 if (X11->use_xrender) {
1590 XRenderPictFormat *format = x11Data->d == 32
1591 ? XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32)
1592 : XRenderFindVisualFormat(xinfo.display(), (Visual *) x11Data->xinfo.visual());
1593 x11Data->picture = XRenderCreatePicture(xinfo.display(), x11Data->hd, format, 0, 0);
1594 }
1595 #endif // QT_CONFIG(xrender)
1596
1597 GC gc = XCreateGC(xinfo.display(), x11Data->hd, 0, 0);
1598 xi = XCreateImage(dpy, (Visual*)x11Data->xinfo.visual(),
1599 x11Data->d,
1600 ZPixmap, 0, (char *)dptr, w, h, 32, 0);
1601 XPutImage(dpy, qt_x11Pixmap(pm)->handle(), gc, xi, 0, 0, 0, 0, w, h);
1602 qSafeXDestroyImage(xi);
1603 XFreeGC(xinfo.display(), gc);
1604
1605 if (x11_mask) { // xform mask, too
1606 pm.setMask(mask_to_bitmap(xinfo.screen()).transformed(transform));
1607 } else if (d != 32 && complex_xform) { // need a mask!
1608 QBitmap mask(ws, hs);
1609 mask.fill(Qt::color1);
1610 pm.setMask(mask.transformed(transform));
1611 }
1612 return pm;
1613 }
1614 }
1615
toImage() const1616 QImage QX11PlatformPixmap::toImage() const
1617 {
1618 return toImage(QRect(0, 0, w, h));
1619 }
1620
toImage(const QRect & rect) const1621 QImage QX11PlatformPixmap::toImage(const QRect &rect) const
1622 {
1623 Window root_return;
1624 int x_return;
1625 int y_return;
1626 unsigned int width_return;
1627 unsigned int height_return;
1628 unsigned int border_width_return;
1629 unsigned int depth_return;
1630
1631 XGetGeometry(xinfo.display(), hd, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return);
1632
1633 QXImageWrapper xiWrapper;
1634 xiWrapper.xi = XGetImage(xinfo.display(), hd, rect.x(), rect.y(), rect.width(), rect.height(),
1635 AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap);
1636
1637 Q_CHECK_PTR(xiWrapper.xi);
1638 if (!xiWrapper.xi)
1639 return QImage();
1640
1641 if (!x11_mask && canTakeQImageFromXImage(xiWrapper))
1642 return takeQImageFromXImage(xiWrapper);
1643
1644 QImage image = toImage(xiWrapper, rect);
1645 qSafeXDestroyImage(xiWrapper.xi);
1646 return image;
1647 }
1648
1649 #if QT_CONFIG(xrender)
qt_renderformat_for_depth(const QXcbX11Info & xinfo,int depth)1650 static XRenderPictFormat *qt_renderformat_for_depth(const QXcbX11Info &xinfo, int depth)
1651 {
1652 if (depth == 1)
1653 return XRenderFindStandardFormat(xinfo.display(), PictStandardA1);
1654 else if (depth == 32)
1655 return XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32);
1656 else
1657 return XRenderFindVisualFormat(xinfo.display(), (Visual *)xinfo.visual());
1658 }
1659 #endif
1660
Q_GLOBAL_STATIC(QX11PaintEngine,qt_x11_paintengine)1661 Q_GLOBAL_STATIC(QX11PaintEngine, qt_x11_paintengine)
1662
1663 QPaintEngine *QX11PlatformPixmap::paintEngine() const
1664 {
1665 QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this);
1666
1667 if ((flags & Readonly)/* && share_mode == QPixmap::ImplicitlyShared*/) {
1668 // if someone wants to draw onto us, copy the shared contents
1669 // and turn it into a fully fledged QPixmap
1670 ::Pixmap hd_copy = XCreatePixmap(xinfo.display(), RootWindow(xinfo.display(), xinfo.screen()),
1671 w, h, d);
1672 #if QT_CONFIG(xrender)
1673 if (picture && d == 32) {
1674 XRenderPictFormat *format = qt_renderformat_for_depth(xinfo, d);
1675 ::Picture picture_copy = XRenderCreatePicture(xinfo.display(),
1676 hd_copy, format,
1677 0, 0);
1678
1679 XRenderComposite(xinfo.display(), PictOpSrc, picture, 0, picture_copy,
1680 0, 0, 0, 0, 0, 0, w, h);
1681 XRenderFreePicture(xinfo.display(), picture);
1682 that->picture = picture_copy;
1683 } else
1684 #endif
1685 {
1686 GC gc = XCreateGC(xinfo.display(), hd_copy, 0, 0);
1687 XCopyArea(xinfo.display(), hd, hd_copy, gc, 0, 0, w, h, 0, 0);
1688 XFreeGC(xinfo.display(), gc);
1689 }
1690 that->hd = hd_copy;
1691 that->flags &= ~QX11PlatformPixmap::Readonly;
1692 }
1693
1694 if (qt_x11_paintengine->isActive()) {
1695 if (!that->pengine)
1696 that->pengine = new QX11PaintEngine;
1697
1698 return that->pengine;
1699 }
1700
1701 return qt_x11_paintengine();
1702 }
1703
devicePixelRatio() const1704 qreal QX11PlatformPixmap::devicePixelRatio() const
1705 {
1706 return dpr;
1707 }
1708
setDevicePixelRatio(qreal scaleFactor)1709 void QX11PlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
1710 {
1711 dpr = scaleFactor;
1712 }
1713
x11ConvertToDefaultDepth()1714 Pixmap QX11PlatformPixmap::x11ConvertToDefaultDepth()
1715 {
1716 #if QT_CONFIG(xrender)
1717 if (d == xinfo.appDepth() || !X11->use_xrender)
1718 return hd;
1719 if (!hd2) {
1720 hd2 = XCreatePixmap(xinfo.display(), hd, w, h, xinfo.appDepth());
1721 XRenderPictFormat *format = XRenderFindVisualFormat(xinfo.display(),
1722 (Visual*) xinfo.visual());
1723 Picture pic = XRenderCreatePicture(xinfo.display(), hd2, format, 0, 0);
1724 XRenderComposite(xinfo.display(), PictOpSrc, picture,
1725 XNone, pic, 0, 0, 0, 0, 0, 0, w, h);
1726 XRenderFreePicture(xinfo.display(), pic);
1727 }
1728 return hd2;
1729 #else
1730 return hd;
1731 #endif
1732 }
1733
createBitmapFromImage(const QImage & image)1734 XID QX11PlatformPixmap::createBitmapFromImage(const QImage &image)
1735 {
1736 QImage img = image.convertToFormat(QImage::Format_MonoLSB);
1737 const QRgb c0 = QColor(Qt::black).rgb();
1738 const QRgb c1 = QColor(Qt::white).rgb();
1739 if (img.color(0) == c0 && img.color(1) == c1) {
1740 img.invertPixels();
1741 img.setColor(0, c1);
1742 img.setColor(1, c0);
1743 }
1744
1745 char *bits;
1746 uchar *tmp_bits;
1747 int w = img.width();
1748 int h = img.height();
1749 int bpl = (w + 7) / 8;
1750 int ibpl = img.bytesPerLine();
1751 if (bpl != ibpl) {
1752 tmp_bits = new uchar[bpl*h];
1753 bits = (char *)tmp_bits;
1754 uchar *p, *b;
1755 int y;
1756 b = tmp_bits;
1757 p = img.scanLine(0);
1758 for (y = 0; y < h; y++) {
1759 memcpy(b, p, bpl);
1760 b += bpl;
1761 p += ibpl;
1762 }
1763 } else {
1764 bits = (char *)img.bits();
1765 tmp_bits = 0;
1766 }
1767 XID hd = XCreateBitmapFromData(QXcbX11Info::display(),
1768 QXcbX11Info::appRootWindow(),
1769 bits, w, h);
1770 if (tmp_bits) // Avoid purify complaint
1771 delete [] tmp_bits;
1772 return hd;
1773 }
1774
isBackingStore() const1775 bool QX11PlatformPixmap::isBackingStore() const
1776 {
1777 return (flags & IsBackingStore);
1778 }
1779
setIsBackingStore(bool on)1780 void QX11PlatformPixmap::setIsBackingStore(bool on)
1781 {
1782 if (on)
1783 flags |= IsBackingStore;
1784 else {
1785 flags &= ~IsBackingStore;
1786 }
1787 }
1788
1789 #if QT_CONFIG(xrender)
convertToARGB32(bool preserveContents)1790 void QX11PlatformPixmap::convertToARGB32(bool preserveContents)
1791 {
1792 if (!X11->use_xrender)
1793 return;
1794
1795 // Q_ASSERT(count == 1);
1796 if ((flags & Readonly)/* && share_mode == QPixmap::ExplicitlyShared*/)
1797 return;
1798
1799 Pixmap pm = XCreatePixmap(xinfo.display(), RootWindow(xinfo.display(), xinfo.screen()),
1800 w, h, 32);
1801 Picture p = XRenderCreatePicture(xinfo.display(), pm,
1802 XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32), 0, 0);
1803 if (picture) {
1804 if (preserveContents)
1805 XRenderComposite(xinfo.display(), PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h);
1806 if (!(flags & Readonly))
1807 XRenderFreePicture(xinfo.display(), picture);
1808 }
1809 if (hd && !(flags & Readonly))
1810 XFreePixmap(xinfo.display(), hd);
1811 if (x11_mask) {
1812 XFreePixmap(xinfo.display(), x11_mask);
1813 if (mask_picture)
1814 XRenderFreePicture(xinfo.display(), mask_picture);
1815 x11_mask = 0;
1816 mask_picture = 0;
1817 }
1818 hd = pm;
1819 picture = p;
1820
1821 d = 32;
1822 xinfo.setDepth(32);
1823
1824 XVisualInfo visinfo;
1825 if (XMatchVisualInfo(xinfo.display(), xinfo.screen(), 32, TrueColor, &visinfo))
1826 xinfo.setVisual(visinfo.visual);
1827 }
1828 #endif
1829
release()1830 void QX11PlatformPixmap::release()
1831 {
1832 delete pengine;
1833 pengine = 0;
1834
1835 if (/*!X11*/ QCoreApplication::closingDown()) {
1836 // At this point, the X server will already have freed our resources,
1837 // so there is nothing to do.
1838 return;
1839 }
1840
1841 if (x11_mask) {
1842 #if QT_CONFIG(xrender)
1843 if (mask_picture)
1844 XRenderFreePicture(xinfo.display(), mask_picture);
1845 mask_picture = 0;
1846 #endif
1847 XFreePixmap(xinfo.display(), x11_mask);
1848 x11_mask = 0;
1849 }
1850
1851 if (hd) {
1852 #if QT_CONFIG(xrender)
1853 if (picture) {
1854 XRenderFreePicture(xinfo.display(), picture);
1855 picture = 0;
1856 }
1857 #endif // QT_CONFIG(xrender)
1858
1859 if (hd2) {
1860 XFreePixmap(xinfo.display(), hd2);
1861 hd2 = 0;
1862 }
1863 if (!(flags & Readonly))
1864 XFreePixmap(xinfo.display(), hd);
1865 hd = 0;
1866 }
1867 }
1868
toImage(const QXImageWrapper & xiWrapper,const QRect & rect) const1869 QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const
1870 {
1871 XImage *xi = xiWrapper.xi;
1872
1873 int d = depth();
1874 Visual *visual = (Visual *)xinfo.visual();
1875 bool trucol = (visual->c_class >= TrueColor) && d > 1;
1876
1877 QImage::Format format = QImage::Format_Mono;
1878 if (d > 1 && d <= 8) {
1879 d = 8;
1880 format = QImage::Format_Indexed8;
1881 }
1882 // we could run into the situation where d == 8 AND trucol is true, which can
1883 // cause problems when converting to and from images. in this case, always treat
1884 // the depth as 32...
1885 if (d > 8 || trucol) {
1886 d = 32;
1887 format = QImage::Format_RGB32;
1888 }
1889
1890 if (d == 1 && xi->bitmap_bit_order == LSBFirst)
1891 format = QImage::Format_MonoLSB;
1892 if (x11_mask && format == QImage::Format_RGB32)
1893 format = QImage::Format_ARGB32;
1894
1895 QImage image(xi->width, xi->height, format);
1896 image.setDevicePixelRatio(devicePixelRatio());
1897 if (image.isNull()) // could not create image
1898 return image;
1899
1900 QImage alpha;
1901 if (x11_mask) {
1902 if (rect.contains(QRect(0, 0, w, h)))
1903 alpha = mask().toImage();
1904 else
1905 alpha = mask().toImage().copy(rect);
1906 }
1907 bool ale = alpha.format() == QImage::Format_MonoLSB;
1908
1909 if (trucol) { // truecolor
1910 const uint red_mask = (uint)visual->red_mask;
1911 const uint green_mask = (uint)visual->green_mask;
1912 const uint blue_mask = (uint)visual->blue_mask;
1913 const int red_shift = highest_bit(red_mask) - 7;
1914 const int green_shift = highest_bit(green_mask) - 7;
1915 const int blue_shift = highest_bit(blue_mask) - 7;
1916
1917 const uint red_bits = n_bits(red_mask);
1918 const uint green_bits = n_bits(green_mask);
1919 const uint blue_bits = n_bits(blue_mask);
1920
1921 static uint red_table_bits = 0;
1922 static uint green_table_bits = 0;
1923 static uint blue_table_bits = 0;
1924
1925 if (red_bits < 8 && red_table_bits != red_bits) {
1926 build_scale_table(&red_scale_table, red_bits);
1927 red_table_bits = red_bits;
1928 }
1929 if (blue_bits < 8 && blue_table_bits != blue_bits) {
1930 build_scale_table(&blue_scale_table, blue_bits);
1931 blue_table_bits = blue_bits;
1932 }
1933 if (green_bits < 8 && green_table_bits != green_bits) {
1934 build_scale_table(&green_scale_table, green_bits);
1935 green_table_bits = green_bits;
1936 }
1937
1938 int r, g, b;
1939
1940 QRgb *dst;
1941 uchar *src;
1942 uint pixel;
1943 int bppc = xi->bits_per_pixel;
1944
1945 if (bppc > 8 && xi->byte_order == LSBFirst)
1946 bppc++;
1947
1948 for (int y = 0; y < xi->height; ++y) {
1949 uchar* asrc = x11_mask ? alpha.scanLine(y) : 0;
1950 dst = (QRgb *)image.scanLine(y);
1951 src = (uchar *)xi->data + xi->bytes_per_line*y;
1952 for (int x = 0; x < xi->width; x++) {
1953 switch (bppc) {
1954 case 8:
1955 pixel = *src++;
1956 break;
1957 case 16: // 16 bit MSB
1958 pixel = src[1] | (uint)src[0] << 8;
1959 src += 2;
1960 break;
1961 case 17: // 16 bit LSB
1962 pixel = src[0] | (uint)src[1] << 8;
1963 src += 2;
1964 break;
1965 case 24: // 24 bit MSB
1966 pixel = src[2] | (uint)src[1] << 8 | (uint)src[0] << 16;
1967 src += 3;
1968 break;
1969 case 25: // 24 bit LSB
1970 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16;
1971 src += 3;
1972 break;
1973 case 32: // 32 bit MSB
1974 pixel = src[3] | (uint)src[2] << 8 | (uint)src[1] << 16 | (uint)src[0] << 24;
1975 src += 4;
1976 break;
1977 case 33: // 32 bit LSB
1978 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24;
1979 src += 4;
1980 break;
1981 default: // should not really happen
1982 x = xi->width; // leave loop
1983 y = xi->height;
1984 pixel = 0; // eliminate compiler warning
1985 qWarning("QPixmap::convertToImage: Invalid depth %d", bppc);
1986 }
1987 if (red_shift > 0)
1988 r = (pixel & red_mask) >> red_shift;
1989 else
1990 r = (pixel & red_mask) << -red_shift;
1991 if (green_shift > 0)
1992 g = (pixel & green_mask) >> green_shift;
1993 else
1994 g = (pixel & green_mask) << -green_shift;
1995 if (blue_shift > 0)
1996 b = (pixel & blue_mask) >> blue_shift;
1997 else
1998 b = (pixel & blue_mask) << -blue_shift;
1999
2000 if (red_bits < 8)
2001 r = red_scale_table[r];
2002 if (green_bits < 8)
2003 g = green_scale_table[g];
2004 if (blue_bits < 8)
2005 b = blue_scale_table[b];
2006
2007 if (x11_mask) {
2008 if (ale) {
2009 *dst++ = (asrc[x >> 3] & (1 << (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
2010 } else {
2011 *dst++ = (asrc[x >> 3] & (0x80 >> (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
2012 }
2013 } else {
2014 *dst++ = qRgb(r, g, b);
2015 }
2016 }
2017 }
2018 } else if (xi->bits_per_pixel == d) { // compatible depth
2019 char *xidata = xi->data; // copy each scanline
2020 int bpl = qMin(int(image.bytesPerLine()),xi->bytes_per_line);
2021 for (int y=0; y<xi->height; y++) {
2022 memcpy(image.scanLine(y), xidata, bpl);
2023 xidata += xi->bytes_per_line;
2024 }
2025 } else {
2026 /* Typically 2 or 4 bits display depth */
2027 qWarning("QPixmap::convertToImage: Display not supported (bpp=%d)",
2028 xi->bits_per_pixel);
2029 return QImage();
2030 }
2031
2032 if (d == 1) { // bitmap
2033 image.setColorCount(2);
2034 image.setColor(0, qRgb(255,255,255));
2035 image.setColor(1, qRgb(0,0,0));
2036 } else if (!trucol) { // pixmap with colormap
2037 uchar *p;
2038 uchar *end;
2039 uchar use[256]; // pixel-in-use table
2040 uchar pix[256]; // pixel translation table
2041 int ncols, bpl;
2042 memset(use, 0, 256);
2043 memset(pix, 0, 256);
2044 bpl = image.bytesPerLine();
2045
2046 if (x11_mask) { // which pixels are used?
2047 for (int i = 0; i < xi->height; i++) {
2048 uchar* asrc = alpha.scanLine(i);
2049 p = image.scanLine(i);
2050 if (ale) {
2051 for (int x = 0; x < xi->width; x++) {
2052 if (asrc[x >> 3] & (1 << (x & 7)))
2053 use[*p] = 1;
2054 ++p;
2055 }
2056 } else {
2057 for (int x = 0; x < xi->width; x++) {
2058 if (asrc[x >> 3] & (0x80 >> (x & 7)))
2059 use[*p] = 1;
2060 ++p;
2061 }
2062 }
2063 }
2064 } else {
2065 for (int i = 0; i < xi->height; i++) {
2066 p = image.scanLine(i);
2067 end = p + bpl;
2068 while (p < end)
2069 use[*p++] = 1;
2070 }
2071 }
2072 ncols = 0;
2073 for (int i = 0; i < 256; i++) { // build translation table
2074 if (use[i])
2075 pix[i] = ncols++;
2076 }
2077 for (int i = 0; i < xi->height; i++) { // translate pixels
2078 p = image.scanLine(i);
2079 end = p + bpl;
2080 while (p < end) {
2081 *p = pix[*p];
2082 p++;
2083 }
2084 }
2085 if (x11_mask) {
2086 int trans;
2087 if (ncols < 256) {
2088 trans = ncols++;
2089 image.setColorCount(ncols); // create color table
2090 image.setColor(trans, 0x00000000);
2091 } else {
2092 image.setColorCount(ncols); // create color table
2093 // oh dear... no spare "transparent" pixel.
2094 // use first pixel in image (as good as any).
2095 trans = image.scanLine(0)[0];
2096 }
2097 for (int i = 0; i < xi->height; i++) {
2098 uchar* asrc = alpha.scanLine(i);
2099 p = image.scanLine(i);
2100 if (ale) {
2101 for (int x = 0; x < xi->width; x++) {
2102 if (!(asrc[x >> 3] & (1 << (x & 7))))
2103 *p = trans;
2104 ++p;
2105 }
2106 } else {
2107 for (int x = 0; x < xi->width; x++) {
2108 if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
2109 *p = trans;
2110 ++p;
2111 }
2112 }
2113 }
2114 } else {
2115 image.setColorCount(ncols); // create color table
2116 }
2117 QVector<QColor> colors = QXcbColormap::instance(xinfo.screen()).colormap();
2118 int j = 0;
2119 for (int i=0; i<colors.size(); i++) { // translate pixels
2120 if (use[i])
2121 image.setColor(j++, 0xff000000 | colors.at(i).rgb());
2122 }
2123 }
2124
2125 return image;
2126 }
2127
2128 QT_END_NAMESPACE
2129