Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qpixmap_blitter_p.h"
++
++ #include <qpainter.h>
++ #include <qimage.h>
++ #include <qrandom.h>
++ #include <qscreen.h>
++
++ #include <private/qguiapplication_p.h>
++ #include <private/qblittable_p.h>
++
++ #include <private/qdrawhelper_p.h>
++ #include <private/qfont_p.h>
++
++ #ifndef QT_NO_BLITTABLE
++ QT_BEGIN_NAMESPACE
++
++ static int global_ser_no = 0;
++
++ QBlittablePlatformPixmap::QBlittablePlatformPixmap()
++ : QPlatformPixmap(QPlatformPixmap::PixmapType,BlitterClass)
++ , m_alpha(false)
++ , m_devicePixelRatio(1.0)
++ #ifdef QT_BLITTER_RASTEROVERLAY
++ ,m_rasterOverlay(0), m_unmergedCopy(0)
++ #endif //QT_BLITTER_RASTEROVERLAY
++ {
++ setSerialNumber(++global_ser_no);
++ }
++
++ QBlittablePlatformPixmap::~QBlittablePlatformPixmap()
++ {
++ #ifdef QT_BLITTER_RASTEROVERLAY
++ delete m_rasterOverlay;
++ delete m_unmergedCopy;
++ #endif //QT_BLITTER_RASTEROVERLAY
++ }
++
++ QBlittable *QBlittablePlatformPixmap::blittable() const
++ {
++ if (!m_blittable) {
++ QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
++ that->m_blittable.reset(this->createBlittable(QSize(w, h), m_alpha));
++ }
++
++ return m_blittable.data();
++ }
++
++ void QBlittablePlatformPixmap::setBlittable(QBlittable *blittable)
++ {
++ resize(blittable->size().width(),blittable->size().height());
++ m_blittable.reset(blittable);
++ }
++
++ void QBlittablePlatformPixmap::resize(int width, int height)
++ {
++ m_blittable.reset(nullptr);
++ m_engine.reset(nullptr);
++ d = QGuiApplication::primaryScreen()->depth();
++ w = width;
++ h = height;
++ is_null = (w <= 0 || h <= 0);
++ setSerialNumber(++global_ser_no);
++ }
++
++ int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
++ {
++ switch (metric) {
++ case QPaintDevice::PdmWidth:
++ return w;
++ case QPaintDevice::PdmHeight:
++ return h;
++ case QPaintDevice::PdmWidthMM:
++ return qRound(w * 25.4 / qt_defaultDpiX());
++ case QPaintDevice::PdmHeightMM:
++ return qRound(h * 25.4 / qt_defaultDpiY());
++ case QPaintDevice::PdmDepth:
++ return 32;
++ case QPaintDevice::PdmDpiX:
++ case QPaintDevice::PdmPhysicalDpiX:
++ return qt_defaultDpiX();
++ case QPaintDevice::PdmDpiY:
++ case QPaintDevice::PdmPhysicalDpiY:
++ return qt_defaultDpiY();
++ case QPaintDevice::PdmDevicePixelRatio:
++ return devicePixelRatio();
++ case QPaintDevice::PdmDevicePixelRatioScaled:
++ return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
++ case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
++ Q_FALLTHROUGH();
++ case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
++ return QPaintDevice::encodeMetricF(metric, devicePixelRatio());
++ default:
++ qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
++ break;
++ }
++
++ return 0;
++ }
++
++ void QBlittablePlatformPixmap::fill(const QColor &color)
++ {
++ if (blittable()->capabilities() & QBlittable::AlphaFillRectCapability) {
++ blittable()->unlock();
++ blittable()->alphaFillRect(QRectF(0,0,w,h),color,QPainter::CompositionMode_Source);
++ } else if (color.alpha() == 255 && blittable()->capabilities() & QBlittable::SolidRectCapability) {
++ blittable()->unlock();
++ blittable()->fillRect(QRectF(0,0,w,h),color);
++ } else {
++ // Need to be backed with an alpha channel now. It would be nice
++ // if we could just change the format, e.g. when going from
++ // RGB32 -> ARGB8888.
++ if (color.alpha() != 255 && !hasAlphaChannel()) {
++ m_blittable.reset(nullptr);
++ m_engine.reset(nullptr);
++ m_alpha = true;
++ }
++
++ blittable()->lock()->fill(color);
++ }
++
++ }
++
++ QImage *QBlittablePlatformPixmap::buffer()
++ {
++ return blittable()->lock();
++ }
++
++ QImage QBlittablePlatformPixmap::toImage() const
++ {
++ return blittable()->lock()->copy();
++ }
++
++ bool QBlittablePlatformPixmap::hasAlphaChannel() const
++ {
++ return blittable()->lock()->hasAlphaChannel();
++ }
++
++ void QBlittablePlatformPixmap::fromImage(const QImage &image,
++ Qt::ImageConversionFlags flags)
++ {
++ m_alpha = image.hasAlphaChannel();
++ m_devicePixelRatio = image.devicePixelRatio();
++ resize(image.width(),image.height());
++ markRasterOverlay(QRect(0,0,w,h));
++ QImage *thisImg = buffer();
++
++ QImage correctFormatPic = image;
++ if (correctFormatPic.format() != thisImg->format())
++ correctFormatPic = correctFormatPic.convertToFormat(thisImg->format(), flags);
++
++ uchar *mem = thisImg->bits();
++ const uchar *bits = correctFormatPic.constBits();
++ qsizetype bytesCopied = 0;
++ while (bytesCopied < correctFormatPic.sizeInBytes()) {
++ memcpy(mem,bits,correctFormatPic.bytesPerLine());
++ mem += thisImg->bytesPerLine();
++ bits += correctFormatPic.bytesPerLine();
++ bytesCopied+=correctFormatPic.bytesPerLine();
++ }
++ }
++
++ qreal QBlittablePlatformPixmap::devicePixelRatio() const
++ {
++ return m_devicePixelRatio;
++ }
++
++ void QBlittablePlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
++ {
++ m_devicePixelRatio = scaleFactor;
++ }
++
++ QPaintEngine *QBlittablePlatformPixmap::paintEngine() const
++ {
++ if (!m_engine) {
++ QBlittablePlatformPixmap *that = const_cast<QBlittablePlatformPixmap *>(this);
++ that->m_engine.reset(new QBlitterPaintEngine(that));
++ }
++ return m_engine.data();
++ }
++
++ #ifdef QT_BLITTER_RASTEROVERLAY
++
++ static bool showRasterOverlay = !qEnvironmentVariableIsEmpty("QT_BLITTER_RASTEROVERLAY");
++
++ void QBlittablePlatformPixmap::mergeOverlay()
++ {
++ if (m_unmergedCopy || !showRasterOverlay)
++ return;
++ m_unmergedCopy = new QImage(buffer()->copy());
++ QPainter p(buffer());
++ p.setCompositionMode(QPainter::CompositionMode_SourceOver);
++ p.drawImage(0,0,*overlay());
++ p.end();
++ }
++
++ void QBlittablePlatformPixmap::unmergeOverlay()
++ {
++ if (!m_unmergedCopy || !showRasterOverlay)
++ return;
++ QPainter p(buffer());
++ p.setCompositionMode(QPainter::CompositionMode_Source);
++ p.drawImage(0,0,*m_unmergedCopy);
++ p.end();
++
++ delete m_unmergedCopy;
++ m_unmergedCopy = 0;
++ }
++
++ QImage *QBlittablePlatformPixmap::overlay()
++ {
++ if (!m_rasterOverlay||
++ m_rasterOverlay->size() != QSize(w,h)){
++ m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
++ m_rasterOverlay->fill(0x00000000);
++ uint color = QRandomGenerator::global()->bounded(11)+7;
++ m_overlayColor = QColor(Qt::GlobalColor(color));
++ m_overlayColor.setAlpha(0x88);
++
++ }
++ return m_rasterOverlay;
++ }
++
++ void QBlittablePlatformPixmap::markRasterOverlayImpl(const QRectF &rect)
++ {
++ if (!showRasterOverlay)
++ return;
++ QRectF transformationRect = clipAndTransformRect(rect);
++ if (!transformationRect.isEmpty()) {
++ QPainter p(overlay());
++ p.setBrush(m_overlayColor);
++ p.setCompositionMode(QPainter::CompositionMode_Source);
++ p.fillRect(transformationRect,QBrush(m_overlayColor));
++ }
++ }
++
++ void QBlittablePlatformPixmap::unmarkRasterOverlayImpl(const QRectF &rect)
++ {
++ if (!showRasterOverlay)
++ return;
++ QRectF transformationRect = clipAndTransformRect(rect);
++ if (!transformationRect.isEmpty()) {
++ QPainter p(overlay());
++ QColor color(0x00,0x00,0x00,0x00);
++ p.setBrush(color);
++ p.setCompositionMode(QPainter::CompositionMode_Source);
++ p.fillRect(transformationRect,QBrush(color));
++ }
++ }
++
++ QRectF QBlittablePlatformPixmap::clipAndTransformRect(const QRectF &rect) const
++ {
++ QRectF transformationRect = rect;
++ paintEngine();
++ if (m_engine->state()) {
++ transformationRect = m_engine->state()->matrix.mapRect(rect);
++ const QClipData *clipData = m_engine->clip();
++ if (clipData) {
++ if (clipData->hasRectClip) {
++ transformationRect &= clipData->clipRect;
++ } else if (clipData->hasRegionClip) {
++ for (const QRect &rect : clipData->clipRegion)
++ transformationRect &= rect;
++ }
++ }
++ }
++ return transformationRect;
++ }
++
++ #endif //QT_BLITTER_RASTEROVERLAY
++
++ QT_END_NAMESPACE
++
++ #endif //QT_NO_BLITTABLE