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 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | static 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. |
32 | static 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 | |
40 | class SvgDebugVisitor : public QSvgVisitor |
41 | { |
42 | public: |
43 | SvgDebugVisitor(QDebug &stream) : debug(stream) {} |
44 | void write(const QSvgTinyDocument *doc); |
45 | |
46 | protected: |
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 | |
62 | private: |
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 | |
71 | void SvgDebugVisitor::handleBaseNode(const QSvgNode *node) |
72 | { |
73 | debug << indent() << typeName(node) << "node, ID:" << node->nodeId(); |
74 | nodeCounter++; |
75 | } |
76 | |
77 | void SvgDebugVisitor::visitNode(const QSvgNode *node) |
78 | { |
79 | handleBaseNode(node); |
80 | debug << Qt::endl; |
81 | } |
82 | |
83 | bool 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 | |
90 | void SvgDebugVisitor::visitStructureNodeEnd(const QSvgStructureNode *node) |
91 | { |
92 | m_indentLevel--; |
93 | debug << indent() << "END node" << node->nodeId() << Qt::endl; |
94 | } |
95 | |
96 | void SvgDebugVisitor::visitAnimationNode(const QSvgAnimation *node) |
97 | { |
98 | handleBaseNode(node); |
99 | debug << Qt::endl; |
100 | } |
101 | |
102 | void SvgDebugVisitor::visitEllipseNode(const QSvgEllipse *node) |
103 | { |
104 | handleBaseNode(node); |
105 | debug << "rect:" << node->rect() << Qt::endl; |
106 | } |
107 | |
108 | void SvgDebugVisitor::visitImageNode(const QSvgImage *node) |
109 | { |
110 | handleBaseNode(node); |
111 | debug << "image:" << node->image() << Qt::endl; |
112 | } |
113 | |
114 | void SvgDebugVisitor::visitLineNode(const QSvgLine *node) |
115 | { |
116 | handleBaseNode(node); |
117 | debug << "line:" << node->line() << Qt::endl; |
118 | } |
119 | |
120 | void SvgDebugVisitor::visitPathNode(const QSvgPath *node) |
121 | { |
122 | handleBaseNode(node); |
123 | debug << "path:" << node->path().elementCount() << "elements." << Qt::endl; |
124 | } |
125 | |
126 | void SvgDebugVisitor::visitPolygonNode(const QSvgPolygon *node) |
127 | { |
128 | handleBaseNode(node); |
129 | debug << "polygon:" << node->polygon().size() << "elements." << Qt::endl; |
130 | } |
131 | |
132 | void SvgDebugVisitor::visitPolylineNode(const QSvgPolyline *node) |
133 | { |
134 | handleBaseNode(node); |
135 | debug << "polygon:" << node->polygon().size() << "elements." << Qt::endl; |
136 | } |
137 | |
138 | void SvgDebugVisitor::visitRectNode(const QSvgRect *node) |
139 | { |
140 | handleBaseNode(node); |
141 | debug << "rect:" << node->rect() << "radius:" << node->radius() << Qt::endl; |
142 | } |
143 | |
144 | void 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 | |
157 | void SvgDebugVisitor::visitUseNode(const QSvgUse *node) |
158 | { |
159 | handleBaseNode(node); |
160 | debug << "link ID:" << node->linkId() << Qt::endl; |
161 | } |
162 | |
163 | void SvgDebugVisitor::visitVideoNode(const QSvgVideo *node) |
164 | { |
165 | handleBaseNode(node); |
166 | debug << Qt::endl; |
167 | } |
168 | |
169 | void 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 | |
177 | QDebug operator<<(QDebug debug, const QSvgTinyDocument &doc) |
178 | { |
179 | SvgDebugVisitor visitor(debug); |
180 | visitor.write(doc: &doc); |
181 | |
182 | return debug; |
183 | } |
184 | |
185 | QT_END_NAMESPACE |
186 | |