Warning, file /office/calligra/libs/flake/KoClipPath.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "KoClipPath.h"
0021 #include "KoPathShape.h"
0022 #include "KoViewConverter.h"
0023 
0024 #include <QTransform>
0025 #include <QPainterPath>
0026 #include <QPainter>
0027 #include <QGraphicsItem>
0028 #include <QVarLengthArray>
0029 
0030 QTransform scaleToPercent(const QSizeF &size)
0031 {
0032     const qreal w = qMax(static_cast<qreal>(1e-5), size.width());
0033     const qreal h = qMax(static_cast<qreal>(1e-5), size.height());
0034     return QTransform().scale(100/w, 100/h);
0035 }
0036 
0037 QTransform scaleFromPercent(const QSizeF &size)
0038 {
0039     const qreal w = qMax(static_cast<qreal>(1e-5), size.width());
0040     const qreal h = qMax(static_cast<qreal>(1e-5), size.height());
0041     return QTransform().scale(w/100, h/100);
0042 }
0043 
0044 class Q_DECL_HIDDEN KoClipData::Private
0045 {
0046 public:
0047     Private() : deleteClipShapes(true)
0048     {
0049     }
0050 
0051     ~Private()
0052     {
0053         if (deleteClipShapes)
0054             qDeleteAll(clipPathShapes);
0055     }
0056 
0057     QList<KoPathShape*> clipPathShapes;
0058     bool deleteClipShapes;
0059 };
0060 
0061 KoClipData::KoClipData(KoPathShape *clipPathShape)
0062         : d(new Private())
0063 {
0064     Q_ASSERT(clipPathShape);
0065     d->clipPathShapes.append(clipPathShape);
0066 }
0067 
0068 KoClipData::KoClipData(const QList<KoPathShape*> &clipPathShapes)
0069         : d(new Private())
0070 {
0071     Q_ASSERT(clipPathShapes.count());
0072     d->clipPathShapes = clipPathShapes;
0073 }
0074 
0075 KoClipData::~KoClipData()
0076 {
0077     delete d;
0078 }
0079 
0080 QList<KoPathShape*> KoClipData::clipPathShapes() const
0081 {
0082     return d->clipPathShapes;
0083 }
0084 
0085 void KoClipData::removeClipShapesOwnership()
0086 {
0087     d->deleteClipShapes = false;
0088 }
0089 
0090 class Q_DECL_HIDDEN KoClipPath::Private
0091 {
0092 public:
0093     Private(KoClipData *data)
0094             : clipData(data)
0095     {}
0096 
0097     ~Private()
0098     {
0099     }
0100 
0101     void compileClipPath(KoShape *clippedShape)
0102     {
0103         QList<KoPathShape*> clipShapes = clipData->clipPathShapes();
0104         if (!clipShapes.count())
0105             return;
0106 
0107         initialShapeSize = clippedShape->outline().boundingRect().size();
0108         initialTransformToShape = clippedShape->absoluteTransformation(0).inverted();
0109 
0110         QTransform transformToShape = initialTransformToShape * scaleToPercent(initialShapeSize);
0111 
0112         foreach(KoPathShape *path, clipShapes) {
0113             if (!path)
0114                 continue;
0115             // map clip path to shape coordinates of clipped shape
0116             QTransform m = path->absoluteTransformation(0) * transformToShape;
0117             if (clipPath.isEmpty())
0118                 clipPath = m.map(path->outline());
0119             else
0120                 clipPath |= m.map(path->outline());
0121         }
0122     }
0123 
0124     QExplicitlySharedDataPointer<KoClipData> clipData; ///< the clip path data
0125     QPainterPath clipPath; ///< the compiled clip path in shape coordinates of the clipped shape
0126     QTransform initialTransformToShape; ///< initial transformation to shape coordinates of the clipped shape
0127     QSizeF initialShapeSize; ///< initial size of clipped shape
0128 };
0129 
0130 KoClipPath::KoClipPath(KoShape *clippedShape, KoClipData *clipData)
0131         : d( new Private(clipData) )
0132 {
0133     d->compileClipPath(clippedShape);
0134 }
0135 
0136 KoClipPath::~KoClipPath()
0137 {
0138     delete d;
0139 }
0140 
0141 void KoClipPath::setClipRule(Qt::FillRule clipRule)
0142 {
0143     d->clipPath.setFillRule(clipRule);
0144 }
0145 
0146 Qt::FillRule KoClipPath::clipRule() const
0147 {
0148     return d->clipPath.fillRule();
0149 }
0150 
0151 void KoClipPath::applyClipping(KoShape *clippedShape, QPainter &painter, const KoViewConverter &converter)
0152 {
0153     QPainterPath clipPath;
0154     KoShape *shape = clippedShape;
0155     while (shape) {
0156         if (shape->clipPath()) {
0157             QTransform m = scaleFromPercent(shape->outline().boundingRect().size()) * shape->absoluteTransformation(0);
0158             if (clipPath.isEmpty())
0159                 clipPath = m.map(shape->clipPath()->path());
0160             else
0161                 clipPath |= m.map(shape->clipPath()->path());
0162         }
0163         shape = shape->parent();
0164     }
0165 
0166     if (!clipPath.isEmpty()) {
0167         QTransform viewMatrix;
0168         qreal zoomX, zoomY;
0169         converter.zoom(&zoomX, &zoomY);
0170         viewMatrix.scale(zoomX, zoomY);
0171         painter.setClipPath(viewMatrix.map(clipPath), Qt::IntersectClip);
0172     }
0173 }
0174 
0175 QPainterPath KoClipPath::path() const
0176 {
0177     return d->clipPath;
0178 }
0179 
0180 QPainterPath KoClipPath::pathForSize(const QSizeF &size) const
0181 {
0182     return scaleFromPercent(size).map(d->clipPath);
0183 }
0184 
0185 QList<KoPathShape*> KoClipPath::clipPathShapes() const
0186 {
0187     return d->clipData->clipPathShapes();
0188 }
0189 
0190 QTransform KoClipPath::clipDataTransformation(KoShape *clippedShape) const
0191 {
0192     if (!clippedShape)
0193         return d->initialTransformToShape;
0194 
0195     // the current transformation of the clipped shape
0196     QTransform currentShapeTransform = clippedShape->absoluteTransformation(0);
0197 
0198     // calculate the transformation which represents any resizing of the clipped shape
0199     const QSizeF currentShapeSize = clippedShape->outline().boundingRect().size();
0200     const qreal sx = currentShapeSize.width() / d->initialShapeSize.width();
0201     const qreal sy = currentShapeSize.height() / d->initialShapeSize.height();
0202     QTransform scaleTransform = QTransform().scale(sx, sy);
0203 
0204     // 1. transform to initial clipped shape coordinates
0205     // 2. apply resizing transformation
0206     // 3. convert to current clipped shape document coordinates
0207     return d->initialTransformToShape * scaleTransform * currentShapeTransform;
0208 }