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