1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
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 | |
79 | QT_BEGIN_NAMESPACE |
80 | |
81 | QPixmap 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 | |
93 | QPixmap 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 | |
107 | inline static void qSafeXDestroyImage(XImage *x) |
108 | { |
109 | if (x->data) { |
110 | free(x->data); |
111 | x->data = 0; |
112 | } |
113 | XDestroyImage(x); |
114 | } |
115 | |
116 | QBitmap 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 | |
129 | Qt::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 | |
152 | static bool xshminit = false; |
153 | static XShmSegmentInfo xshminfo; |
154 | static XImage *xshmimg = 0; |
155 | static Pixmap xshmpm = 0; |
156 | |
157 | static 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 | |
172 | static 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 | 0700); |
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 | |
238 | extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp |
239 | |
240 | // Returns position of highest bit set or -1 if none |
241 | static 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 |
251 | static 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' |
261 | static 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 | |
271 | static uint *red_scale_table = 0; |
272 | static uint *green_scale_table = 0; |
273 | static uint *blue_scale_table = 0; |
274 | |
275 | static 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 | */ |
286 | static 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 | |
307 | static int defaultScreen = -1; |
308 | |
309 | /***************************************************************************** |
310 | QPixmap member functions |
311 | *****************************************************************************/ |
312 | |
313 | QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0); |
314 | int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0; |
315 | |
316 | QX11PixmapData::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 | |
323 | QPixmapData *QX11PixmapData::createCompatiblePixmapData() const |
324 | { |
325 | return new QX11PixmapData(pixelType()); |
326 | } |
327 | |
328 | void QX11PixmapData::resize(int width, int height) |
329 | { |
330 | setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); |
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 | |
379 | struct 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 | |
410 | void QX11PixmapData::fromImage(const QImage &img, |
411 | Qt::ImageConversionFlags flags) |
412 | { |
413 | setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); |
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: |
901 | CYCLE( |
902 | if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
903 | for (int x=0; x<w; x++) { |
904 | *dst++ = qRed (*p); |
905 | *dst++ = qGreen(*p); |
906 | *dst++ = qBlue (*p++); |
907 | } |
908 | } else { |
909 | for (int x=0; x<w; x++) { |
910 | *dst++ = qBlue (*p); |
911 | *dst++ = qGreen(*p); |
912 | *dst++ = qRed (*p++); |
913 | } |
914 | } |
915 | ) |
916 | break; |
917 | case BPP24_MSB: // 24 bit MSB |
918 | CYCLE( |
919 | for (int x=0; x<w; x++) { |
920 | GET_PIXEL |
921 | *dst++ = pixel >> 16; |
922 | *dst++ = pixel >> 8; |
923 | *dst++ = pixel; |
924 | } |
925 | ) |
926 | break; |
927 | case BPP24_LSB: // 24 bit LSB |
928 | CYCLE( |
929 | for (int x=0; x<w; x++) { |
930 | GET_PIXEL |
931 | *dst++ = pixel; |
932 | *dst++ = pixel >> 8; |
933 | *dst++ = pixel >> 16; |
934 | } |
935 | ) |
936 | break; |
937 | case BPP32_8888: |
938 | CYCLE( |
939 | memcpy(dst, p, w * 4); |
940 | ) |
941 | break; |
942 | case BPP32_MSB: // 32 bit MSB |
943 | CYCLE( |
944 | for (int x=0; x<w; x++) { |
945 | GET_PIXEL |
946 | *dst++ = pixel >> 24; |
947 | *dst++ = pixel >> 16; |
948 | *dst++ = pixel >> 8; |
949 | *dst++ = pixel; |
950 | } |
951 | ) |
952 | break; |
953 | case BPP32_LSB: // 32 bit LSB |
954 | CYCLE( |
955 | for (int x=0; x<w; x++) { |
956 | GET_PIXEL |
957 | *dst++ = pixel; |
958 | *dst++ = pixel >> 8; |
959 | *dst++ = pixel >> 16; |
960 | *dst++ = pixel >> 24; |
961 | } |
962 | ) |
963 | break; |
964 | default: |
965 | qFatal("Logic error 2" ); |
966 | } |
967 | } |
968 | xi->data = (char *)newbits; |
969 | } |
970 | |
971 | if (d == 8 && !trucol) { // 8 bit pixmap |
972 | int pop[256]; // pixel popularity |
973 | |
974 | if (image.colorCount() == 0) |
975 | image.setColorCount(1); |
976 | |
977 | const QImage &cimage = image; |
978 | memset(pop, 0, sizeof(int)*256); // reset popularity array |
979 | for (int i = 0; i < h; i++) { // for each scanline... |
980 | const uchar* p = cimage.scanLine(i); |
981 | const uchar *end = p + w; |
982 | while (p < end) // compute popularity |
983 | pop[*p++]++; |
984 | } |
985 | |
986 | newbits = (uchar *)malloc(nbytes); // copy image into newbits |
987 | Q_CHECK_PTR(newbits); |
988 | if (!newbits) // no memory |
989 | return; |
990 | uchar* p = newbits; |
991 | memcpy(p, cimage.bits(), nbytes); // copy image data into newbits |
992 | |
993 | /* |
994 | * The code below picks the most important colors. It is based on the |
995 | * diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley. |
996 | */ |
997 | |
998 | struct PIX { // pixel sort element |
999 | uchar r,g,b,n; // color + pad |
1000 | int use; // popularity |
1001 | int index; // index in colormap |
1002 | int mindist; |
1003 | }; |
1004 | int ncols = 0; |
1005 | for (int i=0; i< cimage.colorCount(); i++) { // compute number of colors |
1006 | if (pop[i] > 0) |
1007 | ncols++; |
1008 | } |
1009 | for (int i = cimage.colorCount(); i < 256; i++) // ignore out-of-range pixels |
1010 | pop[i] = 0; |
1011 | |
1012 | // works since we make sure above to have at least |
1013 | // one color in the image |
1014 | if (ncols == 0) |
1015 | ncols = 1; |
1016 | |
1017 | PIX pixarr[256]; // pixel array |
1018 | PIX pixarr_sorted[256]; // pixel array (sorted) |
1019 | memset(pixarr, 0, ncols*sizeof(PIX)); |
1020 | PIX *px = &pixarr[0]; |
1021 | int maxpop = 0; |
1022 | int maxpix = 0; |
1023 | uint j = 0; |
1024 | QVector<QRgb> ctable = cimage.colorTable(); |
1025 | for (int i = 0; i < 256; i++) { // init pixel array |
1026 | if (pop[i] > 0) { |
1027 | px->r = qRed (ctable[i]); |
1028 | px->g = qGreen(ctable[i]); |
1029 | px->b = qBlue (ctable[i]); |
1030 | px->n = 0; |
1031 | px->use = pop[i]; |
1032 | if (pop[i] > maxpop) { // select most popular entry |
1033 | maxpop = pop[i]; |
1034 | maxpix = j; |
1035 | } |
1036 | px->index = i; |
1037 | px->mindist = 1000000; |
1038 | px++; |
1039 | j++; |
1040 | } |
1041 | } |
1042 | pixarr_sorted[0] = pixarr[maxpix]; |
1043 | pixarr[maxpix].use = 0; |
1044 | |
1045 | for (int i = 1; i < ncols; i++) { // sort pixels |
1046 | int minpix = -1, mindist = -1; |
1047 | px = &pixarr_sorted[i-1]; |
1048 | int r = px->r; |
1049 | int g = px->g; |
1050 | int b = px->b; |
1051 | int dist; |
1052 | if ((i & 1) || i<10) { // sort on max distance |
1053 | for (int j=0; j<ncols; j++) { |
1054 | px = &pixarr[j]; |
1055 | if (px->use) { |
1056 | dist = (px->r - r)*(px->r - r) + |
1057 | (px->g - g)*(px->g - g) + |
1058 | (px->b - b)*(px->b - b); |
1059 | if (px->mindist > dist) |
1060 | px->mindist = dist; |
1061 | if (px->mindist > mindist) { |
1062 | mindist = px->mindist; |
1063 | minpix = j; |
1064 | } |
1065 | } |
1066 | } |
1067 | } else { // sort on max popularity |
1068 | for (int j=0; j<ncols; j++) { |
1069 | px = &pixarr[j]; |
1070 | if (px->use) { |
1071 | dist = (px->r - r)*(px->r - r) + |
1072 | (px->g - g)*(px->g - g) + |
1073 | (px->b - b)*(px->b - b); |
1074 | if (px->mindist > dist) |
1075 | px->mindist = dist; |
1076 | if (px->use > mindist) { |
1077 | mindist = px->use; |
1078 | minpix = j; |
1079 | } |
1080 | } |
1081 | } |
1082 | } |
1083 | pixarr_sorted[i] = pixarr[minpix]; |
1084 | pixarr[minpix].use = 0; |
1085 | } |
1086 | |
1087 | QColormap cmap = QColormap::instance(xinfo.screen()); |
1088 | uint pix[256]; // pixel translation table |
1089 | px = &pixarr_sorted[0]; |
1090 | for (int i = 0; i < ncols; i++) { // allocate colors |
1091 | QColor c(px->r, px->g, px->b); |
1092 | pix[px->index] = cmap.pixel(c); |
1093 | px++; |
1094 | } |
1095 | |
1096 | p = newbits; |
1097 | for (int i = 0; i < nbytes; i++) { // translate pixels |
1098 | *p = pix[*p]; |
1099 | p++; |
1100 | } |
1101 | } |
1102 | |
1103 | if (!xi) { // X image not created |
1104 | xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0); |
1105 | if (xi->bits_per_pixel == 16) { // convert 8 bpp ==> 16 bpp |
1106 | ushort *p2; |
1107 | int p2inc = xi->bytes_per_line/sizeof(ushort); |
1108 | ushort *newerbits = (ushort *)malloc(xi->bytes_per_line * h); |
1109 | Q_CHECK_PTR(newerbits); |
1110 | if (!newerbits) // no memory |
1111 | return; |
1112 | uchar* p = newbits; |
1113 | for (int y = 0; y < h; y++) { // OOPS: Do right byte order!! |
1114 | p2 = newerbits + p2inc*y; |
1115 | for (int x = 0; x < w; x++) |
1116 | *p2++ = *p++; |
1117 | } |
1118 | free(newbits); |
1119 | newbits = (uchar *)newerbits; |
1120 | } else if (xi->bits_per_pixel != 8) { |
1121 | qWarning("QPixmap::fromImage: Display not supported " |
1122 | "(bpp=%d)" , xi->bits_per_pixel); |
1123 | } |
1124 | xi->data = (char *)newbits; |
1125 | } |
1126 | |
1127 | hd = (Qt::HANDLE)XCreatePixmap(X11->display, |
1128 | RootWindow(X11->display, xinfo.screen()), |
1129 | w, h, dd); |
1130 | |
1131 | GC gc = XCreateGC(dpy, hd, 0, 0); |
1132 | XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h); |
1133 | XFreeGC(dpy, gc); |
1134 | |
1135 | qSafeXDestroyImage(xi); |
1136 | d = dd; |
1137 | |
1138 | #ifndef QT_NO_XRENDER |
1139 | if (X11->use_xrender) { |
1140 | XRenderPictFormat *format = d == 1 |
1141 | ? XRenderFindStandardFormat(X11->display, PictStandardA1) |
1142 | : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual()); |
1143 | picture = XRenderCreatePicture(X11->display, hd, format, 0, 0); |
1144 | } |
1145 | #endif |
1146 | |
1147 | if (alphaCheck.hasAlpha()) { |
1148 | QBitmap m = QBitmap::fromImage(image.createAlphaMask(flags)); |
1149 | setMask(m); |
1150 | } |
1151 | } |
1152 | |
1153 | Qt::HANDLE QX11PixmapData::createBitmapFromImage(const QImage &image) |
1154 | { |
1155 | QImage img = image.convertToFormat(QImage::Format_MonoLSB); |
1156 | const QRgb c0 = QColor(Qt::black).rgb(); |
1157 | const QRgb c1 = QColor(Qt::white).rgb(); |
1158 | if (img.color(0) == c0 && img.color(1) == c1) { |
1159 | img.invertPixels(); |
1160 | img.setColor(0, c1); |
1161 | img.setColor(1, c0); |
1162 | } |
1163 | |
1164 | char *bits; |
1165 | uchar *tmp_bits; |
1166 | int w = img.width(); |
1167 | int h = img.height(); |
1168 | int bpl = (w + 7) / 8; |
1169 | int ibpl = img.bytesPerLine(); |
1170 | if (bpl != ibpl) { |
1171 | tmp_bits = new uchar[bpl*h]; |
1172 | bits = (char *)tmp_bits; |
1173 | uchar *p, *b; |
1174 | int y; |
1175 | b = tmp_bits; |
1176 | p = img.scanLine(0); |
1177 | for (y = 0; y < h; y++) { |
1178 | memcpy(b, p, bpl); |
1179 | b += bpl; |
1180 | p += ibpl; |
1181 | } |
1182 | } else { |
1183 | bits = (char *)img.bits(); |
1184 | tmp_bits = 0; |
1185 | } |
1186 | Qt::HANDLE hd = (Qt::HANDLE)XCreateBitmapFromData(X11->display, |
1187 | QX11Info::appRootWindow(), |
1188 | bits, w, h); |
1189 | if (tmp_bits) // Avoid purify complaint |
1190 | delete [] tmp_bits; |
1191 | return hd; |
1192 | } |
1193 | |
1194 | void QX11PixmapData::bitmapFromImage(const QImage &image) |
1195 | { |
1196 | w = image.width(); |
1197 | h = image.height(); |
1198 | d = 1; |
1199 | is_null = (w <= 0 || h <= 0); |
1200 | hd = createBitmapFromImage(image); |
1201 | #ifndef QT_NO_XRENDER |
1202 | if (X11->use_xrender) |
1203 | picture = XRenderCreatePicture(X11->display, hd, |
1204 | XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0); |
1205 | #endif // QT_NO_XRENDER |
1206 | } |
1207 | |
1208 | void QX11PixmapData::fill(const QColor &fillColor) |
1209 | { |
1210 | if (fillColor.alpha() != 255) { |
1211 | #ifndef QT_NO_XRENDER |
1212 | if (X11->use_xrender) { |
1213 | if (!picture || d != 32) |
1214 | convertToARGB32(/*preserveContents = */false); |
1215 | |
1216 | ::Picture src = X11->getSolidFill(xinfo.screen(), fillColor); |
1217 | XRenderComposite(X11->display, PictOpSrc, src, 0, picture, |
1218 | 0, 0, width(), height(), |
1219 | 0, 0, width(), height()); |
1220 | } else |
1221 | #endif |
1222 | { |
1223 | QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied); |
1224 | im.fill(PREMUL(fillColor.rgba())); |
1225 | release(); |
1226 | fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither); |
1227 | } |
1228 | return; |
1229 | } |
1230 | |
1231 | GC gc = XCreateGC(X11->display, hd, 0, 0); |
1232 | if (depth() == 1) { |
1233 | XSetForeground(X11->display, gc, qGray(fillColor.rgb()) > 127 ? 0 : 1); |
1234 | } else if (X11->use_xrender && d >= 24) { |
1235 | XSetForeground(X11->display, gc, fillColor.rgba()); |
1236 | } else { |
1237 | XSetForeground(X11->display, gc, |
1238 | QColormap::instance(xinfo.screen()).pixel(fillColor)); |
1239 | } |
1240 | XFillRectangle(X11->display, hd, gc, 0, 0, width(), height()); |
1241 | XFreeGC(X11->display, gc); |
1242 | } |
1243 | |
1244 | QX11PixmapData::~QX11PixmapData() |
1245 | { |
1246 | // Cleanup hooks have to be called before the handles are freed |
1247 | if (is_cached) { |
1248 | QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(this); |
1249 | is_cached = false; |
1250 | } |
1251 | |
1252 | release(); |
1253 | } |
1254 | |
1255 | void QX11PixmapData::release() |
1256 | { |
1257 | delete pengine; |
1258 | pengine = 0; |
1259 | |
1260 | if (!X11) { |
1261 | // At this point, the X server will already have freed our resources, |
1262 | // so there is nothing to do. |
1263 | return; |
1264 | } |
1265 | |
1266 | if (x11_mask) { |
1267 | #ifndef QT_NO_XRENDER |
1268 | if (mask_picture) |
1269 | XRenderFreePicture(X11->display, mask_picture); |
1270 | mask_picture = 0; |
1271 | #endif |
1272 | XFreePixmap(X11->display, x11_mask); |
1273 | x11_mask = 0; |
1274 | } |
1275 | |
1276 | if (hd) { |
1277 | #ifndef QT_NO_XRENDER |
1278 | if (picture) { |
1279 | XRenderFreePicture(X11->display, picture); |
1280 | picture = 0; |
1281 | } |
1282 | #endif // QT_NO_XRENDER |
1283 | |
1284 | if (hd2) { |
1285 | XFreePixmap(xinfo.display(), hd2); |
1286 | hd2 = 0; |
1287 | } |
1288 | if (!(flags & Readonly)) |
1289 | XFreePixmap(xinfo.display(), hd); |
1290 | hd = 0; |
1291 | } |
1292 | } |
1293 | |
1294 | QPixmap QX11PixmapData::alphaChannel() const |
1295 | { |
1296 | if (!hasAlphaChannel()) { |
1297 | QPixmap pm(w, h); |
1298 | pm.fill(Qt::white); |
1299 | return pm; |
1300 | } |
1301 | QImage im(toImage()); |
1302 | return QPixmap::fromImage(im.alphaChannel(), Qt::OrderedDither); |
1303 | } |
1304 | |
1305 | void QX11PixmapData::setAlphaChannel(const QPixmap &alpha) |
1306 | { |
1307 | QImage image(toImage()); |
1308 | image.setAlphaChannel(alpha.toImage()); |
1309 | release(); |
1310 | fromImage(image, Qt::OrderedDither | Qt::OrderedAlphaDither); |
1311 | } |
1312 | |
1313 | |
1314 | QBitmap QX11PixmapData::mask() const |
1315 | { |
1316 | QBitmap mask; |
1317 | #ifndef QT_NO_XRENDER |
1318 | if (picture && d == 32) { |
1319 | // #### slow - there must be a better way.. |
1320 | mask = QBitmap::fromImage(toImage().createAlphaMask()); |
1321 | } else |
1322 | #endif |
1323 | if (d == 1) { |
1324 | QX11PixmapData *that = const_cast<QX11PixmapData*>(this); |
1325 | mask = QPixmap(that); |
1326 | } else { |
1327 | mask = mask_to_bitmap(xinfo.screen()); |
1328 | } |
1329 | return mask; |
1330 | } |
1331 | |
1332 | /*! |
1333 | Sets a mask bitmap. |
1334 | |
1335 | The \a newmask bitmap defines the clip mask for this pixmap. Every |
1336 | pixel in \a newmask corresponds to a pixel in this pixmap. Pixel |
1337 | value 1 means opaque and pixel value 0 means transparent. The mask |
1338 | must have the same size as this pixmap. |
1339 | |
1340 | \warning Setting the mask on a pixmap will cause any alpha channel |
1341 | data to be cleared. For example: |
1342 | \snippet doc/src/snippets/image/image.cpp 2 |
1343 | Now, alpha and alphacopy are visually different. |
1344 | |
1345 | Setting a null mask resets the mask. |
1346 | |
1347 | The effect of this function is undefined when the pixmap is being |
1348 | painted on. |
1349 | |
1350 | \sa mask(), {QPixmap#Pixmap Transformations}{Pixmap |
1351 | Transformations}, QBitmap |
1352 | */ |
1353 | void QX11PixmapData::setMask(const QBitmap &newmask) |
1354 | { |
1355 | if (newmask.isNull()) { // clear mask |
1356 | #ifndef QT_NO_XRENDER |
1357 | if (picture && d == 32) { |
1358 | QX11PixmapData newData(pixelType()); |
1359 | newData.resize(w, h); |
1360 | newData.fill(Qt::black); |
1361 | XRenderComposite(X11->display, PictOpOver, |
1362 | picture, 0, newData.picture, |
1363 | 0, 0, 0, 0, 0, 0, w, h); |
1364 | release(); |
1365 | *this = newData; |
1366 | // the new QX11PixmapData object isn't referenced yet, so |
1367 | // ref it |
1368 | ref.ref(); |
1369 | |
1370 | // the below is to make sure the QX11PixmapData destructor |
1371 | // doesn't delete our newly created render picture |
1372 | newData.hd = 0; |
1373 | newData.x11_mask = 0; |
1374 | newData.picture = 0; |
1375 | newData.mask_picture = 0; |
1376 | newData.hd2 = 0; |
1377 | } else |
1378 | #endif |
1379 | if (x11_mask) { |
1380 | #ifndef QT_NO_XRENDER |
1381 | if (picture) { |
1382 | XRenderPictureAttributes attrs; |
1383 | attrs.alpha_map = 0; |
1384 | XRenderChangePicture(X11->display, picture, CPAlphaMap, |
1385 | &attrs); |
1386 | } |
1387 | if (mask_picture) |
1388 | XRenderFreePicture(X11->display, mask_picture); |
1389 | mask_picture = 0; |
1390 | #endif |
1391 | XFreePixmap(X11->display, x11_mask); |
1392 | x11_mask = 0; |
1393 | } |
1394 | return; |
1395 | } |
1396 | |
1397 | #ifndef QT_NO_XRENDER |
1398 | if (picture && d == 32) { |
1399 | XRenderComposite(X11->display, PictOpSrc, |
1400 | picture, newmask.x11PictureHandle(), |
1401 | picture, 0, 0, 0, 0, 0, 0, w, h); |
1402 | } else |
1403 | #endif |
1404 | if (depth() == 1) { |
1405 | XGCValues vals; |
1406 | vals.function = GXand; |
1407 | GC gc = XCreateGC(X11->display, hd, GCFunction, &vals); |
1408 | XCopyArea(X11->display, newmask.handle(), hd, gc, 0, 0, |
1409 | width(), height(), 0, 0); |
1410 | XFreeGC(X11->display, gc); |
1411 | } else { |
1412 | // ##### should or the masks together |
1413 | if (x11_mask) { |
1414 | XFreePixmap(X11->display, x11_mask); |
1415 | #ifndef QT_NO_XRENDER |
1416 | if (mask_picture) |
1417 | XRenderFreePicture(X11->display, mask_picture); |
1418 | #endif |
1419 | } |
1420 | x11_mask = QX11PixmapData::bitmap_to_mask(newmask, xinfo.screen()); |
1421 | #ifndef QT_NO_XRENDER |
1422 | if (picture) { |
1423 | mask_picture = XRenderCreatePicture(X11->display, x11_mask, |
1424 | XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0); |
1425 | XRenderPictureAttributes attrs; |
1426 | attrs.alpha_map = mask_picture; |
1427 | XRenderChangePicture(X11->display, picture, CPAlphaMap, &attrs); |
1428 | } |
1429 | #endif |
1430 | } |
1431 | } |
1432 | |
1433 | int QX11PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const |
1434 | { |
1435 | switch (metric) { |
1436 | case QPaintDevice::PdmWidth: |
1437 | return w; |
1438 | case QPaintDevice::PdmHeight: |
1439 | return h; |
1440 | case QPaintDevice::PdmNumColors: |
1441 | return 1 << d; |
1442 | case QPaintDevice::PdmDepth: |
1443 | return d; |
1444 | case QPaintDevice::PdmWidthMM: { |
1445 | const int screen = xinfo.screen(); |
1446 | const int mm = DisplayWidthMM(X11->display, screen) * w |
1447 | / DisplayWidth(X11->display, screen); |
1448 | return mm; |
1449 | } |
1450 | case QPaintDevice::PdmHeightMM: { |
1451 | const int screen = xinfo.screen(); |
1452 | const int mm = (DisplayHeightMM(X11->display, screen) * h) |
1453 | / DisplayHeight(X11->display, screen); |
1454 | return mm; |
1455 | } |
1456 | case QPaintDevice::PdmDpiX: |
1457 | case QPaintDevice::PdmPhysicalDpiX: |
1458 | return QX11Info::appDpiX(xinfo.screen()); |
1459 | case QPaintDevice::PdmDpiY: |
1460 | case QPaintDevice::PdmPhysicalDpiY: |
1461 | return QX11Info::appDpiY(xinfo.screen()); |
1462 | default: |
1463 | qWarning("QX11PixmapData::metric(): Invalid metric" ); |
1464 | return 0; |
1465 | } |
1466 | } |
1467 | |
1468 | struct QXImageWrapper |
1469 | { |
1470 | XImage *xi; |
1471 | }; |
1472 | |
1473 | bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const |
1474 | { |
1475 | XImage *xi = xiWrapper.xi; |
1476 | |
1477 | // ARGB32_Premultiplied |
1478 | if (picture && depth() == 32) |
1479 | return true; |
1480 | |
1481 | Visual *visual = (Visual *)xinfo.visual(); |
1482 | |
1483 | // RGB32 |
1484 | if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000 |
1485 | && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) |
1486 | return true; |
1487 | |
1488 | // RGB16 |
1489 | if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800 |
1490 | && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f) |
1491 | return true; |
1492 | |
1493 | return false; |
1494 | } |
1495 | |
1496 | QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const |
1497 | { |
1498 | XImage *xi = xiWrapper.xi; |
1499 | |
1500 | QImage::Format format = QImage::Format_ARGB32_Premultiplied; |
1501 | if (depth() == 24) |
1502 | format = QImage::Format_RGB32; |
1503 | else if (depth() == 16) |
1504 | format = QImage::Format_RGB16; |
1505 | |
1506 | QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format); |
1507 | // take ownership |
1508 | image.data_ptr()->own_data = true; |
1509 | xi->data = 0; |
1510 | |
1511 | // we may have to swap the byte order |
1512 | if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst) |
1513 | || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst)) |
1514 | { |
1515 | for (int i=0; i < image.height(); i++) { |
1516 | if (depth() == 16) { |
1517 | ushort *p = (ushort*)image.scanLine(i); |
1518 | ushort *end = p + image.width(); |
1519 | while (p < end) { |
1520 | *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff); |
1521 | p++; |
1522 | } |
1523 | } else { |
1524 | uint *p = (uint*)image.scanLine(i); |
1525 | uint *end = p + image.width(); |
1526 | while (p < end) { |
1527 | *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) |
1528 | | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); |
1529 | p++; |
1530 | } |
1531 | } |
1532 | } |
1533 | } |
1534 | |
1535 | // fix-up alpha channel |
1536 | if (format == QImage::Format_RGB32) { |
1537 | QRgb *p = (QRgb *)image.bits(); |
1538 | for (int y = 0; y < xi->height; ++y) { |
1539 | for (int x = 0; x < xi->width; ++x) |
1540 | p[x] |= 0xff000000; |
1541 | p += xi->bytes_per_line / 4; |
1542 | } |
1543 | } |
1544 | |
1545 | XDestroyImage(xi); |
1546 | return image; |
1547 | } |
1548 | |
1549 | QImage QX11PixmapData::toImage(const QRect &rect) const |
1550 | { |
1551 | QXImageWrapper xiWrapper; |
1552 | xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(), |
1553 | AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap); |
1554 | |
1555 | Q_CHECK_PTR(xiWrapper.xi); |
1556 | if (!xiWrapper.xi) |
1557 | return QImage(); |
1558 | |
1559 | if (!x11_mask && canTakeQImageFromXImage(xiWrapper)) |
1560 | return takeQImageFromXImage(xiWrapper); |
1561 | |
1562 | QImage image = toImage(xiWrapper, rect); |
1563 | qSafeXDestroyImage(xiWrapper.xi); |
1564 | return image; |
1565 | } |
1566 | |
1567 | /*! |
1568 | Converts the pixmap to a QImage. Returns a null image if the |
1569 | conversion fails. |
1570 | |
1571 | If the pixmap has 1-bit depth, the returned image will also be 1 |
1572 | bit deep. If the pixmap has 2- to 8-bit depth, the returned image |
1573 | has 8-bit depth. If the pixmap has greater than 8-bit depth, the |
1574 | returned image has 32-bit depth. |
1575 | |
1576 | Note that for the moment, alpha masks on monochrome images are |
1577 | ignored. |
1578 | |
1579 | \sa fromImage(), {QImage#Image Formats}{Image Formats} |
1580 | */ |
1581 | |
1582 | QImage QX11PixmapData::toImage() const |
1583 | { |
1584 | return toImage(QRect(0, 0, w, h)); |
1585 | } |
1586 | |
1587 | QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const |
1588 | { |
1589 | XImage *xi = xiWrapper.xi; |
1590 | |
1591 | int d = depth(); |
1592 | Visual *visual = (Visual *)xinfo.visual(); |
1593 | bool trucol = (visual->c_class >= TrueColor) && d > 1; |
1594 | |
1595 | QImage::Format format = QImage::Format_Mono; |
1596 | if (d > 1 && d <= 8) { |
1597 | d = 8; |
1598 | format = QImage::Format_Indexed8; |
1599 | } |
1600 | // we could run into the situation where d == 8 AND trucol is true, which can |
1601 | // cause problems when converting to and from images. in this case, always treat |
1602 | // the depth as 32... |
1603 | if (d > 8 || trucol) { |
1604 | d = 32; |
1605 | format = QImage::Format_RGB32; |
1606 | } |
1607 | |
1608 | if (d == 1 && xi->bitmap_bit_order == LSBFirst) |
1609 | format = QImage::Format_MonoLSB; |
1610 | if (x11_mask && format == QImage::Format_RGB32) |
1611 | format = QImage::Format_ARGB32; |
1612 | |
1613 | QImage image(xi->width, xi->height, format); |
1614 | if (image.isNull()) // could not create image |
1615 | return image; |
1616 | |
1617 | QImage alpha; |
1618 | if (x11_mask) { |
1619 | if (rect.contains(QRect(0, 0, w, h))) |
1620 | alpha = mask().toImage(); |
1621 | else |
1622 | alpha = mask().toImage().copy(rect); |
1623 | } |
1624 | bool ale = alpha.format() == QImage::Format_MonoLSB; |
1625 | |
1626 | if (trucol) { // truecolor |
1627 | const uint red_mask = (uint)visual->red_mask; |
1628 | const uint green_mask = (uint)visual->green_mask; |
1629 | const uint blue_mask = (uint)visual->blue_mask; |
1630 | const int red_shift = highest_bit(red_mask) - 7; |
1631 | const int green_shift = highest_bit(green_mask) - 7; |
1632 | const int blue_shift = highest_bit(blue_mask) - 7; |
1633 | |
1634 | const uint red_bits = n_bits(red_mask); |
1635 | const uint green_bits = n_bits(green_mask); |
1636 | const uint blue_bits = n_bits(blue_mask); |
1637 | |
1638 | static uint red_table_bits = 0; |
1639 | static uint green_table_bits = 0; |
1640 | static uint blue_table_bits = 0; |
1641 | |
1642 | if (red_bits < 8 && red_table_bits != red_bits) { |
1643 | build_scale_table(&red_scale_table, red_bits); |
1644 | red_table_bits = red_bits; |
1645 | } |
1646 | if (blue_bits < 8 && blue_table_bits != blue_bits) { |
1647 | build_scale_table(&blue_scale_table, blue_bits); |
1648 | blue_table_bits = blue_bits; |
1649 | } |
1650 | if (green_bits < 8 && green_table_bits != green_bits) { |
1651 | build_scale_table(&green_scale_table, green_bits); |
1652 | green_table_bits = green_bits; |
1653 | } |
1654 | |
1655 | int r, g, b; |
1656 | |
1657 | QRgb *dst; |
1658 | uchar *src; |
1659 | uint pixel; |
1660 | int bppc = xi->bits_per_pixel; |
1661 | |
1662 | if (bppc > 8 && xi->byte_order == LSBFirst) |
1663 | bppc++; |
1664 | |
1665 | for (int y = 0; y < xi->height; ++y) { |
1666 | uchar* asrc = x11_mask ? alpha.scanLine(y) : 0; |
1667 | dst = (QRgb *)image.scanLine(y); |
1668 | src = (uchar *)xi->data + xi->bytes_per_line*y; |
1669 | for (int x = 0; x < xi->width; x++) { |
1670 | switch (bppc) { |
1671 | case 8: |
1672 | pixel = *src++; |
1673 | break; |
1674 | case 16: // 16 bit MSB |
1675 | pixel = src[1] | (uint)src[0] << 8; |
1676 | src += 2; |
1677 | break; |
1678 | case 17: // 16 bit LSB |
1679 | pixel = src[0] | (uint)src[1] << 8; |
1680 | src += 2; |
1681 | break; |
1682 | case 24: // 24 bit MSB |
1683 | pixel = src[2] | (uint)src[1] << 8 | (uint)src[0] << 16; |
1684 | src += 3; |
1685 | break; |
1686 | case 25: // 24 bit LSB |
1687 | pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16; |
1688 | src += 3; |
1689 | break; |
1690 | case 32: // 32 bit MSB |
1691 | pixel = src[3] | (uint)src[2] << 8 | (uint)src[1] << 16 | (uint)src[0] << 24; |
1692 | src += 4; |
1693 | break; |
1694 | case 33: // 32 bit LSB |
1695 | pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24; |
1696 | src += 4; |
1697 | break; |
1698 | default: // should not really happen |
1699 | x = xi->width; // leave loop |
1700 | y = xi->height; |
1701 | pixel = 0; // eliminate compiler warning |
1702 | qWarning("QPixmap::convertToImage: Invalid depth %d" , bppc); |
1703 | } |
1704 | if (red_shift > 0) |
1705 | r = (pixel & red_mask) >> red_shift; |
1706 | else |
1707 | r = (pixel & red_mask) << -red_shift; |
1708 | if (green_shift > 0) |
1709 | g = (pixel & green_mask) >> green_shift; |
1710 | else |
1711 | g = (pixel & green_mask) << -green_shift; |
1712 | if (blue_shift > 0) |
1713 | b = (pixel & blue_mask) >> blue_shift; |
1714 | else |
1715 | b = (pixel & blue_mask) << -blue_shift; |
1716 | |
1717 | if (red_bits < 8) |
1718 | r = red_scale_table[r]; |
1719 | if (green_bits < 8) |
1720 | g = green_scale_table[g]; |
1721 | if (blue_bits < 8) |
1722 | b = blue_scale_table[b]; |
1723 | |
1724 | if (x11_mask) { |
1725 | if (ale) { |
1726 | *dst++ = (asrc[x >> 3] & (1 << (x & 7))) ? qRgba(r, g, b, 0xff) : 0; |
1727 | } else { |
1728 | *dst++ = (asrc[x >> 3] & (0x80 >> (x & 7))) ? qRgba(r, g, b, 0xff) : 0; |
1729 | } |
1730 | } else { |
1731 | *dst++ = qRgb(r, g, b); |
1732 | } |
1733 | } |
1734 | } |
1735 | } else if (xi->bits_per_pixel == d) { // compatible depth |
1736 | char *xidata = xi->data; // copy each scanline |
1737 | int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line); |
1738 | for (int y=0; y<xi->height; y++) { |
1739 | memcpy(image.scanLine(y), xidata, bpl); |
1740 | xidata += xi->bytes_per_line; |
1741 | } |
1742 | } else { |
1743 | /* Typically 2 or 4 bits display depth */ |
1744 | qWarning("QPixmap::convertToImage: Display not supported (bpp=%d)" , |
1745 | xi->bits_per_pixel); |
1746 | return QImage(); |
1747 | } |
1748 | |
1749 | if (d == 1) { // bitmap |
1750 | image.setColorCount(2); |
1751 | image.setColor(0, qRgb(255,255,255)); |
1752 | image.setColor(1, qRgb(0,0,0)); |
1753 | } else if (!trucol) { // pixmap with colormap |
1754 | register uchar *p; |
1755 | uchar *end; |
1756 | uchar use[256]; // pixel-in-use table |
1757 | uchar pix[256]; // pixel translation table |
1758 | int ncols, bpl; |
1759 | memset(use, 0, 256); |
1760 | memset(pix, 0, 256); |
1761 | bpl = image.bytesPerLine(); |
1762 | |
1763 | if (x11_mask) { // which pixels are used? |
1764 | for (int i = 0; i < xi->height; i++) { |
1765 | uchar* asrc = alpha.scanLine(i); |
1766 | p = image.scanLine(i); |
1767 | if (ale) { |
1768 | for (int x = 0; x < xi->width; x++) { |
1769 | if (asrc[x >> 3] & (1 << (x & 7))) |
1770 | use[*p] = 1; |
1771 | ++p; |
1772 | } |
1773 | } else { |
1774 | for (int x = 0; x < xi->width; x++) { |
1775 | if (asrc[x >> 3] & (0x80 >> (x & 7))) |
1776 | use[*p] = 1; |
1777 | ++p; |
1778 | } |
1779 | } |
1780 | } |
1781 | } else { |
1782 | for (int i = 0; i < xi->height; i++) { |
1783 | p = image.scanLine(i); |
1784 | end = p + bpl; |
1785 | while (p < end) |
1786 | use[*p++] = 1; |
1787 | } |
1788 | } |
1789 | ncols = 0; |
1790 | for (int i = 0; i < 256; i++) { // build translation table |
1791 | if (use[i]) |
1792 | pix[i] = ncols++; |
1793 | } |
1794 | for (int i = 0; i < xi->height; i++) { // translate pixels |
1795 | p = image.scanLine(i); |
1796 | end = p + bpl; |
1797 | while (p < end) { |
1798 | *p = pix[*p]; |
1799 | p++; |
1800 | } |
1801 | } |
1802 | if (x11_mask) { |
1803 | int trans; |
1804 | if (ncols < 256) { |
1805 | trans = ncols++; |
1806 | image.setColorCount(ncols); // create color table |
1807 | image.setColor(trans, 0x00000000); |
1808 | } else { |
1809 | image.setColorCount(ncols); // create color table |
1810 | // oh dear... no spare "transparent" pixel. |
1811 | // use first pixel in image (as good as any). |
1812 | trans = image.scanLine(0)[0]; |
1813 | } |
1814 | for (int i = 0; i < xi->height; i++) { |
1815 | uchar* asrc = alpha.scanLine(i); |
1816 | p = image.scanLine(i); |
1817 | if (ale) { |
1818 | for (int x = 0; x < xi->width; x++) { |
1819 | if (!(asrc[x >> 3] & (1 << (x & 7)))) |
1820 | *p = trans; |
1821 | ++p; |
1822 | } |
1823 | } else { |
1824 | for (int x = 0; x < xi->width; x++) { |
1825 | if (!(asrc[x >> 3] & (1 << (7 -(x & 7))))) |
1826 | *p = trans; |
1827 | ++p; |
1828 | } |
1829 | } |
1830 | } |
1831 | } else { |
1832 | image.setColorCount(ncols); // create color table |
1833 | } |
1834 | QVector<QColor> colors = QColormap::instance(xinfo.screen()).colormap(); |
1835 | int j = 0; |
1836 | for (int i=0; i<colors.size(); i++) { // translate pixels |
1837 | if (use[i]) |
1838 | image.setColor(j++, 0xff000000 | colors.at(i).rgb()); |
1839 | } |
1840 | } |
1841 | |
1842 | return image; |
1843 | } |
1844 | |
1845 | /*! |
1846 | Returns a copy of the pixmap that is transformed using the given |
1847 | transformation \a matrix and transformation \a mode. The original |
1848 | pixmap is not changed. |
1849 | |
1850 | The transformation \a matrix is internally adjusted to compensate |
1851 | for unwanted translation; i.e. the pixmap produced is the smallest |
1852 | pixmap that contains all the transformed points of the original |
1853 | pixmap. Use the trueMatrix() function to retrieve the actual |
1854 | matrix used for transforming the pixmap. |
1855 | |
1856 | This function is slow because it involves transformation to a |
1857 | QImage, non-trivial computations and a transformation back to a |
1858 | QPixmap. |
1859 | |
1860 | \sa trueMatrix(), {QPixmap#Pixmap Transformations}{Pixmap |
1861 | Transformations} |
1862 | */ |
1863 | QPixmap QX11PixmapData::transformed(const QTransform &transform, |
1864 | Qt::TransformationMode mode ) const |
1865 | { |
1866 | if (mode == Qt::SmoothTransformation || transform.type() >= QTransform::TxProject) { |
1867 | QImage image = toImage(); |
1868 | return QPixmap::fromImage(image.transformed(transform, mode)); |
1869 | } |
1870 | |
1871 | uint w = 0; |
1872 | uint h = 0; // size of target pixmap |
1873 | uint ws, hs; // size of source pixmap |
1874 | uchar *dptr; // data in target pixmap |
1875 | uint dbpl, dbytes; // bytes per line/bytes total |
1876 | uchar *sptr; // data in original pixmap |
1877 | int sbpl; // bytes per line in original |
1878 | int bpp; // bits per pixel |
1879 | bool depth1 = depth() == 1; |
1880 | Display *dpy = X11->display; |
1881 | |
1882 | ws = width(); |
1883 | hs = height(); |
1884 | |
1885 | QTransform mat(transform.m11(), transform.m12(), transform.m13(), |
1886 | transform.m21(), transform.m22(), transform.m23(), |
1887 | 0., 0., 1); |
1888 | bool complex_xform = false; |
1889 | qreal scaledWidth; |
1890 | qreal scaledHeight; |
1891 | |
1892 | if (mat.type() <= QTransform::TxScale) { |
1893 | scaledHeight = qAbs(mat.m22()) * hs + 0.9999; |
1894 | scaledWidth = qAbs(mat.m11()) * ws + 0.9999; |
1895 | h = qAbs(int(scaledHeight)); |
1896 | w = qAbs(int(scaledWidth)); |
1897 | } else { // rotation or shearing |
1898 | QPolygonF a(QRectF(0, 0, ws, hs)); |
1899 | a = mat.map(a); |
1900 | QRect r = a.boundingRect().toAlignedRect(); |
1901 | w = r.width(); |
1902 | h = r.height(); |
1903 | scaledWidth = w; |
1904 | scaledHeight = h; |
1905 | complex_xform = true; |
1906 | } |
1907 | mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix |
1908 | |
1909 | bool invertible; |
1910 | mat = mat.inverted(&invertible); // invert matrix |
1911 | |
1912 | if (h == 0 || w == 0 || !invertible |
1913 | || qAbs(scaledWidth) >= 32768 || qAbs(scaledHeight) >= 32768 ) |
1914 | // error, return null pixmap |
1915 | return QPixmap(); |
1916 | |
1917 | #if defined(QT_MITSHM) |
1918 | static bool try_once = true; |
1919 | if (try_once) { |
1920 | try_once = false; |
1921 | if (!xshminit) |
1922 | qt_create_mitshm_buffer(this, 800, 600); |
1923 | } |
1924 | |
1925 | bool use_mitshm = xshmimg && !depth1 && |
1926 | xshmimg->width >= w && xshmimg->height >= h; |
1927 | #endif |
1928 | XImage *xi = XGetImage(X11->display, handle(), 0, 0, ws, hs, AllPlanes, |
1929 | depth1 ? XYPixmap : ZPixmap); |
1930 | |
1931 | if (!xi) |
1932 | return QPixmap(); |
1933 | |
1934 | sbpl = xi->bytes_per_line; |
1935 | sptr = (uchar *)xi->data; |
1936 | bpp = xi->bits_per_pixel; |
1937 | |
1938 | if (depth1) |
1939 | dbpl = (w+7)/8; |
1940 | else |
1941 | dbpl = ((w*bpp+31)/32)*4; |
1942 | dbytes = dbpl*h; |
1943 | |
1944 | #if defined(QT_MITSHM) |
1945 | if (use_mitshm) { |
1946 | dptr = (uchar *)xshmimg->data; |
1947 | uchar fillbyte = bpp == 8 ? white.pixel() : 0xff; |
1948 | for (int y=0; y<h; y++) |
1949 | memset(dptr + y*xshmimg->bytes_per_line, fillbyte, dbpl); |
1950 | } else { |
1951 | #endif |
1952 | dptr = (uchar *)malloc(dbytes); // create buffer for bits |
1953 | Q_CHECK_PTR(dptr); |
1954 | if (depth1) // fill with zeros |
1955 | memset(dptr, 0, dbytes); |
1956 | else if (bpp == 8) // fill with background color |
1957 | memset(dptr, WhitePixel(X11->display, xinfo.screen()), dbytes); |
1958 | else |
1959 | memset(dptr, 0, dbytes); |
1960 | #if defined(QT_MITSHM) |
1961 | } |
1962 | #endif |
1963 | |
1964 | // #define QT_DEBUG_XIMAGE |
1965 | #if defined(QT_DEBUG_XIMAGE) |
1966 | qDebug("----IMAGE--INFO--------------" ); |
1967 | qDebug("width............. %d" , xi->width); |
1968 | qDebug("height............ %d" , xi->height); |
1969 | qDebug("xoffset........... %d" , xi->xoffset); |
1970 | qDebug("format............ %d" , xi->format); |
1971 | qDebug("byte order........ %d" , xi->byte_order); |
1972 | qDebug("bitmap unit....... %d" , xi->bitmap_unit); |
1973 | qDebug("bitmap bit order.. %d" , xi->bitmap_bit_order); |
1974 | qDebug("depth............. %d" , xi->depth); |
1975 | qDebug("bytes per line.... %d" , xi->bytes_per_line); |
1976 | qDebug("bits per pixel.... %d" , xi->bits_per_pixel); |
1977 | #endif |
1978 | |
1979 | int type; |
1980 | if (xi->bitmap_bit_order == MSBFirst) |
1981 | type = QT_XFORM_TYPE_MSBFIRST; |
1982 | else |
1983 | type = QT_XFORM_TYPE_LSBFIRST; |
1984 | int xbpl, p_inc; |
1985 | if (depth1) { |
1986 | xbpl = (w+7)/8; |
1987 | p_inc = dbpl - xbpl; |
1988 | } else { |
1989 | xbpl = (w*bpp)/8; |
1990 | p_inc = dbpl - xbpl; |
1991 | #if defined(QT_MITSHM) |
1992 | if (use_mitshm) |
1993 | p_inc = xshmimg->bytes_per_line - xbpl; |
1994 | #endif |
1995 | } |
1996 | |
1997 | if (!qt_xForm_helper(mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs)){ |
1998 | qWarning("QPixmap::transform: display not supported (bpp=%d)" ,bpp); |
1999 | QPixmap pm; |
2000 | return pm; |
2001 | } |
2002 | |
2003 | qSafeXDestroyImage(xi); |
2004 | |
2005 | if (depth1) { // mono bitmap |
2006 | QBitmap bm = QBitmap::fromData(QSize(w, h), dptr, |
2007 | BitmapBitOrder(X11->display) == MSBFirst |
2008 | ? QImage::Format_Mono |
2009 | : QImage::Format_MonoLSB); |
2010 | free(dptr); |
2011 | return bm; |
2012 | } else { // color pixmap |
2013 | QX11PixmapData *x11Data = new QX11PixmapData(QPixmapData::PixmapType); |
2014 | QPixmap pm(x11Data); |
2015 | x11Data->flags &= ~QX11PixmapData::Uninitialized; |
2016 | x11Data->xinfo = xinfo; |
2017 | x11Data->d = d; |
2018 | x11Data->w = w; |
2019 | x11Data->h = h; |
2020 | x11Data->is_null = (w <= 0 || h <= 0); |
2021 | x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display, |
2022 | RootWindow(X11->display, xinfo.screen()), |
2023 | w, h, d); |
2024 | x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); |
2025 | |
2026 | #ifndef QT_NO_XRENDER |
2027 | if (X11->use_xrender) { |
2028 | XRenderPictFormat *format = x11Data->d == 32 |
2029 | ? XRenderFindStandardFormat(X11->display, PictStandardARGB32) |
2030 | : XRenderFindVisualFormat(X11->display, (Visual *) x11Data->xinfo.visual()); |
2031 | x11Data->picture = XRenderCreatePicture(X11->display, x11Data->hd, format, 0, 0); |
2032 | } |
2033 | #endif // QT_NO_XRENDER |
2034 | |
2035 | GC gc = XCreateGC(X11->display, x11Data->hd, 0, 0); |
2036 | #if defined(QT_MITSHM) |
2037 | if (use_mitshm) { |
2038 | XCopyArea(dpy, xshmpm, x11Data->hd, gc, 0, 0, w, h, 0, 0); |
2039 | } else |
2040 | #endif |
2041 | { |
2042 | xi = XCreateImage(dpy, (Visual*)x11Data->xinfo.visual(), |
2043 | x11Data->d, |
2044 | ZPixmap, 0, (char *)dptr, w, h, 32, 0); |
2045 | XPutImage(dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h); |
2046 | qSafeXDestroyImage(xi); |
2047 | } |
2048 | XFreeGC(X11->display, gc); |
2049 | |
2050 | if (x11_mask) { // xform mask, too |
2051 | pm.setMask(mask_to_bitmap(xinfo.screen()).transformed(transform)); |
2052 | } else if (d != 32 && complex_xform) { // need a mask! |
2053 | QBitmap mask(ws, hs); |
2054 | mask.fill(Qt::color1); |
2055 | pm.setMask(mask.transformed(transform)); |
2056 | } |
2057 | return pm; |
2058 | } |
2059 | } |
2060 | |
2061 | int QPixmap::x11SetDefaultScreen(int screen) |
2062 | { |
2063 | int old = defaultScreen; |
2064 | defaultScreen = screen; |
2065 | return old; |
2066 | } |
2067 | |
2068 | void QPixmap::x11SetScreen(int screen) |
2069 | { |
2070 | if (paintingActive()) { |
2071 | qWarning("QPixmap::x11SetScreen(): Cannot change screens during painting" ); |
2072 | return; |
2073 | } |
2074 | |
2075 | if (isNull()) |
2076 | return; |
2077 | |
2078 | if (data->classId() != QPixmapData::X11Class) |
2079 | return; |
2080 | |
2081 | if (screen < 0) |
2082 | screen = QX11Info::appScreen(); |
2083 | |
2084 | QX11PixmapData *x11Data = static_cast<QX11PixmapData*>(data.data()); |
2085 | if (screen == x11Data->xinfo.screen()) |
2086 | return; // nothing to do |
2087 | |
2088 | if (isNull()) { |
2089 | QX11InfoData* xd = x11Data->xinfo.getX11Data(true); |
2090 | xd->screen = screen; |
2091 | xd->depth = QX11Info::appDepth(screen); |
2092 | xd->cells = QX11Info::appCells(screen); |
2093 | xd->colormap = QX11Info::appColormap(screen); |
2094 | xd->defaultColormap = QX11Info::appDefaultColormap(screen); |
2095 | xd->visual = (Visual *)QX11Info::appVisual(screen); |
2096 | xd->defaultVisual = QX11Info::appDefaultVisual(screen); |
2097 | x11Data->xinfo.setX11Data(xd); |
2098 | return; |
2099 | } |
2100 | #if 0 |
2101 | qDebug("QPixmap::x11SetScreen for %p from %d to %d. Size is %d/%d" , x11Data, x11Data->xinfo.screen(), screen, width(), height()); |
2102 | #endif |
2103 | |
2104 | x11SetDefaultScreen(screen); |
2105 | *this = qt_toX11Pixmap(toImage()); |
2106 | } |
2107 | |
2108 | QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h) |
2109 | { |
2110 | if (w == 0 || h == 0) |
2111 | return QPixmap(); |
2112 | |
2113 | Display *dpy = X11->display; |
2114 | XWindowAttributes window_attr; |
2115 | if (!XGetWindowAttributes(dpy, window, &window_attr)) |
2116 | return QPixmap(); |
2117 | |
2118 | if (w < 0) |
2119 | w = window_attr.width - x; |
2120 | if (h < 0) |
2121 | h = window_attr.height - y; |
2122 | |
2123 | // determine the screen |
2124 | int scr; |
2125 | for (scr = 0; scr < ScreenCount(dpy); ++scr) { |
2126 | if (window_attr.root == RootWindow(dpy, scr)) // found it |
2127 | break; |
2128 | } |
2129 | if (scr >= ScreenCount(dpy)) // sanity check |
2130 | return QPixmap(); |
2131 | |
2132 | |
2133 | // get the depth of the root window |
2134 | XWindowAttributes root_attr; |
2135 | if (!XGetWindowAttributes(dpy, window_attr.root, &root_attr)) |
2136 | return QPixmap(); |
2137 | |
2138 | if (window_attr.depth == root_attr.depth) { |
2139 | // if the depth of the specified window and the root window are the |
2140 | // same, grab pixels from the root window (so that we get the any |
2141 | // overlapping windows and window manager frames) |
2142 | |
2143 | // map x and y to the root window |
2144 | WId unused; |
2145 | if (!XTranslateCoordinates(dpy, window, window_attr.root, x, y, |
2146 | &x, &y, &unused)) |
2147 | return QPixmap(); |
2148 | |
2149 | window = window_attr.root; |
2150 | window_attr = root_attr; |
2151 | } |
2152 | |
2153 | QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); |
2154 | |
2155 | void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a); |
2156 | qt_x11_getX11InfoForWindow(&data->xinfo,window_attr); |
2157 | |
2158 | data->resize(w, h); |
2159 | |
2160 | QPixmap pm(data); |
2161 | |
2162 | data->flags &= ~QX11PixmapData::Uninitialized; |
2163 | pm.x11SetScreen(scr); |
2164 | |
2165 | GC gc = XCreateGC(dpy, pm.handle(), 0, 0); |
2166 | XSetSubwindowMode(dpy, gc, IncludeInferiors); |
2167 | XCopyArea(dpy, window, pm.handle(), gc, x, y, w, h, 0, 0); |
2168 | XFreeGC(dpy, gc); |
2169 | |
2170 | return pm; |
2171 | } |
2172 | |
2173 | bool QX11PixmapData::hasAlphaChannel() const |
2174 | { |
2175 | return d == 32; |
2176 | } |
2177 | |
2178 | const QX11Info &QPixmap::x11Info() const |
2179 | { |
2180 | if (data && data->classId() == QPixmapData::X11Class) |
2181 | return static_cast<QX11PixmapData*>(data.data())->xinfo; |
2182 | else { |
2183 | static QX11Info nullX11Info; |
2184 | return nullX11Info; |
2185 | } |
2186 | } |
2187 | |
2188 | #if !defined(QT_NO_XRENDER) |
2189 | static XRenderPictFormat *qt_renderformat_for_depth(const QX11Info &xinfo, int depth) |
2190 | { |
2191 | if (depth == 1) |
2192 | return XRenderFindStandardFormat(X11->display, PictStandardA1); |
2193 | else if (depth == 32) |
2194 | return XRenderFindStandardFormat(X11->display, PictStandardARGB32); |
2195 | else |
2196 | return XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual()); |
2197 | } |
2198 | #endif |
2199 | |
2200 | QPaintEngine* QX11PixmapData::paintEngine() const |
2201 | { |
2202 | QX11PixmapData *that = const_cast<QX11PixmapData*>(this); |
2203 | |
2204 | if ((flags & Readonly) && share_mode == QPixmap::ImplicitlyShared) { |
2205 | // if someone wants to draw onto us, copy the shared contents |
2206 | // and turn it into a fully fledged QPixmap |
2207 | ::Pixmap hd_copy = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), |
2208 | w, h, d); |
2209 | #if !defined(QT_NO_XRENDER) |
2210 | XRenderPictFormat *format = qt_renderformat_for_depth(xinfo, d); |
2211 | ::Picture picture_copy = XRenderCreatePicture(X11->display, hd_copy, format, 0, 0); |
2212 | |
2213 | if (picture && d == 32) { |
2214 | XRenderComposite(X11->display, PictOpSrc, picture, 0, picture_copy, |
2215 | 0, 0, 0, 0, 0, 0, w, h); |
2216 | XRenderFreePicture(X11->display, picture); |
2217 | that->picture = picture_copy; |
2218 | } else |
2219 | #endif |
2220 | { |
2221 | GC gc = XCreateGC(X11->display, hd_copy, 0, 0); |
2222 | XCopyArea(X11->display, hd, hd_copy, gc, 0, 0, w, h, 0, 0); |
2223 | XFreeGC(X11->display, gc); |
2224 | } |
2225 | that->hd = hd_copy; |
2226 | that->flags &= ~QX11PixmapData::Readonly; |
2227 | } |
2228 | |
2229 | if (!that->pengine) |
2230 | that->pengine = new QX11PaintEngine; |
2231 | return that->pengine; |
2232 | } |
2233 | |
2234 | Qt::HANDLE QPixmap::x11PictureHandle() const |
2235 | { |
2236 | #ifndef QT_NO_XRENDER |
2237 | if (data && data->classId() == QPixmapData::X11Class) |
2238 | return static_cast<const QX11PixmapData*>(data.data())->picture; |
2239 | else |
2240 | return 0; |
2241 | #else |
2242 | return 0; |
2243 | #endif // QT_NO_XRENDER |
2244 | } |
2245 | |
2246 | Qt::HANDLE QX11PixmapData::x11ConvertToDefaultDepth() |
2247 | { |
2248 | #ifndef QT_NO_XRENDER |
2249 | if (d == QX11Info::appDepth() || !X11->use_xrender) |
2250 | return hd; |
2251 | if (!hd2) { |
2252 | hd2 = XCreatePixmap(xinfo.display(), hd, w, h, QX11Info::appDepth()); |
2253 | XRenderPictFormat *format = XRenderFindVisualFormat(xinfo.display(), |
2254 | (Visual*) xinfo.visual()); |
2255 | Picture pic = XRenderCreatePicture(xinfo.display(), hd2, format, 0, 0); |
2256 | XRenderComposite(xinfo.display(), PictOpSrc, picture, |
2257 | XNone, pic, 0, 0, 0, 0, 0, 0, w, h); |
2258 | XRenderFreePicture(xinfo.display(), pic); |
2259 | } |
2260 | return hd2; |
2261 | #else |
2262 | return hd; |
2263 | #endif |
2264 | } |
2265 | |
2266 | void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect) |
2267 | { |
2268 | if (data->pixelType() == BitmapType) { |
2269 | fromImage(data->toImage().copy(rect), Qt::AutoColor); |
2270 | return; |
2271 | } |
2272 | |
2273 | const QX11PixmapData *x11Data = static_cast<const QX11PixmapData*>(data); |
2274 | |
2275 | setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); |
2276 | |
2277 | flags &= ~Uninitialized; |
2278 | xinfo = x11Data->xinfo; |
2279 | d = x11Data->d; |
2280 | w = rect.width(); |
2281 | h = rect.height(); |
2282 | is_null = (w <= 0 || h <= 0); |
2283 | hd = (Qt::HANDLE)XCreatePixmap(X11->display, |
2284 | RootWindow(X11->display, x11Data->xinfo.screen()), |
2285 | w, h, d); |
2286 | #ifndef QT_NO_XRENDER |
2287 | if (X11->use_xrender) { |
2288 | XRenderPictFormat *format = d == 32 |
2289 | ? XRenderFindStandardFormat(X11->display, PictStandardARGB32) |
2290 | : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual()); |
2291 | picture = XRenderCreatePicture(X11->display, hd, format, 0, 0); |
2292 | } |
2293 | #endif // QT_NO_XRENDER |
2294 | if (x11Data->x11_mask) { |
2295 | x11_mask = XCreatePixmap(X11->display, hd, w, h, 1); |
2296 | #ifndef QT_NO_XRENDER |
2297 | if (X11->use_xrender) { |
2298 | mask_picture = XRenderCreatePicture(X11->display, x11_mask, |
2299 | XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0); |
2300 | XRenderPictureAttributes attrs; |
2301 | attrs.alpha_map = x11Data->mask_picture; |
2302 | XRenderChangePicture(X11->display, x11Data->picture, CPAlphaMap, &attrs); |
2303 | } |
2304 | #endif |
2305 | } |
2306 | |
2307 | #if !defined(QT_NO_XRENDER) |
2308 | if (x11Data->picture && x11Data->d == 32) { |
2309 | XRenderComposite(X11->display, PictOpSrc, |
2310 | x11Data->picture, 0, picture, |
2311 | rect.x(), rect.y(), 0, 0, 0, 0, w, h); |
2312 | } else |
2313 | #endif |
2314 | { |
2315 | GC gc = XCreateGC(X11->display, hd, 0, 0); |
2316 | XCopyArea(X11->display, x11Data->hd, hd, gc, |
2317 | rect.x(), rect.y(), w, h, 0, 0); |
2318 | if (x11Data->x11_mask) { |
2319 | GC monogc = XCreateGC(X11->display, x11_mask, 0, 0); |
2320 | XCopyArea(X11->display, x11Data->x11_mask, x11_mask, monogc, |
2321 | rect.x(), rect.y(), w, h, 0, 0); |
2322 | XFreeGC(X11->display, monogc); |
2323 | } |
2324 | XFreeGC(X11->display, gc); |
2325 | } |
2326 | } |
2327 | |
2328 | bool QX11PixmapData::scroll(int dx, int dy, const QRect &rect) |
2329 | { |
2330 | GC gc = XCreateGC(X11->display, hd, 0, 0); |
2331 | XCopyArea(X11->display, hd, hd, gc, |
2332 | rect.left(), rect.top(), rect.width(), rect.height(), |
2333 | rect.left() + dx, rect.top() + dy); |
2334 | XFreeGC(X11->display, gc); |
2335 | return true; |
2336 | } |
2337 | |
2338 | #if !defined(QT_NO_XRENDER) |
2339 | void QX11PixmapData::convertToARGB32(bool preserveContents) |
2340 | { |
2341 | if (!X11->use_xrender) |
2342 | return; |
2343 | |
2344 | // Q_ASSERT(count == 1); |
2345 | if ((flags & Readonly) && share_mode == QPixmap::ExplicitlyShared) |
2346 | return; |
2347 | |
2348 | Pixmap pm = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), |
2349 | w, h, 32); |
2350 | Picture p = XRenderCreatePicture(X11->display, pm, |
2351 | XRenderFindStandardFormat(X11->display, PictStandardARGB32), 0, 0); |
2352 | if (picture) { |
2353 | if (preserveContents) |
2354 | XRenderComposite(X11->display, PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h); |
2355 | if (!(flags & Readonly)) |
2356 | XRenderFreePicture(X11->display, picture); |
2357 | } |
2358 | if (hd && !(flags & Readonly)) |
2359 | XFreePixmap(X11->display, hd); |
2360 | if (x11_mask) { |
2361 | XFreePixmap(X11->display, x11_mask); |
2362 | if (mask_picture) |
2363 | XRenderFreePicture(X11->display, mask_picture); |
2364 | x11_mask = 0; |
2365 | mask_picture = 0; |
2366 | } |
2367 | hd = pm; |
2368 | picture = p; |
2369 | d = 32; |
2370 | } |
2371 | #endif |
2372 | |
2373 | QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode) |
2374 | { |
2375 | Window root; |
2376 | int x; |
2377 | int y; |
2378 | uint width; |
2379 | uint height; |
2380 | uint border_width; |
2381 | uint depth; |
2382 | XWindowAttributes win_attribs; |
2383 | int num_screens = ScreenCount(X11->display); |
2384 | int screen = 0; |
2385 | |
2386 | XGetGeometry(X11->display, pixmap, &root, &x, &y, &width, &height, &border_width, &depth); |
2387 | XGetWindowAttributes(X11->display, root, &win_attribs); |
2388 | |
2389 | for (; screen < num_screens; ++screen) { |
2390 | if (win_attribs.screen == ScreenOfDisplay(X11->display, screen)) |
2391 | break; |
2392 | } |
2393 | |
2394 | QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType); |
2395 | data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); |
2396 | data->flags = QX11PixmapData::Readonly; |
2397 | data->share_mode = mode; |
2398 | data->w = width; |
2399 | data->h = height; |
2400 | data->is_null = (width <= 0 || height <= 0); |
2401 | data->d = depth; |
2402 | data->hd = pixmap; |
2403 | |
2404 | if (defaultScreen >= 0 && defaultScreen != screen) { |
2405 | QX11InfoData* xd = data->xinfo.getX11Data(true); |
2406 | xd->screen = defaultScreen; |
2407 | xd->depth = QX11Info::appDepth(xd->screen); |
2408 | xd->cells = QX11Info::appCells(xd->screen); |
2409 | xd->colormap = QX11Info::appColormap(xd->screen); |
2410 | xd->defaultColormap = QX11Info::appDefaultColormap(xd->screen); |
2411 | xd->visual = (Visual *)QX11Info::appVisual(xd->screen); |
2412 | xd->defaultVisual = QX11Info::appDefaultVisual(xd->screen); |
2413 | data->xinfo.setX11Data(xd); |
2414 | } |
2415 | |
2416 | #ifndef QT_NO_XRENDER |
2417 | if (X11->use_xrender) { |
2418 | XRenderPictFormat *format = qt_renderformat_for_depth(data->xinfo, depth); |
2419 | data->picture = XRenderCreatePicture(X11->display, data->hd, format, 0, 0); |
2420 | } |
2421 | #endif // QT_NO_XRENDER |
2422 | |
2423 | return QPixmap(data); |
2424 | } |
2425 | |
2426 | |
2427 | QT_END_NAMESPACE |
2428 | |