File indexing completed on 2024-05-19 04:24:55

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2006 C. Boemann Rasmussen <cbo@boemann.dk>
0003    SPDX-FileCopyrightText: 2006-2010 Thomas Zander <zander@kde.org>
0004    SPDX-FileCopyrightText: 2006-2010 Thorsten Zachmann <zachmann@kde.org>
0005    SPDX-FileCopyrightText: 2007-2009, 2011 Jan Hambrecht <jaham@gmx.net>
0006    SPDX-FileCopyrightText: 2010 Boudewijn Rempt <boud@valdyas.org>
0007 
0008    SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 #include <limits>
0012 
0013 #include "KoShape.h"
0014 #include "KoShape_p.h"
0015 #include "KoShapeContainer.h"
0016 #include "KoShapeLayer.h"
0017 #include "KoShapeContainerModel.h"
0018 #include "KoSelection.h"
0019 #include "KoPointerEvent.h"
0020 #include "KoInsets.h"
0021 #include "KoShapeStrokeModel.h"
0022 #include "KoShapeBackground.h"
0023 #include "KoColorBackground.h"
0024 #include "KoHatchBackground.h"
0025 #include "KoGradientBackground.h"
0026 #include "KoPatternBackground.h"
0027 #include "KoShapeManager.h"
0028 #include "KoShapeUserData.h"
0029 #include "KoShapeApplicationData.h"
0030 #include "KoShapeSavingContext.h"
0031 #include "KoShapeLoadingContext.h"
0032 #include "KoViewConverter.h"
0033 #include "KoShapeStroke.h"
0034 #include "KoShapeShadow.h"
0035 #include "KoClipPath.h"
0036 #include "KoPathShape.h"
0037 #include "KoFilterEffectStack.h"
0038 #include <KoSnapData.h>
0039 
0040 #include <KoXmlWriter.h>
0041 #include <KoXmlNS.h>
0042 #include <KoUnit.h>
0043 
0044 #include <QPainter>
0045 #include <QVariant>
0046 #include <QPainterPath>
0047 #include <QList>
0048 #include <QMap>
0049 #include <QByteArray>
0050 #include <FlakeDebug.h>
0051 
0052 #include "kis_assert.h"
0053 
0054 #include <KisHandlePainterHelper.h>
0055 
0056 // KoShape::Private
0057 
0058 KoShape::SharedData::SharedData()
0059     : QSharedData()
0060     , size(50, 50)
0061     , shadow(0)
0062     , filterEffectStack(0)
0063     , transparency(0.0)
0064     , zIndex(0)
0065     , runThrough(0)
0066     , visible(true)
0067     , printable(true)
0068     , geometryProtected(false)
0069     , keepAspect(false)
0070     , selectable(true)
0071     , protectContent(false)
0072     , textRunAroundSide(KoShape::BiggestRunAroundSide)
0073     , textRunAroundDistanceLeft(0.0)
0074     , textRunAroundDistanceTop(0.0)
0075     , textRunAroundDistanceRight(0.0)
0076     , textRunAroundDistanceBottom(0.0)
0077     , textRunAroundThreshold(0.0)
0078     , textRunAroundContour(KoShape::ContourFull)
0079     , paintOrder(QVector<PaintOrder>({Fill, Stroke, Markers}))
0080     , inheritPaintOrder(true)
0081 { }
0082 
0083 KoShape::SharedData::SharedData(const SharedData &rhs)
0084     : QSharedData()
0085     , size(rhs.size)
0086     , shapeId(rhs.shapeId)
0087     , name(rhs.name)
0088     , localMatrix(rhs.localMatrix)
0089     , userData(rhs.userData ? rhs.userData->clone() : 0)
0090     , stroke(rhs.stroke)
0091     , fill(rhs.fill)
0092     , inheritBackground(rhs.inheritBackground)
0093     , inheritStroke(rhs.inheritStroke)
0094     , shadow(0) // WARNING: not implemented in Krita
0095     , clipPath(rhs.clipPath ? rhs.clipPath->clone() : 0)
0096     , clipMask(rhs.clipMask ? rhs.clipMask->clone() : 0)
0097     , additionalAttributes(rhs.additionalAttributes)
0098     , additionalStyleAttributes(rhs.additionalStyleAttributes)
0099     , filterEffectStack(0) // WARNING: not implemented in Krita
0100     , transparency(rhs.transparency)
0101     , hyperLink(rhs.hyperLink)
0102 
0103     , zIndex(rhs.zIndex)
0104     , runThrough(rhs.runThrough)
0105     , visible(rhs.visible)
0106     , printable(rhs.visible)
0107     , geometryProtected(rhs.geometryProtected)
0108     , keepAspect(rhs.keepAspect)
0109     , selectable(rhs.selectable)
0110     , protectContent(rhs.protectContent)
0111 
0112     , textRunAroundSide(rhs.textRunAroundSide)
0113     , textRunAroundDistanceLeft(rhs.textRunAroundDistanceLeft)
0114     , textRunAroundDistanceTop(rhs.textRunAroundDistanceTop)
0115     , textRunAroundDistanceRight(rhs.textRunAroundDistanceRight)
0116     , textRunAroundDistanceBottom(rhs.textRunAroundDistanceBottom)
0117     , textRunAroundThreshold(rhs.textRunAroundThreshold)
0118     , textRunAroundContour(rhs.textRunAroundContour)
0119 
0120     , paintOrder(rhs.paintOrder)
0121     , inheritPaintOrder(rhs.inheritPaintOrder)
0122 {
0123 }
0124 
0125 KoShape::SharedData::~SharedData()
0126 {
0127     if (shadow && !shadow->deref())
0128         delete shadow;
0129     if (filterEffectStack && !filterEffectStack->deref())
0130         delete filterEffectStack;
0131 }
0132 
0133 void KoShape::shapeChangedPriv(KoShape::ChangeType type)
0134 {
0135     if (d->parent)
0136         d->parent->model()->childChanged(this, type);
0137 
0138     this->shapeChanged(type);
0139 
0140     Q_FOREACH (KoShape * shape, d->dependees) {
0141         shape->shapeChanged(type, this);
0142     }
0143 
0144     Q_FOREACH (KoShape::ShapeChangeListener *listener, d->listeners) {
0145         listener->notifyShapeChangedImpl(type, this);
0146     }
0147 }
0148 
0149 void KoShape::addShapeManager(KoShapeManager *manager)
0150 {
0151     d->shapeManagers.insert(manager);
0152 }
0153 
0154 void KoShape::removeShapeManager(KoShapeManager *manager)
0155 {
0156     d->shapeManagers.remove(manager);
0157 }
0158 
0159 // ======== KoShape
0160 
0161 const qint16 KoShape::maxZIndex = std::numeric_limits<qint16>::max();
0162 const qint16 KoShape::minZIndex = std::numeric_limits<qint16>::min();
0163 
0164 KoShape::KoShape()
0165     : d(new Private()),
0166       s(new SharedData)
0167 {
0168     notifyChanged();
0169 }
0170 
0171 KoShape::KoShape(const KoShape &rhs)
0172     : d(new Private()),
0173       s(rhs.s)
0174 {
0175 }
0176 
0177 KoShape::~KoShape()
0178 {
0179     shapeChangedPriv(Deleted);
0180     d->listeners.clear();
0181     /**
0182      * The shape must have already been detached from all the parents and
0183      * shape managers. Otherwise we might accidentally request some RTTI
0184      * information, which is not available anymore (we are in d-tor).
0185      *
0186      * TL;DR: fix the code that caused this destruction without unparenting
0187      *        instead of trying to remove these assert!
0188      */
0189     KIS_SAFE_ASSERT_RECOVER (!d->parent) {
0190         d->parent->removeShape(this);
0191     }
0192 
0193     KIS_SAFE_ASSERT_RECOVER (d->shapeManagers.isEmpty()) {
0194         Q_FOREACH (KoShapeManager *manager, d->shapeManagers) {
0195             manager->shapeInterface()->notifyShapeDestructed(this);
0196         }
0197         d->shapeManagers.clear();
0198     }
0199 }
0200 
0201 KoShape *KoShape::cloneShape() const
0202 {
0203     KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "not implemented!");
0204     qWarning() << shapeId() << "cannot be cloned";
0205     return 0;
0206 }
0207 
0208 KoShape *KoShape::cloneShapeAndBakeAbsoluteTransform() const
0209 {
0210     KoShape *clonedShape = this->cloneShape();
0211 
0212     /**
0213      * The shape is cloned without its parent's transformation, so we should
0214      * adjust it manually.
0215      */
0216     KoShape *oldParentShape = this->parent();
0217     if (oldParentShape && !oldParentShape->absoluteTransformation().isIdentity()) {
0218         clonedShape->applyAbsoluteTransformation(oldParentShape->absoluteTransformation());
0219     }
0220 
0221     return clonedShape;
0222 }
0223 
0224 void KoShape::paintStroke(QPainter &painter) const
0225 {
0226     if (stroke()) {
0227         stroke()->paint(this, painter);
0228     }
0229 }
0230 
0231 void KoShape::paintMarkers(QPainter &painter) const
0232 {
0233     if (stroke()) {
0234         stroke()->paintMarkers(this, painter);
0235     }
0236 }
0237 
0238 void KoShape::scale(qreal sx, qreal sy)
0239 {
0240     QPointF pos = position();
0241     QTransform scaleMatrix;
0242     scaleMatrix.translate(pos.x(), pos.y());
0243     scaleMatrix.scale(sx, sy);
0244     scaleMatrix.translate(-pos.x(), -pos.y());
0245     s->localMatrix = s->localMatrix * scaleMatrix;
0246 
0247     notifyChanged();
0248     shapeChangedPriv(ScaleChanged);
0249 }
0250 
0251 void KoShape::rotate(qreal angle)
0252 {
0253     QPointF center = s->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
0254     QTransform rotateMatrix;
0255     rotateMatrix.translate(center.x(), center.y());
0256     rotateMatrix.rotate(angle);
0257     rotateMatrix.translate(-center.x(), -center.y());
0258     s->localMatrix = s->localMatrix * rotateMatrix;
0259 
0260     notifyChanged();
0261     shapeChangedPriv(RotationChanged);
0262 }
0263 
0264 void KoShape::shear(qreal sx, qreal sy)
0265 {
0266     QPointF pos = position();
0267     QTransform shearMatrix;
0268     shearMatrix.translate(pos.x(), pos.y());
0269     shearMatrix.shear(sx, sy);
0270     shearMatrix.translate(-pos.x(), -pos.y());
0271     s->localMatrix = s->localMatrix * shearMatrix;
0272 
0273     notifyChanged();
0274     shapeChangedPriv(ShearChanged);
0275 }
0276 
0277 void KoShape::setSize(const QSizeF &newSize)
0278 {
0279     QSizeF oldSize(size());
0280 
0281     // always set size, as d->size and size() may vary
0282     setSizeImpl(newSize);
0283 
0284     if (oldSize == newSize)
0285         return;
0286 
0287     notifyChanged();
0288     shapeChangedPriv(SizeChanged);
0289 }
0290 
0291 void KoShape::setSizeImpl(const QSizeF &size) const
0292 {
0293     s->size = size;
0294 }
0295 
0296 void KoShape::setPosition(const QPointF &newPosition)
0297 {
0298     QPointF currentPos = position();
0299     if (newPosition == currentPos)
0300         return;
0301     QTransform translateMatrix;
0302     translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
0303     s->localMatrix = s->localMatrix * translateMatrix;
0304 
0305     notifyChanged();
0306     shapeChangedPriv(PositionChanged);
0307 }
0308 
0309 bool KoShape::hitTest(const QPointF &position) const
0310 {
0311     if (d->parent && d->parent->isClipped(this) && !d->parent->hitTest(position))
0312         return false;
0313 
0314     QPointF point = absoluteTransformation().inverted().map(position);
0315     QRectF bb = outlineRect();
0316 
0317     if (s->stroke) {
0318         KoInsets insets;
0319         s->stroke->strokeInsets(this, insets);
0320         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
0321     }
0322     if (bb.contains(point))
0323         return true;
0324 
0325     // if there is no shadow we can as well just leave
0326     if (! s->shadow)
0327         return false;
0328 
0329     // the shadow has an offset to the shape, so we simply
0330     // check if the position minus the shadow offset hits the shape
0331     point = absoluteTransformation().inverted().map(position - s->shadow->offset());
0332 
0333     return bb.contains(point);
0334 }
0335 
0336 QRectF KoShape::boundingRect() const
0337 {
0338 
0339     QTransform transform = absoluteTransformation();
0340     QRectF bb = outlineRect();
0341     if (s->stroke) {
0342         KoInsets insets;
0343         s->stroke->strokeInsets(this, insets);
0344         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
0345     }
0346     bb = transform.mapRect(bb);
0347     if (s->shadow) {
0348         KoInsets insets;
0349         s->shadow->insets(insets);
0350         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
0351     }
0352     if (s->filterEffectStack) {
0353         QRectF clipRect = s->filterEffectStack->clipRectForBoundingRect(outlineRect());
0354         bb |= transform.mapRect(clipRect);
0355     }
0356 
0357     return bb;
0358 }
0359 
0360 QRectF KoShape::boundingRect(const QList<KoShape *> &shapes)
0361 {
0362     QRectF boundingRect;
0363     Q_FOREACH (KoShape *shape, shapes) {
0364         boundingRect |= shape->boundingRect();
0365     }
0366     return boundingRect;
0367 }
0368 
0369 QRectF KoShape::absoluteOutlineRect() const
0370 {
0371     return absoluteTransformation().map(outline()).boundingRect();
0372 }
0373 
0374 QRectF KoShape::absoluteOutlineRect(const QList<KoShape *> &shapes)
0375 {
0376     QRectF absoluteOutlineRect;
0377     Q_FOREACH (KoShape *shape, shapes) {
0378         absoluteOutlineRect |= shape->absoluteOutlineRect();
0379     }
0380     return absoluteOutlineRect;
0381 }
0382 
0383 QTransform KoShape::absoluteTransformation() const
0384 {
0385     QTransform matrix;
0386     // apply parents matrix to inherit any transformations done there.
0387     KoShapeContainer * container = d->parent;
0388     if (container) {
0389         if (container->inheritsTransform(this)) {
0390             matrix = container->absoluteTransformation();
0391         } else {
0392             QSizeF containerSize = container->size();
0393             QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
0394             matrix.translate(containerPos.x(), containerPos.y());
0395         }
0396     }
0397 
0398     return s->localMatrix * matrix;
0399 }
0400 
0401 void KoShape::applyAbsoluteTransformation(const QTransform &matrix)
0402 {
0403     QTransform globalMatrix = absoluteTransformation();
0404     // the transformation is relative to the global coordinate system
0405     // but we want to change the local matrix, so convert the matrix
0406     // to be relative to the local coordinate system
0407     QTransform transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
0408     applyTransformation(transformMatrix);
0409 }
0410 
0411 void KoShape::applyTransformation(const QTransform &matrix)
0412 {
0413     s->localMatrix = matrix * s->localMatrix;
0414     notifyChanged();
0415     shapeChangedPriv(GenericMatrixChange);
0416 }
0417 
0418 void KoShape::setTransformation(const QTransform &matrix)
0419 {
0420     s->localMatrix = matrix;
0421     notifyChanged();
0422     shapeChangedPriv(GenericMatrixChange);
0423 }
0424 
0425 QTransform KoShape::transformation() const
0426 {
0427     return s->localMatrix;
0428 }
0429 
0430 KoShape::ChildZOrderPolicy KoShape::childZOrderPolicy()
0431 {
0432     return ChildZDefault;
0433 }
0434 
0435 bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
0436 {
0437     /**
0438      * WARNING: Our definition of zIndex is not yet compatible with SVG2's
0439      *          definition. In SVG stacking context of groups with the same
0440      *          zIndex are **merged**, while in Krita the contents of groups
0441      *          is never merged. One group will always below than the other.
0442      *          Therefore, when zIndex of two groups inside the same parent
0443      *          coincide, the resulting painting order in Krita is
0444      *          **UNDEFINED**.
0445      *
0446      *          To avoid this trouble we use  KoShapeReorderCommand::mergeInShape()
0447      *          inside KoShapeCreateCommand.
0448      */
0449 
0450     /**
0451      * The algorithm below doesn't correctly handle the case when the two pointers actually
0452      * point to the same shape. So just check it in advance to guarantee strict weak ordering
0453      * relation requirement
0454      */
0455     if (s1 == s2) return false;
0456 
0457 
0458     // First sort according to runThrough which is sort of a master level
0459     KoShape *parentShapeS1 = s1->parent();
0460     KoShape *parentShapeS2 = s2->parent();
0461     int runThrough1 = s1->runThrough();
0462     int runThrough2 = s2->runThrough();
0463     while (parentShapeS1) {
0464         if (parentShapeS1->childZOrderPolicy() == KoShape::ChildZParentChild) {
0465             runThrough1 = parentShapeS1->runThrough();
0466         } else {
0467             runThrough1 = runThrough1 + parentShapeS1->runThrough();
0468         }
0469         parentShapeS1 = parentShapeS1->parent();
0470     }
0471 
0472     while (parentShapeS2) {
0473         if (parentShapeS2->childZOrderPolicy() == KoShape::ChildZParentChild) {
0474             runThrough2 = parentShapeS2->runThrough();
0475         } else {
0476             runThrough2 = runThrough2 + parentShapeS2->runThrough();
0477         }
0478         parentShapeS2 = parentShapeS2->parent();
0479     }
0480 
0481     if (runThrough1 > runThrough2) {
0482         return false;
0483     }
0484     if (runThrough1 < runThrough2) {
0485         return true;
0486     }
0487 
0488     // If on the same runThrough level then the zIndex is all that matters.
0489     //
0490     // We basically walk up through the parents until we find a common base parent
0491     // To do that we need two loops where the inner loop walks up through the parents
0492     // of s2 every time we step up one parent level on s1
0493     //
0494     // We don't update the index value until after we have seen that it's not a common base
0495     // That way we ensure that two children of a common base are sorted according to their respective
0496     // z value
0497     bool foundCommonParent = false;
0498     int index1 = s1->zIndex();
0499     int index2 = s2->zIndex();
0500     parentShapeS1 = s1;
0501     parentShapeS2 = s2;
0502     while (parentShapeS1 && !foundCommonParent) {
0503         parentShapeS2 = s2;
0504         index2 = parentShapeS2->zIndex();
0505         while (parentShapeS2) {
0506             if (parentShapeS2 == parentShapeS1) {
0507                 foundCommonParent = true;
0508                 break;
0509             }
0510             if (parentShapeS2->childZOrderPolicy() == KoShape::ChildZParentChild) {
0511                 index2 = parentShapeS2->zIndex();
0512             }
0513             parentShapeS2 = parentShapeS2->parent();
0514         }
0515 
0516         if (!foundCommonParent) {
0517             if (parentShapeS1->childZOrderPolicy() == KoShape::ChildZParentChild) {
0518                 index1 = parentShapeS1->zIndex();
0519             }
0520             parentShapeS1 = parentShapeS1->parent();
0521         }
0522     }
0523 
0524     // If the one shape is a parent/child of the other then sort so.
0525     if (s1 == parentShapeS2) {
0526         return true;
0527     }
0528     if (s2 == parentShapeS1) {
0529         return false;
0530     }
0531 
0532     // If we went that far then the z-Index is used for sorting.
0533     return index1 < index2;
0534 }
0535 
0536 void KoShape::setParent(KoShapeContainer *parent)
0537 {
0538 
0539     if (d->parent == parent) {
0540         return;
0541     }
0542 
0543     if (d->parent) {
0544         d->parent->shapeInterface()->removeShape(this);
0545         d->parent = 0;
0546     }
0547 
0548 
0549     KIS_SAFE_ASSERT_RECOVER_NOOP(parent != this);
0550 
0551     if (parent && parent != this) {
0552         d->parent = parent;
0553         parent->shapeInterface()->addShape(this);
0554     }
0555 
0556     notifyChanged();
0557     shapeChangedPriv(ParentChanged);
0558 }
0559 
0560 bool KoShape::inheritsTransformFromAny(const QList<KoShape *> ancestorsInQuestion) const
0561 {
0562     bool result = false;
0563 
0564     KoShape *shape = const_cast<KoShape*>(this);
0565     while (shape) {
0566         KoShapeContainer *parent = shape->parent();
0567         if (parent && !parent->inheritsTransform(shape)) {
0568             break;
0569         }
0570 
0571         if (ancestorsInQuestion.contains(shape)) {
0572             result = true;
0573             break;
0574         }
0575 
0576         shape = parent;
0577     }
0578 
0579     return result;
0580 }
0581 
0582 bool KoShape::hasCommonParent(const KoShape *shape) const
0583 {
0584     const KoShape *thisShape = this;
0585     while (thisShape) {
0586 
0587         const KoShape *otherShape = shape;
0588         while (otherShape) {
0589             if (thisShape == otherShape) {
0590                 return true;
0591             }
0592             otherShape = otherShape->parent();
0593         }
0594 
0595         thisShape = thisShape->parent();
0596     }
0597 
0598     return false;
0599 }
0600 
0601 qint16 KoShape::zIndex() const
0602 {
0603     return s->zIndex;
0604 }
0605 
0606 void KoShape::update() const
0607 {
0608 
0609     if (!d->shapeManagers.empty()) {
0610         const QRectF rect(boundingRect());
0611         Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
0612             manager->update(rect, this, true);
0613         }
0614     }
0615 }
0616 
0617 void KoShape::updateAbsolute(const QRectF &rect) const
0618 {
0619     if (rect.isEmpty() && !rect.isNull()) {
0620         return;
0621     }
0622 
0623 
0624     if (!d->shapeManagers.empty() && isVisible()) {
0625         Q_FOREACH (KoShapeManager *manager, d->shapeManagers) {
0626             manager->update(rect);
0627         }
0628     }
0629 }
0630 
0631 QPainterPath KoShape::outline() const
0632 {
0633     QPainterPath path;
0634     path.addRect(outlineRect());
0635     return path;
0636 }
0637 
0638 QRectF KoShape::outlineRect() const
0639 {
0640     const QSizeF s = size();
0641     return QRectF(QPointF(0, 0), QSizeF(qMax(s.width(),  qreal(0.0001)),
0642                                         qMax(s.height(), qreal(0.0001))));
0643 }
0644 
0645 QPainterPath KoShape::shadowOutline() const
0646 {
0647     if (background()) {
0648         return outline();
0649     }
0650 
0651     return QPainterPath();
0652 }
0653 
0654 QPointF KoShape::absolutePosition(KoFlake::AnchorPosition anchor) const
0655 {
0656     const QRectF rc = outlineRect();
0657 
0658     QPointF point = rc.topLeft();
0659 
0660     bool valid = false;
0661     QPointF anchoredPoint = KoFlake::anchorToPoint(anchor, rc, &valid);
0662     if (valid) {
0663         point = anchoredPoint;
0664     }
0665 
0666     return absoluteTransformation().map(point);
0667 }
0668 
0669 void KoShape::setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor)
0670 {
0671     QPointF currentAbsPosition = absolutePosition(anchor);
0672     QPointF translate = newPosition - currentAbsPosition;
0673     QTransform translateMatrix;
0674     translateMatrix.translate(translate.x(), translate.y());
0675     applyAbsoluteTransformation(translateMatrix);
0676     notifyChanged();
0677     shapeChangedPriv(PositionChanged);
0678 }
0679 
0680 void KoShape::copySettings(const KoShape *shape)
0681 {
0682     s->size = shape->size();
0683     s->zIndex = shape->zIndex();
0684     s->visible = shape->isVisible(false);
0685 
0686     // Ensure printable is true by default
0687     if (!s->visible)
0688         s->printable = true;
0689     else
0690         s->printable = shape->isPrintable();
0691 
0692     s->geometryProtected = shape->isGeometryProtected();
0693     s->protectContent = shape->isContentProtected();
0694     s->selectable = shape->isSelectable();
0695     s->keepAspect = shape->keepAspectRatio();
0696     s->localMatrix = shape->s->localMatrix;
0697 }
0698 
0699 void KoShape::notifyChanged()
0700 {
0701     Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
0702         manager->notifyShapeChanged(this);
0703     }
0704 }
0705 
0706 void KoShape::setUserData(KoShapeUserData *userData)
0707 {
0708     s->userData.reset(userData);
0709 }
0710 
0711 KoShapeUserData *KoShape::userData() const
0712 {
0713     return s->userData.data();
0714 }
0715 
0716 bool KoShape::hasTransparency() const
0717 {
0718     QSharedPointer<KoShapeBackground> bg = background();
0719 
0720     return !bg || bg->hasTransparency() || s->transparency > 0.0;
0721 }
0722 
0723 void KoShape::setTransparency(qreal transparency)
0724 {
0725     s->transparency = qBound<qreal>(0.0, transparency, 1.0);
0726 
0727     shapeChangedPriv(TransparencyChanged);
0728     notifyChanged();
0729 }
0730 
0731 qreal KoShape::transparency(bool recursive) const
0732 {
0733     if (!recursive || !parent()) {
0734         return s->transparency;
0735     } else {
0736         const qreal parentOpacity = 1.0-parent()->transparency(recursive);
0737         const qreal childOpacity = 1.0-s->transparency;
0738         return 1.0-(parentOpacity*childOpacity);
0739     }
0740 }
0741 
0742 KoInsets KoShape::strokeInsets() const
0743 {
0744     KoInsets answer;
0745     if (s->stroke)
0746         s->stroke->strokeInsets(this, answer);
0747     return answer;
0748 }
0749 
0750 void KoShape::setPaintOrder(KoShape::PaintOrder first, KoShape::PaintOrder second)
0751 {
0752     KIS_SAFE_ASSERT_RECOVER_RETURN(first != second);
0753     QVector<PaintOrder> order = {Fill, Stroke, Markers};
0754 
0755     if (first != Fill) {
0756         if (order.at(1) == first) {
0757             order[1] = order[0];
0758             order[0] = first;
0759         } else if (order.at(2) == first) {
0760             order[2] = order[0];
0761             order[0] = first;
0762         }
0763     }
0764     if (second != first && second != Stroke) {
0765         if (order.at(2) == second) {
0766             order[2] = order[1];
0767             order[1] = second;
0768         }
0769     }
0770     s->inheritPaintOrder = false;
0771     s->paintOrder = order;
0772 }
0773 
0774 QVector<KoShape::PaintOrder> KoShape::paintOrder() const
0775 {
0776     QVector<PaintOrder> order = {Fill, Stroke, Markers};
0777     if (!s->inheritPaintOrder) {
0778         order = s->paintOrder;
0779     } else if (parent()) {
0780         order = parent()->paintOrder();
0781     }
0782     return order;
0783 }
0784 
0785 void KoShape::setInheritPaintOrder(bool value)
0786 {
0787     s->inheritPaintOrder = value;
0788 }
0789 
0790 bool KoShape::inheritPaintOrder() const
0791 {
0792     return s->inheritPaintOrder;
0793 }
0794 
0795 qreal KoShape::rotation() const
0796 {
0797     // try to extract the rotation angle out of the local matrix
0798     // if it is a pure rotation matrix
0799 
0800     // check if the matrix has shearing mixed in
0801     if (fabs(fabs(s->localMatrix.m12()) - fabs(s->localMatrix.m21())) > 1e-10)
0802         return std::numeric_limits<qreal>::quiet_NaN();
0803     // check if the matrix has scaling mixed in
0804     if (fabs(s->localMatrix.m11() - s->localMatrix.m22()) > 1e-10)
0805         return std::numeric_limits<qreal>::quiet_NaN();
0806 
0807     // calculate the angle from the matrix elements
0808     qreal angle = atan2(-s->localMatrix.m21(), s->localMatrix.m11()) * 180.0 / M_PI;
0809     if (angle < 0.0)
0810         angle += 360.0;
0811 
0812     return angle;
0813 }
0814 
0815 QSizeF KoShape::size() const
0816 {
0817     return s->size;
0818 }
0819 
0820 QPointF KoShape::position() const
0821 {
0822     QPointF center = outlineRect().center();
0823     return s->localMatrix.map(center) - center;
0824 }
0825 
0826 KoShape::TextRunAroundSide KoShape::textRunAroundSide() const
0827 {
0828     return s->textRunAroundSide;
0829 }
0830 
0831 void KoShape::setTextRunAroundSide(TextRunAroundSide side, RunThroughLevel runThrough)
0832 {
0833 
0834     if (side == RunThrough) {
0835         if (runThrough == Background) {
0836             setRunThrough(-1);
0837         } else {
0838             setRunThrough(1);
0839         }
0840     } else {
0841         setRunThrough(0);
0842     }
0843 
0844     if ( s->textRunAroundSide == side) {
0845         return;
0846     }
0847 
0848     s->textRunAroundSide = side;
0849     notifyChanged();
0850     shapeChangedPriv(TextRunAroundChanged);
0851 }
0852 
0853 qreal KoShape::textRunAroundDistanceTop() const
0854 {
0855     return s->textRunAroundDistanceTop;
0856 }
0857 
0858 void KoShape::setTextRunAroundDistanceTop(qreal distance)
0859 {
0860     s->textRunAroundDistanceTop = distance;
0861 }
0862 
0863 qreal KoShape::textRunAroundDistanceLeft() const
0864 {
0865     return s->textRunAroundDistanceLeft;
0866 }
0867 
0868 void KoShape::setTextRunAroundDistanceLeft(qreal distance)
0869 {
0870     s->textRunAroundDistanceLeft = distance;
0871 }
0872 
0873 qreal KoShape::textRunAroundDistanceRight() const
0874 {
0875     return s->textRunAroundDistanceRight;
0876 }
0877 
0878 void KoShape::setTextRunAroundDistanceRight(qreal distance)
0879 {
0880     s->textRunAroundDistanceRight = distance;
0881 }
0882 
0883 qreal KoShape::textRunAroundDistanceBottom() const
0884 {
0885     return s->textRunAroundDistanceBottom;
0886 }
0887 
0888 void KoShape::setTextRunAroundDistanceBottom(qreal distance)
0889 {
0890     s->textRunAroundDistanceBottom = distance;
0891 }
0892 
0893 qreal KoShape::textRunAroundThreshold() const
0894 {
0895     return s->textRunAroundThreshold;
0896 }
0897 
0898 void KoShape::setTextRunAroundThreshold(qreal threshold)
0899 {
0900     s->textRunAroundThreshold = threshold;
0901 }
0902 
0903 KoShape::TextRunAroundContour KoShape::textRunAroundContour() const
0904 {
0905     return s->textRunAroundContour;
0906 }
0907 
0908 void KoShape::setTextRunAroundContour(KoShape::TextRunAroundContour contour)
0909 {
0910     s->textRunAroundContour = contour;
0911 }
0912 
0913 void KoShape::setBackground(QSharedPointer<KoShapeBackground> fill)
0914 {
0915     s->inheritBackground = false;
0916     s->fill = fill;
0917     shapeChangedPriv(BackgroundChanged);
0918     notifyChanged();
0919 }
0920 
0921 QSharedPointer<KoShapeBackground> KoShape::background() const
0922 {
0923 
0924     QSharedPointer<KoShapeBackground> bg;
0925 
0926     if (!s->inheritBackground) {
0927         bg = s->fill;
0928     } else if (parent()) {
0929         bg = parent()->background();
0930     }
0931 
0932     return bg;
0933 }
0934 
0935 void KoShape::setInheritBackground(bool value)
0936 {
0937 
0938     s->inheritBackground = value;
0939     if (s->inheritBackground) {
0940         s->fill.clear();
0941     }
0942 }
0943 
0944 bool KoShape::inheritBackground() const
0945 {
0946     return s->inheritBackground;
0947 }
0948 
0949 void KoShape::setZIndex(qint16 zIndex)
0950 {
0951     if (s->zIndex == zIndex)
0952         return;
0953     s->zIndex = zIndex;
0954     notifyChanged();
0955 }
0956 
0957 int KoShape::runThrough() const
0958 {
0959     return s->runThrough;
0960 }
0961 
0962 void KoShape::setRunThrough(short int runThrough)
0963 {
0964     s->runThrough = runThrough;
0965 }
0966 
0967 void KoShape::setVisible(bool on)
0968 {
0969     int _on = (on ? 1 : 0);
0970     if (s->visible == _on) return;
0971     s->visible = _on;
0972 }
0973 
0974 bool KoShape::isVisible(bool recursive) const
0975 {
0976     if (!recursive)
0977         return s->visible;
0978 
0979     if (!s->visible)
0980         return false;
0981 
0982     KoShapeContainer * parentShape = parent();
0983 
0984     if (parentShape) {
0985         return parentShape->isVisible(true);
0986     }
0987 
0988     return true;
0989 }
0990 
0991 void KoShape::setPrintable(bool on)
0992 {
0993     s->printable = on;
0994 }
0995 
0996 bool KoShape::isPrintable() const
0997 {
0998     if (s->visible)
0999         return s->printable;
1000     else
1001         return false;
1002 }
1003 
1004 void KoShape::setSelectable(bool selectable)
1005 {
1006     s->selectable = selectable;
1007 }
1008 
1009 bool KoShape::isSelectable() const
1010 {
1011     return s->selectable;
1012 }
1013 
1014 void KoShape::setGeometryProtected(bool on)
1015 {
1016     s->geometryProtected = on;
1017 }
1018 
1019 bool KoShape::isGeometryProtected() const
1020 {
1021     return s->geometryProtected;
1022 }
1023 
1024 void KoShape::setContentProtected(bool protect)
1025 {
1026     s->protectContent = protect;
1027 }
1028 
1029 bool KoShape::isContentProtected() const
1030 {
1031     return s->protectContent;
1032 }
1033 
1034 KoShapeContainer *KoShape::parent() const
1035 {
1036     return d->parent;
1037 }
1038 
1039 void KoShape::setKeepAspectRatio(bool keepAspect)
1040 {
1041     s->keepAspect = keepAspect;
1042 
1043     shapeChangedPriv(KeepAspectRatioChange);
1044     notifyChanged();
1045 }
1046 
1047 bool KoShape::keepAspectRatio() const
1048 {
1049     return s->keepAspect;
1050 }
1051 
1052 QString KoShape::shapeId() const
1053 {
1054     return s->shapeId;
1055 }
1056 
1057 void KoShape::setShapeId(const QString &id)
1058 {
1059     s->shapeId = id;
1060 }
1061 
1062 KoShapeStrokeModelSP KoShape::stroke() const
1063 {
1064 
1065     KoShapeStrokeModelSP stroke;
1066 
1067     if (!s->inheritStroke) {
1068         stroke = s->stroke;
1069     } else if (parent()) {
1070         stroke = parent()->stroke();
1071     }
1072 
1073     return stroke;
1074 }
1075 
1076 void KoShape::setStroke(KoShapeStrokeModelSP stroke)
1077 {
1078 
1079     s->inheritStroke = false;
1080     s->stroke = stroke;
1081     shapeChangedPriv(StrokeChanged);
1082     notifyChanged();
1083 }
1084 
1085 void KoShape::setInheritStroke(bool value)
1086 {
1087     s->inheritStroke = value;
1088     if (s->inheritStroke) {
1089         s->stroke.clear();
1090     }
1091 }
1092 
1093 bool KoShape::inheritStroke() const
1094 {
1095     return s->inheritStroke;
1096 }
1097 
1098 void KoShape::setShadow(KoShapeShadow *shadow)
1099 {
1100     if (s->shadow)
1101         s->shadow->deref();
1102     s->shadow = shadow;
1103     if (s->shadow) {
1104         s->shadow->ref();
1105         // TODO update changed area
1106     }
1107     shapeChangedPriv(ShadowChanged);
1108     notifyChanged();
1109 }
1110 
1111 KoShapeShadow *KoShape::shadow() const
1112 {
1113     return s->shadow;
1114 }
1115 
1116 void KoShape::setClipPath(KoClipPath *clipPath)
1117 {
1118     s->clipPath.reset(clipPath);
1119     shapeChangedPriv(ClipPathChanged);
1120     notifyChanged();
1121 }
1122 
1123 KoClipPath * KoShape::clipPath() const
1124 {
1125     return s->clipPath.data();
1126 }
1127 
1128 void KoShape::setClipMask(KoClipMask *clipMask)
1129 {
1130     s->clipMask.reset(clipMask);
1131     shapeChangedPriv(ClipMaskChanged);
1132     notifyChanged();
1133 }
1134 
1135 KoClipMask* KoShape::clipMask() const
1136 {
1137     return s->clipMask.data();
1138 }
1139 
1140 QTransform KoShape::transform() const
1141 {
1142     return s->localMatrix;
1143 }
1144 
1145 QString KoShape::name() const
1146 {
1147     return s->name;
1148 }
1149 
1150 void KoShape::setName(const QString &name)
1151 {
1152     s->name = name;
1153 }
1154 
1155 void KoShape::waitUntilReady(bool asynchronous) const
1156 {
1157     Q_UNUSED(asynchronous);
1158 }
1159 
1160 bool KoShape::isShapeEditable(bool recursive) const
1161 {
1162     if (!s->visible || s->geometryProtected)
1163         return false;
1164 
1165     if (recursive && d->parent) {
1166         return d->parent->isShapeEditable(true);
1167     }
1168 
1169     return true;
1170 }
1171 
1172 KisHandlePainterHelper KoShape::createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius, int decorationThickness)
1173 {
1174     const QTransform originalPainterTransform = painter->transform();
1175 
1176     painter->setTransform(shape->absoluteTransformation() *
1177                           converter.documentToView() *
1178                           painter->transform());
1179 
1180     // move c-tor
1181     return KisHandlePainterHelper(painter, originalPainterTransform, handleRadius, decorationThickness);
1182 }
1183 
1184 KisHandlePainterHelper KoShape::createHandlePainterHelperDocument(QPainter *painter, KoShape *shape, qreal handleRadius, int decorationThickness)
1185 {
1186     const QTransform originalPainterTransform = painter->transform();
1187 
1188     painter->setTransform(shape->absoluteTransformation() *
1189                           painter->transform());
1190 
1191     // move c-tor
1192     return KisHandlePainterHelper(painter, originalPainterTransform, handleRadius, decorationThickness);
1193 }
1194 
1195 
1196 QPointF KoShape::shapeToDocument(const QPointF &point) const
1197 {
1198     return absoluteTransformation().map(point);
1199 }
1200 
1201 QRectF KoShape::shapeToDocument(const QRectF &rect) const
1202 {
1203     return absoluteTransformation().mapRect(rect);
1204 }
1205 
1206 QPointF KoShape::documentToShape(const QPointF &point) const
1207 {
1208     return absoluteTransformation().inverted().map(point);
1209 }
1210 
1211 QRectF KoShape::documentToShape(const QRectF &rect) const
1212 {
1213     return absoluteTransformation().inverted().mapRect(rect);
1214 }
1215 
1216 bool KoShape::addDependee(KoShape *shape)
1217 {
1218     if (! shape)
1219         return false;
1220 
1221     // refuse to establish a circular dependency
1222     if (shape->hasDependee(this))
1223         return false;
1224 
1225     if (! d->dependees.contains(shape))
1226         d->dependees.append(shape);
1227 
1228     return true;
1229 }
1230 
1231 void KoShape::removeDependee(KoShape *shape)
1232 {
1233     int index = d->dependees.indexOf(shape);
1234     if (index >= 0)
1235         d->dependees.removeAt(index);
1236 }
1237 
1238 bool KoShape::hasDependee(KoShape *shape) const
1239 {
1240     return d->dependees.contains(shape);
1241 }
1242 
1243 QList<KoShape*> KoShape::dependees() const
1244 {
1245     return d->dependees;
1246 }
1247 
1248 void KoShape::shapeChanged(ChangeType type, KoShape *shape)
1249 {
1250     Q_UNUSED(type);
1251     Q_UNUSED(shape);
1252 }
1253 
1254 KoSnapData KoShape::snapData() const
1255 {
1256     return KoSnapData();
1257 }
1258 
1259 void KoShape::setAdditionalAttribute(const QString &name, const QString &value)
1260 {
1261     s->additionalAttributes.insert(name, value);
1262 }
1263 
1264 void KoShape::removeAdditionalAttribute(const QString &name)
1265 {
1266     s->additionalAttributes.remove(name);
1267 }
1268 
1269 bool KoShape::hasAdditionalAttribute(const QString &name) const
1270 {
1271     return s->additionalAttributes.contains(name);
1272 }
1273 
1274 QString KoShape::additionalAttribute(const QString &name) const
1275 {
1276     return s->additionalAttributes.value(name);
1277 }
1278 
1279 void KoShape::setAdditionalStyleAttribute(const char *name, const QString &value)
1280 {
1281     s->additionalStyleAttributes.insert(name, value);
1282 }
1283 
1284 void KoShape::removeAdditionalStyleAttribute(const char *name)
1285 {
1286     s->additionalStyleAttributes.remove(name);
1287 }
1288 
1289 KoFilterEffectStack *KoShape::filterEffectStack() const
1290 {
1291     return s->filterEffectStack;
1292 }
1293 
1294 void KoShape::setFilterEffectStack(KoFilterEffectStack *filterEffectStack)
1295 {
1296     if (s->filterEffectStack)
1297         s->filterEffectStack->deref();
1298     s->filterEffectStack = filterEffectStack;
1299     if (s->filterEffectStack) {
1300         s->filterEffectStack->ref();
1301     }
1302     notifyChanged();
1303 }
1304 
1305 QSet<KoShape*> KoShape::toolDelegates() const
1306 {
1307     return d->toolDelegates;
1308 }
1309 
1310 void KoShape::setToolDelegates(const QSet<KoShape*> &delegates)
1311 {
1312     d->toolDelegates = delegates;
1313 }
1314 
1315 QString KoShape::hyperLink () const
1316 {
1317     return s->hyperLink;
1318 }
1319 
1320 void KoShape::setHyperLink(const QString &hyperLink)
1321 {
1322     s->hyperLink = hyperLink;
1323 }
1324 
1325 KoShape::ShapeChangeListener::~ShapeChangeListener()
1326 {
1327     Q_FOREACH(KoShape *shape, m_registeredShapes) {
1328         shape->removeShapeChangeListener(this);
1329     }
1330 }
1331 
1332 void KoShape::ShapeChangeListener::registerShape(KoShape *shape)
1333 {
1334     KIS_SAFE_ASSERT_RECOVER_RETURN(!m_registeredShapes.contains(shape));
1335     m_registeredShapes.append(shape);
1336 }
1337 
1338 void KoShape::ShapeChangeListener::unregisterShape(KoShape *shape)
1339 {
1340     KIS_SAFE_ASSERT_RECOVER_RETURN(m_registeredShapes.contains(shape));
1341     m_registeredShapes.removeAll(shape);
1342 }
1343 
1344 void KoShape::ShapeChangeListener::notifyShapeChangedImpl(KoShape::ChangeType type, KoShape *shape)
1345 {
1346     KIS_SAFE_ASSERT_RECOVER_RETURN(m_registeredShapes.contains(shape));
1347 
1348     notifyShapeChanged(type, shape);
1349 
1350     if (type == KoShape::Deleted) {
1351         unregisterShape(shape);
1352     }
1353 }
1354 
1355 void KoShape::addShapeChangeListener(KoShape::ShapeChangeListener *listener)
1356 {
1357 
1358     KIS_SAFE_ASSERT_RECOVER_RETURN(!d->listeners.contains(listener));
1359     listener->registerShape(this);
1360     d->listeners.append(listener);
1361 }
1362 
1363 void KoShape::removeShapeChangeListener(KoShape::ShapeChangeListener *listener)
1364 {
1365 
1366     KIS_SAFE_ASSERT_RECOVER_RETURN(d->listeners.contains(listener));
1367     d->listeners.removeAll(listener);
1368     listener->unregisterShape(this);
1369 }
1370 
1371 QList<KoShape::ShapeChangeListener *> KoShape::listeners() const
1372 {
1373     return d->listeners;
1374 }
1375 
1376 QList<KoShape *> KoShape::linearizeSubtree(const QList<KoShape *> &shapes)
1377 {
1378     QList<KoShape *> result;
1379 
1380     Q_FOREACH (KoShape *shape, shapes) {
1381         result << shape;
1382 
1383         KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
1384         if (container) {
1385             result << linearizeSubtree(container->shapes());
1386         }
1387     }
1388 
1389     return result;
1390 }
1391 
1392 QList<KoShape *> KoShape::linearizeSubtreeSorted(const QList<KoShape *> &shapes)
1393 {
1394     QList<KoShape*> sortedShapes = shapes;
1395     std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
1396 
1397     QList<KoShape *> result;
1398 
1399     Q_FOREACH (KoShape *shape, sortedShapes) {
1400         result << shape;
1401 
1402         KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
1403         if (container) {
1404             result << linearizeSubtreeSorted(container->shapes());
1405         }
1406     }
1407 
1408     return result;
1409 }
1410 
1411 void KoShape::setResolution(qreal /*xRes*/, qreal /*yRes*/)
1412 {
1413 }