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 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | QSvgNode::QSvgNode(QSvgNode *parent) |
53 | : m_parent(parent), |
54 | m_visible(true), |
55 | m_displayMode(BlockMode) |
56 | { |
57 | } |
58 | |
59 | QSvgNode::~QSvgNode() |
60 | { |
61 | |
62 | } |
63 | |
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 | |
118 | void QSvgNode::(QPainter *p, QSvgExtraStates &states) const |
119 | { |
120 | m_style.apply(p, this, states); |
121 | } |
122 | |
123 | void QSvgNode::(QPainter *p, QSvgExtraStates &states) const |
124 | { |
125 | m_style.revert(p, states); |
126 | } |
127 | |
128 | 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 | |
190 | 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 | |
199 | QRectF QSvgNode::(QPainter *, QSvgExtraStates &) const |
200 | { |
201 | return QRectF(0, 0, 0, 0); |
202 | } |
203 | |
204 | 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 | |
233 | 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 | |
245 | void QSvgNode::setRequiredFeatures(const QStringList &lst) |
246 | { |
247 | m_requiredFeatures = lst; |
248 | } |
249 | |
250 | const QStringList & QSvgNode::requiredFeatures() const |
251 | { |
252 | return m_requiredFeatures; |
253 | } |
254 | |
255 | void QSvgNode::setRequiredExtensions(const QStringList &lst) |
256 | { |
257 | m_requiredExtensions = lst; |
258 | } |
259 | |
260 | const QStringList & QSvgNode::requiredExtensions() const |
261 | { |
262 | return m_requiredExtensions; |
263 | } |
264 | |
265 | void QSvgNode::setRequiredLanguages(const QStringList &lst) |
266 | { |
267 | m_requiredLanguages = lst; |
268 | } |
269 | |
270 | const QStringList & QSvgNode::requiredLanguages() const |
271 | { |
272 | return m_requiredLanguages; |
273 | } |
274 | |
275 | void QSvgNode::setRequiredFormats(const QStringList &lst) |
276 | { |
277 | m_requiredFormats = lst; |
278 | } |
279 | |
280 | const QStringList & QSvgNode::requiredFormats() const |
281 | { |
282 | return m_requiredFormats; |
283 | } |
284 | |
285 | void QSvgNode::setRequiredFonts(const QStringList &lst) |
286 | { |
287 | m_requiredFonts = lst; |
288 | } |
289 | |
290 | const QStringList & QSvgNode::requiredFonts() const |
291 | { |
292 | return m_requiredFonts; |
293 | } |
294 | |
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 | |
307 | QRectF QSvgNode::(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 | |
315 | void QSvgNode::setNodeId(const QString &i) |
316 | { |
317 | m_id = i; |
318 | } |
319 | |
320 | void QSvgNode::setXmlClass(const QString &str) |
321 | { |
322 | m_class = str; |
323 | } |
324 | |
325 | void QSvgNode::setDisplayMode(DisplayMode mode) |
326 | { |
327 | m_displayMode = mode; |
328 | } |
329 | |
330 | QSvgNode::DisplayMode QSvgNode::displayMode() const |
331 | { |
332 | return m_displayMode; |
333 | } |
334 | |
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 | |