d09afbc1b86a437a80fd3f9621e6f5f5b491bbba
[WebKit-https.git] / Source / WebCore / html / parser / AtomicHTMLToken.h
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
31 namespace WebCore {
32
33 class AtomicHTMLToken {
34 public:
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
72 private:
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 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
94 const Attribute* findAttribute(const Vector<Attribute>&, const QualifiedName&);
95 bool hasAttribute(const Vector<Attribute>&, const AtomicString& localName);
96
97 inline HTMLToken::Type AtomicHTMLToken::type() const
98 {
99     return m_type;
100 }
101
102 inline 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
108 inline 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
114 inline bool AtomicHTMLToken::selfClosing() const
115 {
116     ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
117     return m_selfClosing;
118 }
119
120 inline Vector<Attribute>& AtomicHTMLToken::attributes()
121 {
122     ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
123     return m_attributes;
124 }
125
126 inline const Vector<Attribute>& AtomicHTMLToken::attributes() const
127 {
128     ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
129     return m_attributes;
130 }
131
132 inline const UChar* AtomicHTMLToken::characters() const
133 {
134     ASSERT(m_type == HTMLToken::Character);
135     return m_externalCharacters;
136 }
137
138 inline unsigned AtomicHTMLToken::charactersLength() const
139 {
140     ASSERT(m_type == HTMLToken::Character);
141     return m_externalCharactersLength;
142 }
143
144 inline bool AtomicHTMLToken::charactersIsAll8BitData() const
145 {
146     return m_externalCharactersIsAll8BitData;
147 }
148
149 inline const String& AtomicHTMLToken::comment() const
150 {
151     ASSERT(m_type == HTMLToken::Comment);
152     return m_data;
153 }
154
155 inline bool AtomicHTMLToken::forceQuirks() const
156 {
157     ASSERT(m_type == HTMLToken::DOCTYPE);
158     return m_doctypeData->forceQuirks;
159 }
160
161 inline 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
169 inline String AtomicHTMLToken::systemIdentifier() const
170 {
171     if (!m_doctypeData->hasSystemIdentifier)
172         return String();
173     return StringImpl::create8BitIfPossible(m_doctypeData->systemIdentifier);
174 }
175
176 inline 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
185 inline 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
194 inline 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
213 inline 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
247 inline 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