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