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
54 QT_BEGIN_NAMESPACE
55
56 static int global_ser_no = 0;
57
QBlittablePlatformPixmap()58 QBlittablePlatformPixmap::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
~QBlittablePlatformPixmap()69 QBlittablePlatformPixmap::~QBlittablePlatformPixmap()
70 {
71 #ifdef QT_BLITTER_RASTEROVERLAY
72 delete m_rasterOverlay;
73 delete m_unmergedCopy;
74 #endif //QT_BLITTER_RASTEROVERLAY
75 }
76
blittable() const77 QBlittable *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
setBlittable(QBlittable * blittable)87 void QBlittablePlatformPixmap::setBlittable(QBlittable *blittable)
88 {
89 resize(blittable->size().width(),blittable->size().height());
90 m_blittable.reset(blittable);
91 }
92
resize(int width,int height)93 void QBlittablePlatformPixmap::resize(int width, int height)
94 {
95 m_blittable.reset(nullptr);
96 m_engine.reset(nullptr);
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
metric(QPaintDevice::PaintDeviceMetric metric) const104 int 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
fill(const QColor & color)135 void 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(nullptr);
149 m_engine.reset(nullptr);
150 m_alpha = true;
151 }
152
153 blittable()->lock()->fill(color);
154 }
155
156 }
157
buffer()158 QImage *QBlittablePlatformPixmap::buffer()
159 {
160 return blittable()->lock();
161 }
162
toImage() const163 QImage QBlittablePlatformPixmap::toImage() const
164 {
165 return blittable()->lock()->copy();
166 }
167
hasAlphaChannel() const168 bool QBlittablePlatformPixmap::hasAlphaChannel() const
169 {
170 return blittable()->lock()->hasAlphaChannel();
171 }
172
fromImage(const QImage & image,Qt::ImageConversionFlags flags)173 void 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
devicePixelRatio() const197 qreal QBlittablePlatformPixmap::devicePixelRatio() const
198 {
199 return m_devicePixelRatio;
200 }
201
setDevicePixelRatio(qreal scaleFactor)202 void QBlittablePlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
203 {
204 m_devicePixelRatio = scaleFactor;
205 }
206
paintEngine() const207 QPaintEngine *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
218 static bool showRasterOverlay = !qEnvironmentVariableIsEmpty("QT_BLITTER_RASTEROVERLAY");
219
mergeOverlay()220 void 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
unmergeOverlay()231 void 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
overlay()244 QImage *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
markRasterOverlayImpl(const QRectF & rect)258 void 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
unmarkRasterOverlayImpl(const QRectF & rect)271 void 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
clipAndTransformRect(const QRectF & rect) const285 QRectF 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
306 QT_END_NAMESPACE
307
308 #endif //QT_NO_BLITTABLE
309