| 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 | |
|---|
| 82 | HTMLDocument::HTMLDocument(Frame* frame) |
|---|
| 83 | : Document(frame, false) |
|---|
| 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 | updateStyleSelector(); |
|---|
| 403 | } |
|---|
| 404 | |
|---|
| 405 | void HTMLDocument::clear() |
|---|
| 406 | { |
|---|
| 407 | // FIXME: This does nothing, and that seems unlikely to be correct. |
|---|
| 408 | // We've long had a comment saying that IE doesn't support this. |
|---|
| 409 | // But I do see it in the documentation for Mozilla. |
|---|
| 410 | } |
|---|
| 411 | |
|---|
| 412 | bool HTMLDocument::isFrameSet() const |
|---|
| 413 | { |
|---|
| 414 | HTMLElement* bodyElement = body(); |
|---|
| 415 | return bodyElement && bodyElement->renderer() && bodyElement->hasTagName(framesetTag); |
|---|
| 416 | } |
|---|
| 417 | |
|---|
| 418 | } |
|---|