1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
50 QT_BEGIN_NAMESPACE
51 
QSvgNode(QSvgNode * parent)52 QSvgNode::QSvgNode(QSvgNode *parent)
53     : m_parent(parent),
54       m_visible(true),
55       m_displayMode(BlockMode)
56 {
57 }
58 
~QSvgNode()59 QSvgNode::~QSvgNode()
60 {
61 
62 }
63 
appendStyleProperty(QSvgStyleProperty * prop,const QString & id)64 void 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 
applyStyle(QPainter * p,QSvgExtraStates & states) const118 void QSvgNode::applyStyle(QPainter *p, QSvgExtraStates &states) const
119 {
120     m_style.apply(p, this, states);
121 }
122 
revertStyle(QPainter * p,QSvgExtraStates & states) const123 void QSvgNode::revertStyle(QPainter *p, QSvgExtraStates &states) const
124 {
125     m_style.revert(p, states);
126 }
127 
styleProperty(QSvgStyleProperty::Type type) const128 QSvgStyleProperty * 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 
styleProperty(const QString & id) const190 QSvgFillStyleProperty * 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 
bounds(QPainter *,QSvgExtraStates &) const199 QRectF QSvgNode::bounds(QPainter *, QSvgExtraStates &) const
200 {
201     return QRectF(0, 0, 0, 0);
202 }
203 
transformedBounds() const204 QRectF 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 
document() const233 QSvgTinyDocument * 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 
setRequiredFeatures(const QStringList & lst)245 void QSvgNode::setRequiredFeatures(const QStringList &lst)
246 {
247     m_requiredFeatures = lst;
248 }
249 
requiredFeatures() const250 const QStringList & QSvgNode::requiredFeatures() const
251 {
252     return m_requiredFeatures;
253 }
254 
setRequiredExtensions(const QStringList & lst)255 void QSvgNode::setRequiredExtensions(const QStringList &lst)
256 {
257     m_requiredExtensions = lst;
258 }
259 
requiredExtensions() const260 const QStringList & QSvgNode::requiredExtensions() const
261 {
262     return m_requiredExtensions;
263 }
264 
setRequiredLanguages(const QStringList & lst)265 void QSvgNode::setRequiredLanguages(const QStringList &lst)
266 {
267     m_requiredLanguages = lst;
268 }
269 
requiredLanguages() const270 const QStringList & QSvgNode::requiredLanguages() const
271 {
272     return m_requiredLanguages;
273 }
274 
setRequiredFormats(const QStringList & lst)275 void QSvgNode::setRequiredFormats(const QStringList &lst)
276 {
277     m_requiredFormats = lst;
278 }
279 
requiredFormats() const280 const QStringList & QSvgNode::requiredFormats() const
281 {
282     return m_requiredFormats;
283 }
284 
setRequiredFonts(const QStringList & lst)285 void QSvgNode::setRequiredFonts(const QStringList &lst)
286 {
287     m_requiredFonts = lst;
288 }
289 
requiredFonts() const290 const QStringList & QSvgNode::requiredFonts() const
291 {
292     return m_requiredFonts;
293 }
294 
setVisible(bool visible)295 void 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 
transformedBounds(QPainter * p,QSvgExtraStates & states) const307 QRectF 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 
setNodeId(const QString & i)315 void QSvgNode::setNodeId(const QString &i)
316 {
317     m_id = i;
318 }
319 
setXmlClass(const QString & str)320 void QSvgNode::setXmlClass(const QString &str)
321 {
322     m_class = str;
323 }
324 
setDisplayMode(DisplayMode mode)325 void QSvgNode::setDisplayMode(DisplayMode mode)
326 {
327     m_displayMode = mode;
328 }
329 
displayMode() const330 QSvgNode::DisplayMode QSvgNode::displayMode() const
331 {
332     return m_displayMode;
333 }
334 
strokeWidth(QPainter * p)335 qreal 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 
343 QT_END_NAMESPACE
344 
345 #endif // QT_NO_SVG
346