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#include <qdebug.h>
43#include "qnativeimage_p.h"
44#include "qcolormap.h"
45
46#include "private/qpaintengine_raster_p.h"
47
48#include "private/qapplication_p.h"
49#include "private/qgraphicssystem_p.h"
50
51#if defined(Q_WS_X11) && !defined(QT_NO_MITSHM)
52#include <qx11info_x11.h>
53#include <sys/ipc.h>
54#include <sys/shm.h>
55#include <qwidget.h>
56#endif
57
58#ifdef Q_WS_MAC
59#include <private/qpaintengine_mac_p.h>
60#endif
61
62QT_BEGIN_NAMESPACE
63
64#ifdef Q_WS_WIN
65typedef struct {
66 BITMAPINFOHEADER bmiHeader;
67 DWORD redMask;
68 DWORD greenMask;
69 DWORD blueMask;
70} BITMAPINFO_MASK;
71
72
73QNativeImage::QNativeImage(int width, int height, QImage::Format format, bool isTextBuffer, QWidget *)
74{
75#ifndef Q_WS_WINCE
76 Q_UNUSED(isTextBuffer);
77#endif
78 BITMAPINFO_MASK bmi;
79 memset(&bmi, 0, sizeof(bmi));
80 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
81 bmi.bmiHeader.biWidth = width;
82 bmi.bmiHeader.biHeight = -height;
83 bmi.bmiHeader.biPlanes = 1;
84 bmi.bmiHeader.biSizeImage = 0;
85
86 if (format == QImage::Format_RGB16) {
87 bmi.bmiHeader.biBitCount = 16;
88#ifdef Q_WS_WINCE
89 if (isTextBuffer) {
90 bmi.bmiHeader.biCompression = BI_RGB;
91 bmi.redMask = 0;
92 bmi.greenMask = 0;
93 bmi.blueMask = 0;
94 } else
95#endif
96 {
97 bmi.bmiHeader.biCompression = BI_BITFIELDS;
98 bmi.redMask = 0xF800;
99 bmi.greenMask = 0x07E0;
100 bmi.blueMask = 0x001F;
101 }
102 } else {
103 bmi.bmiHeader.biBitCount = 32;
104 bmi.bmiHeader.biCompression = BI_RGB;
105 bmi.redMask = 0;
106 bmi.greenMask = 0;
107 bmi.blueMask = 0;
108 }
109
110 HDC display_dc = GetDC(0);
111 hdc = CreateCompatibleDC(display_dc);
112 ReleaseDC(0, display_dc);
113 Q_ASSERT(hdc);
114
115 uchar *bits = 0;
116 bitmap = CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bmi), DIB_RGB_COLORS, (void**) &bits, 0, 0);
117 Q_ASSERT(bitmap);
118 Q_ASSERT(bits);
119
120 null_bitmap = (HBITMAP)SelectObject(hdc, bitmap);
121 image = QImage(bits, width, height, format);
122
123 Q_ASSERT(image.paintEngine()->type() == QPaintEngine::Raster);
124 static_cast<QRasterPaintEngine *>(image.paintEngine())->setDC(hdc);
125
126#ifndef Q_WS_WINCE
127 GdiFlush();
128#endif
129}
130
131QNativeImage::~QNativeImage()
132{
133 if (bitmap || hdc) {
134 Q_ASSERT(hdc);
135 Q_ASSERT(bitmap);
136 if (null_bitmap)
137 SelectObject(hdc, null_bitmap);
138 DeleteDC(hdc);
139 DeleteObject(bitmap);
140 }
141}
142
143QImage::Format QNativeImage::systemFormat()
144{
145 if (QColormap::instance().depth() == 16)
146 return QImage::Format_RGB16;
147 return QImage::Format_RGB32;
148}
149
150
151#elif defined(Q_WS_X11) && !defined(QT_NO_MITSHM)
152
153QNativeImage::QNativeImage(int width, int height, QImage::Format format,bool /* isTextBuffer */, QWidget *widget)
154 : xshmimg(0), xshmpm(0)
155{
156 QX11Info info = widget->x11Info();
157
158 int dd = info.depth();
159 Visual *vis = (Visual*) info.visual();
160
161 if (!X11->use_mitshm || format != QImage::Format_RGB16 && X11->bppForDepth.value(dd) != 32) {
162 image = QImage(width, height, format);
163 // follow good coding practice and set xshminfo attributes, though values not used in this case
164 xshminfo.readOnly = true;
165 xshminfo.shmaddr = 0;
166 xshminfo.shmid = 0;
167 xshminfo.shmseg = 0;
168 return;
169 }
170
171 xshmimg = XShmCreateImage(X11->display, vis, dd, ZPixmap, 0, &xshminfo, width, height);
172 if (!xshmimg) {
173 qWarning("QNativeImage: Unable to create shared XImage.");
174 return;
175 }
176
177 bool ok;
178 xshminfo.shmid = shmget(IPC_PRIVATE, xshmimg->bytes_per_line * xshmimg->height,
179 IPC_CREAT | 0700);
180 ok = xshminfo.shmid != -1;
181 if (ok) {
182 xshmimg->data = (char*)shmat(xshminfo.shmid, 0, 0);
183 xshminfo.shmaddr = xshmimg->data;
184 ok = (xshminfo.shmaddr != (char*)-1);
185 if (ok)
186 image = QImage((uchar *)xshmimg->data, width, height, format);
187 }
188 xshminfo.readOnly = false;
189 if (ok) {
190 ok = XShmAttach(X11->display, &xshminfo);
191 XSync(X11->display, False);
192 if (shmctl(xshminfo.shmid, IPC_RMID, 0) == -1)
193 qWarning() << "Error while marking the shared memory segment to be destroyed";
194 }
195 if (!ok) {
196 qWarning() << "QNativeImage: Unable to attach to shared memory segment.";
197 if (xshmimg->data) {
198 free(xshmimg->data);
199 xshmimg->data = 0;
200 }
201 XDestroyImage(xshmimg);
202 xshmimg = 0;
203 if (xshminfo.shmaddr)
204 shmdt(xshminfo.shmaddr);
205 if (xshminfo.shmid != -1)
206 shmctl(xshminfo.shmid, IPC_RMID, 0);
207 return;
208 }
209 if (X11->use_mitshm_pixmaps) {
210 xshmpm = XShmCreatePixmap(X11->display, DefaultRootWindow(X11->display), xshmimg->data,
211 &xshminfo, width, height, dd);
212 if (!xshmpm) {
213 qWarning() << "QNativeImage: Unable to create shared Pixmap.";
214 }
215 }
216}
217
218
219QNativeImage::~QNativeImage()
220{
221 if (!xshmimg)
222 return;
223
224 if (xshmpm) {
225 XFreePixmap(X11->display, xshmpm);
226 xshmpm = 0;
227 }
228 XShmDetach(X11->display, &xshminfo);
229 xshmimg->data = 0;
230 XDestroyImage(xshmimg);
231 xshmimg = 0;
232 shmdt(xshminfo.shmaddr);
233 shmctl(xshminfo.shmid, IPC_RMID, 0);
234}
235
236QImage::Format QNativeImage::systemFormat()
237{
238 if (QX11Info::appDepth() == 16)
239 return QImage::Format_RGB16;
240 return QImage::Format_RGB32;
241}
242
243#elif defined(Q_WS_MAC)
244
245QNativeImage::QNativeImage(int width, int height, QImage::Format format, bool /* isTextBuffer */, QWidget *widget)
246 : image(width, height, format)
247{
248
249 uint cgflags = kCGImageAlphaNoneSkipFirst;
250 switch (format) {
251 case QImage::Format_ARGB32:
252 cgflags = kCGImageAlphaFirst;
253 break;
254 case QImage::Format_ARGB32_Premultiplied:
255 case QImage::Format_ARGB8565_Premultiplied:
256 case QImage::Format_ARGB6666_Premultiplied:
257 case QImage::Format_ARGB8555_Premultiplied:
258 case QImage::Format_ARGB4444_Premultiplied:
259 cgflags = kCGImageAlphaPremultipliedFirst;
260 break;
261 default:
262 break;
263 }
264
265#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
266 cgflags |= kCGBitmapByteOrder32Host;
267#endif
268
269 cg = CGBitmapContextCreate(image.bits(), width, height, 8, image.bytesPerLine(),
270 QCoreGraphicsPaintEngine::macDisplayColorSpace(widget), cgflags);
271 CGContextTranslateCTM(cg, 0, height);
272 CGContextScaleCTM(cg, 1, -1);
273
274 Q_ASSERT(image.paintEngine()->type() == QPaintEngine::Raster);
275 static_cast<QRasterPaintEngine *>(image.paintEngine())->setCGContext(cg);
276}
277
278
279QNativeImage::~QNativeImage()
280{
281 CGContextRelease(cg);
282}
283
284QImage::Format QNativeImage::systemFormat()
285{
286 return QImage::Format_RGB32;
287}
288
289
290#else // other platforms...
291
292QNativeImage::QNativeImage(int width, int height, QImage::Format format, bool /* isTextBuffer */, QWidget *)
293 : image(width, height, format)
294{
295
296}
297
298
299QNativeImage::~QNativeImage()
300{
301}
302
303QImage::Format QNativeImage::systemFormat()
304{
305#ifdef Q_WS_QPA
306 return QApplicationPrivate::platformIntegration()->screens().at(0)->format();
307#else
308 return QImage::Format_RGB32;
309#endif
310}
311
312#endif // platforms
313
314QT_END_NAMESPACE
315
316