Flutter Engine
The Flutter Engine
SkDOM.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/xml/SkDOM.h"
9
10#include <memory>
11
14#include "src/xml/SkXMLParser.h"
15#include "src/xml/SkXMLWriter.h"
16
17bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
18 const char* elemName = dom.getName(node);
19
20 if (this->startElement(elemName)) {
21 return false;
22 }
23
24 SkDOM::AttrIter iter(dom, node);
25 const char* name, *value;
26
27 while ((name = iter.next(&value)) != nullptr) {
28 if (this->addAttribute(name, value)) {
29 return false;
30 }
31 }
32
33 if ((node = dom.getFirstChild(node)) != nullptr) {
34 do {
35 if (!this->parse(dom, node)) {
36 return false;
37 }
38 } while ((node = dom.getNextSibling(node)) != nullptr);
39 }
40 return !this->endElement(elemName);
41}
42
43/////////////////////////////////////////////////////////////////////////
44
45struct SkDOMAttr {
46 const char* fName;
47 const char* fValue;
48};
49
50struct SkDOMNode {
51 const char* fName;
55 uint16_t fAttrCount;
56 uint8_t fType;
57 uint8_t fPad;
58
59 const SkDOMAttr* attrs() const {
60 return fAttrs;
61 }
62
64 return fAttrs;
65 }
66};
67
68/////////////////////////////////////////////////////////////////////////
69
70#define kMinChunkSize 4096
71
72SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
73
75
77 return fRoot;
78}
79
80const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
81 SkASSERT(node);
82 const Node* child = node->fFirstChild;
83
84 if (name) {
85 for (; child != nullptr; child = child->fNextSibling) {
86 if (!strcmp(name, child->fName)) {
87 break;
88 }
89 }
90 }
91 return child;
92}
93
94const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
95 SkASSERT(node);
96 const Node* sibling = node->fNextSibling;
97 if (name) {
98 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
99 if (!strcmp(name, sibling->fName)) {
100 break;
101 }
102 }
103 }
104 return sibling;
105}
106
107SkDOM::Type SkDOM::getType(const Node* node) const {
108 SkASSERT(node);
109 return (Type)node->fType;
110}
111
112const char* SkDOM::getName(const Node* node) const {
113 SkASSERT(node);
114 return node->fName;
115}
116
117const char* SkDOM::findAttr(const Node* node, const char name[]) const {
118 SkASSERT(node);
119 const Attr* attr = node->attrs();
120 const Attr* stop = attr + node->fAttrCount;
121
122 while (attr < stop) {
123 if (!strcmp(attr->fName, name)) {
124 return attr->fValue;
125 }
126 attr += 1;
127 }
128 return nullptr;
129}
130
131/////////////////////////////////////////////////////////////////////////////////////
132
133const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
134 return node->fAttrCount ? node->attrs() : nullptr;
135}
136
137const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
138 SkASSERT(node);
139 if (attr == nullptr) {
140 return nullptr;
141 }
142 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
143}
144
145const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
146 SkASSERT(node);
147 SkASSERT(attr);
148 return attr->fName;
149}
150
151const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
152 SkASSERT(node);
153 SkASSERT(attr);
154 return attr->fValue;
155}
156
157/////////////////////////////////////////////////////////////////////////////////////
158
160 SkASSERT(node);
161 fAttr = node->attrs();
162 fStop = fAttr + node->fAttrCount;
163}
164
165const char* SkDOM::AttrIter::next(const char** value) {
166 const char* name = nullptr;
167
168 if (fAttr < fStop) {
169 name = fAttr->fName;
170 if (value)
171 *value = fAttr->fValue;
172 fAttr += 1;
173 }
174 return name;
175}
176
177//////////////////////////////////////////////////////////////////////////////
178
180#include "src/xml/SkXMLParser.h"
181
182static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
183 SkASSERT(chunk && src);
184 char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
185 memcpy(dst, src, srcLen);
186 dst[srcLen] = '\0';
187 return dst;
188}
189
190class SkDOMParser : public SkXMLParser {
191public:
192 SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
193 fAlloc->reset();
194 fRoot = nullptr;
195 fLevel = 0;
196 fNeedToFlush = true;
197 }
198 SkDOM::Node* getRoot() const { return fRoot; }
200
201protected:
203 SkASSERT(fLevel > 0);
204
205 int attrCount = fAttrs.size();
206
207 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
208 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
209
210 node->fName = fElemName;
211 node->fFirstChild = nullptr;
212 node->fAttrCount = SkToU16(attrCount);
213 node->fAttrs = attrs;
214 node->fType = fElemType;
215
216 if (fRoot == nullptr) {
217 node->fNextSibling = nullptr;
218 fRoot = node;
219 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
220 SkDOM::Node* parent = fParentStack.back();
221 SkASSERT(fRoot && parent);
222 node->fNextSibling = parent->fFirstChild;
223 parent->fFirstChild = node;
224 }
225 *fParentStack.append() = node;
226
227 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
228 fAttrs.reset();
229 }
230
231 bool onStartElement(const char elem[]) override {
232 this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
233 return false;
234 }
235
236 bool onAddAttribute(const char name[], const char value[]) override {
237 SkDOM::Attr* attr = fAttrs.append();
238 attr->fName = dupstr(fAlloc, name, strlen(name));
239 attr->fValue = dupstr(fAlloc, value, strlen(value));
240 return false;
241 }
242
243 bool onEndElement(const char elem[]) override {
244 if (fNeedToFlush)
245 this->flushAttributes();
246 fNeedToFlush = false;
247 --fLevel;
248
249 SkDOM::Node* parent = fParentStack.back();
250 fParentStack.pop_back();
251
252 SkDOM::Node* child = parent->fFirstChild;
253 SkDOM::Node* prev = nullptr;
254 while (child) {
255 SkDOM::Node* next = child->fNextSibling;
256 child->fNextSibling = prev;
257 prev = child;
258 child = next;
259 }
260 parent->fFirstChild = prev;
261 return false;
262 }
263
264 bool onText(const char text[], int len) override {
265 this->startCommon(text, len, SkDOM::kText_Type);
266 this->SkDOMParser::onEndElement(fElemName);
267
268 return false;
269 }
270
271private:
272 void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
273 if (fLevel > 0 && fNeedToFlush) {
274 this->flushAttributes();
275 }
276 fNeedToFlush = true;
277 fElemName = dupstr(fAlloc, elem, elemSize);
278 fElemType = type;
279 ++fLevel;
280 }
281
282 SkTDArray<SkDOM::Node*> fParentStack;
283 SkArenaAllocWithReset* fAlloc;
284 SkDOM::Node* fRoot;
285 bool fNeedToFlush;
286
287 // state needed for flushAttributes()
289 char* fElemName;
290 SkDOM::Type fElemType;
291 int fLevel;
292};
293
295 SkDOMParser parser(&fAlloc);
296 if (!parser.parse(docStream))
297 {
298 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
299 fRoot = nullptr;
300 fAlloc.reset();
301 return nullptr;
302 }
303 fRoot = parser.getRoot();
304 return fRoot;
305}
306
307///////////////////////////////////////////////////////////////////////////
308
309static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
310 const char* elem = dom.getName(node);
311 if (dom.getType(node) == SkDOM::kText_Type) {
312 SkASSERT(dom.countChildren(node) == 0);
313 parser->text(elem, SkToInt(strlen(elem)));
314 return;
315 }
316
317 parser->startElement(elem);
318
319 SkDOM::AttrIter iter(dom, node);
320 const char* name;
321 const char* value;
322 while ((name = iter.next(&value)) != nullptr)
323 parser->addAttribute(name, value);
324
325 node = dom.getFirstChild(node, nullptr);
326 while (node)
327 {
328 walk_dom(dom, node, parser);
329 node = dom.getNextSibling(node, nullptr);
330 }
331
332 parser->endElement(elem);
333}
334
335const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
336 SkDOMParser parser(&fAlloc);
337
338 walk_dom(dom, node, &parser);
339
340 fRoot = parser.getRoot();
341 return fRoot;
342}
343
345 SkASSERT(!fParser);
346 fParser = std::make_unique<SkDOMParser>(&fAlloc);
347
348 return fParser.get();
349}
350
352 SkASSERT(fParser);
353 fRoot = fParser->getRoot();
354 fParser.reset();
355
356 return fRoot;
357}
358
359//////////////////////////////////////////////////////////////////////////
360
361int SkDOM::countChildren(const Node* node, const char elem[]) const {
362 int count = 0;
363
364 node = this->getFirstChild(node, elem);
365 while (node) {
366 count += 1;
367 node = this->getNextSibling(node, elem);
368 }
369 return count;
370}
371
372//////////////////////////////////////////////////////////////////////////
373
375
376bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
377 const char* vstr = this->findAttr(node, name);
378 return vstr && SkParse::FindS32(vstr, value);
379}
380
381bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
382 const char* vstr = this->findAttr(node, name);
383 return vstr && SkParse::FindScalars(vstr, value, count);
384}
385
386bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
387 const char* vstr = this->findAttr(node, name);
388 return vstr && SkParse::FindHex(vstr, value);
389}
390
391bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
392 const char* vstr = this->findAttr(node, name);
393 return vstr && SkParse::FindBool(vstr, value);
394}
395
396int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
397 const char* vstr = this->findAttr(node, name);
398 return vstr ? SkParse::FindList(vstr, list) : -1;
399}
400
401bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
402 const char* vstr = this->findAttr(node, name);
403 return vstr && !strcmp(vstr, value);
404}
405
406bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
407 const char* vstr = this->findAttr(node, name);
408 int32_t value;
409 return vstr && SkParse::FindS32(vstr, &value) && value == target;
410}
411
412bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
413 const char* vstr = this->findAttr(node, name);
415 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
416}
417
418bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
419 const char* vstr = this->findAttr(node, name);
420 uint32_t value;
421 return vstr && SkParse::FindHex(vstr, &value) && value == target;
422}
423
424bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
425 const char* vstr = this->findAttr(node, name);
426 bool value;
427 return vstr && SkParse::FindBool(vstr, &value) && value == target;
428}
int count
Definition: FontMgrTest.cpp:50
static float next(float f)
static float prev(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define kMinChunkSize
Definition: SkDOM.cpp:70
static void walk_dom(const SkDOM &dom, const SkDOM::Node *node, SkXMLParser *parser)
Definition: SkDOM.cpp:309
static char * dupstr(SkArenaAlloc *chunk, const char src[], size_t srcLen)
Definition: SkDOM.cpp:182
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
Definition: SkMalloc.h:125
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr uint16_t SkToU16(S x)
Definition: SkTo.h:24
constexpr int SkToInt(S x)
Definition: SkTo.h:29
GLenum type
T * makeArrayDefault(size_t count)
Definition: SkArenaAlloc.h:171
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
bool onEndElement(const char elem[]) override
Definition: SkDOM.cpp:243
SkXMLParserError fParserError
Definition: SkDOM.cpp:199
void flushAttributes()
Definition: SkDOM.cpp:202
SkDOM::Node * getRoot() const
Definition: SkDOM.cpp:198
bool onAddAttribute(const char name[], const char value[]) override
Definition: SkDOM.cpp:236
SkDOMParser(SkArenaAllocWithReset *chunk)
Definition: SkDOM.cpp:192
bool onText(const char text[], int len) override
Definition: SkDOM.cpp:264
bool onStartElement(const char elem[]) override
Definition: SkDOM.cpp:231
const char * next(const char **value)
Definition: SkDOM.cpp:165
AttrIter(const SkDOM &, const Node *)
Definition: SkDOM.cpp:159
Definition: SkDOM.h:24
const Node * finishParsing()
Definition: SkDOM.cpp:351
const Attr * getNextAttr(const Node *, const Attr *) const
Definition: SkDOM.cpp:137
bool hasS32(const Node *, const char name[], int32_t value) const
Definition: SkDOM.cpp:406
Type
Definition: SkDOM.h:42
@ kText_Type
Definition: SkDOM.h:44
@ kElement_Type
Definition: SkDOM.h:43
bool findS32(const Node *, const char name[], int32_t *value) const
Definition: SkDOM.cpp:376
const Attr * getFirstAttr(const Node *) const
Definition: SkDOM.cpp:133
int findList(const Node *, const char name[], const char list[]) const
Definition: SkDOM.cpp:396
const char * getAttrValue(const Node *, const Attr *) const
Definition: SkDOM.cpp:151
bool findBool(const Node *, const char name[], bool *) const
Definition: SkDOM.cpp:391
const Node * getRootNode() const
Definition: SkDOM.cpp:76
const Node * copy(const SkDOM &dom, const Node *node)
Definition: SkDOM.cpp:335
bool findScalars(const Node *, const char name[], SkScalar value[], int count) const
Definition: SkDOM.cpp:381
bool hasScalar(const Node *, const char name[], SkScalar value) const
Definition: SkDOM.cpp:412
const Node * getNextSibling(const Node *, const char elem[]=nullptr) const
Definition: SkDOM.cpp:94
bool hasHex(const Node *, const char name[], uint32_t value) const
Definition: SkDOM.cpp:418
SkDOM()
Definition: SkDOM.cpp:72
~SkDOM()
Definition: SkDOM.cpp:74
bool findHex(const Node *, const char name[], uint32_t *value) const
Definition: SkDOM.cpp:386
bool hasAttr(const Node *, const char name[], const char value[]) const
Definition: SkDOM.cpp:401
const Node * getFirstChild(const Node *, const char elem[]=nullptr) const
Definition: SkDOM.cpp:80
const char * getName(const Node *) const
Definition: SkDOM.cpp:112
bool hasBool(const Node *, const char name[], bool value) const
Definition: SkDOM.cpp:424
Type getType(const Node *) const
Definition: SkDOM.cpp:107
SkXMLParser * beginParsing()
Definition: SkDOM.cpp:344
const Node * build(SkStream &)
Definition: SkDOM.cpp:294
int countChildren(const Node *node, const char elem[]=nullptr) const
Definition: SkDOM.cpp:361
const char * findAttr(const Node *, const char attrName[]) const
Definition: SkDOM.cpp:117
const char * getAttrName(const Node *, const Attr *) const
Definition: SkDOM.cpp:145
static const char * FindScalar(const char str[], SkScalar *value)
Definition: SkParse.cpp:216
static const char * FindHex(const char str[], uint32_t *value)
Definition: SkParse.cpp:114
static const char * FindS32(const char str[], int32_t *value)
Definition: SkParse.cpp:143
static const char * FindScalars(const char str[], SkScalar value[], int count)
Definition: SkParse.cpp:231
static int FindList(const char str[], const char list[])
Definition: SkParse.cpp:278
static bool FindBool(const char str[], bool *value)
Definition: SkParse.cpp:260
bool startElement(const char elem[])
bool endElement(const char elem[])
bool addAttribute(const char name[], const char value[])
bool parse(const char doc[], size_t len)
float SkScalar
Definition: extension.cpp:12
uint8_t value
uint32_t * target
std::u16string text
Definition: dom.py:1
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
dst
Definition: cp.py:12
parser
Definition: zip.py:78
const char * fValue
Definition: SkDOM.cpp:47
const char * fName
Definition: SkDOM.cpp:46
SkDOMNode * fNextSibling
Definition: SkDOM.cpp:53
uint8_t fPad
Definition: SkDOM.cpp:57
SkDOMNode * fFirstChild
Definition: SkDOM.cpp:52
SkDOMAttr * fAttrs
Definition: SkDOM.cpp:54
uint16_t fAttrCount
Definition: SkDOM.cpp:55
const char * fName
Definition: SkDOM.cpp:51
SkDOMAttr * attrs()
Definition: SkDOM.cpp:63
uint8_t fType
Definition: SkDOM.cpp:56
const SkDOMAttr * attrs() const
Definition: SkDOM.cpp:59