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