1/*
2 * Copyright (C) 2013 Google, Inc. All Rights Reserved.
3 * Copyright (C) 2015 Apple Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include "HTMLToken.h"
30
31namespace WebCore {
32
33class AtomicHTMLToken {
34public:
35 explicit AtomicHTMLToken(HTMLToken&);
36 AtomicHTMLToken(HTMLToken::Type, const AtomicString& name, Vector<Attribute>&& = { }); // Only StartTag or EndTag.
37
38 AtomicHTMLToken(const AtomicHTMLToken&) = delete;
39 AtomicHTMLToken(AtomicHTMLToken&&) = default;
40
41 HTMLToken::Type type() const;
42
43 // StartTag, EndTag, DOCTYPE.
44
45 void setName(const AtomicString&);
46
47 const AtomicString& name() const;
48
49 // DOCTYPE.
50
51 bool forceQuirks() const;
52 String publicIdentifier() const;
53 String systemIdentifier() const;
54
55 // StartTag, EndTag.
56
57 Vector<Attribute>& attributes();
58
59 bool selfClosing() const;
60 const Vector<Attribute>& attributes() const;
61
62 // Characters
63
64 const UChar* characters() const;
65 unsigned charactersLength() const;
66 bool charactersIsAll8BitData() const;
67
68 // Comment
69
70 const String& comment() const;
71
72private:
73 HTMLToken::Type m_type;
74
75 void initializeAttributes(const HTMLToken::AttributeList& attributes);
76
77 AtomicString m_name; // StartTag, EndTag, DOCTYPE.
78
79 String m_data; // Comment
80
81 // We don't want to copy the characters out of the HTMLToken, so we keep a pointer to its buffer instead.
82 // This buffer is owned by the HTMLToken and causes a lifetime dependence between these objects.
83 // FIXME: Add a mechanism for "internalizing" the characters when the HTMLToken is destroyed.
84 const UChar* m_externalCharacters; // Character
85 unsigned m_externalCharactersLength; // Character
86 bool m_externalCharactersIsAll8BitData; // Character
87
88 std::unique_ptr<DoctypeData> m_doctypeData; // DOCTYPE.
89
90 bool m_selfClosing; // StartTag, EndTag.
91 Vector<Attribute> m_attributes; // StartTag, EndTag.
92};
93
94const Attribute* findAttribute(const Vector<Attribute>&, const QualifiedName&);
95bool hasAttribute(const Vector<Attribute>&, const AtomicString& localName);
96
97inline HTMLToken::Type AtomicHTMLToken::type() const
98{
99 return m_type;
100}
101
102inline const AtomicString& AtomicHTMLToken::name() const
103{
104 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
105 return m_name;
106}
107
108inline void AtomicHTMLToken::setName(const AtomicString& name)
109{
110 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
111 m_name = name;
112}
113
114inline bool AtomicHTMLToken::selfClosing() const
115{
116 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
117 return m_selfClosing;
118}
119
120inline Vector<Attribute>& AtomicHTMLToken::attributes()
121{
122 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
123 return m_attributes;
124}
125
126inline const Vector<Attribute>& AtomicHTMLToken::attributes() const
127{
128 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
129 return m_attributes;
130}
131
132inline const UChar* AtomicHTMLToken::characters() const
133{
134 ASSERT(m_type == HTMLToken::Character);
135 return m_externalCharacters;
136}
137
138inline unsigned AtomicHTMLToken::charactersLength() const
139{
140 ASSERT(m_type == HTMLToken::Character);
141 return m_externalCharactersLength;
142}
143
144inline bool AtomicHTMLToken::charactersIsAll8BitData() const
145{
146 return m_externalCharactersIsAll8BitData;
147}
148
149inline const String& AtomicHTMLToken::comment() const
150{
151 ASSERT(m_type == HTMLToken::Comment);
152 return m_data;
153}
154
155inline bool AtomicHTMLToken::forceQuirks() const
156{
157 ASSERT(m_type == HTMLToken::DOCTYPE);
158 return m_doctypeData->forceQuirks;
159}
160
161inline String AtomicHTMLToken::publicIdentifier() const
162{
163 ASSERT(m_type == HTMLToken::DOCTYPE);
164 if (!m_doctypeData->hasPublicIdentifier)
165 return String();
166 return StringImpl::create8BitIfPossible(m_doctypeData->publicIdentifier);
167}
168
169inline String AtomicHTMLToken::systemIdentifier() const
170{
171 if (!m_doctypeData->hasSystemIdentifier)
172 return String();
173 return StringImpl::create8BitIfPossible(m_doctypeData->systemIdentifier);
174}
175
176inline const Attribute* findAttribute(const Vector<Attribute>& attributes, const QualifiedName& name)
177{
178 for (auto& attribute : attributes) {
179 if (attribute.name().matches(name))
180 return &attribute;
181 }
182 return nullptr;
183}
184
185inline bool hasAttribute(const Vector<Attribute>& attributes, const AtomicString& localName)
186{
187 for (auto& attribute : attributes) {
188 if (attribute.localName() == localName)
189 return true;
190 }
191 return false;
192}
193
194inline void AtomicHTMLToken::initializeAttributes(const HTMLToken::AttributeList& attributes)
195{
196 unsigned size = attributes.size();
197 if (!size)
198 return;
199
200 m_attributes.reserveInitialCapacity(size);
201 for (auto& attribute : attributes) {
202 if (attribute.name.isEmpty())
203 continue;
204
205 AtomicString localName(attribute.name);
206
207 // FIXME: This is N^2 for the number of attributes.
208 if (!hasAttribute(m_attributes, localName))
209 m_attributes.uncheckedAppend(Attribute(QualifiedName(nullAtom(), localName, nullAtom()), AtomicString(attribute.value)));
210 }
211}
212
213inline AtomicHTMLToken::AtomicHTMLToken(HTMLToken& token)
214 : m_type(token.type())
215{
216 switch (m_type) {
217 case HTMLToken::Uninitialized:
218 ASSERT_NOT_REACHED();
219 return;
220 case HTMLToken::DOCTYPE:
221 m_name = AtomicString(token.name());
222 m_doctypeData = token.releaseDoctypeData();
223 return;
224 case HTMLToken::EndOfFile:
225 return;
226 case HTMLToken::StartTag:
227 case HTMLToken::EndTag:
228 m_selfClosing = token.selfClosing();
229 m_name = AtomicString(token.name());
230 initializeAttributes(token.attributes());
231 return;
232 case HTMLToken::Comment:
233 if (token.commentIsAll8BitData())
234 m_data = String::make8BitFrom16BitSource(token.comment());
235 else
236 m_data = String(token.comment());
237 return;
238 case HTMLToken::Character:
239 m_externalCharacters = token.characters().data();
240 m_externalCharactersLength = token.characters().size();
241 m_externalCharactersIsAll8BitData = token.charactersIsAll8BitData();
242 return;
243 }
244 ASSERT_NOT_REACHED();
245}
246
247inline AtomicHTMLToken::AtomicHTMLToken(HTMLToken::Type type, const AtomicString& name, Vector<Attribute>&& attributes)
248 : m_type(type)
249 , m_name(name)
250 , m_selfClosing(false)
251 , m_attributes(WTFMove(attributes))
252{
253 ASSERT(type == HTMLToken::StartTag || type == HTMLToken::EndTag);
254}
255
256} // namespace WebCore
257