1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt SVG 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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qsvgstructure_p.h"
41
42 #include "qsvgnode_p.h"
43 #include "qsvgstyle_p.h"
44 #include "qsvgtinydocument_p.h"
45
46 #include "qpainter.h"
47 #include "qlocale.h"
48 #include "qdebug.h"
49
50 #include <qscopedvaluerollback.h>
51
52 QT_BEGIN_NAMESPACE
53
QSvgG(QSvgNode * parent)54 QSvgG::QSvgG(QSvgNode *parent)
55 : QSvgStructureNode(parent)
56 {
57
58 }
59
~QSvgStructureNode()60 QSvgStructureNode::~QSvgStructureNode()
61 {
62 qDeleteAll(m_renderers);
63 }
64
draw(QPainter * p,QSvgExtraStates & states)65 void QSvgG::draw(QPainter *p, QSvgExtraStates &states)
66 {
67 QList<QSvgNode*>::iterator itr = m_renderers.begin();
68 applyStyle(p, states);
69
70 while (itr != m_renderers.end()) {
71 QSvgNode *node = *itr;
72 if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode))
73 node->draw(p, states);
74 ++itr;
75 }
76 revertStyle(p, states);
77 }
78
type() const79 QSvgNode::Type QSvgG::type() const
80 {
81 return G;
82 }
83
QSvgStructureNode(QSvgNode * parent)84 QSvgStructureNode::QSvgStructureNode(QSvgNode *parent)
85 :QSvgNode(parent)
86 {
87
88 }
89
scopeNode(const QString & id) const90 QSvgNode * QSvgStructureNode::scopeNode(const QString &id) const
91 {
92 QSvgTinyDocument *doc = document();
93 return doc ? doc->namedNode(id) : 0;
94 }
95
addChild(QSvgNode * child,const QString & id)96 void QSvgStructureNode::addChild(QSvgNode *child, const QString &id)
97 {
98 m_renderers.append(child);
99
100 if (id.isEmpty())
101 return; //we can't add it to scope without id
102
103 QSvgTinyDocument *doc = document();
104 if (doc)
105 doc->addNamedNode(id, child);
106 }
107
QSvgDefs(QSvgNode * parent)108 QSvgDefs::QSvgDefs(QSvgNode *parent)
109 : QSvgStructureNode(parent)
110 {
111 }
112
draw(QPainter *,QSvgExtraStates &)113 void QSvgDefs::draw(QPainter *, QSvgExtraStates &)
114 {
115 //noop
116 }
117
type() const118 QSvgNode::Type QSvgDefs::type() const
119 {
120 return DEFS;
121 }
122
123 /*
124 Below is a lookup function based on the gperf output using the following set:
125
126 http://www.w3.org/Graphics/SVG/feature/1.2/#SVG
127 http://www.w3.org/Graphics/SVG/feature/1.2/#SVG-static
128 http://www.w3.org/Graphics/SVG/feature/1.2/#CoreAttribute
129 http://www.w3.org/Graphics/SVG/feature/1.2/#Structure
130 http://www.w3.org/Graphics/SVG/feature/1.2/#ConditionalProcessing
131 http://www.w3.org/Graphics/SVG/feature/1.2/#ConditionalProcessingAttribute
132 http://www.w3.org/Graphics/SVG/feature/1.2/#Image
133 http://www.w3.org/Graphics/SVG/feature/1.2/#Prefetch
134 http://www.w3.org/Graphics/SVG/feature/1.2/#Shape
135 http://www.w3.org/Graphics/SVG/feature/1.2/#Text
136 http://www.w3.org/Graphics/SVG/feature/1.2/#PaintAttribute
137 http://www.w3.org/Graphics/SVG/feature/1.2/#OpacityAttribute
138 http://www.w3.org/Graphics/SVG/feature/1.2/#GraphicsAttribute
139 http://www.w3.org/Graphics/SVG/feature/1.2/#Gradient
140 http://www.w3.org/Graphics/SVG/feature/1.2/#SolidColor
141 http://www.w3.org/Graphics/SVG/feature/1.2/#XlinkAttribute
142 http://www.w3.org/Graphics/SVG/feature/1.2/#ExternalResourcesRequiredAttribute
143 http://www.w3.org/Graphics/SVG/feature/1.2/#Font
144 http://www.w3.org/Graphics/SVG/feature/1.2/#Hyperlinking
145 http://www.w3.org/Graphics/SVG/feature/1.2/#Extensibility
146 */
147
148 // ----- begin of generated code -----
149
150 /* C code produced by gperf version 3.0.2 */
151 /* Command-line: gperf -c -L c svg */
152 /* Computed positions: -k'45-46' */
153
154 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
155 && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
156 && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
157 && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
158 && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
159 && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
160 && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
161 && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
162 && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
163 && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
164 && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
165 && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
166 && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
167 && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
168 && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
169 && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
170 && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
171 && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
172 && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
173 && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
174 && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
175 && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
176 && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
177 /* The character set is not based on ISO-646. */
178 #error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
179 #endif
180
181 enum {
182 TOTAL_KEYWORDS = 20,
183 MIN_WORD_LENGTH = 47,
184 MAX_WORD_LENGTH = 78,
185 MIN_HASH_VALUE = 48,
186 MAX_HASH_VALUE = 88
187 };
188 /* maximum key range = 41, duplicates = 0 */
189
isSupportedSvgFeature(const QString & str)190 inline static bool isSupportedSvgFeature(const QString &str)
191 {
192 static const unsigned char asso_values[] = {
193 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
194 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
195 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
196 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
197 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
198 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
199 89, 89, 89, 89, 89, 89, 89, 0, 89, 5,
200 15, 5, 0, 10, 89, 89, 89, 89, 89, 0,
201 15, 89, 89, 0, 0, 89, 5, 89, 0, 89,
202 89, 89, 89, 89, 89, 89, 89, 0, 89, 89,
203 89, 0, 89, 89, 0, 89, 89, 89, 0, 5,
204 89, 0, 0, 89, 5, 89, 0, 89, 89, 89,
205 5, 0, 89, 89, 89, 89, 89, 89, 89, 89,
206 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
207 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
208 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
209 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
210 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
211 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
212 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
213 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
214 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
215 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
216 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
217 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
218 89, 89, 89, 89, 89, 89
219 };
220
221 static const char * wordlist[] = {
222 "", "", "", "", "", "", "", "", "",
223 "", "", "", "", "", "", "", "", "",
224 "", "", "", "", "", "", "", "", "",
225 "", "", "", "", "", "", "", "", "",
226 "", "", "", "", "", "", "", "", "",
227 "", "", "",
228 "http://www.w3.org/Graphics/SVG/feature/1.2/#Text",
229 "http://www.w3.org/Graphics/SVG/feature/1.2/#Shape",
230 "", "",
231 "http://www.w3.org/Graphics/SVG/feature/1.2/#SVG",
232 "http://www.w3.org/Graphics/SVG/feature/1.2/#Structure",
233 "http://www.w3.org/Graphics/SVG/feature/1.2/#SolidColor",
234 "",
235 "http://www.w3.org/Graphics/SVG/feature/1.2/#Hyperlinking",
236 "http://www.w3.org/Graphics/SVG/feature/1.2/#CoreAttribute",
237 "http://www.w3.org/Graphics/SVG/feature/1.2/#XlinkAttribute",
238 "http://www.w3.org/Graphics/SVG/feature/1.2/#SVG-static",
239 "http://www.w3.org/Graphics/SVG/feature/1.2/#OpacityAttribute",
240 "",
241 "http://www.w3.org/Graphics/SVG/feature/1.2/#Gradient",
242 "http://www.w3.org/Graphics/SVG/feature/1.2/#Font",
243 "http://www.w3.org/Graphics/SVG/feature/1.2/#Image",
244 "http://www.w3.org/Graphics/SVG/feature/1.2/#ConditionalProcessing",
245 "",
246 "http://www.w3.org/Graphics/SVG/feature/1.2/#Extensibility",
247 "", "", "",
248 "http://www.w3.org/Graphics/SVG/feature/1.2/#GraphicsAttribute",
249 "http://www.w3.org/Graphics/SVG/feature/1.2/#Prefetch",
250 "http://www.w3.org/Graphics/SVG/feature/1.2/#PaintAttribute",
251 "http://www.w3.org/Graphics/SVG/feature/1.2/#ConditionalProcessingAttribute",
252 "", "", "", "", "", "", "", "", "",
253 "", "", "", "",
254 "http://www.w3.org/Graphics/SVG/feature/1.2/#ExternalResourcesRequiredAttribute"
255 };
256
257 if (str.length() <= MAX_WORD_LENGTH && str.length() >= MIN_WORD_LENGTH) {
258 const char16_t unicode44 = str.at(44).unicode();
259 const char16_t unicode45 = str.at(45).unicode();
260 if (unicode44 >= sizeof(asso_values) || unicode45 >= sizeof(asso_values))
261 return false;
262 const int key = str.length()
263 + asso_values[unicode45]
264 + asso_values[unicode44];
265 if (key <= MAX_HASH_VALUE && key >= 0)
266 return str == QLatin1String(wordlist[key]);
267 }
268 return false;
269 }
270
271 // ----- end of generated code -----
272
isSupportedSvgExtension(const QString &)273 static inline bool isSupportedSvgExtension(const QString &)
274 {
275 return false;
276 }
277
278
QSvgSwitch(QSvgNode * parent)279 QSvgSwitch::QSvgSwitch(QSvgNode *parent)
280 : QSvgStructureNode(parent)
281 {
282 init();
283 }
284
draw(QPainter * p,QSvgExtraStates & states)285 void QSvgSwitch::draw(QPainter *p, QSvgExtraStates &states)
286 {
287 QList<QSvgNode*>::iterator itr = m_renderers.begin();
288 applyStyle(p, states);
289
290 while (itr != m_renderers.end()) {
291 QSvgNode *node = *itr;
292 if (node->isVisible() && (node->displayMode() != QSvgNode::NoneMode)) {
293 const QStringList &features = node->requiredFeatures();
294 const QStringList &extensions = node->requiredExtensions();
295 const QStringList &languages = node->requiredLanguages();
296 const QStringList &formats = node->requiredFormats();
297 const QStringList &fonts = node->requiredFonts();
298
299 bool okToRender = true;
300 if (!features.isEmpty()) {
301 QStringList::const_iterator sitr = features.constBegin();
302 for (; sitr != features.constEnd(); ++sitr) {
303 if (!isSupportedSvgFeature(*sitr)) {
304 okToRender = false;
305 break;
306 }
307 }
308 }
309
310 if (okToRender && !extensions.isEmpty()) {
311 QStringList::const_iterator sitr = extensions.constBegin();
312 for (; sitr != extensions.constEnd(); ++sitr) {
313 if (!isSupportedSvgExtension(*sitr)) {
314 okToRender = false;
315 break;
316 }
317 }
318 }
319
320 if (okToRender && !languages.isEmpty()) {
321 QStringList::const_iterator sitr = languages.constBegin();
322 okToRender = false;
323 for (; sitr != languages.constEnd(); ++sitr) {
324 if ((*sitr).startsWith(m_systemLanguagePrefix)) {
325 okToRender = true;
326 break;
327 }
328 }
329 }
330
331 if (okToRender && !formats.isEmpty()) {
332 okToRender = false;
333 }
334
335 if (okToRender && !fonts.isEmpty()) {
336 okToRender = false;
337 }
338
339 if (okToRender) {
340 node->draw(p, states);
341 break;
342 }
343 }
344 ++itr;
345 }
346 revertStyle(p, states);
347 }
348
type() const349 QSvgNode::Type QSvgSwitch::type() const
350 {
351 return SWITCH;
352 }
353
init()354 void QSvgSwitch::init()
355 {
356 QLocale locale;
357 m_systemLanguage = locale.name().replace(QLatin1Char('_'), QLatin1Char('-'));
358 int idx = m_systemLanguage.indexOf(QLatin1Char('-'));
359 m_systemLanguagePrefix = m_systemLanguage.mid(0, idx);
360 }
361
bounds(QPainter * p,QSvgExtraStates & states) const362 QRectF QSvgStructureNode::bounds(QPainter *p, QSvgExtraStates &states) const
363 {
364 QRectF bounds;
365 if (!m_recursing) {
366 QScopedValueRollback<bool> guard(m_recursing, true);
367 for (QSvgNode *node : qAsConst(m_renderers))
368 bounds |= node->transformedBounds(p, states);
369 }
370 return bounds;
371 }
372
previousSiblingNode(QSvgNode * n) const373 QSvgNode * QSvgStructureNode::previousSiblingNode(QSvgNode *n) const
374 {
375 QSvgNode *prev = 0;
376 QList<QSvgNode*>::const_iterator itr = m_renderers.constBegin();
377 for (; itr != m_renderers.constEnd(); ++itr) {
378 QSvgNode *node = *itr;
379 if (node == n)
380 return prev;
381 prev = node;
382 }
383 return prev;
384 }
385
386 QT_END_NAMESPACE
387