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 }