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

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KOBAKEDSHAPERENDERER_H
0008 #define KOBAKEDSHAPERENDERER_H
0009 
0010 #include <QImage>
0011 #include <QPainter>
0012 #include <QPainterPath>
0013 #include <QTransform>
0014 
0015 #include <kis_debug.h>
0016 #include <kis_algebra_2d.h>
0017 
0018 
0019 struct KoBakedShapeRenderer {
0020     KoBakedShapeRenderer(const QPainterPath &dstShapeOutline, const QTransform &dstShapeTransform,
0021                        const QTransform &bakedTransform,
0022                        const QRectF &referenceRect,
0023                        bool contentIsObb, const QRectF &bakedShapeBoundingRect,
0024                        bool referenceIsObb,
0025                        const QTransform &patternTransform)
0026         : m_dstShapeOutline(dstShapeOutline),
0027           m_dstShapeTransform(dstShapeTransform),
0028           m_contentIsObb(contentIsObb),
0029           m_patternTransform(patternTransform)
0030     {
0031         KIS_SAFE_ASSERT_RECOVER_NOOP(!contentIsObb || !bakedShapeBoundingRect.isEmpty());
0032 
0033         const QRectF dstShapeBoundingRect = dstShapeOutline.boundingRect();
0034 
0035         QTransform relativeToBakedShape;
0036 
0037         if (referenceIsObb || contentIsObb) {
0038             m_relativeToShape = KisAlgebra2D::mapToRect(dstShapeBoundingRect);
0039             relativeToBakedShape = KisAlgebra2D::mapToRect(bakedShapeBoundingRect);
0040         }
0041 
0042 
0043         m_referenceRectUser =
0044             referenceIsObb ?
0045             m_relativeToShape.mapRect(referenceRect).toAlignedRect() :
0046             referenceRect.toAlignedRect();
0047 
0048         m_patch = QImage(m_referenceRectUser.size(), QImage::Format_ARGB32);
0049         m_patch.fill(0);
0050         m_patchPainter.begin(&m_patch);
0051 
0052         m_patchPainter.translate(-m_referenceRectUser.topLeft());
0053         m_patchPainter.setClipRect(m_referenceRectUser);
0054 
0055         if (contentIsObb) {
0056             m_patchPainter.setTransform(m_relativeToShape, true);
0057             m_patchPainter.setTransform(relativeToBakedShape.inverted(), true);
0058         }
0059 
0060         m_patchPainter.setTransform(bakedTransform.inverted(), true);
0061     }
0062 
0063     QPainter* bakeShapePainter() {
0064         return &m_patchPainter;
0065     }
0066 
0067     void renderShape(QPainter &painter) {
0068         painter.save();
0069 
0070         painter.setTransform(m_dstShapeTransform, true);
0071         painter.setClipPath(m_dstShapeOutline);
0072 
0073         QTransform brushTransform;
0074 
0075         QPointF patternOffset = m_referenceRectUser.topLeft();
0076 
0077         brushTransform =
0078             brushTransform *
0079             QTransform::fromTranslate(patternOffset.x(), patternOffset.y());
0080 
0081         if (m_contentIsObb) {
0082             brushTransform = brushTransform * m_relativeToShape.inverted();
0083         }
0084 
0085         brushTransform = brushTransform * m_patternTransform;
0086 
0087         if (m_contentIsObb) {
0088             brushTransform = brushTransform * m_relativeToShape;
0089         }
0090 
0091         QBrush brush(m_patch);
0092         brush.setTransform(brushTransform);
0093 
0094         painter.setBrush(brush);
0095         painter.drawPath(m_dstShapeOutline);
0096 
0097         painter.restore();
0098     }
0099 
0100     QImage patchImage() const {
0101         return m_patch;
0102     }
0103 
0104 
0105 private:
0106     QPainterPath m_dstShapeOutline;
0107     QTransform m_dstShapeTransform;
0108 
0109     bool m_contentIsObb;
0110     const QTransform &m_patternTransform;
0111 
0112     QImage m_patch;
0113     QPainter m_patchPainter;
0114 
0115     QTransform m_relativeToShape;
0116     QRect m_referenceRectUser;
0117 };
0118 
0119 #endif // KOBAKEDSHAPERENDERER_H