File indexing completed on 2024-05-12 15:56:39

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "KoClipMaskPainter.h"
0008 
0009 #include <QPainter>
0010 #include <QPainterPath>
0011 #include <QRectF>
0012 
0013 #include "kis_assert.h"
0014 
0015 struct Q_DECL_HIDDEN KoClipMaskPainter::Private
0016 {
0017     QPainter *globalPainter;
0018 
0019     QImage shapeImage;
0020     QImage maskImage;
0021 
0022     QPainter shapePainter;
0023     QPainter maskPainter;
0024 
0025     QRect alignedGlobalClipRect;
0026 };
0027 
0028 KoClipMaskPainter::KoClipMaskPainter(QPainter *painter, const QRectF &globalClipRect)
0029     : m_d(new Private)
0030 {
0031     m_d->globalPainter = painter;
0032     m_d->alignedGlobalClipRect = globalClipRect.toAlignedRect();
0033 
0034     m_d->shapeImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
0035     m_d->maskImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
0036 
0037     m_d->shapeImage.fill(0);
0038     m_d->maskImage.fill(0);
0039 
0040     QTransform moveToBufferTransform =
0041         QTransform::fromTranslate(-m_d->alignedGlobalClipRect.x(),
0042                                   -m_d->alignedGlobalClipRect.y());
0043 
0044     m_d->shapePainter.begin(&m_d->shapeImage);
0045     m_d->shapePainter.setTransform(moveToBufferTransform);
0046     m_d->shapePainter.setTransform(painter->transform(), true);
0047     if (painter->hasClipping()) {
0048         m_d->shapePainter.setClipPath(painter->clipPath());
0049     }
0050     m_d->shapePainter.setOpacity(painter->opacity());
0051     m_d->shapePainter.setBrush(painter->brush());
0052     m_d->shapePainter.setPen(painter->pen());
0053 
0054     m_d->maskPainter.begin(&m_d->maskImage);
0055     m_d->maskPainter.setTransform(moveToBufferTransform);
0056     m_d->maskPainter.setTransform(painter->transform(), true);
0057     if (painter->hasClipping()) {
0058         m_d->maskPainter.setClipPath(painter->clipPath());
0059     }
0060     m_d->maskPainter.setOpacity(painter->opacity());
0061     m_d->maskPainter.setBrush(painter->brush());
0062     m_d->maskPainter.setPen(painter->pen());
0063 }
0064 
0065 KoClipMaskPainter::~KoClipMaskPainter()
0066 {
0067 }
0068 
0069 QPainter *KoClipMaskPainter::shapePainter()
0070 {
0071     return &m_d->shapePainter;
0072 }
0073 
0074 QPainter *KoClipMaskPainter::maskPainter()
0075 {
0076     return &m_d->maskPainter;
0077 }
0078 
0079 void KoClipMaskPainter::renderOnGlobalPainter()
0080 {
0081     KIS_ASSERT_RECOVER_RETURN(m_d->maskImage.size() == m_d->shapeImage.size());
0082 
0083     for (int y = 0; y < m_d->maskImage.height(); y++) {
0084         QRgb *shapeData = reinterpret_cast<QRgb*>(m_d->shapeImage.scanLine(y));
0085         QRgb *maskData = reinterpret_cast<QRgb*>(m_d->maskImage.scanLine(y));
0086 
0087         for (int x = 0; x < m_d->maskImage.width(); x++) {
0088 
0089             const qreal normCoeff = 1.0 / 255.0 * 255.0;
0090 
0091             qreal maskValue = qreal(qAlpha(*maskData)) *
0092                 (0.2125 * qRed(*maskData) +
0093                  0.7154 * qGreen(*maskData) +
0094                  0.0721 * qBlue(*maskData));
0095 
0096             int alpha = qRound(maskValue * qAlpha(*shapeData) * normCoeff);
0097 
0098             *shapeData = (alpha << 24) | (*shapeData & 0x00ffffff);
0099 
0100             shapeData++;
0101             maskData++;
0102         }
0103     }
0104 
0105     KIS_ASSERT_RECOVER_RETURN(m_d->shapeImage.size() == m_d->alignedGlobalClipRect.size());
0106     QPainterPath globalClipPath;
0107 
0108     if (m_d->globalPainter->hasClipping()) {
0109         globalClipPath = m_d->globalPainter->transform().map(m_d->globalPainter->clipPath());
0110     }
0111 
0112     m_d->globalPainter->save();
0113 
0114     m_d->globalPainter->setTransform(QTransform());
0115 
0116     if (!globalClipPath.isEmpty()) {
0117         m_d->globalPainter->setClipPath(globalClipPath);
0118     }
0119 
0120     m_d->globalPainter->drawImage(m_d->alignedGlobalClipRect.topLeft(), m_d->shapeImage);
0121     m_d->globalPainter->restore();
0122 }
0123