1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSvg module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qsvgnode_p.h"
43#include "qsvgtinydocument_p.h"
44
45#ifndef QT_NO_SVG
46
47#include "qdebug.h"
48#include "qstack.h"
49
50QT_BEGIN_NAMESPACE
51
52QSvgNode::QSvgNode(QSvgNode *parent)
53 : m_parent(parent),
54 m_visible(true),
55 m_displayMode(BlockMode)
56{
57}
58
59QSvgNode::~QSvgNode()
60{
61
62}
63
64void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id)
65{
66 //qDebug()<<"appending "<<prop->type()<< " ("<< id <<") "<<"to "<<this<<this->type();
67 QSvgTinyDocument *doc;
68 switch (prop->type()) {
69 case QSvgStyleProperty::QUALITY:
70 m_style.quality = static_cast<QSvgQualityStyle*>(prop);
71 break;
72 case QSvgStyleProperty::FILL:
73 m_style.fill = static_cast<QSvgFillStyle*>(prop);
74 break;
75 case QSvgStyleProperty::VIEWPORT_FILL:
76 m_style.viewportFill = static_cast<QSvgViewportFillStyle*>(prop);
77 break;
78 case QSvgStyleProperty::FONT:
79 m_style.font = static_cast<QSvgFontStyle*>(prop);
80 break;
81 case QSvgStyleProperty::STROKE:
82 m_style.stroke = static_cast<QSvgStrokeStyle*>(prop);
83 break;
84 case QSvgStyleProperty::SOLID_COLOR:
85 m_style.solidColor = static_cast<QSvgSolidColorStyle*>(prop);
86 doc = document();
87 if (doc && !id.isEmpty())
88 doc->addNamedStyle(id, m_style.solidColor);
89 break;
90 case QSvgStyleProperty::GRADIENT:
91 m_style.gradient = static_cast<QSvgGradientStyle*>(prop);
92 doc = document();
93 if (doc && !id.isEmpty())
94 doc->addNamedStyle(id, m_style.gradient);
95 break;
96 case QSvgStyleProperty::TRANSFORM:
97 m_style.transform = static_cast<QSvgTransformStyle*>(prop);
98 break;
99 case QSvgStyleProperty::ANIMATE_COLOR:
100 m_style.animateColor = static_cast<QSvgAnimateColor*>(prop);
101 break;
102 case QSvgStyleProperty::ANIMATE_TRANSFORM:
103 m_style.animateTransforms.append(
104 static_cast<QSvgAnimateTransform*>(prop));
105 break;
106 case QSvgStyleProperty::OPACITY:
107 m_style.opacity = static_cast<QSvgOpacityStyle*>(prop);
108 break;
109 case QSvgStyleProperty::COMP_OP:
110 m_style.compop = static_cast<QSvgCompOpStyle*>(prop);
111 break;
112 default:
113 qDebug("QSvgNode: Trying to append unknown property!");
114 break;
115 }
116}
117
118void QSvgNode::applyStyle(QPainter *p, QSvgExtraStates &states) const
119{
120 m_style.apply(p, this, states);
121}
122
123void QSvgNode::revertStyle(QPainter *p, QSvgExtraStates &states) const
124{
125 m_style.revert(p, states);
126}
127
128QSvgStyleProperty * QSvgNode::styleProperty(QSvgStyleProperty::Type type) const
129{
130 const QSvgNode *node = this;
131 while (node) {
132 switch (type) {
133 case QSvgStyleProperty::QUALITY:
134 if (node->m_style.quality)
135 return node->m_style.quality;
136 break;
137 case QSvgStyleProperty::FILL:
138 if (node->m_style.fill)
139 return node->m_style.fill;
140 break;
141 case QSvgStyleProperty::VIEWPORT_FILL:
142 if (m_style.viewportFill)
143 return node->m_style.viewportFill;
144 break;
145 case QSvgStyleProperty::FONT:
146 if (node->m_style.font)
147 return node->m_style.font;
148 break;
149 case QSvgStyleProperty::STROKE:
150 if (node->m_style.stroke)
151 return node->m_style.stroke;
152 break;
153 case QSvgStyleProperty::SOLID_COLOR:
154 if (node->m_style.solidColor)
155 return node->m_style.solidColor;
156 break;
157 case QSvgStyleProperty::GRADIENT:
158 if (node->m_style.gradient)
159 return node->m_style.gradient;
160 break;
161 case QSvgStyleProperty::TRANSFORM:
162 if (node->m_style.transform)
163 return node->m_style.transform;
164 break;
165 case QSvgStyleProperty::ANIMATE_COLOR:
166 if (node->m_style.animateColor)
167 return node->m_style.animateColor;
168 break;
169 case QSvgStyleProperty::ANIMATE_TRANSFORM:
170 if (!node->m_style.animateTransforms.isEmpty())
171 return node->m_style.animateTransforms.first();
172 break;
173 case QSvgStyleProperty::OPACITY:
174 if (node->m_style.opacity)
175 return node->m_style.opacity;
176 break;
177 case QSvgStyleProperty::COMP_OP:
178 if (node->m_style.compop)
179 return node->m_style.compop;
180 break;
181 default:
182 break;
183 }
184 node = node->parent();
185 }
186
187 return 0;
188}
189
190QSvgFillStyleProperty * QSvgNode::styleProperty(const QString &id) const
191{
192 QString rid = id;
193 if (rid.startsWith(QLatin1Char('#')))
194 rid.remove(0, 1);
195 QSvgTinyDocument *doc = document();
196 return doc ? doc->namedStyle(rid) : 0;
197}
198
199QRectF QSvgNode::bounds(QPainter *, QSvgExtraStates &) const
200{
201 return QRectF(0, 0, 0, 0);
202}
203
204QRectF QSvgNode::transformedBounds() const
205{
206 if (!m_cachedBounds.isEmpty())
207 return m_cachedBounds;
208
209 QImage dummy(1, 1, QImage::Format_RGB32);
210 QPainter p(&dummy);
211 QSvgExtraStates states;
212
213 QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
214 pen.setMiterLimit(4);
215 p.setPen(pen);
216
217 QStack<QSvgNode*> parentApplyStack;
218 QSvgNode *parent = m_parent;
219 while (parent) {
220 parentApplyStack.push(parent);
221 parent = parent->parent();
222 }
223
224 for (int i = parentApplyStack.size() - 1; i >= 0; --i)
225 parentApplyStack[i]->applyStyle(&p, states);
226
227 p.setWorldTransform(QTransform());
228
229 m_cachedBounds = transformedBounds(&p, states);
230 return m_cachedBounds;
231}
232
233QSvgTinyDocument * QSvgNode::document() const
234{
235 QSvgTinyDocument *doc = 0;
236 QSvgNode *node = const_cast<QSvgNode*>(this);
237 while (node && node->type() != QSvgNode::DOC) {
238 node = node->parent();
239 }
240 doc = static_cast<QSvgTinyDocument*>(node);
241
242 return doc;
243}
244
245void QSvgNode::setRequiredFeatures(const QStringList &lst)
246{
247 m_requiredFeatures = lst;
248}
249
250const QStringList & QSvgNode::requiredFeatures() const
251{
252 return m_requiredFeatures;
253}
254
255void QSvgNode::setRequiredExtensions(const QStringList &lst)
256{
257 m_requiredExtensions = lst;
258}
259
260const QStringList & QSvgNode::requiredExtensions() const
261{
262 return m_requiredExtensions;
263}
264
265void QSvgNode::setRequiredLanguages(const QStringList &lst)
266{
267 m_requiredLanguages = lst;
268}
269
270const QStringList & QSvgNode::requiredLanguages() const
271{
272 return m_requiredLanguages;
273}
274
275void QSvgNode::setRequiredFormats(const QStringList &lst)
276{
277 m_requiredFormats = lst;
278}
279
280const QStringList & QSvgNode::requiredFormats() const
281{
282 return m_requiredFormats;
283}
284
285void QSvgNode::setRequiredFonts(const QStringList &lst)
286{
287 m_requiredFonts = lst;
288}
289
290const QStringList & QSvgNode::requiredFonts() const
291{
292 return m_requiredFonts;
293}
294
295void QSvgNode::setVisible(bool visible)
296{
297 //propagate visibility change of true to the parent
298 //not propagating false is just a small performance
299 //degradation since we'll iterate over children without
300 //drawing any of them
301 if (m_parent && visible && !m_parent->isVisible())
302 m_parent->setVisible(true);
303
304 m_visible = visible;
305}
306
307QRectF QSvgNode::transformedBounds(QPainter *p, QSvgExtraStates &states) const
308{
309 applyStyle(p, states);
310 QRectF rect = bounds(p, states);
311 revertStyle(p, states);
312 return rect;
313}
314
315void QSvgNode::setNodeId(const QString &i)
316{
317 m_id = i;
318}
319
320void QSvgNode::setXmlClass(const QString &str)
321{
322 m_class = str;
323}
324
325void QSvgNode::setDisplayMode(DisplayMode mode)
326{
327 m_displayMode = mode;
328}
329
330QSvgNode::DisplayMode QSvgNode::displayMode() const
331{
332 return m_displayMode;
333}
334
335qreal QSvgNode::strokeWidth(QPainter *p)
336{
337 QPen pen = p->pen();
338 if (pen.style() == Qt::NoPen || pen.brush().style() == Qt::NoBrush || pen.isCosmetic())
339 return 0;
340 return pen.widthF();
341}
342
343QT_END_NAMESPACE
344
345#endif // QT_NO_SVG
346