Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qxcbimage.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qxcbimage.h"
6#include <QtCore/QtEndian>
7#include <QtGui/QColor>
8#include <QtGui/private/qimage_p.h>
9#include <QtGui/private/qdrawhelper_p.h>
10
11#include <xcb/render.h>
12#include <xcb/xcb_renderutil.h>
13
14#include "qxcbconnection.h"
16
17namespace {
18
19QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, int blue_mask)
20{
21 if (bits_per_pixel == 32) {
22 switch (depth) {
23 case 32:
24 if (red_mask == 0xff0000 && blue_mask == 0xff)
25 return QImage::Format_ARGB32_Premultiplied;
26#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
27 if (red_mask == 0xff && blue_mask == 0xff0000)
28 return QImage::Format_RGBA8888_Premultiplied;
29#else
30 if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00)
31 return QImage::Format_RGBA8888_Premultiplied;
32#endif
33 if (red_mask == 0x3ff && blue_mask == 0x3ff00000)
34 return QImage::Format_A2BGR30_Premultiplied;
35 if (red_mask == 0x3ff00000 && blue_mask == 0x3ff)
36 return QImage::Format_A2RGB30_Premultiplied;
37 break;
38 case 30:
39 if (red_mask == 0x3ff && blue_mask == 0x3ff00000)
40 return QImage::Format_BGR30;
41 if (blue_mask == 0x3ff && red_mask == 0x3ff00000)
42 return QImage::Format_RGB30;
43 break;
44 case 24:
45 if (red_mask == 0xff0000 && blue_mask == 0xff)
46 return QImage::Format_RGB32;
47#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
48 if (red_mask == 0xff && blue_mask == 0xff0000)
49 return QImage::Format_RGBX8888;
50#else
51 if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00)
52 return QImage::Format_RGBX8888;
53#endif
54 break;
55 }
56 } else if (bits_per_pixel == 16) {
57 if (depth == 16 && red_mask == 0xf800 && blue_mask == 0x1f)
58 return QImage::Format_RGB16;
59 if (depth == 15 && red_mask == 0x7c00 && blue_mask == 0x1f)
60 return QImage::Format_RGB555;
61 }
62 return QImage::Format_Invalid;
63}
64
65} // namespace
66
68
69bool qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, const xcb_visualtype_t *visual,
70 QImage::Format *imageFormat, bool *needsRgbSwap)
71{
72 Q_ASSERT(connection && visual && imageFormat);
73
74 if (needsRgbSwap)
75 *needsRgbSwap = false;
76 *imageFormat = QImage::Format_Invalid;
77
78 if (depth == 8) {
79 if (visual->_class == XCB_VISUAL_CLASS_GRAY_SCALE) {
80 *imageFormat = QImage::Format_Grayscale8;
81 return true;
82 }
83#if QT_CONFIG(xcb_native_painting)
84 if (QXcbIntegration::instance() && QXcbIntegration::instance()->nativePaintingEnabled()) {
85 *imageFormat = QImage::Format_Indexed8;
86 return true;
87 }
88#endif
89 return false;
90 }
91
92 const xcb_format_t *format = connection->formatForDepth(depth);
93 if (!format)
94 return false;
95
96 const bool connectionEndianSwap = connection->imageNeedsEndianSwap();
97 // We swap the masks and see if we can recognize it as a host format
98 const quint32 red_mask = connectionEndianSwap ? qbswap(visual->red_mask) : visual->red_mask;
99 const quint32 blue_mask = connectionEndianSwap ? qbswap(visual->blue_mask) : visual->blue_mask;
100
101 *imageFormat = imageFormatForMasks(depth, format->bits_per_pixel, red_mask, blue_mask);
102 if (*imageFormat != QImage::Format_Invalid)
103 return true;
104
105 if (needsRgbSwap) {
106 *imageFormat = imageFormatForMasks(depth, format->bits_per_pixel, blue_mask, red_mask);
107 if (*imageFormat != QImage::Format_Invalid) {
108 *needsRgbSwap = true;
109 return true;
110 }
111 }
112
113 qWarning("Unsupported screen format: depth: %d, bits_per_pixel: %d, red_mask: %x, blue_mask: %x", depth, format->bits_per_pixel, red_mask, blue_mask);
114
115 return false;
116}
117
118QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
119 int width, int height, int depth,
120 const xcb_visualtype_t *visual)
121{
122 xcb_connection_t *conn = connection->xcb_connection();
123
124 auto image_reply = Q_XCB_REPLY_UNCHECKED(xcb_get_image, conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap,
125 0, 0, width, height, 0xffffffff);
126 if (!image_reply) {
127 return QPixmap();
128 }
129
130 uint8_t *data = xcb_get_image_data(image_reply.get());
131 uint32_t length = xcb_get_image_data_length(image_reply.get());
132
133 QPixmap result;
134
135 QImage::Format format;
136 bool needsRgbSwap;
137 if (qt_xcb_imageFormatForVisual(connection, depth, visual, &format, &needsRgbSwap)) {
138 uint32_t bytes_per_line = length / height;
139 QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format);
140
141 if (needsRgbSwap)
142 image = std::move(image).rgbSwapped();
143
144 // fix-up alpha channel
145 if (format == QImage::Format_RGB32 || format == QImage::Format_RGBX8888) {
146 QRgb *p = (QRgb *)image.bits();
147 for (int y = 0; y < height; ++y) {
148 for (int x = 0; x < width; ++x)
149 p[x] |= 0xff000000;
150 p += bytes_per_line / 4;
151 }
152 } else if (format == QImage::Format_BGR30 || format == QImage::Format_RGB30) {
153 QRgb *p = (QRgb *)image.bits();
154 for (int y = 0; y < height; ++y) {
155 for (int x = 0; x < width; ++x)
156 p[x] |= 0xc0000000;
157 p += bytes_per_line / 4;
158 }
159 }
160
161 result = QPixmap::fromImage(image.copy());
162 }
163
164 return result;
165}
166
167xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
168{
169 xcb_connection_t *conn = screen->xcb_connection();
170 QImage bitmap = image.convertToFormat(QImage::Format_MonoLSB);
171 const QRgb c0 = QColor(Qt::black).rgb();
172 const QRgb c1 = QColor(Qt::white).rgb();
173 if (bitmap.color(0) == c0 && bitmap.color(1) == c1) {
174 bitmap.invertPixels();
175 bitmap.setColor(0, c1);
176 bitmap.setColor(1, c0);
177 }
178 const int width = bitmap.width();
179 const int height = bitmap.height();
180 const qsizetype bytesPerLine = bitmap.bytesPerLine();
181 int destLineSize = width / 8;
182 if (width % 8)
183 ++destLineSize;
184 const uchar *map = bitmap.bits();
185 uint8_t *buf = new uint8_t[height * destLineSize];
186 for (int i = 0; i < height; i++)
187 memcpy(buf + (destLineSize * i), map + (bytesPerLine * i), destLineSize);
188 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, screen->root(), buf,
189 width, height, 1, 0, 0, nullptr);
190 delete[] buf;
191 return pm;
192}
193
194xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image,
195 const QPoint &spot)
196{
197 xcb_connection_t *conn = screen->xcb_connection();
198 const int w = image.width();
199 const int h = image.height();
200 auto formats = Q_XCB_REPLY(xcb_render_query_pict_formats, conn);
201 if (!formats) {
202 qWarning("qt_xcb_createCursorXRender: query_pict_formats failed");
203 return XCB_NONE;
204 }
205 xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formats.get(),
206 XCB_PICT_STANDARD_ARGB_32);
207 if (!fmt) {
208 qWarning("qt_xcb_createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32");
209 return XCB_NONE;
210 }
211
212 QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
213 xcb_image_t *xi = xcb_image_create(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
214 32, 32, 32, 32,
215 QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST,
216 XCB_IMAGE_ORDER_MSB_FIRST,
217 nullptr, 0, nullptr);
218 if (!xi) {
219 qWarning("qt_xcb_createCursorXRender: xcb_image_create failed");
220 return XCB_NONE;
221 }
222 xi->data = (uint8_t *) malloc(xi->stride * h);
223 if (!xi->data) {
224 qWarning("qt_xcb_createCursorXRender: Failed to malloc() image data");
225 xcb_image_destroy(xi);
226 return XCB_NONE;
227 }
228 memcpy(xi->data, img.constBits(), img.sizeInBytes());
229
230 xcb_pixmap_t pix = xcb_generate_id(conn);
231 xcb_create_pixmap(conn, 32, pix, screen->root(), w, h);
232
233 xcb_render_picture_t pic = xcb_generate_id(conn);
234 xcb_render_create_picture(conn, pic, pix, fmt->id, 0, nullptr);
235
236 xcb_gcontext_t gc = xcb_generate_id(conn);
237 xcb_create_gc(conn, gc, pix, 0, nullptr);
238 xcb_image_put(conn, pix, gc, xi, 0, 0, 0);
239 xcb_free_gc(conn, gc);
240
241 xcb_cursor_t cursor = xcb_generate_id(conn);
242 xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y());
243
244 free(xi->data);
245 xcb_image_destroy(xi);
246 xcb_render_free_picture(conn, pic);
247 xcb_free_pixmap(conn, pix);
248 return cursor;
249}
250
251QT_END_NAMESPACE
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)
xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
QT_BEGIN_NAMESPACE bool qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, const xcb_visualtype_t *visual, QImage::Format *imageFormat, bool *needsRgbSwap=nullptr)
Definition qxcbimage.cpp:69
xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, const QPoint &spot)
QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap, int width, int height, int depth, const xcb_visualtype_t *visual)