blob: e6c343515fbacf6b3cdb1255bd8674016938c454 [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
Hal Canaryfdcfb8b2018-06-13 09:42:32 -04008#include "SkDOM.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
fmalita7a048692015-02-20 13:54:40 -080010#include "SkStream.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040011#include "SkTo.h"
Mike Reedc3063e52017-01-07 16:16:02 -050012#include "SkXMLParser.h"
fmalita7a048692015-02-20 13:54:40 -080013#include "SkXMLWriter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
Mike Reedc3063e52017-01-07 16:16:02 -050015bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000016 const char* elemName = dom.getName(node);
17
Mike Reedc3063e52017-01-07 16:16:02 -050018 if (this->startElement(elemName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000019 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050020 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000021
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 SkDOM::AttrIter iter(dom, node);
23 const char* name, *value;
rmistry@google.comd6176b02012-08-23 18:14:13 +000024
Mike Reedc3063e52017-01-07 16:16:02 -050025 while ((name = iter.next(&value)) != nullptr) {
26 if (this->addAttribute(name, value)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000027 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050028 }
29 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000030
Mike Reedc3063e52017-01-07 16:16:02 -050031 if ((node = dom.getFirstChild(node)) != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 do {
Mike Reedc3063e52017-01-07 16:16:02 -050033 if (!this->parse(dom, node)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 return false;
Mike Reedc3063e52017-01-07 16:16:02 -050035 }
halcanary96fcdcc2015-08-27 07:41:13 -070036 } while ((node = dom.getNextSibling(node)) != nullptr);
Mike Reedc3063e52017-01-07 16:16:02 -050037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 return !this->endElement(elemName);
39}
40
41/////////////////////////////////////////////////////////////////////////
42
43struct SkDOMAttr {
44 const char* fName;
45 const char* fValue;
46};
47
48struct SkDOMNode {
49 const char* fName;
50 SkDOMNode* fFirstChild;
51 SkDOMNode* fNextSibling;
Herb Derby70c60632017-02-14 15:21:07 -050052 SkDOMAttr* fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 uint16_t fAttrCount;
54 uint8_t fType;
55 uint8_t fPad;
56
Mike Reedc3063e52017-01-07 16:16:02 -050057 const SkDOMAttr* attrs() const {
Herb Derby70c60632017-02-14 15:21:07 -050058 return fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 }
Mike Reedc3063e52017-01-07 16:16:02 -050060
61 SkDOMAttr* attrs() {
Herb Derby70c60632017-02-14 15:21:07 -050062 return fAttrs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 }
64};
65
66/////////////////////////////////////////////////////////////////////////
67
Mike Reedf67c4592017-02-17 17:06:11 -050068#define kMinChunkSize 4096
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
Mike Reedc3063e52017-01-07 16:16:02 -050070SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
Mike Reedc3063e52017-01-07 16:16:02 -050072SkDOM::~SkDOM() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000073
Mike Reedc3063e52017-01-07 16:16:02 -050074const SkDOM::Node* SkDOM::getRootNode() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 return fRoot;
76}
77
Mike Reedc3063e52017-01-07 16:16:02 -050078const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 SkASSERT(node);
80 const Node* child = node->fFirstChild;
81
Mike Reedc3063e52017-01-07 16:16:02 -050082 if (name) {
83 for (; child != nullptr; child = child->fNextSibling) {
84 if (!strcmp(name, child->fName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 break;
Mike Reedc3063e52017-01-07 16:16:02 -050086 }
87 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 }
89 return child;
90}
91
Mike Reedc3063e52017-01-07 16:16:02 -050092const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 SkASSERT(node);
94 const Node* sibling = node->fNextSibling;
Mike Reedc3063e52017-01-07 16:16:02 -050095 if (name) {
96 for (; sibling != nullptr; sibling = sibling->fNextSibling) {
97 if (!strcmp(name, sibling->fName)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 break;
Mike Reedc3063e52017-01-07 16:16:02 -050099 }
100 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 }
102 return sibling;
103}
104
Mike Reedc3063e52017-01-07 16:16:02 -0500105SkDOM::Type SkDOM::getType(const Node* node) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 SkASSERT(node);
107 return (Type)node->fType;
108}
109
Mike Reedc3063e52017-01-07 16:16:02 -0500110const char* SkDOM::getName(const Node* node) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 SkASSERT(node);
112 return node->fName;
113}
114
Mike Reedc3063e52017-01-07 16:16:02 -0500115const char* SkDOM::findAttr(const Node* node, const char name[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 SkASSERT(node);
117 const Attr* attr = node->attrs();
118 const Attr* stop = attr + node->fAttrCount;
119
Mike Reedc3063e52017-01-07 16:16:02 -0500120 while (attr < stop) {
121 if (!strcmp(attr->fName, name)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 return attr->fValue;
Mike Reedc3063e52017-01-07 16:16:02 -0500123 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 attr += 1;
125 }
halcanary96fcdcc2015-08-27 07:41:13 -0700126 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127}
128
129/////////////////////////////////////////////////////////////////////////////////////
130
Mike Reedc3063e52017-01-07 16:16:02 -0500131const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700132 return node->fAttrCount ? node->attrs() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133}
134
Mike Reedc3063e52017-01-07 16:16:02 -0500135const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 SkASSERT(node);
Mike Reedc3063e52017-01-07 16:16:02 -0500137 if (attr == nullptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700138 return nullptr;
Mike Reedc3063e52017-01-07 16:16:02 -0500139 }
halcanary96fcdcc2015-08-27 07:41:13 -0700140 return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141}
142
Mike Reedc3063e52017-01-07 16:16:02 -0500143const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 SkASSERT(node);
145 SkASSERT(attr);
146 return attr->fName;
147}
148
Mike Reedc3063e52017-01-07 16:16:02 -0500149const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 SkASSERT(node);
151 SkASSERT(attr);
152 return attr->fValue;
153}
154
155/////////////////////////////////////////////////////////////////////////////////////
156
Mike Reedc3063e52017-01-07 16:16:02 -0500157SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 SkASSERT(node);
159 fAttr = node->attrs();
160 fStop = fAttr + node->fAttrCount;
161}
162
Mike Reedc3063e52017-01-07 16:16:02 -0500163const char* SkDOM::AttrIter::next(const char** value) {
halcanary96fcdcc2015-08-27 07:41:13 -0700164 const char* name = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165
Mike Reedc3063e52017-01-07 16:16:02 -0500166 if (fAttr < fStop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 name = fAttr->fName;
168 if (value)
169 *value = fAttr->fValue;
170 fAttr += 1;
171 }
172 return name;
173}
174
175//////////////////////////////////////////////////////////////////////////////
176
177#include "SkXMLParser.h"
178#include "SkTDArray.h"
179
Herb Derby70c60632017-02-14 15:21:07 -0500180static char* dupstr(SkArenaAlloc* chunk, const char src[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 SkASSERT(chunk && src);
182 size_t len = strlen(src);
Herb Derby70c60632017-02-14 15:21:07 -0500183 char* dst = chunk->makeArrayDefault<char>(len + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 memcpy(dst, src, len + 1);
185 return dst;
186}
187
188class SkDOMParser : public SkXMLParser {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189public:
Herb Derby70c60632017-02-14 15:21:07 -0500190 SkDOMParser(SkArenaAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk) {
fmalita7a048692015-02-20 13:54:40 -0800191 fAlloc->reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700192 fRoot = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 fLevel = 0;
194 fNeedToFlush = true;
195 }
196 SkDOM::Node* getRoot() const { return fRoot; }
197 SkXMLParserError fParserError;
fmalita7a048692015-02-20 13:54:40 -0800198
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199protected:
Mike Reedc3063e52017-01-07 16:16:02 -0500200 void flushAttributes() {
fmalita7a048692015-02-20 13:54:40 -0800201 SkASSERT(fLevel > 0);
202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 int attrCount = fAttrs.count();
204
Herb Derby70c60632017-02-14 15:21:07 -0500205 SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
206 SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207
208 node->fName = fElemName;
halcanary96fcdcc2015-08-27 07:41:13 -0700209 node->fFirstChild = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 node->fAttrCount = SkToU16(attrCount);
Herb Derby70c60632017-02-14 15:21:07 -0500211 node->fAttrs = attrs;
fmalita7a048692015-02-20 13:54:40 -0800212 node->fType = fElemType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
Mike Reedc3063e52017-01-07 16:16:02 -0500214 if (fRoot == nullptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700215 node->fNextSibling = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 fRoot = node;
Mike Reedc3063e52017-01-07 16:16:02 -0500217 } else { // this adds siblings in reverse order. gets corrected in onEndElement()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 SkDOM::Node* parent = fParentStack.top();
219 SkASSERT(fRoot && parent);
220 node->fNextSibling = parent->fFirstChild;
221 parent->fFirstChild = node;
222 }
223 *fParentStack.push() = node;
224
mtklein067e90e2015-12-10 07:42:47 -0800225 sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 fAttrs.reset();
227
228 }
fmalita7a048692015-02-20 13:54:40 -0800229
230 bool onStartElement(const char elem[]) override {
231 this->startCommon(elem, SkDOM::kElement_Type);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 return false;
233 }
fmalita7a048692015-02-20 13:54:40 -0800234
235 bool onAddAttribute(const char name[], const char value[]) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 SkDOM::Attr* attr = fAttrs.append();
237 attr->fName = dupstr(fAlloc, name);
238 attr->fValue = dupstr(fAlloc, value);
239 return false;
240 }
fmalita7a048692015-02-20 13:54:40 -0800241
242 bool onEndElement(const char elem[]) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 --fLevel;
244 if (fNeedToFlush)
245 this->flushAttributes();
246 fNeedToFlush = false;
247
248 SkDOM::Node* parent;
249
250 fParentStack.pop(&parent);
251
252 SkDOM::Node* child = parent->fFirstChild;
halcanary96fcdcc2015-08-27 07:41:13 -0700253 SkDOM::Node* prev = nullptr;
Mike Reedc3063e52017-01-07 16:16:02 -0500254 while (child) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 SkDOM::Node* next = child->fNextSibling;
256 child->fNextSibling = prev;
257 prev = child;
258 child = next;
259 }
260 parent->fFirstChild = prev;
261 return false;
262 }
fmalita7a048692015-02-20 13:54:40 -0800263
264 bool onText(const char text[], int len) override {
265 SkString str(text, len);
266 this->startCommon(str.c_str(), SkDOM::kText_Type);
267 this->SkDOMParser::onEndElement(str.c_str());
268
269 return false;
270 }
271
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272private:
fmalita7a048692015-02-20 13:54:40 -0800273 void startCommon(const char elem[], SkDOM::Type type) {
Mike Reedc3063e52017-01-07 16:16:02 -0500274 if (fLevel > 0 && fNeedToFlush) {
fmalita7a048692015-02-20 13:54:40 -0800275 this->flushAttributes();
Mike Reedc3063e52017-01-07 16:16:02 -0500276 }
fmalita7a048692015-02-20 13:54:40 -0800277 fNeedToFlush = true;
278 fElemName = dupstr(fAlloc, elem);
279 fElemType = type;
280 ++fLevel;
281 }
282
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 SkTDArray<SkDOM::Node*> fParentStack;
Herb Derby70c60632017-02-14 15:21:07 -0500284 SkArenaAlloc* fAlloc;
fmalita7a048692015-02-20 13:54:40 -0800285 SkDOM::Node* fRoot;
286 bool fNeedToFlush;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
288 // state needed for flushAttributes()
289 SkTDArray<SkDOM::Attr> fAttrs;
290 char* fElemName;
fmalita7a048692015-02-20 13:54:40 -0800291 SkDOM::Type fElemType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 int fLevel;
293};
294
fmalita7445e862016-07-14 19:14:06 -0700295const SkDOM::Node* SkDOM::build(SkStream& docStream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 SkDOMParser parser(&fAlloc);
fmalita7445e862016-07-14 19:14:06 -0700297 if (!parser.parse(docStream))
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 {
299 SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fRoot = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 fAlloc.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700302 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 }
304 fRoot = parser.getRoot();
305 return fRoot;
306}
307
308///////////////////////////////////////////////////////////////////////////
309
Mike Reedc3063e52017-01-07 16:16:02 -0500310static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311 const char* elem = dom.getName(node);
fmalita7a048692015-02-20 13:54:40 -0800312 if (dom.getType(node) == SkDOM::kText_Type) {
313 SkASSERT(dom.countChildren(node) == 0);
314 parser->text(elem, SkToInt(strlen(elem)));
315 return;
316 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317
318 parser->startElement(elem);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 SkDOM::AttrIter iter(dom, node);
321 const char* name;
322 const char* value;
halcanary96fcdcc2015-08-27 07:41:13 -0700323 while ((name = iter.next(&value)) != nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 parser->addAttribute(name, value);
325
halcanary96fcdcc2015-08-27 07:41:13 -0700326 node = dom.getFirstChild(node, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 while (node)
328 {
329 walk_dom(dom, node, parser);
halcanary96fcdcc2015-08-27 07:41:13 -0700330 node = dom.getNextSibling(node, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 }
332
333 parser->endElement(elem);
334}
335
Mike Reedc3063e52017-01-07 16:16:02 -0500336const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 SkDOMParser parser(&fAlloc);
338
339 walk_dom(dom, node, &parser);
340
341 fRoot = parser.getRoot();
342 return fRoot;
343}
344
fmalita7a048692015-02-20 13:54:40 -0800345SkXMLParser* SkDOM::beginParsing() {
346 SkASSERT(!fParser);
halcanary385fe4d2015-08-26 13:07:48 -0700347 fParser.reset(new SkDOMParser(&fAlloc));
fmalita7a048692015-02-20 13:54:40 -0800348
349 return fParser.get();
350}
351
352const SkDOM::Node* SkDOM::finishParsing() {
353 SkASSERT(fParser);
354 fRoot = fParser->getRoot();
mtklein852f15d2016-03-17 10:51:27 -0700355 fParser.reset();
fmalita7a048692015-02-20 13:54:40 -0800356
357 return fRoot;
358}
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360//////////////////////////////////////////////////////////////////////////
361
Mike Reedc3063e52017-01-07 16:16:02 -0500362int SkDOM::countChildren(const Node* node, const char elem[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 int count = 0;
364
365 node = this->getFirstChild(node, elem);
Mike Reedc3063e52017-01-07 16:16:02 -0500366 while (node) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 count += 1;
368 node = this->getNextSibling(node, elem);
369 }
370 return count;
371}
372
373//////////////////////////////////////////////////////////////////////////
374
375#include "SkParse.h"
376
Mike Reedc3063e52017-01-07 16:16:02 -0500377bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const char* vstr = this->findAttr(node, name);
379 return vstr && SkParse::FindS32(vstr, value);
380}
381
Mike Reedc3063e52017-01-07 16:16:02 -0500382bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 const char* vstr = this->findAttr(node, name);
384 return vstr && SkParse::FindScalars(vstr, value, count);
385}
386
Mike Reedc3063e52017-01-07 16:16:02 -0500387bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 const char* vstr = this->findAttr(node, name);
389 return vstr && SkParse::FindHex(vstr, value);
390}
391
Mike Reedc3063e52017-01-07 16:16:02 -0500392bool SkDOM::findBool(const Node* node, const char name[], bool* value) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393 const char* vstr = this->findAttr(node, name);
394 return vstr && SkParse::FindBool(vstr, value);
395}
396
Mike Reedc3063e52017-01-07 16:16:02 -0500397int SkDOM::findList(const Node* node, const char name[], const char list[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398 const char* vstr = this->findAttr(node, name);
399 return vstr ? SkParse::FindList(vstr, list) : -1;
400}
401
Mike Reedc3063e52017-01-07 16:16:02 -0500402bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 const char* vstr = this->findAttr(node, name);
404 return vstr && !strcmp(vstr, value);
405}
406
Mike Reedc3063e52017-01-07 16:16:02 -0500407bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408 const char* vstr = this->findAttr(node, name);
409 int32_t value;
410 return vstr && SkParse::FindS32(vstr, &value) && value == target;
411}
412
Mike Reedc3063e52017-01-07 16:16:02 -0500413bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 const char* vstr = this->findAttr(node, name);
415 SkScalar value;
416 return vstr && SkParse::FindScalar(vstr, &value) && value == target;
417}
418
Mike Reedc3063e52017-01-07 16:16:02 -0500419bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420 const char* vstr = this->findAttr(node, name);
421 uint32_t value;
422 return vstr && SkParse::FindHex(vstr, &value) && value == target;
423}
424
Mike Reedc3063e52017-01-07 16:16:02 -0500425bool SkDOM::hasBool(const Node* node, const char name[], bool target) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 const char* vstr = this->findAttr(node, name);
427 bool value;
428 return vstr && SkParse::FindBool(vstr, &value) && value == target;
429}