• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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