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 "HTMLDocument.h"
55
56#include "CSSPropertyNames.h"
57#include "CookieJar.h"
58#include "DocumentLoader.h"
59#include "DocumentType.h"
60#include "ExceptionCode.h"
61#include "FocusController.h"
62#include "Frame.h"
63#include "FrameLoader.h"
64#include "FrameTree.h"
65#include "FrameView.h"
66#include "HashTools.h"
67#include "HTMLDocumentParser.h"
68#include "HTMLBodyElement.h"
69#include "HTMLElementFactory.h"
70#include "HTMLFrameOwnerElement.h"
71#include "HTMLNames.h"
72#include "InspectorInstrumentation.h"
73#include "KURL.h"
74#include "Page.h"
75#include "ScriptController.h"
76#include "Settings.h"
77#include "StyleResolver.h"
78#include <wtf/text/CString.h>
79
80namespace WebCore {
81
82using namespace HTMLNames;
83
84HTMLDocument::HTMLDocument(Frame* frame, const KURL& url, DocumentClassFlags documentClasses)
85    : Document(frame, url, documentClasses | HTMLDocumentClass)
86{
87    clearXMLVersion();
88}
89
90HTMLDocument::~HTMLDocument()
91{
92}
93
94int HTMLDocument::width()
95{
96    updateLayoutIgnorePendingStylesheets();
97    FrameView* frameView = view();
98    return frameView ? frameView->contentsWidth() : 0;
99}
100
101int HTMLDocument::height()
102{
103    updateLayoutIgnorePendingStylesheets();
104    FrameView* frameView = view();
105    return frameView ? frameView->contentsHeight() : 0;
106}
107
108String HTMLDocument::dir()
109{
110    HTMLElement* b = body();
111    if (!b)
112        return String();
113    return b->getAttribute(dirAttr);
114}
115
116void HTMLDocument::setDir(const String& value)
117{
118    HTMLElement* b = body();
119    if (b)
120        b->setAttribute(dirAttr, value);
121}
122
123String HTMLDocument::designMode() const
124{
125    return inDesignMode() ? "on" : "off";
126}
127
128void HTMLDocument::setDesignMode(const String& value)
129{
130    InheritedBool mode;
131    if (equalIgnoringCase(value, "on"))
132        mode = on;
133    else if (equalIgnoringCase(value, "off"))
134        mode = off;
135    else
136        mode = inherit;
137    Document::setDesignMode(mode);
138}
139
140Element* HTMLDocument::activeElement()
141{
142    if (Element* element = treeScope()->focusedElement())
143        return element;
144    return body();
145}
146
147bool HTMLDocument::hasFocus()
148{
149    Page* page = this->page();
150    if (!page)
151        return false;
152    if (!page->focusController()->isActive())
153        return false;
154    if (Frame* focusedFrame = page->focusController()->focusedFrame()) {
155        if (focusedFrame->tree()->isDescendantOf(frame()))
156            return true;
157    }
158    return false;
159}
160
161String HTMLDocument::bgColor()
162{
163    HTMLElement* b = body();
164    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
165
166    if (!bodyElement)
167        return String();
168    return bodyElement->bgColor();
169}
170
171void HTMLDocument::setBgColor(const String& value)
172{
173    HTMLElement* b = body();
174    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
175
176    if (bodyElement)
177        bodyElement->setBgColor(value);
178}
179
180String HTMLDocument::fgColor()
181{
182    HTMLElement* b = body();
183    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
184
185    if (!bodyElement)
186        return String();
187    return bodyElement->text();
188}
189
190void HTMLDocument::setFgColor(const String& value)
191{
192    HTMLElement* b = body();
193    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
194
195    if (bodyElement)
196        bodyElement->setText(value);
197}
198
199String HTMLDocument::alinkColor()
200{
201    HTMLElement* b = body();
202    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
203
204    if (!bodyElement)
205        return String();
206    return bodyElement->aLink();
207}
208
209void HTMLDocument::setAlinkColor(const String& value)
210{
211    HTMLElement* b = body();
212    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
213
214    if (bodyElement) {
215        // This check is a bit silly, but some benchmarks like to set the
216        // document's link colors over and over to the same value and we
217        // don't want to incur a style update each time.
218        if (bodyElement->aLink() != value)
219            bodyElement->setALink(value);
220    }
221}
222
223String HTMLDocument::linkColor()
224{
225    HTMLElement* b = body();
226    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
227
228    if (!bodyElement)
229        return String();
230    return bodyElement->link();
231}
232
233void HTMLDocument::setLinkColor(const String& value)
234{
235    HTMLElement* b = body();
236    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
237
238    if (bodyElement) {
239        // This check is a bit silly, but some benchmarks like to set the
240        // document's link colors over and over to the same value and we
241        // don't want to incur a style update each time.
242        if (bodyElement->link() != value)
243            bodyElement->setLink(value);
244    }
245}
246
247String HTMLDocument::vlinkColor()
248{
249    HTMLElement* b = body();
250    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
251
252    if (!bodyElement)
253        return String();
254    return bodyElement->vLink();
255}
256
257void HTMLDocument::setVlinkColor(const String& value)
258{
259    HTMLElement* b = body();
260    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
261
262    if (bodyElement) {
263        // This check is a bit silly, but some benchmarks like to set the
264        // document's link colors over and over to the same value and we
265        // don't want to incur a style update each time.
266        if (bodyElement->vLink() != value)
267            bodyElement->setVLink(value);
268    }
269}
270
271void HTMLDocument::captureEvents()
272{
273}
274
275void HTMLDocument::releaseEvents()
276{
277}
278
279PassRefPtr<DocumentParser> HTMLDocument::createParser()
280{
281    bool reportErrors = InspectorInstrumentation::collectingHTMLParseErrors(this->page());
282    return HTMLDocumentParser::create(this, reportErrors);
283}
284
285// --------------------------------------------------------------------------
286// not part of the DOM
287// --------------------------------------------------------------------------
288
289PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec)
290{
291    if (!isValidName(name)) {
292        ec = INVALID_CHARACTER_ERR;
293        return 0;
294    }
295    return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false);
296}
297
298static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
299{
300    set->add(qName.localName().impl());
301}
302
303static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
304{
305    // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
306    // Mozilla treats all other values as case-sensitive, thus so do we.
307    HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
308
309    addLocalNameToSet(attrSet, accept_charsetAttr);
310    addLocalNameToSet(attrSet, acceptAttr);
311    addLocalNameToSet(attrSet, alignAttr);
312    addLocalNameToSet(attrSet, alinkAttr);
313    addLocalNameToSet(attrSet, axisAttr);
314    addLocalNameToSet(attrSet, bgcolorAttr);
315    addLocalNameToSet(attrSet, charsetAttr);
316    addLocalNameToSet(attrSet, checkedAttr);
317    addLocalNameToSet(attrSet, clearAttr);
318    addLocalNameToSet(attrSet, codetypeAttr);
319    addLocalNameToSet(attrSet, colorAttr);
320    addLocalNameToSet(attrSet, compactAttr);
321    addLocalNameToSet(attrSet, declareAttr);
322    addLocalNameToSet(attrSet, deferAttr);
323    addLocalNameToSet(attrSet, dirAttr);
324    addLocalNameToSet(attrSet, disabledAttr);
325    addLocalNameToSet(attrSet, enctypeAttr);
326    addLocalNameToSet(attrSet, faceAttr);
327    addLocalNameToSet(attrSet, frameAttr);
328    addLocalNameToSet(attrSet, hreflangAttr);
329    addLocalNameToSet(attrSet, http_equivAttr);
330    addLocalNameToSet(attrSet, langAttr);
331    addLocalNameToSet(attrSet, languageAttr);
332    addLocalNameToSet(attrSet, linkAttr);
333    addLocalNameToSet(attrSet, mediaAttr);
334    addLocalNameToSet(attrSet, methodAttr);
335    addLocalNameToSet(attrSet, multipleAttr);
336    addLocalNameToSet(attrSet, nohrefAttr);
337    addLocalNameToSet(attrSet, noresizeAttr);
338    addLocalNameToSet(attrSet, noshadeAttr);
339    addLocalNameToSet(attrSet, nowrapAttr);
340    addLocalNameToSet(attrSet, readonlyAttr);
341    addLocalNameToSet(attrSet, relAttr);
342    addLocalNameToSet(attrSet, revAttr);
343    addLocalNameToSet(attrSet, rulesAttr);
344    addLocalNameToSet(attrSet, scopeAttr);
345    addLocalNameToSet(attrSet, scrollingAttr);
346    addLocalNameToSet(attrSet, selectedAttr);
347    addLocalNameToSet(attrSet, shapeAttr);
348    addLocalNameToSet(attrSet, targetAttr);
349    addLocalNameToSet(attrSet, textAttr);
350    addLocalNameToSet(attrSet, typeAttr);
351    addLocalNameToSet(attrSet, valignAttr);
352    addLocalNameToSet(attrSet, valuetypeAttr);
353    addLocalNameToSet(attrSet, vlinkAttr);
354
355    return attrSet;
356}
357
358bool HTMLDocument::isCaseSensitiveAttribute(const QualifiedName& attributeName)
359{
360    static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
361    bool isPossibleHTMLAttr = !attributeName.hasPrefix() && (attributeName.namespaceURI() == nullAtom);
362    return !isPossibleHTMLAttr || !htmlCaseInsensitiveAttributesSet->contains(attributeName.localName().impl());
363}
364
365void HTMLDocument::clear()
366{
367    // FIXME: This does nothing, and that seems unlikely to be correct.
368    // We've long had a comment saying that IE doesn't support this.
369    // But I do see it in the documentation for Mozilla.
370}
371
372bool HTMLDocument::isFrameSet() const
373{
374    HTMLElement* bodyElement = body();
375    return bodyElement && bodyElement->hasTagName(framesetTag);
376}
377
378}
379