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