1// Copyright (C) 2023 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 "qsvgvisitor_p.h"
5#include <QDebug>
6
7QT_BEGIN_NAMESPACE
8
9static const char *nodeTypeStrings[] = {
10 "DOC",
11 "G",
12 "DEFS",
13 "SWITCH",
14 "ANIMATION",
15 "ARC",
16 "CIRCLE",
17 "ELLIPSE",
18 "IMAGE",
19 "LINE",
20 "PATH",
21 "POLYGON",
22 "POLYLINE",
23 "RECT",
24 "TEXT",
25 "TEXTAREA",
26 "TSPAN",
27 "USE",
28 "VIDEO"
29};
30
31// TODO: something like this is needed in several places. Make a common version.
32static const char *typeName(const QSvgNode *node)
33{
34 constexpr int typeNameCount = sizeof(nodeTypeStrings) / sizeof(const char *);
35 if (node->type() < typeNameCount)
36 return nodeTypeStrings[node->type()];
37 return "UNKNOWN";
38}
39
40class SvgDebugVisitor : public QSvgVisitor
41{
42public:
43 SvgDebugVisitor(QDebug &stream) : debug(stream) {}
44 void write(const QSvgTinyDocument *doc);
45
46protected:
47 void visitNode(const QSvgNode *) override;
48 bool visitStructureNodeStart(const QSvgStructureNode *node) override;
49 void visitStructureNodeEnd(const QSvgStructureNode *) override;
50 void visitAnimationNode(const QSvgAnimation *node) override;
51 void visitEllipseNode(const QSvgEllipse *node) override;
52 void visitImageNode(const QSvgImage *node) override;
53 void visitLineNode(const QSvgLine *node) override;
54 void visitPathNode(const QSvgPath *node) override;
55 void visitPolygonNode(const QSvgPolygon *node) override;
56 void visitPolylineNode(const QSvgPolyline *node) override;
57 void visitRectNode(const QSvgRect *node) override;
58 void visitTextNode(const QSvgText *node) override;
59 void visitUseNode(const QSvgUse *node) override;
60 void visitVideoNode(const QSvgVideo *node) override;
61
62private:
63 const char *indent() { m_indent.fill(c: ' ', size: m_indentLevel * 2); return m_indent.constData();}
64 void handleBaseNode(const QSvgNode *node);
65 QDebug &debug;
66 int m_indentLevel = 0;
67 QByteArray m_indent;
68 int nodeCounter = 0;
69};
70
71void SvgDebugVisitor::handleBaseNode(const QSvgNode *node)
72{
73 debug << indent() << typeName(node) << "node, ID:" << node->nodeId();
74 nodeCounter++;
75}
76
77void SvgDebugVisitor::visitNode(const QSvgNode *node)
78{
79 handleBaseNode(node);
80 debug << Qt::endl;
81}
82
83bool SvgDebugVisitor::visitStructureNodeStart(const QSvgStructureNode *node)
84{
85 debug << indent() << "START node" << node->nodeId() << "type" << typeName(node) << node->type() << Qt::endl;
86 m_indentLevel++;
87 return true;
88}
89
90void SvgDebugVisitor::visitStructureNodeEnd(const QSvgStructureNode *node)
91{
92 m_indentLevel--;
93 debug << indent() << "END node" << node->nodeId() << Qt::endl;
94}
95
96void SvgDebugVisitor::visitAnimationNode(const QSvgAnimation *node)
97{
98 handleBaseNode(node);
99 debug << Qt::endl;
100}
101
102void SvgDebugVisitor::visitEllipseNode(const QSvgEllipse *node)
103{
104 handleBaseNode(node);
105 debug << "rect:" << node->rect() << Qt::endl;
106}
107
108void SvgDebugVisitor::visitImageNode(const QSvgImage *node)
109{
110 handleBaseNode(node);
111 debug << "image:" << node->image() << Qt::endl;
112}
113
114void SvgDebugVisitor::visitLineNode(const QSvgLine *node)
115{
116 handleBaseNode(node);
117 debug << "line:" << node->line() << Qt::endl;
118}
119
120void SvgDebugVisitor::visitPathNode(const QSvgPath *node)
121{
122 handleBaseNode(node);
123 debug << "path:" << node->path().elementCount() << "elements." << Qt::endl;
124}
125
126void SvgDebugVisitor::visitPolygonNode(const QSvgPolygon *node)
127{
128 handleBaseNode(node);
129 debug << "polygon:" << node->polygon().size() << "elements." << Qt::endl;
130}
131
132void SvgDebugVisitor::visitPolylineNode(const QSvgPolyline *node)
133{
134 handleBaseNode(node);
135 debug << "polygon:" << node->polygon().size() << "elements." << Qt::endl;
136}
137
138void SvgDebugVisitor::visitRectNode(const QSvgRect *node)
139{
140 handleBaseNode(node);
141 debug << "rect:" << node->rect() << "radius:" << node->radius() << Qt::endl;
142}
143
144void SvgDebugVisitor::visitTextNode(const QSvgText *node)
145{
146 handleBaseNode(node);
147 QString text;
148 for (const auto *tspan : node->tspans()) {
149 if (!tspan)
150 text += QStringLiteral("\\n");
151 else
152 text += tspan->text();
153 }
154 debug << "text:" << text << Qt::endl;
155}
156
157void SvgDebugVisitor::visitUseNode(const QSvgUse *node)
158{
159 handleBaseNode(node);
160 debug << "link ID:" << node->linkId() << Qt::endl;
161}
162
163void SvgDebugVisitor::visitVideoNode(const QSvgVideo *node)
164{
165 handleBaseNode(node);
166 debug << Qt::endl;
167}
168
169void SvgDebugVisitor::write(const QSvgTinyDocument *doc)
170{
171 debug << "SVG" << doc->size() << "viewBox" << doc->viewBox() << Qt::endl;
172 traverse(node: doc);
173
174 debug << "END SVG" << nodeCounter << "nodes";
175}
176
177QDebug operator<<(QDebug debug, const QSvgTinyDocument &doc)
178{
179 SvgDebugVisitor visitor(debug);
180 visitor.write(doc: &doc);
181
182 return debug;
183}
184
185QT_END_NAMESPACE
186

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