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 "KoClipMask.h" 0008 0009 #include <QRectF> 0010 #include <QTransform> 0011 #include <QPainter> 0012 #include <QSharedData> 0013 #include <QPainterPath> 0014 #include <KoShape.h> 0015 #include "kis_algebra_2d.h" 0016 0017 #include <KoShapePainter.h> 0018 0019 struct Q_DECL_HIDDEN KoClipMask::Private : public QSharedData 0020 { 0021 Private() 0022 : QSharedData() 0023 {} 0024 0025 Private(const Private &rhs) 0026 : QSharedData() 0027 , coordinates(rhs.coordinates) 0028 , contentCoordinates(rhs.contentCoordinates) 0029 , maskRect(rhs.maskRect) 0030 , extraShapeTransform(rhs.extraShapeTransform) 0031 { 0032 Q_FOREACH (KoShape *shape, rhs.shapes) { 0033 KoShape *clonedShape = shape->cloneShape(); 0034 KIS_ASSERT_RECOVER(clonedShape) { continue; } 0035 0036 shapes << clonedShape; 0037 } 0038 } 0039 0040 ~Private() { 0041 qDeleteAll(shapes); 0042 shapes.clear(); 0043 } 0044 0045 0046 KoFlake::CoordinateSystem coordinates = KoFlake::ObjectBoundingBox; 0047 KoFlake::CoordinateSystem contentCoordinates = KoFlake::UserSpaceOnUse; 0048 0049 QRectF maskRect = QRectF(-0.1, -0.1, 1.2, 1.2); 0050 0051 QList<KoShape*> shapes; 0052 QTransform extraShapeTransform; // TODO: not used anymore, use direct shape transform instead 0053 0054 }; 0055 0056 KoClipMask::KoClipMask() 0057 : m_d(new Private) 0058 { 0059 } 0060 0061 KoClipMask::~KoClipMask() 0062 { 0063 } 0064 0065 KoClipMask::KoClipMask(const KoClipMask &rhs) 0066 : m_d(new Private(*rhs.m_d)) 0067 { 0068 } 0069 0070 KoClipMask &KoClipMask::operator=(const KoClipMask &rhs) 0071 { 0072 m_d = rhs.m_d; 0073 return *this; 0074 } 0075 0076 KoClipMask *KoClipMask::clone() const 0077 { 0078 return new KoClipMask(*this); 0079 } 0080 0081 KoFlake::CoordinateSystem KoClipMask::coordinates() const 0082 { 0083 return m_d->coordinates; 0084 } 0085 0086 void KoClipMask::setCoordinates(KoFlake::CoordinateSystem value) 0087 { 0088 m_d->coordinates = value; 0089 } 0090 0091 KoFlake::CoordinateSystem KoClipMask::contentCoordinates() const 0092 { 0093 return m_d->contentCoordinates; 0094 } 0095 0096 void KoClipMask::setContentCoordinates(KoFlake::CoordinateSystem value) 0097 { 0098 m_d->contentCoordinates = value; 0099 } 0100 0101 QRectF KoClipMask::maskRect() const 0102 { 0103 return m_d->maskRect; 0104 } 0105 0106 void KoClipMask::setMaskRect(const QRectF &value) 0107 { 0108 m_d->maskRect = value; 0109 } 0110 0111 QList<KoShape *> KoClipMask::shapes() const 0112 { 0113 return m_d->shapes; 0114 } 0115 0116 void KoClipMask::setShapes(const QList<KoShape *> &value) 0117 { 0118 m_d->shapes = value; 0119 } 0120 0121 bool KoClipMask::isEmpty() const 0122 { 0123 return m_d->shapes.isEmpty(); 0124 } 0125 0126 void KoClipMask::setExtraShapeOffset(const QPointF &value) 0127 { 0128 /** 0129 * TODO: when we implement source shapes sharing, please wrap the shapes 0130 * into a group and apply this transform to the group instead 0131 */ 0132 0133 if (m_d->contentCoordinates == KoFlake::UserSpaceOnUse) { 0134 const QTransform t = QTransform::fromTranslate(value.x(), value.y()); 0135 0136 Q_FOREACH (KoShape *shape, m_d->shapes) { 0137 shape->applyAbsoluteTransformation(t); 0138 } 0139 } 0140 0141 if (m_d->coordinates == KoFlake::UserSpaceOnUse) { 0142 m_d->maskRect.translate(value); 0143 } 0144 } 0145 0146 void KoClipMask::drawMask(QPainter *painter, KoShape *shape) 0147 { 0148 painter->save(); 0149 0150 QPainterPath clipPathInShapeSpace; 0151 0152 if (m_d->coordinates == KoFlake::ObjectBoundingBox) { 0153 QTransform relativeToShape = KisAlgebra2D::mapToRect(shape->outlineRect()); 0154 clipPathInShapeSpace.addPolygon(relativeToShape.map(m_d->maskRect)); 0155 } else { 0156 clipPathInShapeSpace.addRect(m_d->maskRect); 0157 clipPathInShapeSpace = m_d->extraShapeTransform.map(clipPathInShapeSpace); 0158 } 0159 0160 painter->setClipPath(clipPathInShapeSpace, Qt::IntersectClip); 0161 0162 if (m_d->contentCoordinates == KoFlake::ObjectBoundingBox) { 0163 QTransform relativeToShape = KisAlgebra2D::mapToRect(shape->outlineRect()); 0164 0165 painter->setTransform(relativeToShape, true); 0166 } else { 0167 painter->setTransform(m_d->extraShapeTransform, true); 0168 } 0169 0170 KoShapePainter p; 0171 p.setShapes(m_d->shapes); 0172 p.paint(*painter); 0173 0174 painter->restore(); 0175 }