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

source code of qtsvg/src/svg/qsvgstructure.cpp