1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qpixmap_blitter_p.h"
41
42#include <qpainter.h>
43#include <qimage.h>
44#include <qrandom.h>
45#include <qscreen.h>
46
47#include <private/qguiapplication_p.h>
48#include <private/qblittable_p.h>
49
50#include <private/qdrawhelper_p.h>
51#include <private/qfont_p.h>
52
53#ifndef QT_NO_BLITTABLE
54QT_BEGIN_NAMESPACE
55
56static int global_ser_no = 0;
57
58QBlittablePlatformPixmap::QBlittablePlatformPixmap()
59 : QPlatformPixmap(QPlatformPixmap::PixmapType,BlitterClass)
60 , m_alpha(false)
61 , m_devicePixelRatio(1.0)
62#ifdef QT_BLITTER_RASTEROVERLAY
63 ,m_rasterOverlay(0), m_unmergedCopy(0)
64#endif //QT_BLITTER_RASTEROVERLAY
65{
66 setSerialNumber(++global_ser_no);
67}
68
69QBlittablePlatformPixmap::~QBlittablePlatformPixmap()
70{
71#ifdef QT_BLITTER_RASTEROVERLAY
72 delete m_rasterOverlay;
73 delete m_unmergedCopy;
74#endif //QT_BLITTER_RASTEROVERLAY
75}
76
77QBlittable *QBlittablePlatformPixmap::blittable() const
78{
79 if (!m_blittable) {
80 QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
81 that->m_blittable.reset(this->createBlittable(QSize(w, h), m_alpha));
82 }
83
84 return m_blittable.data();
85}
86
87void QBlittablePlatformPixmap::setBlittable(QBlittable *blittable)
88{
89 resize(blittable->size().width(),blittable->size().height());
90 m_blittable.reset(blittable);
91}
92
93void QBlittablePlatformPixmap::resize(int width, int height)
94{
95 m_blittable.reset(0);
96 m_engine.reset(0);
97 d = QGuiApplication::primaryScreen()->depth();
98 w = width;
99 h = height;
100 is_null = (w <= 0 || h <= 0);
101 setSerialNumber(++global_ser_no);
102}
103
104int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
105{
106 switch (metric) {
107 case QPaintDevice::PdmWidth:
108 return w;
109 case QPaintDevice::PdmHeight:
110 return h;
111 case QPaintDevice::PdmWidthMM:
112 return qRound(w * 25.4 / qt_defaultDpiX());
113 case QPaintDevice::PdmHeightMM:
114 return qRound(h * 25.4 / qt_defaultDpiY());
115 case QPaintDevice::PdmDepth:
116 return 32;
117 case QPaintDevice::PdmDpiX:
118 case QPaintDevice::PdmPhysicalDpiX:
119 return qt_defaultDpiX();
120 case QPaintDevice::PdmDpiY:
121 case QPaintDevice::PdmPhysicalDpiY:
122 return qt_defaultDpiY();
123 case QPaintDevice::PdmDevicePixelRatio:
124 return devicePixelRatio();
125 case QPaintDevice::PdmDevicePixelRatioScaled:
126 return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
127 default:
128 qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
129 break;
130 }
131
132 return 0;
133}
134
135void QBlittablePlatformPixmap::fill(const QColor &color)
136{
137 if (blittable()->capabilities() & QBlittable::AlphaFillRectCapability) {
138 blittable()->unlock();
139 blittable()->alphaFillRect(QRectF(0,0,w,h),color,QPainter::CompositionMode_Source);
140 } else if (color.alpha() == 255 && blittable()->capabilities() & QBlittable::SolidRectCapability) {
141 blittable()->unlock();
142 blittable()->fillRect(QRectF(0,0,w,h),color);
143 } else {
144 // Need to be backed with an alpha channel now. It would be nice
145 // if we could just change the format, e.g. when going from
146 // RGB32 -> ARGB8888.
147 if (color.alpha() != 255 && !hasAlphaChannel()) {
148 m_blittable.reset(0);
149 m_engine.reset(0);
150 m_alpha = true;
151 }
152
153 blittable()->lock()->fill(color);
154 }
155
156}
157
158QImage *QBlittablePlatformPixmap::buffer()
159{
160 return blittable()->lock();
161}
162
163QImage QBlittablePlatformPixmap::toImage() const
164{
165 return blittable()->lock()->copy();
166}
167
168bool QBlittablePlatformPixmap::hasAlphaChannel() const
169{
170 return blittable()->lock()->hasAlphaChannel();
171}
172
173void QBlittablePlatformPixmap::fromImage(const QImage &image,
174 Qt::ImageConversionFlags flags)
175{
176 m_alpha = image.hasAlphaChannel();
177 m_devicePixelRatio = image.devicePixelRatio();
178 resize(image.width(),image.height());
179 markRasterOverlay(QRect(0,0,w,h));
180 QImage *thisImg = buffer();
181
182 QImage correctFormatPic = image;
183 if (correctFormatPic.format() != thisImg->format())
184 correctFormatPic = correctFormatPic.convertToFormat(thisImg->format(), flags);
185
186 uchar *mem = thisImg->bits();
187 const uchar *bits = correctFormatPic.constBits();
188 qsizetype bytesCopied = 0;
189 while (bytesCopied < correctFormatPic.sizeInBytes()) {
190 memcpy(mem,bits,correctFormatPic.bytesPerLine());
191 mem += thisImg->bytesPerLine();
192 bits += correctFormatPic.bytesPerLine();
193 bytesCopied+=correctFormatPic.bytesPerLine();
194 }
195}
196
197qreal QBlittablePlatformPixmap::devicePixelRatio() const
198{
199 return m_devicePixelRatio;
200}
201
202void QBlittablePlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
203{
204 m_devicePixelRatio = scaleFactor;
205}
206
207QPaintEngine *QBlittablePlatformPixmap::paintEngine() const
208{
209 if (!m_engine) {
210 QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
211 that->m_engine.reset(new QBlitterPaintEngine(that));
212 }
213 return m_engine.data();
214}
215
216#ifdef QT_BLITTER_RASTEROVERLAY
217
218static bool showRasterOverlay = !qEnvironmentVariableIsEmpty("QT_BLITTER_RASTEROVERLAY");
219
220void QBlittablePlatformPixmap::mergeOverlay()
221{
222 if (m_unmergedCopy || !showRasterOverlay)
223 return;
224 m_unmergedCopy = new QImage(buffer()->copy());
225 QPainter p(buffer());
226 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
227 p.drawImage(0,0,*overlay());
228 p.end();
229}
230
231void QBlittablePlatformPixmap::unmergeOverlay()
232{
233 if (!m_unmergedCopy || !showRasterOverlay)
234 return;
235 QPainter p(buffer());
236 p.setCompositionMode(QPainter::CompositionMode_Source);
237 p.drawImage(0,0,*m_unmergedCopy);
238 p.end();
239
240 delete m_unmergedCopy;
241 m_unmergedCopy = 0;
242}
243
244QImage *QBlittablePlatformPixmap::overlay()
245{
246 if (!m_rasterOverlay||
247 m_rasterOverlay->size() != QSize(w,h)){
248 m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
249 m_rasterOverlay->fill(0x00000000);
250 uint color = QRandomGenerator::global()->bounded(11)+7;
251 m_overlayColor = QColor(Qt::GlobalColor(color));
252 m_overlayColor.setAlpha(0x88);
253
254 }
255 return m_rasterOverlay;
256}
257
258void QBlittablePlatformPixmap::markRasterOverlayImpl(const QRectF &rect)
259{
260 if (!showRasterOverlay)
261 return;
262 QRectF transformationRect = clipAndTransformRect(rect);
263 if(!transformationRect.isEmpty()) {
264 QPainter p(overlay());
265 p.setBrush(m_overlayColor);
266 p.setCompositionMode(QPainter::CompositionMode_Source);
267 p.fillRect(transformationRect,QBrush(m_overlayColor));
268 }
269}
270
271void QBlittablePlatformPixmap::unmarkRasterOverlayImpl(const QRectF &rect)
272{
273 if (!showRasterOverlay)
274 return;
275 QRectF transformationRect = clipAndTransformRect(rect);
276 if (!transformationRect.isEmpty()) {
277 QPainter p(overlay());
278 QColor color(0x00,0x00,0x00,0x00);
279 p.setBrush(color);
280 p.setCompositionMode(QPainter::CompositionMode_Source);
281 p.fillRect(transformationRect,QBrush(color));
282 }
283}
284
285QRectF QBlittablePlatformPixmap::clipAndTransformRect(const QRectF &rect) const
286{
287 QRectF transformationRect = rect;
288 paintEngine();
289 if (m_engine->state()) {
290 transformationRect = m_engine->state()->matrix.mapRect(rect);
291 const QClipData *clipData = m_engine->clip();
292 if (clipData) {
293 if (clipData->hasRectClip) {
294 transformationRect &= clipData->clipRect;
295 } else if (clipData->hasRegionClip) {
296 for (const QRect &rect : clipData->clipRegion)
297 transformationRect &= rect;
298 }
299 }
300 }
301 return transformationRect;
302}
303
304#endif //QT_BLITTER_RASTEROVERLAY
305
306QT_END_NAMESPACE
307
308#endif //QT_NO_BLITTABLE
309