blob: 49d4db2923b0653dd0c41630976f748a544f1281 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/xml/SkDOM.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
11
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkStream.h"
13#include "include/private/SkTo.h"
14#include "src/xml/SkXMLParser.h"
15#include "src/xml/SkXMLWriter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
Mike Reedc3063e52017-01-07 16:16:02 -050017bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000018 const char* elemName = dom.getName(node);
19
Mike Reedc3063e52017-01-07 16:16:02 -050020 if (this->startElement(elemName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050022 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000023
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 SkDOM::AttrIter iter(dom, node);
25 const char* name, *value;
rmistry@google.comd6176b02012-08-23 18:14:13 +000026
Mike Reedc3063e52017-01-07 16:16:02 -050027 while ((name = iter.next(&value)) != nullptr) {
28 if (this->addAttribute(name, value)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050030 }
31 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
Mike Reedc3063e52017-01-07 16:16:02 -050033 if ((node = dom.getFirstChild(node)) != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 do {
Mike Reedc3063e52017-01-07 16:16:02 -050035 if (!this->parse(dom, node)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050037 }
halcanary96fcdcc2015-08-27 07:41:13 -070038 } while ((node = dom.getNextSibling(node)) != nullptr);
Mike Reedc3063e52017-01-07 16:16:02 -050039 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 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;
52 SkDOMNode* fFirstChild;
53 SkDOMNode* fNextSibling;
Herb Derby70c60632017-02-14 15:21:07 -050054 SkDOMAttr* fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 uint16_t fAttrCount;
56 uint8_t fType;
57 uint8_t fPad;
58
Mike Reedc3063e52017-01-07 16:16:02 -050059 const SkDOMAttr* attrs() const {
Herb Derby70c60632017-02-14 15:21:07 -050060 return fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 }
Mike Reedc3063e52017-01-07 16:16:02 -050062
63 SkDOMAttr* attrs() {
Herb Derby70c60632017-02-14 15:21:07 -050064 return fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 }
66};
67
68/////////////////////////////////////////////////////////////////////////
69
Mike Reedf67c4592017-02-17 17:06:11 -050070#define kMinChunkSize 4096
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
Mike Reedc3063e52017-01-07 16:16:02 -050072SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000073
Mike Reedc3063e52017-01-07 16:16:02 -050074SkDOM::~SkDOM() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000075
Mike Reedc3063e52017-01-07 16:16:02 -050076const SkDOM::Node* SkDOM::getRootNode() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 return fRoot;
78}
79
Mike Reedc3063e52017-01-07 16:16:02 -050080const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 SkASSERT(node);
82 const Node* child = node->fFirstChild;
83
Mike Reedc3063e52017-01-07 16:16:02 -050084 if (name) {
85 for (; child != nullptr; child = child->fNextSibling) {
86 if (!strcmp(name, child->fName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 break;
Mike Reedc3063e52017-01-07 16:16:02 -050088 }
89 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 }
91 return child;
92}
93
Mike Reedc3063e52017-01-07 16:16:02 -050094const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 SkASSERT(node);
96 const Node* sibling = node->fNextSibling;
Mike Reedc3063e52017-01-07 16:16:02 -050097 if (name) {
98 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
99 if (!strcmp(name, sibling->fName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 break;
Mike Reedc3063e52017-01-07 16:16:02 -0500101 }
102 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 }
104 return sibling;
105}
106
Mike Reedc3063e52017-01-07 16:16:02 -0500107SkDOM::Type SkDOM::getType(const Node* node) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 SkASSERT(node);
109 return (Type)node->fType;
110}
111
Mike Reedc3063e52017-01-07 16:16:02 -0500112const char* SkDOM::getName(const Node* node) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 SkASSERT(node);
114 return node->fName;
115}
116
Mike Reedc3063e52017-01-07 16:16:02 -0500117const char* SkDOM::findAttr(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 SkASSERT(node);
119 const Attr* attr = node->attrs();
120 const Attr* stop = attr + node->fAttrCount;
121
Mike Reedc3063e52017-01-07 16:16:02 -0500122 while (attr < stop) {
123 if (!strcmp(attr->fName, name)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 return attr->fValue;
Mike Reedc3063e52017-01-07 16:16:02 -0500125 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 attr += 1;
127 }
halcanary96fcdcc2015-08-27 07:41:13 -0700128 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129}
130
131/////////////////////////////////////////////////////////////////////////////////////
132
Mike Reedc3063e52017-01-07 16:16:02 -0500133const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700134 return node->fAttrCount ? node->attrs() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135}
136
Mike Reedc3063e52017-01-07 16:16:02 -0500137const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 SkASSERT(node);
Mike Reedc3063e52017-01-07 16:16:02 -0500139 if (attr == nullptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700140 return nullptr;
Mike Reedc3063e52017-01-07 16:16:02 -0500141 }
halcanary96fcdcc2015-08-27 07:41:13 -0700142 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143}
144
Mike Reedc3063e52017-01-07 16:16:02 -0500145const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 SkASSERT(node);
147 SkASSERT(attr);
148 return attr->fName;
149}
150
Mike Reedc3063e52017-01-07 16:16:02 -0500151const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 SkASSERT(node);
153 SkASSERT(attr);
154 return attr->fValue;
155}
156
157/////////////////////////////////////////////////////////////////////////////////////
158
Mike Reedc3063e52017-01-07 16:16:02 -0500159SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 SkASSERT(node);
161 fAttr = node->attrs();
162 fStop = fAttr + node->fAttrCount;
163}
164
Mike Reedc3063e52017-01-07 16:16:02 -0500165const char* SkDOM::AttrIter::next(const char** value) {
halcanary96fcdcc2015-08-27 07:41:13 -0700166 const char* name = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167
Mike Reedc3063e52017-01-07 16:16:02 -0500168 if (fAttr < fStop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 name = fAttr->fName;
170 if (value)
171 *value = fAttr->fValue;
172 fAttr += 1;
173 }
174 return name;
175}
176
177//////////////////////////////////////////////////////////////////////////////
178
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500179#include "include/private/SkTDArray.h"
180#include "src/xml/SkXMLParser.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500182static char* dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 SkASSERT(chunk && src);
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500184 char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
185 memcpy(dst, src, srcLen);
186 dst[srcLen] = '\0';
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 return dst;
188}
189
190class SkDOMParser : public SkXMLParser {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191public:
Herb Derby6e2c56f2020-08-01 16:26:04 -0400192 SkDOMParser(SkArenaAllocWithReset* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
fmalita7a048692015-02-20 13:54:40 -0800193 fAlloc->reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700194 fRoot = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 fLevel = 0;
196 fNeedToFlush = true;
197 }
198 SkDOM::Node* getRoot() const { return fRoot; }
199 SkXMLParserError fParserError;
fmalita7a048692015-02-20 13:54:40 -0800200
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201protected:
Mike Reedc3063e52017-01-07 16:16:02 -0500202 void flushAttributes() {
fmalita7a048692015-02-20 13:54:40 -0800203 SkASSERT(fLevel > 0);
204
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 int attrCount = fAttrs.count();
206
Herb Derby70c60632017-02-14 15:21:07 -0500207 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
208 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
210 node->fName = fElemName;
halcanary96fcdcc2015-08-27 07:41:13 -0700211 node->fFirstChild = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 node->fAttrCount = SkToU16(attrCount);
Herb Derby70c60632017-02-14 15:21:07 -0500213 node->fAttrs = attrs;
fmalita7a048692015-02-20 13:54:40 -0800214 node->fType = fElemType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215
Mike Reedc3063e52017-01-07 16:16:02 -0500216 if (fRoot == nullptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700217 node->fNextSibling = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 fRoot = node;
Mike Reedc3063e52017-01-07 16:16:02 -0500219 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 SkDOM::Node* parent = fParentStack.top();
221 SkASSERT(fRoot && parent);
222 node->fNextSibling = parent->fFirstChild;
223 parent->fFirstChild = node;
224 }
225 *fParentStack.push() = node;
226
mtklein067e90e2015-12-10 07:42:47 -0800227 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 fAttrs.reset();
229
230 }
fmalita7a048692015-02-20 13:54:40 -0800231
232 bool onStartElement(const char elem[]) override {
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500233 this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 return false;
235 }
fmalita7a048692015-02-20 13:54:40 -0800236
237 bool onAddAttribute(const char name[], const char value[]) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 SkDOM::Attr* attr = fAttrs.append();
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500239 attr->fName = dupstr(fAlloc, name, strlen(name));
240 attr->fValue = dupstr(fAlloc, value, strlen(value));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 return false;
242 }
fmalita7a048692015-02-20 13:54:40 -0800243
244 bool onEndElement(const char elem[]) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 --fLevel;
246 if (fNeedToFlush)
247 this->flushAttributes();
248 fNeedToFlush = false;
249
250 SkDOM::Node* parent;
251
252 fParentStack.pop(&parent);
253
254 SkDOM::Node* child = parent->fFirstChild;
halcanary96fcdcc2015-08-27 07:41:13 -0700255 SkDOM::Node* prev = nullptr;
Mike Reedc3063e52017-01-07 16:16:02 -0500256 while (child) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 SkDOM::Node* next = child->fNextSibling;
258 child->fNextSibling = prev;
259 prev = child;
260 child = next;
261 }
262 parent->fFirstChild = prev;
263 return false;
264 }
fmalita7a048692015-02-20 13:54:40 -0800265
266 bool onText(const char text[], int len) override {
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500267 this->startCommon(text, len, SkDOM::kText_Type);
268 this->SkDOMParser::onEndElement(fElemName);
fmalita7a048692015-02-20 13:54:40 -0800269
270 return false;
271 }
272
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273private:
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500274 void startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
Mike Reedc3063e52017-01-07 16:16:02 -0500275 if (fLevel > 0 && fNeedToFlush) {
fmalita7a048692015-02-20 13:54:40 -0800276 this->flushAttributes();
Mike Reedc3063e52017-01-07 16:16:02 -0500277 }
fmalita7a048692015-02-20 13:54:40 -0800278 fNeedToFlush = true;
Ben Wagner81bc8fe2021-01-11 16:13:45 -0500279 fElemName = dupstr(fAlloc, elem, elemSize);
fmalita7a048692015-02-20 13:54:40 -0800280 fElemType = type;
281 ++fLevel;
282 }
283
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 SkTDArray<SkDOM::Node*> fParentStack;
Herb Derby6e2c56f2020-08-01 16:26:04 -0400285 SkArenaAllocWithReset* fAlloc;
fmalita7a048692015-02-20 13:54:40 -0800286 SkDOM::Node* fRoot;
287 bool fNeedToFlush;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288
289 // state needed for flushAttributes()
290 SkTDArray<SkDOM::Attr> fAttrs;
291 char* fElemName;
fmalita7a048692015-02-20 13:54:40 -0800292 SkDOM::Type fElemType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 int fLevel;
294};
295
fmalita7445e862016-07-14 19:14:06 -0700296const SkDOM::Node* SkDOM::build(SkStream& docStream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 SkDOMParser parser(&fAlloc);
fmalita7445e862016-07-14 19:14:06 -0700298 if (!parser.parse(docStream))
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 {
300 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
halcanary96fcdcc2015-08-27 07:41:13 -0700301 fRoot = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 fAlloc.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700303 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 }
305 fRoot = parser.getRoot();
306 return fRoot;
307}
308
309///////////////////////////////////////////////////////////////////////////
310
Mike Reedc3063e52017-01-07 16:16:02 -0500311static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 const char* elem = dom.getName(node);
fmalita7a048692015-02-20 13:54:40 -0800313 if (dom.getType(node) == SkDOM::kText_Type) {
314 SkASSERT(dom.countChildren(node) == 0);
315 parser->text(elem, SkToInt(strlen(elem)));
316 return;
317 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318
319 parser->startElement(elem);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000320
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 SkDOM::AttrIter iter(dom, node);
322 const char* name;
323 const char* value;
halcanary96fcdcc2015-08-27 07:41:13 -0700324 while ((name = iter.next(&value)) != nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 parser->addAttribute(name, value);
326
halcanary96fcdcc2015-08-27 07:41:13 -0700327 node = dom.getFirstChild(node, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 while (node)
329 {
330 walk_dom(dom, node, parser);
halcanary96fcdcc2015-08-27 07:41:13 -0700331 node = dom.getNextSibling(node, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 }
333
334 parser->endElement(elem);
335}
336
Mike Reedc3063e52017-01-07 16:16:02 -0500337const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 SkDOMParser parser(&fAlloc);
339
340 walk_dom(dom, node, &parser);
341
342 fRoot = parser.getRoot();
343 return fRoot;
344}
345
fmalita7a048692015-02-20 13:54:40 -0800346SkXMLParser* SkDOM::beginParsing() {
347 SkASSERT(!fParser);
John Stilesfbd050b2020-08-03 13:21:46 -0400348 fParser = std::make_unique<SkDOMParser>(&fAlloc);
fmalita7a048692015-02-20 13:54:40 -0800349
350 return fParser.get();
351}
352
353const SkDOM::Node* SkDOM::finishParsing() {
354 SkASSERT(fParser);
355 fRoot = fParser->getRoot();
mtklein852f15d2016-03-17 10:51:27 -0700356 fParser.reset();
fmalita7a048692015-02-20 13:54:40 -0800357
358 return fRoot;
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361//////////////////////////////////////////////////////////////////////////
362
Mike Reedc3063e52017-01-07 16:16:02 -0500363int SkDOM::countChildren(const Node* node, const char elem[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 int count = 0;
365
366 node = this->getFirstChild(node, elem);
Mike Reedc3063e52017-01-07 16:16:02 -0500367 while (node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 count += 1;
369 node = this->getNextSibling(node, elem);
370 }
371 return count;
372}
373
374//////////////////////////////////////////////////////////////////////////
375
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500376#include "include/utils/SkParse.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377
Mike Reedc3063e52017-01-07 16:16:02 -0500378bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const char* vstr = this->findAttr(node, name);
380 return vstr && SkParse::FindS32(vstr, value);
381}
382
Mike Reedc3063e52017-01-07 16:16:02 -0500383bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 const char* vstr = this->findAttr(node, name);
385 return vstr && SkParse::FindScalars(vstr, value, count);
386}
387
Mike Reedc3063e52017-01-07 16:16:02 -0500388bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 const char* vstr = this->findAttr(node, name);
390 return vstr && SkParse::FindHex(vstr, value);
391}
392
Mike Reedc3063e52017-01-07 16:16:02 -0500393bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 const char* vstr = this->findAttr(node, name);
395 return vstr && SkParse::FindBool(vstr, value);
396}
397
Mike Reedc3063e52017-01-07 16:16:02 -0500398int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 const char* vstr = this->findAttr(node, name);
400 return vstr ? SkParse::FindList(vstr, list) : -1;
401}
402
Mike Reedc3063e52017-01-07 16:16:02 -0500403bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 const char* vstr = this->findAttr(node, name);
405 return vstr && !strcmp(vstr, value);
406}
407
Mike Reedc3063e52017-01-07 16:16:02 -0500408bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 const char* vstr = this->findAttr(node, name);
410 int32_t value;
411 return vstr && SkParse::FindS32(vstr, &value) && value == target;
412}
413
Mike Reedc3063e52017-01-07 16:16:02 -0500414bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 const char* vstr = this->findAttr(node, name);
416 SkScalar value;
417 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
418}
419
Mike Reedc3063e52017-01-07 16:16:02 -0500420bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 const char* vstr = this->findAttr(node, name);
422 uint32_t value;
423 return vstr && SkParse::FindHex(vstr, &value) && value == target;
424}
425
Mike Reedc3063e52017-01-07 16:16:02 -0500426bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 const char* vstr = this->findAttr(node, name);
428 bool value;
429 return vstr && SkParse::FindBool(vstr, &value) && value == target;
430}