1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) 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 (at) 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 82 HTMLDocument::HTMLDocument(Frame* frame) 83 : Document(frame, false, true) 84 { 85 clearXMLVersion(); 86 setParseMode(Compat); 87 } 88 89 HTMLDocument::~HTMLDocument() 90 { 91 } 92 93 int HTMLDocument::width() 94 { 95 updateLayoutIgnorePendingStylesheets(); 96 FrameView* frameView = view(); 97 return frameView ? frameView->contentsWidth() : 0; 98 } 99 100 int HTMLDocument::height() 101 { 102 updateLayoutIgnorePendingStylesheets(); 103 FrameView* frameView = view(); 104 return frameView ? frameView->contentsHeight() : 0; 105 } 106 107 String HTMLDocument::dir() 108 { 109 HTMLElement* b = body(); 110 if (!b) 111 return String(); 112 return b->getAttribute(dirAttr); 113 } 114 115 void HTMLDocument::setDir(const String& value) 116 { 117 HTMLElement* b = body(); 118 if (b) 119 b->setAttribute(dirAttr, value); 120 } 121 122 String HTMLDocument::designMode() const 123 { 124 return inDesignMode() ? "on" : "off"; 125 } 126 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 139 String HTMLDocument::compatMode() const 140 { 141 return inCompatMode() ? "BackCompat" : "CSS1Compat"; 142 } 143 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 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 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 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 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 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 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 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 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 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 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 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 276 void HTMLDocument::captureEvents() 277 { 278 } 279 280 void HTMLDocument::releaseEvents() 281 { 282 } 283 284 Tokenizer *HTMLDocument::createTokenizer() 285 { 286 bool reportErrors = false; 287 #if ENABLE(INSPECTOR) 288 if (Page* page = this->page()) 289 reportErrors = page->inspectorController()->windowVisible(); 290 #endif 291 292 return new HTMLTokenizer(this, reportErrors); 293 } 294 295 // -------------------------------------------------------------------------- 296 // not part of the DOM 297 // -------------------------------------------------------------------------- 298 299 bool HTMLDocument::childAllowed(Node *newChild) 300 { 301 return newChild->hasTagName(htmlTag) || newChild->isCommentNode() || (newChild->nodeType() == DOCUMENT_TYPE_NODE && !doctype()); 302 } 303 304 PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec) 305 { 306 if (!isValidName(name)) { 307 ec = INVALID_CHARACTER_ERR; 308 return 0; 309 } 310 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false); 311 } 312 313 static void addItemToMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name) 314 { 315 if (name.isEmpty()) 316 return; 317 map.add(name.impl()); 318 } 319 320 static void removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name) 321 { 322 if (name.isEmpty()) 323 return; 324 map.remove(name.impl()); 325 } 326 327 void HTMLDocument::addNamedItem(const AtomicString& name) 328 { 329 addItemToMap(m_namedItemCounts, name); 330 } 331 332 void HTMLDocument::removeNamedItem(const AtomicString& name) 333 { 334 removeItemFromMap(m_namedItemCounts, name); 335 } 336 337 void HTMLDocument::addExtraNamedItem(const AtomicString& name) 338 { 339 addItemToMap(m_extraNamedItemCounts, name); 340 } 341 342 void HTMLDocument::removeExtraNamedItem(const AtomicString& name) 343 { 344 removeItemFromMap(m_extraNamedItemCounts, name); 345 } 346 347 void HTMLDocument::determineParseMode() 348 { 349 // FIXME: It's terrible that this code runs separately and isn't just built in to the 350 // HTML tokenizer/parser. 351 352 // This code more or less mimics Mozilla's implementation (specifically the 353 // doctype parsing implemented by David Baron in Mozilla's nsParser.cpp). 354 // 355 // There are three possible parse modes: 356 // COMPAT - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can 357 // be omitted from numbers. 358 // ALMOST STRICT - This mode is identical to strict mode except for its treatment of line-height in the inline box model. For 359 // now (until the inline box model is re-written), this mode is identical to STANDARDS mode. 360 // STRICT - no quirks apply. Web pages will obey the specifications to the letter. 361 bool wasInCompatMode = inCompatMode(); 362 DocumentType* docType = doctype(); 363 if (!docType || !equalIgnoringCase(docType->name(), "html")) 364 // No doctype found at all or the doctype is not HTML. Default to quirks mode and Html4. 365 setParseMode(Compat); 366 else if (!doctype()->systemId().isEmpty() && equalIgnoringCase(docType->systemId(), "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")) 367 // Assume quirks mode for this particular system ID. In the HTML5 spec, this is the only 368 // system identifier that is examined. 369 setParseMode(Compat); 370 else if (docType->publicId().isEmpty()) 371 // A doctype without a public ID means use strict mode. 372 setParseMode(Strict); 373 else { 374 // We have to check a list of public IDs to see what we 375 // should do. 376 String lowerPubID = docType->publicId().lower(); 377 CString pubIDStr = lowerPubID.latin1(); 378 379 // Look up the entry in our gperf-generated table. 380 const PubIDInfo* doctypeEntry = findDoctypeEntry(pubIDStr.data(), pubIDStr.length()); 381 if (!doctypeEntry) 382 // The DOCTYPE is not in the list. Assume strict mode. 383 setParseMode(Strict); 384 else { 385 switch (docType->systemId().isEmpty() ? 386 doctypeEntry->mode_if_no_sysid : 387 doctypeEntry->mode_if_sysid) { 388 case PubIDInfo::eQuirks3: 389 case PubIDInfo::eQuirks: 390 setParseMode(Compat); 391 break; 392 case PubIDInfo::eAlmostStandards: 393 setParseMode(AlmostStrict); 394 break; 395 default: 396 ASSERT(false); 397 } 398 } 399 } 400 401 if (inCompatMode() != wasInCompatMode) { 402 clearPageUserSheet(); 403 clearPageGroupUserSheets(); 404 updateStyleSelector(); 405 } 406 } 407 408 void HTMLDocument::clear() 409 { 410 // FIXME: This does nothing, and that seems unlikely to be correct. 411 // We've long had a comment saying that IE doesn't support this. 412 // But I do see it in the documentation for Mozilla. 413 } 414 415 bool HTMLDocument::isFrameSet() const 416 { 417 HTMLElement* bodyElement = body(); 418 return bodyElement && bodyElement->renderer() && bodyElement->hasTagName(framesetTag); 419 } 420 421 #ifdef ANDROID_INSTRUMENT 422 void* HTMLDocument::operator new(size_t size) 423 { 424 return Node::operator new(size); 425 } 426 427 void* HTMLDocument::operator new[](size_t size) 428 { 429 return Node::operator new[](size); 430 } 431 432 void HTMLDocument::operator delete(void* p, size_t size) 433 { 434 Node::operator delete(p, size); 435 } 436 437 void HTMLDocument::operator delete[](void* p, size_t size) 438 { 439 Node::operator delete[](p, size); 440 } 441 #endif 442 443 } 444