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
4#include "qpixmap_blitter_p.h"
5
6#include <qpainter.h>
7#include <qimage.h>
8#include <qrandom.h>
9#include <qscreen.h>
10
11#include <private/qguiapplication_p.h>
12#include <private/qblittable_p.h>
13
14#include <private/qdrawhelper_p.h>
15#include <private/qfont_p.h>
16
17#ifndef QT_NO_BLITTABLE
18QT_BEGIN_NAMESPACE
19
20static int global_ser_no = 0;
21
22QBlittablePlatformPixmap::QBlittablePlatformPixmap()
23 : QPlatformPixmap(QPlatformPixmap::PixmapType,BlitterClass)
24 , m_alpha(false)
25 , m_devicePixelRatio(1.0)
26#ifdef QT_BLITTER_RASTEROVERLAY
27 ,m_rasterOverlay(0), m_unmergedCopy(0)
28#endif //QT_BLITTER_RASTEROVERLAY
29{
30 setSerialNumber(++global_ser_no);
31}
32
33QBlittablePlatformPixmap::~QBlittablePlatformPixmap()
34{
35#ifdef QT_BLITTER_RASTEROVERLAY
36 delete m_rasterOverlay;
37 delete m_unmergedCopy;
38#endif //QT_BLITTER_RASTEROVERLAY
39}
40
41QBlittable *QBlittablePlatformPixmap::blittable() const
42{
43 if (!m_blittable) {
44 QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
45 that->m_blittable.reset(other: this->createBlittable(size: QSize(w, h), alpha: m_alpha));
46 }
47
48 return m_blittable.data();
49}
50
51void QBlittablePlatformPixmap::setBlittable(QBlittable *blittable)
52{
53 resize(width: blittable->size().width(),height: blittable->size().height());
54 m_blittable.reset(other: blittable);
55}
56
57void QBlittablePlatformPixmap::resize(int width, int height)
58{
59 m_blittable.reset(other: nullptr);
60 m_engine.reset(other: nullptr);
61 d = QGuiApplication::primaryScreen()->depth();
62 w = width;
63 h = height;
64 is_null = (w <= 0 || h <= 0);
65 setSerialNumber(++global_ser_no);
66}
67
68int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
69{
70 switch (metric) {
71 case QPaintDevice::PdmWidth:
72 return w;
73 case QPaintDevice::PdmHeight:
74 return h;
75 case QPaintDevice::PdmWidthMM:
76 return qRound(d: w * 25.4 / qt_defaultDpiX());
77 case QPaintDevice::PdmHeightMM:
78 return qRound(d: h * 25.4 / qt_defaultDpiY());
79 case QPaintDevice::PdmDepth:
80 return 32;
81 case QPaintDevice::PdmDpiX:
82 case QPaintDevice::PdmPhysicalDpiX:
83 return qt_defaultDpiX();
84 case QPaintDevice::PdmDpiY:
85 case QPaintDevice::PdmPhysicalDpiY:
86 return qt_defaultDpiY();
87 case QPaintDevice::PdmDevicePixelRatio:
88 return devicePixelRatio();
89 case QPaintDevice::PdmDevicePixelRatioScaled:
90 return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
91 case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
92 Q_FALLTHROUGH();
93 case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
94 return QPaintDevice::encodeMetricF(metric, value: devicePixelRatio());
95 default:
96 qWarning(msg: "QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
97 break;
98 }
99
100 return 0;
101}
102
103void QBlittablePlatformPixmap::fill(const QColor &color)
104{
105 if (blittable()->capabilities() & QBlittable::AlphaFillRectCapability) {
106 blittable()->unlock();
107 blittable()->alphaFillRect(rect: QRectF(0,0,w,h),color,cmode: QPainter::CompositionMode_Source);
108 } else if (color.alpha() == 255 && blittable()->capabilities() & QBlittable::SolidRectCapability) {
109 blittable()->unlock();
110 blittable()->fillRect(rect: QRectF(0,0,w,h),color);
111 } else {
112 // Need to be backed with an alpha channel now. It would be nice
113 // if we could just change the format, e.g. when going from
114 // RGB32 -> ARGB8888.
115 if (color.alpha() != 255 && !hasAlphaChannel()) {
116 m_blittable.reset(other: nullptr);
117 m_engine.reset(other: nullptr);
118 m_alpha = true;
119 }
120
121 blittable()->lock()->fill(color);
122 }
123
124}
125
126QImage *QBlittablePlatformPixmap::buffer()
127{
128 return blittable()->lock();
129}
130
131QImage QBlittablePlatformPixmap::toImage() const
132{
133 return blittable()->lock()->copy();
134}
135
136bool QBlittablePlatformPixmap::hasAlphaChannel() const
137{
138 return blittable()->lock()->hasAlphaChannel();
139}
140
141void QBlittablePlatformPixmap::fromImage(const QImage &image,
142 Qt::ImageConversionFlags flags)
143{
144 m_alpha = image.hasAlphaChannel();
145 m_devicePixelRatio = image.devicePixelRatio();
146 resize(width: image.width(),height: image.height());
147 markRasterOverlay(rect: QRect(0,0,w,h));
148 QImage *thisImg = buffer();
149
150 QImage correctFormatPic = image;
151 if (correctFormatPic.format() != thisImg->format())
152 correctFormatPic = correctFormatPic.convertToFormat(f: thisImg->format(), flags);
153
154 uchar *mem = thisImg->bits();
155 const uchar *bits = correctFormatPic.constBits();
156 qsizetype bytesCopied = 0;
157 while (bytesCopied < correctFormatPic.sizeInBytes()) {
158 memcpy(dest: mem,src: bits,n: correctFormatPic.bytesPerLine());
159 mem += thisImg->bytesPerLine();
160 bits += correctFormatPic.bytesPerLine();
161 bytesCopied+=correctFormatPic.bytesPerLine();
162 }
163}
164
165qreal QBlittablePlatformPixmap::devicePixelRatio() const
166{
167 return m_devicePixelRatio;
168}
169
170void QBlittablePlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
171{
172 m_devicePixelRatio = scaleFactor;
173}
174
175QPaintEngine *QBlittablePlatformPixmap::paintEngine() const
176{
177 if (!m_engine) {
178 QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
179 that->m_engine.reset(other: new QBlitterPaintEngine(that));
180 }
181 return m_engine.data();
182}
183
184#ifdef QT_BLITTER_RASTEROVERLAY
185
186static bool showRasterOverlay = !qEnvironmentVariableIsEmpty("QT_BLITTER_RASTEROVERLAY");
187
188void QBlittablePlatformPixmap::mergeOverlay()
189{
190 if (m_unmergedCopy || !showRasterOverlay)
191 return;
192 m_unmergedCopy = new QImage(buffer()->copy());
193 QPainter p(buffer());
194 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
195 p.drawImage(0,0,*overlay());
196 p.end();
197}
198
199void QBlittablePlatformPixmap::unmergeOverlay()
200{
201 if (!m_unmergedCopy || !showRasterOverlay)
202 return;
203 QPainter p(buffer());
204 p.setCompositionMode(QPainter::CompositionMode_Source);
205 p.drawImage(0,0,*m_unmergedCopy);
206 p.end();
207
208 delete m_unmergedCopy;
209 m_unmergedCopy = 0;
210}
211
212QImage *QBlittablePlatformPixmap::overlay()
213{
214 if (!m_rasterOverlay||
215 m_rasterOverlay->size() != QSize(w,h)){
216 m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
217 m_rasterOverlay->fill(0x00000000);
218 uint color = QRandomGenerator::global()->bounded(11)+7;
219 m_overlayColor = QColor(Qt::GlobalColor(color));
220 m_overlayColor.setAlpha(0x88);
221
222 }
223 return m_rasterOverlay;
224}
225
226void QBlittablePlatformPixmap::markRasterOverlayImpl(const QRectF &rect)
227{
228 if (!showRasterOverlay)
229 return;
230 QRectF transformationRect = clipAndTransformRect(rect);
231 if (!transformationRect.isEmpty()) {
232 QPainter p(overlay());
233 p.setBrush(m_overlayColor);
234 p.setCompositionMode(QPainter::CompositionMode_Source);
235 p.fillRect(transformationRect,QBrush(m_overlayColor));
236 }
237}
238
239void QBlittablePlatformPixmap::unmarkRasterOverlayImpl(const QRectF &rect)
240{
241 if (!showRasterOverlay)
242 return;
243 QRectF transformationRect = clipAndTransformRect(rect);
244 if (!transformationRect.isEmpty()) {
245 QPainter p(overlay());
246 QColor color(0x00,0x00,0x00,0x00);
247 p.setBrush(color);
248 p.setCompositionMode(QPainter::CompositionMode_Source);
249 p.fillRect(transformationRect,QBrush(color));
250 }
251}
252
253QRectF QBlittablePlatformPixmap::clipAndTransformRect(const QRectF &rect) const
254{
255 QRectF transformationRect = rect;
256 paintEngine();
257 if (m_engine->state()) {
258 transformationRect = m_engine->state()->matrix.mapRect(rect);
259 const QClipData *clipData = m_engine->clip();
260 if (clipData) {
261 if (clipData->hasRectClip) {
262 transformationRect &= clipData->clipRect;
263 } else if (clipData->hasRegionClip) {
264 for (const QRect &rect : clipData->clipRegion)
265 transformationRect &= rect;
266 }
267 }
268 }
269 return transformationRect;
270}
271
272#endif //QT_BLITTER_RASTEROVERLAY
273
274QT_END_NAMESPACE
275
276#endif //QT_NO_BLITTABLE
277

source code of qtbase/src/gui/image/qpixmap_blitter.cpp