1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 * Portions are Copyright (C) 2002 Netscape Communications Corporation.
22 * Other contributors: David Baron <dbaron@fas.harvard.edu>
23 *
24 * This library is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU Lesser General Public
26 * License as published by the Free Software Foundation; either
27 * version 2.1 of the License, or (at your option) any later version.
28 *
29 * This library is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 * Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this library; if not, write to the Free Software
36 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
37 *
38 * Alternatively, the document type parsing portions of this file may be used
39 * under the terms of either the Mozilla Public License Version 1.1, found at
40 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
41 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
42 * (the "GPL"), in which case the provisions of the MPL or the GPL are
43 * applicable instead of those above. If you wish to allow use of your
44 * version of this file only under the terms of one of those two
45 * licenses (the MPL or the GPL) and not to allow others to use your
46 * version of this file under the LGPL, indicate your decision by
47 * deleting the provisions above and replace them with the notice and
48 * other provisions required by the MPL or the GPL, as the case may be.
49 * If you do not delete the provisions above, a recipient may use your
50 * version of this file under any of the LGPL, the MPL or the GPL.
51 */
52
53 #include "config.h"
54 #include "core/html/HTMLDocument.h"
55
56 #include "HTMLNames.h"
57 #include "bindings/v8/ScriptController.h"
58 #include "core/frame/DOMWindow.h"
59 #include "core/frame/Frame.h"
60 #include "core/frame/FrameView.h"
61 #include "core/html/HTMLBodyElement.h"
62 #include "core/page/FocusController.h"
63 #include "core/page/FrameTree.h"
64 #include "core/page/Page.h"
65 #include "wtf/text/StringBuilder.h"
66
67 namespace WebCore {
68
69 using namespace HTMLNames;
70
HTMLDocument(const DocumentInit & initializer,DocumentClassFlags extendedDocumentClasses)71 HTMLDocument::HTMLDocument(const DocumentInit& initializer, DocumentClassFlags extendedDocumentClasses)
72 : Document(initializer, HTMLDocumentClass | extendedDocumentClasses)
73 {
74 ScriptWrappable::init(this);
75 clearXMLVersion();
76 }
77
~HTMLDocument()78 HTMLDocument::~HTMLDocument()
79 {
80 }
81
dir()82 const AtomicString& HTMLDocument::dir()
83 {
84 HTMLElement* b = body();
85 if (!b)
86 return nullAtom;
87 return b->getAttribute(dirAttr);
88 }
89
setDir(const AtomicString & value)90 void HTMLDocument::setDir(const AtomicString& value)
91 {
92 HTMLElement* b = body();
93 if (b)
94 b->setAttribute(dirAttr, value);
95 }
96
designMode() const97 String HTMLDocument::designMode() const
98 {
99 return inDesignMode() ? "on" : "off";
100 }
101
setDesignMode(const String & value)102 void HTMLDocument::setDesignMode(const String& value)
103 {
104 InheritedBool mode;
105 if (equalIgnoringCase(value, "on"))
106 mode = on;
107 else if (equalIgnoringCase(value, "off"))
108 mode = off;
109 else
110 mode = inherit;
111 Document::setDesignMode(mode);
112 }
113
activeElement()114 Element* HTMLDocument::activeElement()
115 {
116 if (Element* element = treeScope().adjustedFocusedElement())
117 return element;
118 return body();
119 }
120
hasFocus()121 bool HTMLDocument::hasFocus()
122 {
123 Page* page = this->page();
124 if (!page)
125 return false;
126 if (!page->focusController().isActive() || !page->focusController().isFocused())
127 return false;
128 if (Frame* focusedFrame = page->focusController().focusedFrame()) {
129 if (focusedFrame->tree().isDescendantOf(frame()))
130 return true;
131 }
132 return false;
133 }
134
htmlBodyElement() const135 HTMLBodyElement* HTMLDocument::htmlBodyElement() const
136 {
137 HTMLElement* body = this->body();
138 return (body && body->hasTagName(bodyTag)) ? toHTMLBodyElement(body) : 0;
139 }
140
bodyAttributeValue(const QualifiedName & name) const141 const AtomicString& HTMLDocument::bodyAttributeValue(const QualifiedName& name) const
142 {
143 if (HTMLBodyElement* body = htmlBodyElement())
144 return body->fastGetAttribute(name);
145 return nullAtom;
146 }
147
setBodyAttribute(const QualifiedName & name,const AtomicString & value)148 void HTMLDocument::setBodyAttribute(const QualifiedName& name, const AtomicString& value)
149 {
150 if (HTMLBodyElement* body = htmlBodyElement()) {
151 // FIXME: This check is apparently for benchmarks that set the same value repeatedly.
152 // It's not clear what benchmarks though, it's also not clear why we don't avoid
153 // causing a style recalc when setting the same value to a presentational attribute
154 // in the common case.
155 if (body->fastGetAttribute(name) != value)
156 body->setAttribute(name, value);
157 }
158 }
159
bgColor() const160 const AtomicString& HTMLDocument::bgColor() const
161 {
162 return bodyAttributeValue(bgcolorAttr);
163 }
164
setBgColor(const AtomicString & value)165 void HTMLDocument::setBgColor(const AtomicString& value)
166 {
167 setBodyAttribute(bgcolorAttr, value);
168 }
169
fgColor() const170 const AtomicString& HTMLDocument::fgColor() const
171 {
172 return bodyAttributeValue(textAttr);
173 }
174
setFgColor(const AtomicString & value)175 void HTMLDocument::setFgColor(const AtomicString& value)
176 {
177 setBodyAttribute(textAttr, value);
178 }
179
alinkColor() const180 const AtomicString& HTMLDocument::alinkColor() const
181 {
182 return bodyAttributeValue(alinkAttr);
183 }
184
setAlinkColor(const AtomicString & value)185 void HTMLDocument::setAlinkColor(const AtomicString& value)
186 {
187 setBodyAttribute(alinkAttr, value);
188 }
189
linkColor() const190 const AtomicString& HTMLDocument::linkColor() const
191 {
192 return bodyAttributeValue(linkAttr);
193 }
194
setLinkColor(const AtomicString & value)195 void HTMLDocument::setLinkColor(const AtomicString& value)
196 {
197 setBodyAttribute(linkAttr, value);
198 }
199
vlinkColor() const200 const AtomicString& HTMLDocument::vlinkColor() const
201 {
202 return bodyAttributeValue(vlinkAttr);
203 }
204
setVlinkColor(const AtomicString & value)205 void HTMLDocument::setVlinkColor(const AtomicString& value)
206 {
207 setBodyAttribute(vlinkAttr, value);
208 }
209
cloneDocumentWithoutChildren()210 PassRefPtr<Document> HTMLDocument::cloneDocumentWithoutChildren()
211 {
212 return create(DocumentInit(url()).withRegistrationContext(registrationContext()));
213 }
214
215 // --------------------------------------------------------------------------
216 // not part of the DOM
217 // --------------------------------------------------------------------------
218
addItemToMap(HashCountedSet<AtomicString> & map,const AtomicString & name)219 void HTMLDocument::addItemToMap(HashCountedSet<AtomicString>& map, const AtomicString& name)
220 {
221 if (name.isEmpty())
222 return;
223 map.add(name);
224 if (Frame* f = frame())
225 f->script().namedItemAdded(this, name);
226 }
227
removeItemFromMap(HashCountedSet<AtomicString> & map,const AtomicString & name)228 void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicString>& map, const AtomicString& name)
229 {
230 if (name.isEmpty())
231 return;
232 map.remove(name);
233 if (Frame* f = frame())
234 f->script().namedItemRemoved(this, name);
235 }
236
addNamedItem(const AtomicString & name)237 void HTMLDocument::addNamedItem(const AtomicString& name)
238 {
239 addItemToMap(m_namedItemCounts, name);
240 }
241
removeNamedItem(const AtomicString & name)242 void HTMLDocument::removeNamedItem(const AtomicString& name)
243 {
244 removeItemFromMap(m_namedItemCounts, name);
245 }
246
addExtraNamedItem(const AtomicString & name)247 void HTMLDocument::addExtraNamedItem(const AtomicString& name)
248 {
249 addItemToMap(m_extraNamedItemCounts, name);
250 }
251
removeExtraNamedItem(const AtomicString & name)252 void HTMLDocument::removeExtraNamedItem(const AtomicString& name)
253 {
254 removeItemFromMap(m_extraNamedItemCounts, name);
255 }
256
addLocalNameToSet(HashSet<StringImpl * > * set,const QualifiedName & qName)257 static void addLocalNameToSet(HashSet<StringImpl*>* set, const QualifiedName& qName)
258 {
259 set->add(qName.localName().impl());
260 }
261
createHtmlCaseInsensitiveAttributesSet()262 static HashSet<StringImpl*>* createHtmlCaseInsensitiveAttributesSet()
263 {
264 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
265 // Mozilla treats all other values as case-sensitive, thus so do we.
266 HashSet<StringImpl*>* attrSet = new HashSet<StringImpl*>;
267
268 addLocalNameToSet(attrSet, accept_charsetAttr);
269 addLocalNameToSet(attrSet, acceptAttr);
270 addLocalNameToSet(attrSet, alignAttr);
271 addLocalNameToSet(attrSet, alinkAttr);
272 addLocalNameToSet(attrSet, axisAttr);
273 addLocalNameToSet(attrSet, bgcolorAttr);
274 addLocalNameToSet(attrSet, charsetAttr);
275 addLocalNameToSet(attrSet, checkedAttr);
276 addLocalNameToSet(attrSet, clearAttr);
277 addLocalNameToSet(attrSet, codetypeAttr);
278 addLocalNameToSet(attrSet, colorAttr);
279 addLocalNameToSet(attrSet, compactAttr);
280 addLocalNameToSet(attrSet, declareAttr);
281 addLocalNameToSet(attrSet, deferAttr);
282 addLocalNameToSet(attrSet, dirAttr);
283 addLocalNameToSet(attrSet, disabledAttr);
284 addLocalNameToSet(attrSet, enctypeAttr);
285 addLocalNameToSet(attrSet, faceAttr);
286 addLocalNameToSet(attrSet, frameAttr);
287 addLocalNameToSet(attrSet, hreflangAttr);
288 addLocalNameToSet(attrSet, http_equivAttr);
289 addLocalNameToSet(attrSet, langAttr);
290 addLocalNameToSet(attrSet, languageAttr);
291 addLocalNameToSet(attrSet, linkAttr);
292 addLocalNameToSet(attrSet, mediaAttr);
293 addLocalNameToSet(attrSet, methodAttr);
294 addLocalNameToSet(attrSet, multipleAttr);
295 addLocalNameToSet(attrSet, nohrefAttr);
296 addLocalNameToSet(attrSet, noresizeAttr);
297 addLocalNameToSet(attrSet, noshadeAttr);
298 addLocalNameToSet(attrSet, nowrapAttr);
299 addLocalNameToSet(attrSet, readonlyAttr);
300 addLocalNameToSet(attrSet, relAttr);
301 addLocalNameToSet(attrSet, revAttr);
302 addLocalNameToSet(attrSet, rulesAttr);
303 addLocalNameToSet(attrSet, scopeAttr);
304 addLocalNameToSet(attrSet, scrollingAttr);
305 addLocalNameToSet(attrSet, selectedAttr);
306 addLocalNameToSet(attrSet, shapeAttr);
307 addLocalNameToSet(attrSet, targetAttr);
308 addLocalNameToSet(attrSet, textAttr);
309 addLocalNameToSet(attrSet, typeAttr);
310 addLocalNameToSet(attrSet, valignAttr);
311 addLocalNameToSet(attrSet, valuetypeAttr);
312 addLocalNameToSet(attrSet, vlinkAttr);
313
314 return attrSet;
315 }
316
isCaseSensitiveAttribute(const QualifiedName & attributeName)317 bool HTMLDocument::isCaseSensitiveAttribute(const QualifiedName& attributeName)
318 {
319 static HashSet<StringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
320 bool isPossibleHTMLAttr = !attributeName.hasPrefix() && (attributeName.namespaceURI() == nullAtom);
321 return !isPossibleHTMLAttr || !htmlCaseInsensitiveAttributesSet->contains(attributeName.localName().impl());
322 }
323
clear()324 void HTMLDocument::clear()
325 {
326 // FIXME: This does nothing, and that seems unlikely to be correct.
327 // We've long had a comment saying that IE doesn't support this.
328 // But I do see it in the documentation for Mozilla.
329 }
330
write(DOMWindow * activeWindow,const Vector<String> & text)331 void HTMLDocument::write(DOMWindow* activeWindow, const Vector<String>& text)
332 {
333 ASSERT(activeWindow);
334 StringBuilder builder;
335 for (size_t i = 0; i < text.size(); ++i)
336 builder.append(text[i]);
337 write(builder.toString(), activeWindow->document());
338 }
339
writeln(DOMWindow * activeWindow,const Vector<String> & text)340 void HTMLDocument::writeln(DOMWindow* activeWindow, const Vector<String>& text)
341 {
342 ASSERT(activeWindow);
343 StringBuilder builder;
344 for (size_t i = 0; i < text.size(); ++i)
345 builder.append(text[i]);
346 writeln(builder.toString(), activeWindow->document());
347 }
348
349 }
350