source: trunk/src/gui/image/qpixmap_x11.cpp@ 661

Last change on this file since 661 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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