1 /* This file is part of the KDE project
2  * Copyright (C) 2007,2009 Jan Hambrecht <jaham@gmx.net>
3  * Copyright (C) 2010 Thorsten Zachmann <zachmann@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "SvgGradientHelper.h"
22 
23 #include <QConicalGradient>
24 #include <QLinearGradient>
25 #include <QRadialGradient>
26 
27 #include <cmath>
28 #include <KoFlake.h>
29 
SvgGradientHelper()30 SvgGradientHelper::SvgGradientHelper()
31         : m_gradient(0), m_gradientUnits(ObjectBoundingBox)
32 {
33 }
34 
~SvgGradientHelper()35 SvgGradientHelper::~SvgGradientHelper()
36 {
37     delete m_gradient;
38 }
39 
SvgGradientHelper(const SvgGradientHelper & other)40 SvgGradientHelper::SvgGradientHelper(const SvgGradientHelper &other)
41         : m_gradient(0), m_gradientUnits(ObjectBoundingBox)
42 {
43     m_gradientUnits = other.m_gradientUnits;
44     m_gradientTransform = other.m_gradientTransform;
45     copyGradient(other.m_gradient);
46 }
47 
operator =(const SvgGradientHelper & rhs)48 SvgGradientHelper & SvgGradientHelper::operator = (const SvgGradientHelper & rhs)
49 {
50     if (this == &rhs)
51         return *this;
52 
53     m_gradientUnits = rhs.m_gradientUnits;
54     m_gradientTransform = rhs.m_gradientTransform;
55     copyGradient(rhs.m_gradient);
56 
57     return *this;
58 }
59 
setGradientUnits(Units units)60 void SvgGradientHelper::setGradientUnits(Units units)
61 {
62     m_gradientUnits = units;
63 }
64 
gradientUnits() const65 SvgGradientHelper::Units SvgGradientHelper::gradientUnits() const
66 {
67     return m_gradientUnits;
68 }
69 
gradient()70 QGradient * SvgGradientHelper::gradient()
71 {
72     return m_gradient;
73 }
74 
setGradient(QGradient * g)75 void SvgGradientHelper::setGradient(QGradient * g)
76 {
77     delete m_gradient;
78     m_gradient = g;
79 }
80 
copyGradient(QGradient * other)81 void SvgGradientHelper::copyGradient(QGradient * other)
82 {
83     delete m_gradient;
84     m_gradient = duplicateGradient(other, QTransform());
85 }
86 
adjustedFill(const QRectF & bound)87 QBrush SvgGradientHelper::adjustedFill(const QRectF &bound)
88 {
89     QBrush brush;
90 
91     QGradient * g = adjustedGradient(bound);
92     if (g) {
93         brush = QBrush(*g);
94         delete g;
95     }
96 
97     return brush;
98 }
99 
transform() const100 QTransform SvgGradientHelper::transform() const
101 {
102     return m_gradientTransform;
103 }
104 
setTransform(const QTransform & transform)105 void SvgGradientHelper::setTransform(const QTransform &transform)
106 {
107     m_gradientTransform = transform;
108 }
109 
adjustedGradient(const QRectF & bound) const110 QGradient * SvgGradientHelper::adjustedGradient(const QRectF &bound) const
111 {
112     QTransform matrix;
113     matrix.scale(0.01 * bound.width(), 0.01 * bound.height());
114 
115     return duplicateGradient(m_gradient, matrix);
116 }
117 
duplicateGradient(const QGradient * originalGradient,const QTransform & transform)118 QGradient * SvgGradientHelper::duplicateGradient(const QGradient * originalGradient, const QTransform &transform)
119 {
120     if (! originalGradient)
121         return 0;
122 
123     QGradient * duplicatedGradient = 0;
124 
125     switch (originalGradient->type()) {
126     case QGradient::ConicalGradient: {
127         const QConicalGradient * o = static_cast<const QConicalGradient*>(originalGradient);
128         QConicalGradient * g = new QConicalGradient();
129         g->setAngle(o->angle());
130         g->setCenter(transform.map(o->center()));
131         duplicatedGradient = g;
132     }
133     break;
134     case QGradient::LinearGradient: {
135         const QLinearGradient * o = static_cast<const QLinearGradient*>(originalGradient);
136         QLinearGradient * g = new QLinearGradient();
137         g->setStart(transform.map(o->start()));
138         g->setFinalStop(transform.map(o->finalStop()));
139         duplicatedGradient = g;
140     }
141     break;
142     case QGradient::RadialGradient: {
143         const QRadialGradient * o = static_cast<const QRadialGradient*>(originalGradient);
144         QRadialGradient * g = new QRadialGradient();
145         g->setCenter(transform.map(o->center()));
146         g->setFocalPoint(transform.map(o->focalPoint()));
147         g->setRadius(transform.map(QPointF(o->radius(), 0.0)).x());
148         duplicatedGradient = g;
149     }
150     break;
151     default:
152         return 0;
153     }
154 
155     duplicatedGradient->setCoordinateMode(originalGradient->coordinateMode());
156     duplicatedGradient->setStops(originalGradient->stops());
157     duplicatedGradient->setSpread(originalGradient->spread());
158 
159     return duplicatedGradient;
160 }
161 
convertGradient(const QGradient * originalGradient,const QSizeF & size)162 QGradient *SvgGradientHelper::convertGradient(const QGradient *originalGradient, const QSizeF &size)
163 {
164     if (! originalGradient)
165         return 0;
166 
167     if (originalGradient->coordinateMode() != QGradient::LogicalMode) {
168         return duplicateGradient(originalGradient, QTransform());
169     }
170 
171     QGradient *duplicatedGradient = 0;
172 
173     switch (originalGradient->type()) {
174     case QGradient::ConicalGradient:
175         {
176             const QConicalGradient *o = static_cast<const QConicalGradient*>(originalGradient);
177             QConicalGradient *g = new QConicalGradient();
178             g->setAngle(o->angle());
179             g->setCenter(KoFlake::toRelative(o->center(),size));
180             duplicatedGradient = g;
181         }
182         break;
183     case QGradient::LinearGradient:
184         {
185             const QLinearGradient *o = static_cast<const QLinearGradient*>(originalGradient);
186             QLinearGradient *g = new QLinearGradient();
187             g->setStart(KoFlake::toRelative(o->start(),size));
188             g->setFinalStop(KoFlake::toRelative(o->finalStop(),size));
189             duplicatedGradient = g;
190         }
191         break;
192     case QGradient::RadialGradient:
193         {
194             const QRadialGradient *o = static_cast<const QRadialGradient*>(originalGradient);
195             QRadialGradient *g = new QRadialGradient();
196             g->setCenter(KoFlake::toRelative(o->center(),size));
197             g->setFocalPoint(KoFlake::toRelative(o->focalPoint(),size));
198             g->setRadius(KoFlake::toRelative(QPointF(o->radius(), 0.0),
199                          QSizeF(sqrt(size.width() * size.width() + size.height() * size.height()), 0.0)).x());
200             duplicatedGradient = g;
201         }
202         break;
203     default:
204         return 0;
205     }
206 
207     duplicatedGradient->setCoordinateMode(QGradient::ObjectBoundingMode);
208     duplicatedGradient->setStops(originalGradient->stops());
209     duplicatedGradient->setSpread(originalGradient->spread());
210 
211     return duplicatedGradient;
212 }
213 
214