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 "CSSStyleSelector.h"
58 #include "CString.h"
59 #include "CookieJar.h"
60 #include "DocumentLoader.h"
61 #include "DocumentType.h"
62 #include "ExceptionCode.h"
63 #include "FocusController.h"
64 #include "Frame.h"
65 #include "FrameLoader.h"
66 #include "FrameTree.h"
67 #include "FrameView.h"
68 #include "HTMLBodyElement.h"
69 #include "HTMLElementFactory.h"
70 #include "HTMLNames.h"
71 #include "HTMLTokenizer.h"
72 #include "InspectorController.h"
73 #include "KURL.h"
74 #include "Page.h"
75
76 #include "DocTypeStrings.cpp"
77
78 namespace WebCore {
79
80 using namespace HTMLNames;
81
HTMLDocument(Frame * frame)82 HTMLDocument::HTMLDocument(Frame* frame)
83 : Document(frame, false)
84 {
85 clearXMLVersion();
86 setParseMode(Compat);
87 }
88
~HTMLDocument()89 HTMLDocument::~HTMLDocument()
90 {
91 }
92
width()93 int HTMLDocument::width()
94 {
95 updateLayoutIgnorePendingStylesheets();
96 FrameView* frameView = view();
97 return frameView ? frameView->contentsWidth() : 0;
98 }
99
height()100 int HTMLDocument::height()
101 {
102 updateLayoutIgnorePendingStylesheets();
103 FrameView* frameView = view();
104 return frameView ? frameView->contentsHeight() : 0;
105 }
106
dir()107 String HTMLDocument::dir()
108 {
109 HTMLElement* b = body();
110 if (!b)
111 return String();
112 return b->dir();
113 }
114
setDir(const String & value)115 void HTMLDocument::setDir(const String& value)
116 {
117 HTMLElement* b = body();
118 if (b)
119 b->setDir(value);
120 }
121
designMode() const122 String HTMLDocument::designMode() const
123 {
124 return inDesignMode() ? "on" : "off";
125 }
126
setDesignMode(const String & value)127 void HTMLDocument::setDesignMode(const String& value)
128 {
129 InheritedBool mode;
130 if (equalIgnoringCase(value, "on"))
131 mode = on;
132 else if (equalIgnoringCase(value, "off"))
133 mode = off;
134 else
135 mode = inherit;
136 Document::setDesignMode(mode);
137 }
138
compatMode() const139 String HTMLDocument::compatMode() const
140 {
141 return inCompatMode() ? "BackCompat" : "CSS1Compat";
142 }
143
activeElement()144 Element* HTMLDocument::activeElement()
145 {
146 if (Node* node = focusedNode())
147 if (node->isElementNode())
148 return static_cast<Element*>(node);
149 return body();
150 }
151
hasFocus()152 bool HTMLDocument::hasFocus()
153 {
154 Page* page = this->page();
155 if (!page)
156 return false;
157 if (!page->focusController()->isActive())
158 return false;
159 if (Frame* focusedFrame = page->focusController()->focusedFrame()) {
160 if (focusedFrame->tree()->isDescendantOf(frame()))
161 return true;
162 }
163 return false;
164 }
165
bgColor()166 String HTMLDocument::bgColor()
167 {
168 HTMLElement* b = body();
169 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
170
171 if (!bodyElement)
172 return String();
173 return bodyElement->bgColor();
174 }
175
setBgColor(const String & value)176 void HTMLDocument::setBgColor(const String& value)
177 {
178 HTMLElement* b = body();
179 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
180
181 if (bodyElement)
182 bodyElement->setBgColor(value);
183 }
184
fgColor()185 String HTMLDocument::fgColor()
186 {
187 HTMLElement* b = body();
188 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
189
190 if (!bodyElement)
191 return String();
192 return bodyElement->text();
193 }
194
setFgColor(const String & value)195 void HTMLDocument::setFgColor(const String& value)
196 {
197 HTMLElement* b = body();
198 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
199
200 if (bodyElement)
201 bodyElement->setText(value);
202 }
203
alinkColor()204 String HTMLDocument::alinkColor()
205 {
206 HTMLElement* b = body();
207 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
208
209 if (!bodyElement)
210 return String();
211 return bodyElement->aLink();
212 }
213
setAlinkColor(const String & value)214 void HTMLDocument::setAlinkColor(const String& value)
215 {
216 HTMLElement* b = body();
217 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
218
219 if (bodyElement) {
220 // This check is a bit silly, but some benchmarks like to set the
221 // document's link colors over and over to the same value and we
222 // don't want to incur a style update each time.
223 if (bodyElement->aLink() != value)
224 bodyElement->setALink(value);
225 }
226 }
227
linkColor()228 String HTMLDocument::linkColor()
229 {
230 HTMLElement* b = body();
231 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
232
233 if (!bodyElement)
234 return String();
235 return bodyElement->link();
236 }
237
setLinkColor(const String & value)238 void HTMLDocument::setLinkColor(const String& value)
239 {
240 HTMLElement* b = body();
241 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
242
243 if (bodyElement) {
244 // This check is a bit silly, but some benchmarks like to set the
245 // document's link colors over and over to the same value and we
246 // don't want to incur a style update each time.
247 if (bodyElement->link() != value)
248 bodyElement->setLink(value);
249 }
250 }
251
vlinkColor()252 String HTMLDocument::vlinkColor()
253 {
254 HTMLElement* b = body();
255 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
256
257 if (!bodyElement)
258 return String();
259 return bodyElement->vLink();
260 }
261
setVlinkColor(const String & value)262 void HTMLDocument::setVlinkColor(const String& value)
263 {
264 HTMLElement* b = body();
265 HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
266
267 if (bodyElement) {
268 // This check is a bit silly, but some benchmarks like to set the
269 // document's link colors over and over to the same value and we
270 // don't want to incur a style update each time.
271 if (bodyElement->vLink() != value)
272 bodyElement->setVLink(value);
273 }
274 }
275
captureEvents()276 void HTMLDocument::captureEvents()
277 {
278 }
279
releaseEvents()280 void HTMLDocument::releaseEvents()
281 {
282 }
283
createTokenizer()284 Tokenizer *HTMLDocument::createTokenizer()
285 {
286 bool reportErrors = false;
287 if (Page* page = this->page())
288 reportErrors = page->inspectorController()->windowVisible();
289
290 return new HTMLTokenizer(this, reportErrors);
291 }
292
293 // --------------------------------------------------------------------------
294 // not part of the DOM
295 // --------------------------------------------------------------------------
296
childAllowed(Node * newChild)297 bool HTMLDocument::childAllowed(Node *newChild)
298 {
299 return newChild->hasTagName(htmlTag) || newChild->isCommentNode() || (newChild->nodeType() == DOCUMENT_TYPE_NODE && !doctype());
300 }
301
createElement(const AtomicString & name,ExceptionCode & ec)302 PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec)
303 {
304 if (!isValidName(name)) {
305 ec = INVALID_CHARACTER_ERR;
306 return 0;
307 }
308 AtomicString lowerName = name.string().impl()->isLower() ? name : AtomicString(name.string().lower());
309 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, lowerName, xhtmlNamespaceURI), this, 0, false);
310 }
311
addItemToMap(HashCountedSet<AtomicStringImpl * > & map,const AtomicString & name)312 static void addItemToMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
313 {
314 if (name.isEmpty())
315 return;
316 map.add(name.impl());
317 }
318
removeItemFromMap(HashCountedSet<AtomicStringImpl * > & map,const AtomicString & name)319 static void removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
320 {
321 if (name.isEmpty())
322 return;
323 map.remove(name.impl());
324 }
325
addNamedItem(const AtomicString & name)326 void HTMLDocument::addNamedItem(const AtomicString& name)
327 {
328 addItemToMap(m_namedItemCounts, name);
329 }
330
removeNamedItem(const AtomicString & name)331 void HTMLDocument::removeNamedItem(const AtomicString& name)
332 {
333 removeItemFromMap(m_namedItemCounts, name);
334 }
335
addExtraNamedItem(const AtomicString & name)336 void HTMLDocument::addExtraNamedItem(const AtomicString& name)
337 {
338 addItemToMap(m_extraNamedItemCounts, name);
339 }
340
removeExtraNamedItem(const AtomicString & name)341 void HTMLDocument::removeExtraNamedItem(const AtomicString& name)
342 {
343 removeItemFromMap(m_extraNamedItemCounts, name);
344 }
345
determineParseMode()346 void HTMLDocument::determineParseMode()
347 {
348 // FIXME: It's terrible that this code runs separately and isn't just built in to the
349 // HTML tokenizer/parser.
350
351 // This code more or less mimics Mozilla's implementation (specifically the
352 // doctype parsing implemented by David Baron in Mozilla's nsParser.cpp).
353 //
354 // There are three possible parse modes:
355 // COMPAT - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can
356 // be omitted from numbers.
357 // ALMOST STRICT - This mode is identical to strict mode except for its treatment of line-height in the inline box model. For
358 // now (until the inline box model is re-written), this mode is identical to STANDARDS mode.
359 // STRICT - no quirks apply. Web pages will obey the specifications to the letter.
360 bool wasInCompatMode = inCompatMode();
361 DocumentType* docType = doctype();
362 if (!docType || !equalIgnoringCase(docType->name(), "html"))
363 // No doctype found at all or the doctype is not HTML. Default to quirks mode and Html4.
364 setParseMode(Compat);
365 else if (!doctype()->systemId().isEmpty() && equalIgnoringCase(docType->systemId(), "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"))
366 // Assume quirks mode for this particular system ID. In the HTML5 spec, this is the only
367 // system identifier that is examined.
368 setParseMode(Compat);
369 else if (docType->publicId().isEmpty())
370 // A doctype without a public ID means use strict mode.
371 setParseMode(Strict);
372 else {
373 // We have to check a list of public IDs to see what we
374 // should do.
375 String lowerPubID = docType->publicId().lower();
376 CString pubIDStr = lowerPubID.latin1();
377
378 // Look up the entry in our gperf-generated table.
379 const PubIDInfo* doctypeEntry = findDoctypeEntry(pubIDStr.data(), pubIDStr.length());
380 if (!doctypeEntry)
381 // The DOCTYPE is not in the list. Assume strict mode.
382 setParseMode(Strict);
383 else {
384 switch (docType->systemId().isEmpty() ?
385 doctypeEntry->mode_if_no_sysid :
386 doctypeEntry->mode_if_sysid) {
387 case PubIDInfo::eQuirks3:
388 case PubIDInfo::eQuirks:
389 setParseMode(Compat);
390 break;
391 case PubIDInfo::eAlmostStandards:
392 setParseMode(AlmostStrict);
393 break;
394 default:
395 ASSERT(false);
396 }
397 }
398 }
399
400 if (inCompatMode() != wasInCompatMode)
401 updateStyleSelector();
402 }
403
clear()404 void HTMLDocument::clear()
405 {
406 // FIXME: This does nothing, and that seems unlikely to be correct.
407 // We've long had a comment saying that IE doesn't support this.
408 // But I do see it in the documentation for Mozilla.
409 }
410
isFrameSet() const411 bool HTMLDocument::isFrameSet() const
412 {
413 HTMLElement* bodyElement = body();
414 return bodyElement && bodyElement->renderer() && bodyElement->hasTagName(framesetTag);
415 }
416
417 }
418