Add PLUGIN_CLASS_NAME to qtbase plugins
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the plugins 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 #include "qxcbimage.h"
43 #include <QtGui/QColor>
44 #include <QtGui/private/qimage_p.h>
45 #include <QtGui/private/qdrawhelper_p.h>
46 #ifdef XCB_USE_RENDER
47 #include <xcb/render.h>
48 // 'template' is used as a function argument name in xcb_renderutil.h
49 #define template template_param
50 // extern "C" is missing too
51 extern "C" {
52 #include <xcb/xcb_renderutil.h>
53 }
54 #undef template
55 #endif
56
57 QT_BEGIN_NAMESPACE
58
59 QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth,
60                                            const xcb_visualtype_t *visual)
61 {
62     const xcb_format_t *format = connection->formatForDepth(depth);
63
64     if (!visual || !format)
65         return QImage::Format_Invalid;
66
67     if (depth == 32 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
68         && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
69         return QImage::Format_ARGB32_Premultiplied;
70
71     if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
72         && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
73         return QImage::Format_RGB32;
74
75     if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800
76         && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
77         return QImage::Format_RGB16;
78
79     return QImage::Format_Invalid;
80 }
81
82 QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
83                                  int width, int height, int depth,
84                                  const xcb_visualtype_t *visual)
85 {
86     xcb_connection_t *conn = connection->xcb_connection();
87
88     xcb_get_image_cookie_t get_image_cookie =
89         xcb_get_image_unchecked(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap,
90                       0, 0, width, height, 0xffffffff);
91
92     xcb_get_image_reply_t *image_reply =
93         xcb_get_image_reply(conn, get_image_cookie, NULL);
94
95     if (!image_reply) {
96         return QPixmap();
97     }
98
99     uint8_t *data = xcb_get_image_data(image_reply);
100     uint32_t length = xcb_get_image_data_length(image_reply);
101
102     QPixmap result;
103
104     QImage::Format format = qt_xcb_imageFormatForVisual(connection, depth, visual);
105     if (format != QImage::Format_Invalid) {
106         uint32_t bytes_per_line = length / height;
107         QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format);
108         uint8_t image_byte_order = connection->setup()->image_byte_order;
109
110         // we may have to swap the byte order
111         if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST)
112             || (QSysInfo::ByteOrder == QSysInfo::BigEndian && image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST))
113         {
114             for (int i=0; i < image.height(); i++) {
115                 switch (format) {
116                 case QImage::Format_RGB16: {
117                     ushort *p = (ushort*)image.scanLine(i);
118                     ushort *end = p + image.width();
119                     while (p < end) {
120                         *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
121                         p++;
122                     }
123                     break;
124                 }
125                 case QImage::Format_RGB32: // fall-through
126                 case QImage::Format_ARGB32_Premultiplied: {
127                     uint *p = (uint*)image.scanLine(i);
128                     uint *end = p + image.width();
129                     while (p < end) {
130                         *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
131                             | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
132                         p++;
133                     }
134                     break;
135                 }
136                 default:
137                     Q_ASSERT(false);
138                 }
139             }
140         }
141
142         // fix-up alpha channel
143         if (format == QImage::Format_RGB32) {
144             QRgb *p = (QRgb *)image.bits();
145             for (int y = 0; y < height; ++y) {
146                 for (int x = 0; x < width; ++x)
147                     p[x] |= 0xff000000;
148                 p += bytes_per_line / 4;
149             }
150         }
151
152         result = QPixmap::fromImage(image.copy());
153     }
154
155     free(image_reply);
156     return result;
157 }
158
159 xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
160 {
161     xcb_connection_t *conn = screen->xcb_connection();
162     QImage bitmap = image.convertToFormat(QImage::Format_MonoLSB);
163     const QRgb c0 = QColor(Qt::black).rgb();
164     const QRgb c1 = QColor(Qt::white).rgb();
165     if (bitmap.color(0) == c0 && bitmap.color(1) == c1) {
166         bitmap.invertPixels();
167         bitmap.setColor(0, c1);
168         bitmap.setColor(1, c0);
169     }
170     const int width = bitmap.width();
171     const int height = bitmap.height();
172     const int bytesPerLine = bitmap.bytesPerLine();
173     int destLineSize = width / 8;
174     if (width % 8)
175         ++destLineSize;
176     const uchar *map = bitmap.bits();
177     uint8_t *buf = new uint8_t[height * destLineSize];
178     for (int i = 0; i < height; i++)
179         memcpy(buf + (destLineSize * i), map + (bytesPerLine * i), destLineSize);
180     xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, screen->root(), buf,
181                                                          width, height, 1, 0, 0, 0);
182     delete[] buf;
183     return pm;
184 }
185
186 xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image,
187                                         const QPoint &spot)
188 {
189 #ifdef XCB_USE_RENDER
190     xcb_connection_t *conn = screen->xcb_connection();
191     const int w = image.width();
192     const int h = image.height();
193     xcb_generic_error_t *error = 0;
194     xcb_render_query_pict_formats_cookie_t formatsCookie = xcb_render_query_pict_formats(conn);
195     xcb_render_query_pict_formats_reply_t *formatsReply = xcb_render_query_pict_formats_reply(conn,
196                                                                                               formatsCookie,
197                                                                                               &error);
198     if (!formatsReply || error) {
199         qWarning("qt_xcb_createCursorXRender: query_pict_formats failed");
200         free(formatsReply);
201         free(error);
202         return XCB_NONE;
203     }
204     xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply,
205                                                                           XCB_PICT_STANDARD_ARGB_32);
206     if (!fmt) {
207         qWarning("qt_xcb_createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32");
208         free(formatsReply);
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                                        0, 0, 0);
218     if (!xi) {
219         qWarning("qt_xcb_createCursorXRender: xcb_image_create failed");
220         free(formatsReply);
221         return XCB_NONE;
222     }
223     xi->data = (uint8_t *) malloc(xi->stride * h);
224     if (!xi->data) {
225         qWarning("qt_xcb_createCursorXRender: Failed to malloc() image data");
226         xcb_image_destroy(xi);
227         free(formatsReply);
228         return XCB_NONE;
229     }
230     memcpy(xi->data, img.constBits(), img.byteCount());
231
232     xcb_pixmap_t pix = xcb_generate_id(conn);
233     xcb_create_pixmap(conn, 32, pix, screen->root(), w, h);
234
235     xcb_render_picture_t pic = xcb_generate_id(conn);
236     xcb_render_create_picture(conn, pic, pix, fmt->id, 0, 0);
237
238     xcb_gcontext_t gc = xcb_generate_id(conn);
239     xcb_create_gc(conn, gc, pix, 0, 0);
240     xcb_image_put(conn, pix, gc, xi, 0, 0, 0);
241     xcb_free_gc(conn, gc);
242
243     xcb_cursor_t cursor = xcb_generate_id(conn);
244     xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y());
245
246     free(xi->data);
247     xcb_image_destroy(xi);
248     xcb_render_free_picture(conn, pic);
249     xcb_free_pixmap(conn, pix);
250     free(formatsReply);
251     return cursor;
252
253 #else
254     Q_UNUSED(screen);
255     Q_UNUSED(image);
256     Q_UNUSED(spot);
257     return XCB_NONE;
258 #endif
259 }
260
261 QT_END_NAMESPACE