xref: /third_party/skia/src/xml/SkDOMParser.cpp (revision cb93a386)
1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Description: Implementation for Css style parser.
4 * Create: 2023/4/25
5 */
6
7#include "src/xml/SkDOM.h"
8#include "src/xml/SkDOMParser.h"
9
10char* SkDOMParser::dupstr(SkArenaAlloc* chunk, const char src[], size_t srcLen) {
11    SkASSERT(chunk && src);
12    char* dst = chunk->makeArrayDefault<char>(srcLen + 1);
13    memcpy(dst, src, srcLen);
14    dst[srcLen] = '\0';
15    return dst;
16}
17
18SkDOM::Node* SkDOMParser::getRoot() const {
19    return fRoot;
20}
21
22void SkDOMParser::flushAttributes() {
23    SkASSERT(fLevel > 0);
24
25    int attrCount = fAttrs.count();
26
27    SkDOMAttr* attrs = fAlloc->makeArrayDefault<SkDOMAttr>(attrCount);
28    SkDOM::Node* node = fAlloc->make<SkDOM::Node>();
29
30    node->fName = fElemName;
31    node->fFirstChild = nullptr;
32    node->fAttrCount = SkToU16(attrCount);
33    node->fAttrs = attrs;
34    node->fType = fElemType;
35
36    if (fRoot == nullptr) {
37        node->fNextSibling = nullptr;
38        fRoot = node;
39    } else { // this adds siblings in reverse order. gets corrected in onEndElement()
40        SkDOM::Node* parent = fParentStack.top();
41        SkASSERT(fRoot && parent);
42        node->fNextSibling = parent->fFirstChild;
43        parent->fFirstChild = node;
44    }
45    *fParentStack.push() = node;
46
47    sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
48    fAttrs.reset();
49}
50
51bool SkDOMParser::onStartElement(const char elem[]) {
52    this->startCommon(elem, strlen(elem), SkDOM::kElement_Type);
53    return false;
54}
55
56bool SkDOMParser::onAddAttribute(const char name[], const char value[]) {
57    SkDOM::Attr* attr = fAttrs.append();
58    attr->fName = dupstr(fAlloc, name, strlen(name));
59    attr->fValue = dupstr(fAlloc, value, strlen(value));
60    return false;
61}
62
63bool SkDOMParser::onEndElement(const char elem[]) {
64    --fLevel;
65    if (fNeedToFlush)
66        flushAttributes();
67    fNeedToFlush = false;
68
69    SkDOM::Node* parent;
70
71    fParentStack.pop(&parent);
72
73    SkDOM::Node* child = parent->fFirstChild;
74    SkDOM::Node* prev = nullptr;
75    while (child) {
76        SkDOM::Node* next = child->fNextSibling;
77        child->fNextSibling = prev;
78        prev = child;
79        child = next;
80    }
81    parent->fFirstChild = prev;
82    return false;
83}
84
85bool SkDOMParser::onText(const char text[], int len) {
86    startCommon(text, len, SkDOM::kText_Type);
87    SkDOMParser::onEndElement(fElemName);
88
89    return false;
90}
91
92void SkDOMParser::startCommon(const char elem[], size_t elemSize, SkDOM::Type type) {
93    if (fLevel > 0 && fNeedToFlush) {
94        flushAttributes();
95    }
96    fNeedToFlush = true;
97    fElemName = dupstr(fAlloc, elem, elemSize);
98    fElemType = type;
99    ++fLevel;
100}
101