1/*
2 * Copyright (C) 2013 Google, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef AtomicHTMLToken_h
27#define AtomicHTMLToken_h
28
29#include "Attribute.h"
30#include "CompactHTMLToken.h"
31#include "HTMLToken.h"
32#include <wtf/RefCounted.h>
33#include <wtf/RefPtr.h>
34
35namespace WebCore {
36
37class AtomicHTMLToken : public RefCounted<AtomicHTMLToken> {
38 WTF_MAKE_NONCOPYABLE(AtomicHTMLToken);
39public:
40 static PassRefPtr<AtomicHTMLToken> create(HTMLToken& token)
41 {
42 return adoptRef(new AtomicHTMLToken(token));
43 }
44
45#if ENABLE(THREADED_HTML_PARSER)
46
47 static PassRefPtr<AtomicHTMLToken> create(const CompactHTMLToken& token)
48 {
49 return adoptRef(new AtomicHTMLToken(token));
50 }
51
52#endif
53
54 static PassRefPtr<AtomicHTMLToken> create(HTMLToken::Type type, const AtomicString& name, const Vector<Attribute>& attributes = Vector<Attribute>())
55 {
56 return adoptRef(new AtomicHTMLToken(type, name, attributes));
57 }
58
59 bool forceQuirks() const
60 {
61 ASSERT(m_type == HTMLToken::DOCTYPE);
62 return m_doctypeData->m_forceQuirks;
63 }
64
65 HTMLToken::Type type() const { return m_type; }
66
67 const AtomicString& name() const
68 {
69 ASSERT(usesName());
70 return m_name;
71 }
72
73 void setName(const AtomicString& name)
74 {
75 ASSERT(usesName());
76 m_name = name;
77 }
78
79 bool selfClosing() const
80 {
81 ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
82 return m_selfClosing;
83 }
84
85 Attribute* getAttributeItem(const QualifiedName& attributeName)
86 {
87 ASSERT(usesAttributes());
88 return findAttributeInVector(m_attributes, attributeName);
89 }
90
91 Vector<Attribute>& attributes()
92 {
93 ASSERT(usesAttributes());
94 return m_attributes;
95 }
96
97 const Vector<Attribute>& attributes() const
98 {
99 ASSERT(usesAttributes());
100 return m_attributes;
101 }
102
103 const UChar* characters() const
104 {
105 ASSERT(m_type == HTMLToken::Character);
106 return m_externalCharacters;
107 }
108
109 size_t charactersLength() const
110 {
111 ASSERT(m_type == HTMLToken::Character);
112 return m_externalCharactersLength;
113 }
114
115 bool isAll8BitData() const
116 {
117 return m_isAll8BitData;
118 }
119
120 const String& comment() const
121 {
122 ASSERT(m_type == HTMLToken::Comment);
123 return m_data;
124 }
125
126 // FIXME: Distinguish between a missing public identifer and an empty one.
127 WTF::Vector<UChar>& publicIdentifier() const
128 {
129 ASSERT(m_type == HTMLToken::DOCTYPE);
130 return m_doctypeData->m_publicIdentifier;
131 }
132
133 // FIXME: Distinguish between a missing system identifer and an empty one.
134 WTF::Vector<UChar>& systemIdentifier() const
135 {
136 ASSERT(m_type == HTMLToken::DOCTYPE);
137 return m_doctypeData->m_systemIdentifier;
138 }
139
140 void clearExternalCharacters()
141 {
142 m_externalCharacters = 0;
143 m_externalCharactersLength = 0;
144 m_isAll8BitData = false;
145 }
146
147private:
148 explicit AtomicHTMLToken(HTMLToken& token)
149 : m_type(token.type())
150 {
151 switch (m_type) {
152 case HTMLToken::Uninitialized:
153 ASSERT_NOT_REACHED();
154 break;
155 case HTMLToken::DOCTYPE:
156 m_name = AtomicString(token.nameString());
157 m_doctypeData = token.releaseDoctypeData();
158 break;
159 case HTMLToken::EndOfFile:
160 break;
161 case HTMLToken::StartTag:
162 case HTMLToken::EndTag: {
163 m_selfClosing = token.selfClosing();
164 m_name = AtomicString(token.nameString());
165 initializeAttributes(token.attributes());
166 break;
167 }
168 case HTMLToken::Comment:
169 if (token.isAll8BitData())
170 m_data = String::make8BitFrom16BitSource(token.comment().data(), token.comment().size());
171 else
172 m_data = String(token.comment().data(), token.comment().size());
173 break;
174 case HTMLToken::Character:
175 m_externalCharacters = token.characters().data();
176 m_externalCharactersLength = token.characters().size();
177 m_isAll8BitData = token.isAll8BitData();
178 break;
179 }
180 }
181
182#if ENABLE(THREADED_HTML_PARSER)
183
184 explicit AtomicHTMLToken(const CompactHTMLToken& token)
185 : m_type(token.type())
186 {
187 switch (m_type) {
188 case HTMLToken::Uninitialized:
189 ASSERT_NOT_REACHED();
190 break;
191 case HTMLToken::DOCTYPE:
192 m_name = token.data();
193 m_doctypeData = adoptPtr(new DoctypeData());
194 m_doctypeData->m_hasPublicIdentifier = true;
195 m_doctypeData->m_publicIdentifier.append(token.publicIdentifier().characters(), token.publicIdentifier().length());
196 m_doctypeData->m_hasSystemIdentifier = true;
197 m_doctypeData->m_systemIdentifier.append(token.systemIdentifier().characters(), token.systemIdentifier().length());
198 m_doctypeData->m_forceQuirks = token.doctypeForcesQuirks();
199 break;
200 case HTMLToken::EndOfFile:
201 break;
202 case HTMLToken::StartTag:
203 m_attributes.reserveInitialCapacity(token.attributes().size());
204 for (Vector<CompactAttribute>::const_iterator it = token.attributes().begin(); it != token.attributes().end(); ++it)
205 m_attributes.append(Attribute(QualifiedName(nullAtom, it->name(), nullAtom), it->value()));
206 // Fall through!
207 case HTMLToken::EndTag:
208 m_selfClosing = token.selfClosing();
209 m_name = AtomicString(token.data());
210 break;
211 case HTMLToken::Comment:
212 m_data = token.data();
213 break;
214 case HTMLToken::Character:
215 m_externalCharacters = token.data().characters();
216 m_externalCharactersLength = token.data().length();
217 m_isAll8BitData = token.isAll8BitData();
218 break;
219 }
220 }
221
222#endif
223
224 explicit AtomicHTMLToken(HTMLToken::Type type)
225 : m_type(type)
226 , m_externalCharacters(0)
227 , m_externalCharactersLength(0)
228 , m_isAll8BitData(false)
229 , m_selfClosing(false)
230 {
231 }
232
233 AtomicHTMLToken(HTMLToken::Type type, const AtomicString& name, const Vector<Attribute>& attributes = Vector<Attribute>())
234 : m_type(type)
235 , m_name(name)
236 , m_externalCharacters(0)
237 , m_externalCharactersLength(0)
238 , m_isAll8BitData(false)
239 , m_selfClosing(false)
240 , m_attributes(attributes)
241 {
242 ASSERT(usesName());
243 }
244
245 HTMLToken::Type m_type;
246
247 void initializeAttributes(const HTMLToken::AttributeList& attributes);
248 QualifiedName nameForAttribute(const HTMLToken::Attribute&) const;
249
250 bool usesName() const;
251
252 bool usesAttributes() const;
253
254 // "name" for DOCTYPE, StartTag, and EndTag
255 AtomicString m_name;
256
257 // "data" for Comment
258 String m_data;
259
260 // "characters" for Character
261 //
262 // We don't want to copy the the characters out of the Token, so we
263 // keep a pointer to its buffer instead. This buffer is owned by the
264 // Token and causes a lifetime dependence between these objects.
265 //
266 // FIXME: Add a mechanism for "internalizing" the characters when the
267 // HTMLToken is destructed.
268 const UChar* m_externalCharacters;
269 size_t m_externalCharactersLength;
270 bool m_isAll8BitData;
271
272 // For DOCTYPE
273 OwnPtr<DoctypeData> m_doctypeData;
274
275 // For StartTag and EndTag
276 bool m_selfClosing;
277
278 Vector<Attribute> m_attributes;
279};
280
281inline void AtomicHTMLToken::initializeAttributes(const HTMLToken::AttributeList& attributes)
282{
283 size_t size = attributes.size();
284 if (!size)
285 return;
286
287 m_attributes.clear();
288 m_attributes.reserveInitialCapacity(size);
289 for (size_t i = 0; i < size; ++i) {
290 const HTMLToken::Attribute& attribute = attributes[i];
291 if (attribute.m_name.isEmpty())
292 continue;
293
294 // FIXME: We should be able to add the following ASSERT once we fix
295 // https://bugs.webkit.org/show_bug.cgi?id=62971
296 // ASSERT(attribute.m_nameRange.m_start);
297 ASSERT(attribute.m_nameRange.m_end);
298 ASSERT(attribute.m_valueRange.m_start);
299 ASSERT(attribute.m_valueRange.m_end);
300
301 AtomicString value(attribute.m_value.data(), attribute.m_value.size());
302 const QualifiedName& name = nameForAttribute(attribute);
303 if (!findAttributeInVector(m_attributes, name))
304 m_attributes.append(Attribute(name, value));
305 }
306}
307
308}
309
310#endif