SkDOM.cpp revision 852f15da7ceb53cfb49b9f728baa6dbc53b27694
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDOM.h"
117a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkStream.h"
127a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkXMLWriter.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkXMLParser.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node)
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* elemName = dom.getName(node);
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->startElement(elemName))
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
23d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOM::AttrIter iter(dom, node);
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char*     name, *value;
26d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
2796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    while ((name = iter.next(&value)) != nullptr)
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->addAttribute(name, value))
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if ((node = dom.getFirstChild(node)) != nullptr)
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!this->parse(dom, node))
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return false;
3596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        } while ((node = dom.getNextSibling(node)) != nullptr);
36d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return !this->endElement(elemName);
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkDOMAttr {
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* fName;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* fValue;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkDOMNode {
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* fName;
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMNode*  fFirstChild;
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMNode*  fNextSibling;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint16_t    fAttrCount;
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t     fType;
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t     fPad;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkDOMAttr* attrs() const
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (const SkDOMAttr*)(this + 1);
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMAttr* attrs()
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (SkDOMAttr*)(this + 1);
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kMinChunkSize   512
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6996fcdcc219d2a0d3579719b84b28bede76efba64halcanarySkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nullptr)
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDOM::~SkDOM()
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Node* SkDOM::getRootNode() const
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fRoot;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Node* child = node->fFirstChild;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (name)
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
8996fcdcc219d2a0d3579719b84b28bede76efba64halcanary        for (; child != nullptr; child = child->fNextSibling)
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!strcmp(name, child->fName))
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return child;
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Node* sibling = node->fNextSibling;
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (name)
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
10296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        for (; sibling != nullptr; sibling = sibling->fNextSibling)
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!strcmp(name, sibling->fName))
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return sibling;
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDOM::Type SkDOM::getType(const Node* node) const
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (Type)node->fType;
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst char* SkDOM::getName(const Node* node) const
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return node->fName;
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst char* SkDOM::findAttr(const Node* node, const char name[]) const
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Attr* attr = node->attrs();
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Attr* stop = attr + node->fAttrCount;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (attr < stop)
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!strcmp(attr->fName, name))
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return attr->fValue;
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        attr += 1;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    return nullptr;
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
14096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    return node->fAttrCount ? node->attrs() : nullptr;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
14696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (attr == nullptr)
14796fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
14896fcdcc219d2a0d3579719b84b28bede76efba64halcanary    return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nullptr;
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst char* SkDOM::getAttrName(const Node* node, const Attr* attr) const
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(attr);
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return attr->fName;
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(attr);
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return attr->fValue;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node)
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(node);
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fAttr = node->attrs();
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fStop = fAttr + node->fAttrCount;
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst char* SkDOM::AttrIter::next(const char** value)
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
17696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    const char* name = nullptr;
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fAttr < fStop)
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        name = fAttr->fName;
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value)
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *value = fAttr->fValue;
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAttr += 1;
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return name;
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkXMLParser.h"
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTDArray.h"
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic char* dupstr(SkChunkAlloc* chunk, const char src[])
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(chunk && src);
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t  len = strlen(src);
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char*   dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    memcpy(dst, src, len + 1);
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return dst;
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkDOMParser : public SkXMLParser {
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk)
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
2067a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        fAlloc->reset();
20796fcdcc219d2a0d3579719b84b28bede76efba64halcanary        fRoot = nullptr;
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fLevel = 0;
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fNeedToFlush = true;
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOM::Node* getRoot() const { return fRoot; }
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkXMLParserError fParserError;
2137a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void flushAttributes()
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
2177a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkASSERT(fLevel > 0);
2187a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int attrCount = fAttrs.count();
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + attrCount * sizeof(SkDOM::Attr),
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                        SkChunkAlloc::kThrow_AllocFailType);
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        node->fName = fElemName;
22596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        node->fFirstChild = nullptr;
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        node->fAttrCount = SkToU16(attrCount);
2277a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        node->fType = fElemType;
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
22996fcdcc219d2a0d3579719b84b28bede76efba64halcanary        if (fRoot == nullptr)
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
23196fcdcc219d2a0d3579719b84b28bede76efba64halcanary            node->fNextSibling = nullptr;
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fRoot = node;
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        else    // this adds siblings in reverse order. gets corrected in onEndElement()
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDOM::Node* parent = fParentStack.top();
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(fRoot && parent);
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            node->fNextSibling = parent->fFirstChild;
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            parent->fFirstChild = node;
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *fParentStack.push() = node;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
243067e90e72fdeba83eff7aeb917b2b25f74759282mtklein        sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAttrs.reset();
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2477a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2487a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    bool onStartElement(const char elem[]) override {
2497a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        this->startCommon(elem, SkDOM::kElement_Type);
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2527a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2537a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    bool onAddAttribute(const char name[], const char value[]) override {
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDOM::Attr* attr = fAttrs.append();
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        attr->fName = dupstr(fAlloc, name);
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        attr->fValue = dupstr(fAlloc, value);
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2597a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2607a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    bool onEndElement(const char elem[]) override {
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        --fLevel;
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fNeedToFlush)
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            this->flushAttributes();
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fNeedToFlush = false;
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDOM::Node* parent;
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fParentStack.pop(&parent);
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDOM::Node* child = parent->fFirstChild;
27196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        SkDOM::Node* prev = nullptr;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (child)
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDOM::Node* next = child->fNextSibling;
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            child->fNextSibling = prev;
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            prev = child;
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            child = next;
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        parent->fFirstChild = prev;
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2827a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2837a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    bool onText(const char text[], int len) override {
2847a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkString str(text, len);
2857a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        this->startCommon(str.c_str(), SkDOM::kText_Type);
2867a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        this->SkDOMParser::onEndElement(str.c_str());
2877a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2887a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        return false;
2897a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
2907a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
2927a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    void startCommon(const char elem[], SkDOM::Type type) {
2937a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        if (fLevel > 0 && fNeedToFlush)
2947a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            this->flushAttributes();
2957a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
2967a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        fNeedToFlush = true;
2977a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        fElemName = dupstr(fAlloc, elem);
2987a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        fElemType = type;
2997a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        ++fLevel;
3007a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
3017a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<SkDOM::Node*> fParentStack;
3037a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkChunkAlloc*           fAlloc;
3047a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkDOM::Node*            fRoot;
3057a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    bool                    fNeedToFlush;
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // state needed for flushAttributes()
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<SkDOM::Attr>  fAttrs;
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char*                   fElemName;
3107a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkDOM::Type             fElemType;
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int                     fLevel;
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Node* SkDOM::build(const char doc[], size_t len)
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMParser parser(&fAlloc);
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!parser.parse(doc, len))
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
32096fcdcc219d2a0d3579719b84b28bede76efba64halcanary        fRoot = nullptr;
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAlloc.reset();
32296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRoot = parser.getRoot();
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fRoot;
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser)
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* elem = dom.getName(node);
3337a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    if (dom.getType(node) == SkDOM::kText_Type) {
3347a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkASSERT(dom.countChildren(node) == 0);
3357a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        parser->text(elem, SkToInt(strlen(elem)));
3367a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        return;
3377a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    parser->startElement(elem);
340d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOM::AttrIter iter(dom, node);
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char*     name;
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char*     value;
34496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    while ((name = iter.next(&value)) != nullptr)
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        parser->addAttribute(name, value);
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
34796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    node = dom.getFirstChild(node, nullptr);
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (node)
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        walk_dom(dom, node, parser);
35196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        node = dom.getNextSibling(node, nullptr);
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    parser->endElement(elem);
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node)
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOMParser parser(&fAlloc);
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    walk_dom(dom, node, &parser);
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRoot = parser.getRoot();
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fRoot;
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3677a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitaSkXMLParser* SkDOM::beginParsing() {
3687a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkASSERT(!fParser);
369385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    fParser.reset(new SkDOMParser(&fAlloc));
3707a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
3717a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    return fParser.get();
3727a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
3737a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
3747a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitaconst SkDOM::Node* SkDOM::finishParsing() {
3757a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkASSERT(fParser);
3767a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    fRoot = fParser->getRoot();
377852f15da7ceb53cfb49b9f728baa6dbc53b27694mtklein    fParser.reset();
3787a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
3797a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    return fRoot;
3807a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
3817a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkDOM::countChildren(const Node* node, const char elem[]) const
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = 0;
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    node = this->getFirstChild(node, elem);
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (node)
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count += 1;
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        node = this->getNextSibling(node, elem);
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return count;
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkParse.h"
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindS32(vstr, value);
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindScalars(vstr, value, count);
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindHex(vstr, value);
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::findBool(const Node* node, const char name[], bool* value) const
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindBool(vstr, value);
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkDOM::findList(const Node* node, const char name[], const char list[]) const
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr ? SkParse::FindList(vstr, list) : -1;
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && !strcmp(vstr, value);
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t     value;
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindS32(vstr, &value) && value == target;
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    value;
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindScalar(vstr, &value) && value == target;
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    value;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindHex(vstr, &value) && value == target;
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDOM::hasBool(const Node* node, const char name[], bool target) const
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* vstr = this->findAttr(node, name);
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        value;
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return vstr && SkParse::FindBool(vstr, &value) && value == target;
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDOM::dump(const Node* node, int level) const
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
47196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (node == nullptr)
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        node = this->getRootNode();
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4747a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkDebugWStream debugStream;
4757a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkXMLStreamWriter xmlWriter(&debugStream);
4767a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    xmlWriter.writeDOM(*this, node, false);
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDOM::UnitTest()
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_SUPPORT_UNITTEST
482d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    static const char gDoc[] =
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "<root a='1' b='2'>"
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            "<elem1 c='3' />"
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            "<elem2 d='4' />"
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            "<elem3 e='5'>"
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                "<subelem1/>"
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                "<subelem2 f='6' g='7'/>"
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            "</elem3>"
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            "<elem4 h='8'/>"
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "</root>"
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ;
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDOM   dom;
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(dom.getRootNode() == nullptr);
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Node* root = dom.build(gDoc, sizeof(gDoc) - 1);
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(root && dom.getRootNode() == root);
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* v = dom.findAttr(root, "a");
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(v && !strcmp(v, "1"));
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    v = dom.findAttr(root, "b");
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(v && !strcmp(v, "2"));
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    v = dom.findAttr(root, "c");
50696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(v == nullptr);
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dom.getFirstChild(root, "elem1"));
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(!dom.getFirstChild(root, "subelem1"));
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dom.dump();
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
516