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

Last change on this file since 890 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 82.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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), gl_surface(0), hd(0),
318 flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(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 = image->isNull() ? false : 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
1145Qt::HANDLE QX11PixmapData::createBitmapFromImage(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 int w = img.width();
1159 int h = img.height();
1160 int bpl = (w + 7) / 8;
1161 int ibpl = img.bytesPerLine();
1162 if (bpl != ibpl) {
1163 tmp_bits = new uchar[bpl*h];
1164 bits = (char *)tmp_bits;
1165 uchar *p, *b;
1166 int y;
1167 b = tmp_bits;
1168 p = img.scanLine(0);
1169 for (y = 0; y < h; y++) {
1170 memcpy(b, p, bpl);
1171 b += bpl;
1172 p += ibpl;
1173 }
1174 } else {
1175 bits = (char *)img.bits();
1176 tmp_bits = 0;
1177 }
1178 Qt::HANDLE hd = (Qt::HANDLE)XCreateBitmapFromData(X11->display,
1179 QX11Info::appRootWindow(),
1180 bits, w, h);
1181 if (tmp_bits) // Avoid purify complaint
1182 delete [] tmp_bits;
1183 return hd;
1184}
1185
1186void QX11PixmapData::bitmapFromImage(const QImage &image)
1187{
1188 w = image.width();
1189 h = image.height();
1190 d = 1;
1191 is_null = (w <= 0 || h <= 0);
1192 hd = createBitmapFromImage(image);
1193#ifndef QT_NO_XRENDER
1194 if (X11->use_xrender)
1195 picture = XRenderCreatePicture(X11->display, hd,
1196 XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
1197#endif // QT_NO_XRENDER
1198}
1199
1200void QX11PixmapData::fill(const QColor &fillColor)
1201{
1202 if (fillColor.alpha() != 255) {
1203#ifndef QT_NO_XRENDER
1204 if (X11->use_xrender) {
1205 if (!picture || d != 32)
1206 convertToARGB32(/*preserveContents = */false);
1207
1208 ::Picture src = X11->getSolidFill(xinfo.screen(), fillColor);
1209 XRenderComposite(X11->display, PictOpSrc, src, 0, picture,
1210 0, 0, width(), height(),
1211 0, 0, width(), height());
1212 } else
1213#endif
1214 {
1215 QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
1216 im.fill(PREMUL(fillColor.rgba()));
1217 release();
1218 fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
1219 }
1220 return;
1221 }
1222
1223 GC gc = XCreateGC(X11->display, hd, 0, 0);
1224 if (depth() == 1) {
1225 XSetForeground(X11->display, gc, qGray(fillColor.rgb()) > 127 ? 0 : 1);
1226 } else if (X11->use_xrender && d >= 24) {
1227 XSetForeground(X11->display, gc, fillColor.rgba());
1228 } else {
1229 XSetForeground(X11->display, gc,
1230 QColormap::instance(xinfo.screen()).pixel(fillColor));
1231 }
1232 XFillRectangle(X11->display, hd, gc, 0, 0, width(), height());
1233 XFreeGC(X11->display, gc);
1234}
1235
1236QX11PixmapData::~QX11PixmapData()
1237{
1238 // Cleanup hooks have to be called before the handles are freed
1239 if (is_cached) {
1240 QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(this);
1241 is_cached = false;
1242 }
1243
1244 release();
1245}
1246
1247void QX11PixmapData::release()
1248{
1249 delete pengine;
1250 pengine = 0;
1251
1252 if (!X11) {
1253 // At this point, the X server will already have freed our resources,
1254 // so there is nothing to do.
1255 return;
1256 }
1257
1258 if (x11_mask) {
1259#ifndef QT_NO_XRENDER
1260 if (mask_picture)
1261 XRenderFreePicture(X11->display, mask_picture);
1262 mask_picture = 0;
1263#endif
1264 XFreePixmap(X11->display, x11_mask);
1265 x11_mask = 0;
1266 }
1267
1268 if (hd) {
1269#ifndef QT_NO_XRENDER
1270 if (picture) {
1271 XRenderFreePicture(X11->display, picture);
1272 picture = 0;
1273 }
1274#endif // QT_NO_XRENDER
1275
1276 if (hd2) {
1277 XFreePixmap(xinfo.display(), hd2);
1278 hd2 = 0;
1279 }
1280 if (!(flags & Readonly))
1281 XFreePixmap(xinfo.display(), hd);
1282 hd = 0;
1283 }
1284}
1285
1286QPixmap QX11PixmapData::alphaChannel() const
1287{
1288 if (!hasAlphaChannel()) {
1289 QPixmap pm(w, h);
1290 pm.fill(Qt::white);
1291 return pm;
1292 }
1293 QImage im(toImage());
1294 return QPixmap::fromImage(im.alphaChannel(), Qt::OrderedDither);
1295}
1296
1297void QX11PixmapData::setAlphaChannel(const QPixmap &alpha)
1298{
1299 QImage image(toImage());
1300 image.setAlphaChannel(alpha.toImage());
1301 release();
1302 fromImage(image, Qt::OrderedDither | Qt::OrderedAlphaDither);
1303}
1304
1305
1306QBitmap QX11PixmapData::mask() const
1307{
1308 QBitmap mask;
1309#ifndef QT_NO_XRENDER
1310 if (picture && d == 32) {
1311 // #### slow - there must be a better way..
1312 mask = QBitmap::fromImage(toImage().createAlphaMask());
1313 } else
1314#endif
1315 if (d == 1) {
1316 QX11PixmapData *that = const_cast<QX11PixmapData*>(this);
1317 mask = QPixmap(that);
1318 } else {
1319 mask = mask_to_bitmap(xinfo.screen());
1320 }
1321 return mask;
1322}
1323
1324/*!
1325 Sets a mask bitmap.
1326
1327 The \a newmask bitmap defines the clip mask for this pixmap. Every
1328 pixel in \a newmask corresponds to a pixel in this pixmap. Pixel
1329 value 1 means opaque and pixel value 0 means transparent. The mask
1330 must have the same size as this pixmap.
1331
1332 \warning Setting the mask on a pixmap will cause any alpha channel
1333 data to be cleared. For example:
1334 \snippet doc/src/snippets/image/image.cpp 2
1335 Now, alpha and alphacopy are visually different.
1336
1337 Setting a null mask resets the mask.
1338
1339 The effect of this function is undefined when the pixmap is being
1340 painted on.
1341
1342 \sa mask(), {QPixmap#Pixmap Transformations}{Pixmap
1343 Transformations}, QBitmap
1344*/
1345void QX11PixmapData::setMask(const QBitmap &newmask)
1346{
1347 if (newmask.isNull()) { // clear mask
1348#ifndef QT_NO_XRENDER
1349 if (picture && d == 32) {
1350 QX11PixmapData newData(pixelType());
1351 newData.resize(w, h);
1352 newData.fill(Qt::black);
1353 XRenderComposite(X11->display, PictOpOver,
1354 picture, 0, newData.picture,
1355 0, 0, 0, 0, 0, 0, w, h);
1356 release();
1357 *this = newData;
1358 // the new QX11PixmapData object isn't referenced yet, so
1359 // ref it
1360 ref.ref();
1361
1362 // the below is to make sure the QX11PixmapData destructor
1363 // doesn't delete our newly created render picture
1364 newData.hd = 0;
1365 newData.x11_mask = 0;
1366 newData.picture = 0;
1367 newData.mask_picture = 0;
1368 newData.hd2 = 0;
1369 } else
1370#endif
1371 if (x11_mask) {
1372#ifndef QT_NO_XRENDER
1373 if (picture) {
1374 XRenderPictureAttributes attrs;
1375 attrs.alpha_map = 0;
1376 XRenderChangePicture(X11->display, picture, CPAlphaMap,
1377 &attrs);
1378 }
1379 if (mask_picture)
1380 XRenderFreePicture(X11->display, mask_picture);
1381 mask_picture = 0;
1382#endif
1383 XFreePixmap(X11->display, x11_mask);
1384 x11_mask = 0;
1385 }
1386 return;
1387 }
1388
1389#ifndef QT_NO_XRENDER
1390 if (picture && d == 32) {
1391 XRenderComposite(X11->display, PictOpSrc,
1392 picture, newmask.x11PictureHandle(),
1393 picture, 0, 0, 0, 0, 0, 0, w, h);
1394 } else
1395#endif
1396 if (depth() == 1) {
1397 XGCValues vals;
1398 vals.function = GXand;
1399 GC gc = XCreateGC(X11->display, hd, GCFunction, &vals);
1400 XCopyArea(X11->display, newmask.handle(), hd, gc, 0, 0,
1401 width(), height(), 0, 0);
1402 XFreeGC(X11->display, gc);
1403 } else {
1404 // ##### should or the masks together
1405 if (x11_mask) {
1406 XFreePixmap(X11->display, x11_mask);
1407#ifndef QT_NO_XRENDER
1408 if (mask_picture)
1409 XRenderFreePicture(X11->display, mask_picture);
1410#endif
1411 }
1412 x11_mask = QX11PixmapData::bitmap_to_mask(newmask, xinfo.screen());
1413#ifndef QT_NO_XRENDER
1414 if (picture) {
1415 mask_picture = XRenderCreatePicture(X11->display, x11_mask,
1416 XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
1417 XRenderPictureAttributes attrs;
1418 attrs.alpha_map = mask_picture;
1419 XRenderChangePicture(X11->display, picture, CPAlphaMap, &attrs);
1420 }
1421#endif
1422 }
1423}
1424
1425int QX11PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
1426{
1427 switch (metric) {
1428 case QPaintDevice::PdmWidth:
1429 return w;
1430 case QPaintDevice::PdmHeight:
1431 return h;
1432 case QPaintDevice::PdmNumColors:
1433 return 1 << d;
1434 case QPaintDevice::PdmDepth:
1435 return d;
1436 case QPaintDevice::PdmWidthMM: {
1437 const int screen = xinfo.screen();
1438 const int mm = DisplayWidthMM(X11->display, screen) * w
1439 / DisplayWidth(X11->display, screen);
1440 return mm;
1441 }
1442 case QPaintDevice::PdmHeightMM: {
1443 const int screen = xinfo.screen();
1444 const int mm = (DisplayHeightMM(X11->display, screen) * h)
1445 / DisplayHeight(X11->display, screen);
1446 return mm;
1447 }
1448 case QPaintDevice::PdmDpiX:
1449 case QPaintDevice::PdmPhysicalDpiX:
1450 return QX11Info::appDpiX(xinfo.screen());
1451 case QPaintDevice::PdmDpiY:
1452 case QPaintDevice::PdmPhysicalDpiY:
1453 return QX11Info::appDpiY(xinfo.screen());
1454 default:
1455 qWarning("QX11PixmapData::metric(): Invalid metric");
1456 return 0;
1457 }
1458}
1459
1460struct QXImageWrapper
1461{
1462 XImage *xi;
1463};
1464
1465bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const
1466{
1467 XImage *xi = xiWrapper.xi;
1468
1469 // ARGB32_Premultiplied
1470 if (picture && depth() == 32)
1471 return true;
1472
1473 Visual *visual = (Visual *)xinfo.visual();
1474
1475 // RGB32
1476 if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000
1477 && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
1478 return true;
1479
1480 // RGB16
1481 if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800
1482 && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
1483 return true;
1484
1485 return false;
1486}
1487
1488QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const
1489{
1490 XImage *xi = xiWrapper.xi;
1491
1492 QImage::Format format = QImage::Format_ARGB32_Premultiplied;
1493 if (depth() == 24)
1494 format = QImage::Format_RGB32;
1495 else if (depth() == 16)
1496 format = QImage::Format_RGB16;
1497
1498 QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format);
1499 // take ownership
1500 image.data_ptr()->own_data = true;
1501 xi->data = 0;
1502
1503 // we may have to swap the byte order
1504 if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
1505 || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
1506 {
1507 for (int i=0; i < image.height(); i++) {
1508 if (depth() == 16) {
1509 ushort *p = (ushort*)image.scanLine(i);
1510 ushort *end = p + image.width();
1511 while (p < end) {
1512 *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
1513 p++;
1514 }
1515 } else {
1516 uint *p = (uint*)image.scanLine(i);
1517 uint *end = p + image.width();
1518 while (p < end) {
1519 *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
1520 | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
1521 p++;
1522 }
1523 }
1524 }
1525 }
1526
1527 // fix-up alpha channel
1528 if (format == QImage::Format_RGB32) {
1529 QRgb *p = (QRgb *)image.bits();
1530 for (int y = 0; y < xi->height; ++y) {
1531 for (int x = 0; x < xi->width; ++x)
1532 p[x] |= 0xff000000;
1533 p += xi->bytes_per_line / 4;
1534 }
1535 }
1536
1537 XDestroyImage(xi);
1538 return image;
1539}
1540
1541QImage QX11PixmapData::toImage(const QRect &rect) const
1542{
1543 QXImageWrapper xiWrapper;
1544 xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(),
1545 AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap);
1546
1547 Q_CHECK_PTR(xiWrapper.xi);
1548 if (!xiWrapper.xi)
1549 return QImage();
1550
1551 if (!x11_mask && canTakeQImageFromXImage(xiWrapper))
1552 return takeQImageFromXImage(xiWrapper);
1553
1554 QImage image = toImage(xiWrapper, rect);
1555 qSafeXDestroyImage(xiWrapper.xi);
1556 return image;
1557}
1558
1559/*!
1560 Converts the pixmap to a QImage. Returns a null image if the
1561 conversion fails.
1562
1563 If the pixmap has 1-bit depth, the returned image will also be 1
1564 bit deep. If the pixmap has 2- to 8-bit depth, the returned image
1565 has 8-bit depth. If the pixmap has greater than 8-bit depth, the
1566 returned image has 32-bit depth.
1567
1568 Note that for the moment, alpha masks on monochrome images are
1569 ignored.
1570
1571 \sa fromImage(), {QImage#Image Formats}{Image Formats}
1572*/
1573
1574QImage QX11PixmapData::toImage() const
1575{
1576 return toImage(QRect(0, 0, w, h));
1577}
1578
1579QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const
1580{
1581 XImage *xi = xiWrapper.xi;
1582
1583 int d = depth();
1584 Visual *visual = (Visual *)xinfo.visual();
1585 bool trucol = (visual->c_class >= TrueColor) && d > 1;
1586
1587 QImage::Format format = QImage::Format_Mono;
1588 if (d > 1 && d <= 8) {
1589 d = 8;
1590 format = QImage::Format_Indexed8;
1591 }
1592 // we could run into the situation where d == 8 AND trucol is true, which can
1593 // cause problems when converting to and from images. in this case, always treat
1594 // the depth as 32...
1595 if (d > 8 || trucol) {
1596 d = 32;
1597 format = QImage::Format_RGB32;
1598 }
1599
1600 if (d == 1 && xi->bitmap_bit_order == LSBFirst)
1601 format = QImage::Format_MonoLSB;
1602 if (x11_mask && format == QImage::Format_RGB32)
1603 format = QImage::Format_ARGB32;
1604
1605 QImage image(xi->width, xi->height, format);
1606 if (image.isNull()) // could not create image
1607 return image;
1608
1609 QImage alpha;
1610 if (x11_mask) {
1611 if (rect.contains(QRect(0, 0, w, h)))
1612 alpha = mask().toImage();
1613 else
1614 alpha = mask().toImage().copy(rect);
1615 }
1616 bool ale = alpha.format() == QImage::Format_MonoLSB;
1617
1618 if (trucol) { // truecolor
1619 const uint red_mask = (uint)visual->red_mask;
1620 const uint green_mask = (uint)visual->green_mask;
1621 const uint blue_mask = (uint)visual->blue_mask;
1622 const int red_shift = highest_bit(red_mask) - 7;
1623 const int green_shift = highest_bit(green_mask) - 7;
1624 const int blue_shift = highest_bit(blue_mask) - 7;
1625
1626 const uint red_bits = n_bits(red_mask);
1627 const uint green_bits = n_bits(green_mask);
1628 const uint blue_bits = n_bits(blue_mask);
1629
1630 static uint red_table_bits = 0;
1631 static uint green_table_bits = 0;
1632 static uint blue_table_bits = 0;
1633
1634 if (red_bits < 8 && red_table_bits != red_bits) {
1635 build_scale_table(&red_scale_table, red_bits);
1636 red_table_bits = red_bits;
1637 }
1638 if (blue_bits < 8 && blue_table_bits != blue_bits) {
1639 build_scale_table(&blue_scale_table, blue_bits);
1640 blue_table_bits = blue_bits;
1641 }
1642 if (green_bits < 8 && green_table_bits != green_bits) {
1643 build_scale_table(&green_scale_table, green_bits);
1644 green_table_bits = green_bits;
1645 }
1646
1647 int r, g, b;
1648
1649 QRgb *dst;
1650 uchar *src;
1651 uint pixel;
1652 int bppc = xi->bits_per_pixel;
1653
1654 if (bppc > 8 && xi->byte_order == LSBFirst)
1655 bppc++;
1656
1657 for (int y = 0; y < xi->height; ++y) {
1658 uchar* asrc = x11_mask ? alpha.scanLine(y) : 0;
1659 dst = (QRgb *)image.scanLine(y);
1660 src = (uchar *)xi->data + xi->bytes_per_line*y;
1661 for (int x = 0; x < xi->width; x++) {
1662 switch (bppc) {
1663 case 8:
1664 pixel = *src++;
1665 break;
1666 case 16: // 16 bit MSB
1667 pixel = src[1] | (uint)src[0] << 8;
1668 src += 2;
1669 break;
1670 case 17: // 16 bit LSB
1671 pixel = src[0] | (uint)src[1] << 8;
1672 src += 2;
1673 break;
1674 case 24: // 24 bit MSB
1675 pixel = src[2] | (uint)src[1] << 8 | (uint)src[0] << 16;
1676 src += 3;
1677 break;
1678 case 25: // 24 bit LSB
1679 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16;
1680 src += 3;
1681 break;
1682 case 32: // 32 bit MSB
1683 pixel = src[3] | (uint)src[2] << 8 | (uint)src[1] << 16 | (uint)src[0] << 24;
1684 src += 4;
1685 break;
1686 case 33: // 32 bit LSB
1687 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24;
1688 src += 4;
1689 break;
1690 default: // should not really happen
1691 x = xi->width; // leave loop
1692 y = xi->height;
1693 pixel = 0; // eliminate compiler warning
1694 qWarning("QPixmap::convertToImage: Invalid depth %d", bppc);
1695 }
1696 if (red_shift > 0)
1697 r = (pixel & red_mask) >> red_shift;
1698 else
1699 r = (pixel & red_mask) << -red_shift;
1700 if (green_shift > 0)
1701 g = (pixel & green_mask) >> green_shift;
1702 else
1703 g = (pixel & green_mask) << -green_shift;
1704 if (blue_shift > 0)
1705 b = (pixel & blue_mask) >> blue_shift;
1706 else
1707 b = (pixel & blue_mask) << -blue_shift;
1708
1709 if (red_bits < 8)
1710 r = red_scale_table[r];
1711 if (green_bits < 8)
1712 g = green_scale_table[g];
1713 if (blue_bits < 8)
1714 b = blue_scale_table[b];
1715
1716 if (x11_mask) {
1717 if (ale) {
1718 *dst++ = (asrc[x >> 3] & (1 << (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
1719 } else {
1720 *dst++ = (asrc[x >> 3] & (0x80 >> (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
1721 }
1722 } else {
1723 *dst++ = qRgb(r, g, b);
1724 }
1725 }
1726 }
1727 } else if (xi->bits_per_pixel == d) { // compatible depth
1728 char *xidata = xi->data; // copy each scanline
1729 int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
1730 for (int y=0; y<xi->height; y++) {
1731 memcpy(image.scanLine(y), xidata, bpl);
1732 xidata += xi->bytes_per_line;
1733 }
1734 } else {
1735 /* Typically 2 or 4 bits display depth */
1736 qWarning("QPixmap::convertToImage: Display not supported (bpp=%d)",
1737 xi->bits_per_pixel);
1738 return QImage();
1739 }
1740
1741 if (d == 1) { // bitmap
1742 image.setColorCount(2);
1743 image.setColor(0, qRgb(255,255,255));
1744 image.setColor(1, qRgb(0,0,0));
1745 } else if (!trucol) { // pixmap with colormap
1746 register uchar *p;
1747 uchar *end;
1748 uchar use[256]; // pixel-in-use table
1749 uchar pix[256]; // pixel translation table
1750 int ncols, bpl;
1751 memset(use, 0, 256);
1752 memset(pix, 0, 256);
1753 bpl = image.bytesPerLine();
1754
1755 if (x11_mask) { // which pixels are used?
1756 for (int i = 0; i < xi->height; i++) {
1757 uchar* asrc = alpha.scanLine(i);
1758 p = image.scanLine(i);
1759 if (ale) {
1760 for (int x = 0; x < xi->width; x++) {
1761 if (asrc[x >> 3] & (1 << (x & 7)))
1762 use[*p] = 1;
1763 ++p;
1764 }
1765 } else {
1766 for (int x = 0; x < xi->width; x++) {
1767 if (asrc[x >> 3] & (0x80 >> (x & 7)))
1768 use[*p] = 1;
1769 ++p;
1770 }
1771 }
1772 }
1773 } else {
1774 for (int i = 0; i < xi->height; i++) {
1775 p = image.scanLine(i);
1776 end = p + bpl;
1777 while (p < end)
1778 use[*p++] = 1;
1779 }
1780 }
1781 ncols = 0;
1782 for (int i = 0; i < 256; i++) { // build translation table
1783 if (use[i])
1784 pix[i] = ncols++;
1785 }
1786 for (int i = 0; i < xi->height; i++) { // translate pixels
1787 p = image.scanLine(i);
1788 end = p + bpl;
1789 while (p < end) {
1790 *p = pix[*p];
1791 p++;
1792 }
1793 }
1794 if (x11_mask) {
1795 int trans;
1796 if (ncols < 256) {
1797 trans = ncols++;
1798 image.setColorCount(ncols); // create color table
1799 image.setColor(trans, 0x00000000);
1800 } else {
1801 image.setColorCount(ncols); // create color table
1802 // oh dear... no spare "transparent" pixel.
1803 // use first pixel in image (as good as any).
1804 trans = image.scanLine(0)[0];
1805 }
1806 for (int i = 0; i < xi->height; i++) {
1807 uchar* asrc = alpha.scanLine(i);
1808 p = image.scanLine(i);
1809 if (ale) {
1810 for (int x = 0; x < xi->width; x++) {
1811 if (!(asrc[x >> 3] & (1 << (x & 7))))
1812 *p = trans;
1813 ++p;
1814 }
1815 } else {
1816 for (int x = 0; x < xi->width; x++) {
1817 if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
1818 *p = trans;
1819 ++p;
1820 }
1821 }
1822 }
1823 } else {
1824 image.setColorCount(ncols); // create color table
1825 }
1826 QVector<QColor> colors = QColormap::instance(xinfo.screen()).colormap();
1827 int j = 0;
1828 for (int i=0; i<colors.size(); i++) { // translate pixels
1829 if (use[i])
1830 image.setColor(j++, 0xff000000 | colors.at(i).rgb());
1831 }
1832 }
1833
1834 return image;
1835}
1836
1837/*!
1838 Returns a copy of the pixmap that is transformed using the given
1839 transformation \a matrix and transformation \a mode. The original
1840 pixmap is not changed.
1841
1842 The transformation \a matrix is internally adjusted to compensate
1843 for unwanted translation; i.e. the pixmap produced is the smallest
1844 pixmap that contains all the transformed points of the original
1845 pixmap. Use the trueMatrix() function to retrieve the actual
1846 matrix used for transforming the pixmap.
1847
1848 This function is slow because it involves transformation to a
1849 QImage, non-trivial computations and a transformation back to a
1850 QPixmap.
1851
1852 \sa trueMatrix(), {QPixmap#Pixmap Transformations}{Pixmap
1853 Transformations}
1854*/
1855QPixmap QX11PixmapData::transformed(const QTransform &transform,
1856 Qt::TransformationMode mode ) const
1857{
1858 if (mode == Qt::SmoothTransformation || transform.type() >= QTransform::TxProject) {
1859 QImage image = toImage();
1860 return QPixmap::fromImage(image.transformed(transform, mode));
1861 }
1862
1863 uint w = 0;
1864 uint h = 0; // size of target pixmap
1865 uint ws, hs; // size of source pixmap
1866 uchar *dptr; // data in target pixmap
1867 uint dbpl, dbytes; // bytes per line/bytes total
1868 uchar *sptr; // data in original pixmap
1869 int sbpl; // bytes per line in original
1870 int bpp; // bits per pixel
1871 bool depth1 = depth() == 1;
1872 Display *dpy = X11->display;
1873
1874 ws = width();
1875 hs = height();
1876
1877 QTransform mat(transform.m11(), transform.m12(), transform.m13(),
1878 transform.m21(), transform.m22(), transform.m23(),
1879 0., 0., 1);
1880 bool complex_xform = false;
1881 qreal scaledWidth;
1882 qreal scaledHeight;
1883
1884 if (mat.type() <= QTransform::TxScale) {
1885 scaledHeight = qAbs(mat.m22()) * hs + 0.9999;
1886 scaledWidth = qAbs(mat.m11()) * ws + 0.9999;
1887 h = qAbs(int(scaledHeight));
1888 w = qAbs(int(scaledWidth));
1889 } else { // rotation or shearing
1890 QPolygonF a(QRectF(0, 0, ws, hs));
1891 a = mat.map(a);
1892 QRect r = a.boundingRect().toAlignedRect();
1893 w = r.width();
1894 h = r.height();
1895 scaledWidth = w;
1896 scaledHeight = h;
1897 complex_xform = true;
1898 }
1899 mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix
1900
1901 bool invertible;
1902 mat = mat.inverted(&invertible); // invert matrix
1903
1904 if (h == 0 || w == 0 || !invertible
1905 || qAbs(scaledWidth) >= 32768 || qAbs(scaledHeight) >= 32768 )
1906 // error, return null pixmap
1907 return QPixmap();
1908
1909#if defined(QT_MITSHM)
1910 static bool try_once = true;
1911 if (try_once) {
1912 try_once = false;
1913 if (!xshminit)
1914 qt_create_mitshm_buffer(this, 800, 600);
1915 }
1916
1917 bool use_mitshm = xshmimg && !depth1 &&
1918 xshmimg->width >= w && xshmimg->height >= h;
1919#endif
1920 XImage *xi = XGetImage(X11->display, handle(), 0, 0, ws, hs, AllPlanes,
1921 depth1 ? XYPixmap : ZPixmap);
1922
1923 if (!xi)
1924 return QPixmap();
1925
1926 sbpl = xi->bytes_per_line;
1927 sptr = (uchar *)xi->data;
1928 bpp = xi->bits_per_pixel;
1929
1930 if (depth1)
1931 dbpl = (w+7)/8;
1932 else
1933 dbpl = ((w*bpp+31)/32)*4;
1934 dbytes = dbpl*h;
1935
1936#if defined(QT_MITSHM)
1937 if (use_mitshm) {
1938 dptr = (uchar *)xshmimg->data;
1939 uchar fillbyte = bpp == 8 ? white.pixel() : 0xff;
1940 for (int y=0; y<h; y++)
1941 memset(dptr + y*xshmimg->bytes_per_line, fillbyte, dbpl);
1942 } else {
1943#endif
1944 dptr = (uchar *)malloc(dbytes); // create buffer for bits
1945 Q_CHECK_PTR(dptr);
1946 if (depth1) // fill with zeros
1947 memset(dptr, 0, dbytes);
1948 else if (bpp == 8) // fill with background color
1949 memset(dptr, WhitePixel(X11->display, xinfo.screen()), dbytes);
1950 else
1951 memset(dptr, 0, dbytes);
1952#if defined(QT_MITSHM)
1953 }
1954#endif
1955
1956 // #define QT_DEBUG_XIMAGE
1957#if defined(QT_DEBUG_XIMAGE)
1958 qDebug("----IMAGE--INFO--------------");
1959 qDebug("width............. %d", xi->width);
1960 qDebug("height............ %d", xi->height);
1961 qDebug("xoffset........... %d", xi->xoffset);
1962 qDebug("format............ %d", xi->format);
1963 qDebug("byte order........ %d", xi->byte_order);
1964 qDebug("bitmap unit....... %d", xi->bitmap_unit);
1965 qDebug("bitmap bit order.. %d", xi->bitmap_bit_order);
1966 qDebug("depth............. %d", xi->depth);
1967 qDebug("bytes per line.... %d", xi->bytes_per_line);
1968 qDebug("bits per pixel.... %d", xi->bits_per_pixel);
1969#endif
1970
1971 int type;
1972 if (xi->bitmap_bit_order == MSBFirst)
1973 type = QT_XFORM_TYPE_MSBFIRST;
1974 else
1975 type = QT_XFORM_TYPE_LSBFIRST;
1976 int xbpl, p_inc;
1977 if (depth1) {
1978 xbpl = (w+7)/8;
1979 p_inc = dbpl - xbpl;
1980 } else {
1981 xbpl = (w*bpp)/8;
1982 p_inc = dbpl - xbpl;
1983#if defined(QT_MITSHM)
1984 if (use_mitshm)
1985 p_inc = xshmimg->bytes_per_line - xbpl;
1986#endif
1987 }
1988
1989 if (!qt_xForm_helper(mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs)){
1990 qWarning("QPixmap::transform: display not supported (bpp=%d)",bpp);
1991 QPixmap pm;
1992 return pm;
1993 }
1994
1995 qSafeXDestroyImage(xi);
1996
1997 if (depth1) { // mono bitmap
1998 QBitmap bm = QBitmap::fromData(QSize(w, h), dptr,
1999 BitmapBitOrder(X11->display) == MSBFirst
2000 ? QImage::Format_Mono
2001 : QImage::Format_MonoLSB);
2002 free(dptr);
2003 return bm;
2004 } else { // color pixmap
2005 QX11PixmapData *x11Data = new QX11PixmapData(QPixmapData::PixmapType);
2006 QPixmap pm(x11Data);
2007 x11Data->flags &= ~QX11PixmapData::Uninitialized;
2008 x11Data->xinfo = xinfo;
2009 x11Data->d = d;
2010 x11Data->w = w;
2011 x11Data->h = h;
2012 x11Data->is_null = (w <= 0 || h <= 0);
2013 x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display,
2014 RootWindow(X11->display, xinfo.screen()),
2015 w, h, d);
2016 x11Data->setSerialNumber(++qt_pixmap_serial);
2017
2018#ifndef QT_NO_XRENDER
2019 if (X11->use_xrender) {
2020 XRenderPictFormat *format = x11Data->d == 32
2021 ? XRenderFindStandardFormat(X11->display, PictStandardARGB32)
2022 : XRenderFindVisualFormat(X11->display, (Visual *) x11Data->xinfo.visual());
2023 x11Data->picture = XRenderCreatePicture(X11->display, x11Data->hd, format, 0, 0);
2024 }
2025#endif // QT_NO_XRENDER
2026
2027 GC gc = XCreateGC(X11->display, x11Data->hd, 0, 0);
2028#if defined(QT_MITSHM)
2029 if (use_mitshm) {
2030 XCopyArea(dpy, xshmpm, x11Data->hd, gc, 0, 0, w, h, 0, 0);
2031 } else
2032#endif
2033 {
2034 xi = XCreateImage(dpy, (Visual*)x11Data->xinfo.visual(),
2035 x11Data->d,
2036 ZPixmap, 0, (char *)dptr, w, h, 32, 0);
2037 XPutImage(dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h);
2038 qSafeXDestroyImage(xi);
2039 }
2040 XFreeGC(X11->display, gc);
2041
2042 if (x11_mask) { // xform mask, too
2043 pm.setMask(mask_to_bitmap(xinfo.screen()).transformed(transform));
2044 } else if (d != 32 && complex_xform) { // need a mask!
2045 QBitmap mask(ws, hs);
2046 mask.fill(Qt::color1);
2047 pm.setMask(mask.transformed(transform));
2048 }
2049 return pm;
2050 }
2051}
2052
2053int QPixmap::x11SetDefaultScreen(int screen)
2054{
2055 int old = defaultScreen;
2056 defaultScreen = screen;
2057 return old;
2058}
2059
2060void QPixmap::x11SetScreen(int screen)
2061{
2062 if (paintingActive()) {
2063 qWarning("QPixmap::x11SetScreen(): Cannot change screens during painting");
2064 return;
2065 }
2066
2067 if (isNull())
2068 return;
2069
2070 if (data->classId() != QPixmapData::X11Class)
2071 return;
2072
2073 if (screen < 0)
2074 screen = QX11Info::appScreen();
2075
2076 QX11PixmapData *x11Data = static_cast<QX11PixmapData*>(data.data());
2077 if (screen == x11Data->xinfo.screen())
2078 return; // nothing to do
2079
2080 if (isNull()) {
2081 QX11InfoData* xd = x11Data->xinfo.getX11Data(true);
2082 xd->screen = screen;
2083 xd->depth = QX11Info::appDepth(screen);
2084 xd->cells = QX11Info::appCells(screen);
2085 xd->colormap = QX11Info::appColormap(screen);
2086 xd->defaultColormap = QX11Info::appDefaultColormap(screen);
2087 xd->visual = (Visual *)QX11Info::appVisual(screen);
2088 xd->defaultVisual = QX11Info::appDefaultVisual(screen);
2089 x11Data->xinfo.setX11Data(xd);
2090 return;
2091 }
2092#if 0
2093 qDebug("QPixmap::x11SetScreen for %p from %d to %d. Size is %d/%d", x11Data, x11Data->xinfo.screen(), screen, width(), height());
2094#endif
2095
2096 x11SetDefaultScreen(screen);
2097 *this = qt_toX11Pixmap(toImage());
2098}
2099
2100QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
2101{
2102 if (w == 0 || h == 0)
2103 return QPixmap();
2104
2105 Display *dpy = X11->display;
2106 XWindowAttributes window_attr;
2107 if (!XGetWindowAttributes(dpy, window, &window_attr))
2108 return QPixmap();
2109
2110 if (w < 0)
2111 w = window_attr.width - x;
2112 if (h < 0)
2113 h = window_attr.height - y;
2114
2115 // determine the screen
2116 int scr;
2117 for (scr = 0; scr < ScreenCount(dpy); ++scr) {
2118 if (window_attr.root == RootWindow(dpy, scr)) // found it
2119 break;
2120 }
2121 if (scr >= ScreenCount(dpy)) // sanity check
2122 return QPixmap();
2123
2124
2125 // get the depth of the root window
2126 XWindowAttributes root_attr;
2127 if (!XGetWindowAttributes(dpy, window_attr.root, &root_attr))
2128 return QPixmap();
2129
2130 if (window_attr.depth == root_attr.depth) {
2131 // if the depth of the specified window and the root window are the
2132 // same, grab pixels from the root window (so that we get the any
2133 // overlapping windows and window manager frames)
2134
2135 // map x and y to the root window
2136 WId unused;
2137 if (!XTranslateCoordinates(dpy, window, window_attr.root, x, y,
2138 &x, &y, &unused))
2139 return QPixmap();
2140
2141 window = window_attr.root;
2142 window_attr = root_attr;
2143 }
2144
2145 QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
2146
2147 void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a);
2148 qt_x11_getX11InfoForWindow(&data->xinfo,window_attr);
2149
2150 data->resize(w, h);
2151
2152 QPixmap pm(data);
2153
2154 data->flags &= ~QX11PixmapData::Uninitialized;
2155 pm.x11SetScreen(scr);
2156
2157 GC gc = XCreateGC(dpy, pm.handle(), 0, 0);
2158 XSetSubwindowMode(dpy, gc, IncludeInferiors);
2159 XCopyArea(dpy, window, pm.handle(), gc, x, y, w, h, 0, 0);
2160 XFreeGC(dpy, gc);
2161
2162 return pm;
2163}
2164
2165bool QX11PixmapData::hasAlphaChannel() const
2166{
2167 return d == 32;
2168}
2169
2170const QX11Info &QPixmap::x11Info() const
2171{
2172 if (data && data->classId() == QPixmapData::X11Class)
2173 return static_cast<QX11PixmapData*>(data.data())->xinfo;
2174 else {
2175 static QX11Info nullX11Info;
2176 return nullX11Info;
2177 }
2178}
2179
2180#if !defined(QT_NO_XRENDER)
2181static XRenderPictFormat *qt_renderformat_for_depth(const QX11Info &xinfo, int depth)
2182{
2183 if (depth == 1)
2184 return XRenderFindStandardFormat(X11->display, PictStandardA1);
2185 else if (depth == 32)
2186 return XRenderFindStandardFormat(X11->display, PictStandardARGB32);
2187 else
2188 return XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
2189}
2190#endif
2191
2192QPaintEngine* QX11PixmapData::paintEngine() const
2193{
2194 QX11PixmapData *that = const_cast<QX11PixmapData*>(this);
2195
2196 if ((flags & Readonly) && share_mode == QPixmap::ImplicitlyShared) {
2197 // if someone wants to draw onto us, copy the shared contents
2198 // and turn it into a fully fledged QPixmap
2199 ::Pixmap hd_copy = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
2200 w, h, d);
2201#if !defined(QT_NO_XRENDER)
2202 XRenderPictFormat *format = qt_renderformat_for_depth(xinfo, d);
2203 ::Picture picture_copy = XRenderCreatePicture(X11->display, hd_copy, format, 0, 0);
2204
2205 if (picture && d == 32) {
2206 XRenderComposite(X11->display, PictOpSrc, picture, 0, picture_copy,
2207 0, 0, 0, 0, 0, 0, w, h);
2208 XRenderFreePicture(X11->display, picture);
2209 that->picture = picture_copy;
2210 } else
2211#endif
2212 {
2213 GC gc = XCreateGC(X11->display, hd_copy, 0, 0);
2214 XCopyArea(X11->display, hd, hd_copy, gc, 0, 0, w, h, 0, 0);
2215 XFreeGC(X11->display, gc);
2216 }
2217 that->hd = hd_copy;
2218 that->flags &= ~QX11PixmapData::Readonly;
2219 }
2220
2221 if (!that->pengine)
2222 that->pengine = new QX11PaintEngine;
2223 return that->pengine;
2224}
2225
2226Qt::HANDLE QPixmap::x11PictureHandle() const
2227{
2228#ifndef QT_NO_XRENDER
2229 if (data && data->classId() == QPixmapData::X11Class)
2230 return static_cast<const QX11PixmapData*>(data.data())->picture;
2231 else
2232 return 0;
2233#else
2234 return 0;
2235#endif // QT_NO_XRENDER
2236}
2237
2238Qt::HANDLE QX11PixmapData::x11ConvertToDefaultDepth()
2239{
2240#ifndef QT_NO_XRENDER
2241 if (d == QX11Info::appDepth() || !X11->use_xrender)
2242 return hd;
2243 if (!hd2) {
2244 hd2 = XCreatePixmap(xinfo.display(), hd, w, h, QX11Info::appDepth());
2245 XRenderPictFormat *format = XRenderFindVisualFormat(xinfo.display(),
2246 (Visual*) xinfo.visual());
2247 Picture pic = XRenderCreatePicture(xinfo.display(), hd2, format, 0, 0);
2248 XRenderComposite(xinfo.display(), PictOpSrc, picture,
2249 XNone, pic, 0, 0, 0, 0, 0, 0, w, h);
2250 XRenderFreePicture(xinfo.display(), pic);
2251 }
2252 return hd2;
2253#else
2254 return hd;
2255#endif
2256}
2257
2258void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect)
2259{
2260 if (data->pixelType() == BitmapType) {
2261 fromImage(data->toImage().copy(rect), Qt::AutoColor);
2262 return;
2263 }
2264
2265 const QX11PixmapData *x11Data = static_cast<const QX11PixmapData*>(data);
2266
2267 setSerialNumber(++qt_pixmap_serial);
2268
2269 flags &= ~Uninitialized;
2270 xinfo = x11Data->xinfo;
2271 d = x11Data->d;
2272 w = rect.width();
2273 h = rect.height();
2274 is_null = (w <= 0 || h <= 0);
2275 hd = (Qt::HANDLE)XCreatePixmap(X11->display,
2276 RootWindow(X11->display, x11Data->xinfo.screen()),
2277 w, h, d);
2278#ifndef QT_NO_XRENDER
2279 if (X11->use_xrender) {
2280 XRenderPictFormat *format = d == 32
2281 ? XRenderFindStandardFormat(X11->display, PictStandardARGB32)
2282 : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
2283 picture = XRenderCreatePicture(X11->display, hd, format, 0, 0);
2284 }
2285#endif // QT_NO_XRENDER
2286 if (x11Data->x11_mask) {
2287 x11_mask = XCreatePixmap(X11->display, hd, w, h, 1);
2288#ifndef QT_NO_XRENDER
2289 if (X11->use_xrender) {
2290 mask_picture = XRenderCreatePicture(X11->display, x11_mask,
2291 XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
2292 XRenderPictureAttributes attrs;
2293 attrs.alpha_map = x11Data->mask_picture;
2294 XRenderChangePicture(X11->display, x11Data->picture, CPAlphaMap, &attrs);
2295 }
2296#endif
2297 }
2298
2299#if !defined(QT_NO_XRENDER)
2300 if (x11Data->picture && x11Data->d == 32) {
2301 XRenderComposite(X11->display, PictOpSrc,
2302 x11Data->picture, 0, picture,
2303 rect.x(), rect.y(), 0, 0, 0, 0, w, h);
2304 } else
2305#endif
2306 {
2307 GC gc = XCreateGC(X11->display, hd, 0, 0);
2308 XCopyArea(X11->display, x11Data->hd, hd, gc,
2309 rect.x(), rect.y(), w, h, 0, 0);
2310 if (x11Data->x11_mask) {
2311 GC monogc = XCreateGC(X11->display, x11_mask, 0, 0);
2312 XCopyArea(X11->display, x11Data->x11_mask, x11_mask, monogc,
2313 rect.x(), rect.y(), w, h, 0, 0);
2314 XFreeGC(X11->display, monogc);
2315 }
2316 XFreeGC(X11->display, gc);
2317 }
2318}
2319
2320bool QX11PixmapData::scroll(int dx, int dy, const QRect &rect)
2321{
2322 GC gc = XCreateGC(X11->display, hd, 0, 0);
2323 XCopyArea(X11->display, hd, hd, gc,
2324 rect.left(), rect.top(), rect.width(), rect.height(),
2325 rect.left() + dx, rect.top() + dy);
2326 XFreeGC(X11->display, gc);
2327 return true;
2328}
2329
2330#if !defined(QT_NO_XRENDER)
2331void QX11PixmapData::convertToARGB32(bool preserveContents)
2332{
2333 if (!X11->use_xrender)
2334 return;
2335
2336 // Q_ASSERT(count == 1);
2337 if ((flags & Readonly) && share_mode == QPixmap::ExplicitlyShared)
2338 return;
2339
2340 Pixmap pm = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
2341 w, h, 32);
2342 Picture p = XRenderCreatePicture(X11->display, pm,
2343 XRenderFindStandardFormat(X11->display, PictStandardARGB32), 0, 0);
2344 if (picture) {
2345 if (preserveContents)
2346 XRenderComposite(X11->display, PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h);
2347 if (!(flags & Readonly))
2348 XRenderFreePicture(X11->display, picture);
2349 }
2350 if (hd && !(flags & Readonly))
2351 XFreePixmap(X11->display, hd);
2352 if (x11_mask) {
2353 XFreePixmap(X11->display, x11_mask);
2354 if (mask_picture)
2355 XRenderFreePicture(X11->display, mask_picture);
2356 x11_mask = 0;
2357 mask_picture = 0;
2358 }
2359 hd = pm;
2360 picture = p;
2361 d = 32;
2362}
2363#endif
2364
2365QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode)
2366{
2367 Window root;
2368 int x;
2369 int y;
2370 uint width;
2371 uint height;
2372 uint border_width;
2373 uint depth;
2374 XWindowAttributes win_attribs;
2375 int num_screens = ScreenCount(X11->display);
2376 int screen = 0;
2377
2378 XGetGeometry(X11->display, pixmap, &root, &x, &y, &width, &height, &border_width, &depth);
2379 XGetWindowAttributes(X11->display, root, &win_attribs);
2380
2381 for (; screen < num_screens; ++screen) {
2382 if (win_attribs.screen == ScreenOfDisplay(X11->display, screen))
2383 break;
2384 }
2385
2386 QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType);
2387 data->setSerialNumber(++qt_pixmap_serial);
2388 data->flags = QX11PixmapData::Readonly;
2389 data->share_mode = mode;
2390 data->w = width;
2391 data->h = height;
2392 data->is_null = (width <= 0 || height <= 0);
2393 data->d = depth;
2394 data->hd = pixmap;
2395
2396 if (defaultScreen >= 0 && defaultScreen != screen) {
2397 QX11InfoData* xd = data->xinfo.getX11Data(true);
2398 xd->screen = defaultScreen;
2399 xd->depth = QX11Info::appDepth(xd->screen);
2400 xd->cells = QX11Info::appCells(xd->screen);
2401 xd->colormap = QX11Info::appColormap(xd->screen);
2402 xd->defaultColormap = QX11Info::appDefaultColormap(xd->screen);
2403 xd->visual = (Visual *)QX11Info::appVisual(xd->screen);
2404 xd->defaultVisual = QX11Info::appDefaultVisual(xd->screen);
2405 data->xinfo.setX11Data(xd);
2406 }
2407
2408#ifndef QT_NO_XRENDER
2409 if (X11->use_xrender) {
2410 XRenderPictFormat *format = qt_renderformat_for_depth(data->xinfo, depth);
2411 data->picture = XRenderCreatePicture(X11->display, data->hd, format, 0, 0);
2412 }
2413#endif // QT_NO_XRENDER
2414
2415 return QPixmap(data);
2416}
2417
2418
2419QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.