1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2008, 2009 Google Inc. All rights reserved. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 */ 25 26 #include "config.h" 27 #include "Document.h" 28 29 #include "AXObjectCache.h" 30 #include "AnimationController.h" 31 #include "Attr.h" 32 #include "CDATASection.h" 33 #include "CSSHelper.h" 34 #include "CSSStyleSelector.h" 35 #include "CSSStyleSheet.h" 36 #include "CSSValueKeywords.h" 37 #include "CString.h" 38 #include "CachedCSSStyleSheet.h" 39 #include "Chrome.h" 40 #include "ChromeClient.h" 41 #include "Comment.h" 42 #include "Console.h" 43 #include "CookieJar.h" 44 #include "DOMImplementation.h" 45 #include "DOMWindow.h" 46 #include "DocLoader.h" 47 #include "DocumentFragment.h" 48 #include "DocumentLoader.h" 49 #include "DocumentType.h" 50 #include "EditingText.h" 51 #include "Editor.h" 52 #include "EntityReference.h" 53 #include "Event.h" 54 #include "EventHandler.h" 55 #include "EventListener.h" 56 #include "EventNames.h" 57 #include "ExceptionCode.h" 58 #include "FocusController.h" 59 #include "Frame.h" 60 #include "FrameLoader.h" 61 #include "FrameTree.h" 62 #include "FrameView.h" 63 #include "HTMLAllCollection.h" 64 #include "HTMLAnchorElement.h" 65 #include "HTMLBodyElement.h" 66 #include "HTMLCanvasElement.h" 67 #include "HTMLCollection.h" 68 #include "HTMLDocument.h" 69 #include "HTMLElementFactory.h" 70 #include "HTMLFrameOwnerElement.h" 71 #include "HTMLHeadElement.h" 72 #include "HTMLIFrameElement.h" 73 #include "HTMLInputElement.h" 74 #include "HTMLLinkElement.h" 75 #include "HTMLMapElement.h" 76 #include "HTMLNameCollection.h" 77 #include "HTMLNames.h" 78 #include "HTMLParser.h" 79 #include "HTMLStyleElement.h" 80 #include "HTMLTitleElement.h" 81 #include "HTTPParsers.h" 82 #include "HistoryItem.h" 83 #include "HitTestRequest.h" 84 #include "HitTestResult.h" 85 #include "ImageLoader.h" 86 #include "InspectorController.h" 87 #include "InspectorTimelineAgent.h" 88 #include "KeyboardEvent.h" 89 #include "Logging.h" 90 #include "MappedAttribute.h" 91 #include "MessageEvent.h" 92 #include "MouseEvent.h" 93 #include "MouseEventWithHitTestResults.h" 94 #include "MutationEvent.h" 95 #include "NameNodeList.h" 96 #include "NodeFilter.h" 97 #include "NodeIterator.h" 98 #include "NodeWithIndex.h" 99 #include "OverflowEvent.h" 100 #include "Page.h" 101 #include "PageGroup.h" 102 #include "PageTransitionEvent.h" 103 #include "PlatformKeyboardEvent.h" 104 #include "PopStateEvent.h" 105 #include "ProcessingInstruction.h" 106 #include "ProgressEvent.h" 107 #include "RegisteredEventListener.h" 108 #include "RenderArena.h" 109 #include "RenderTextControl.h" 110 #include "RenderView.h" 111 #include "RenderWidget.h" 112 #include "ScriptController.h" 113 #include "ScriptElement.h" 114 #include "ScriptEventListener.h" 115 #include "SecurityOrigin.h" 116 #include "SegmentedString.h" 117 #include "SelectionController.h" 118 #include "Settings.h" 119 #include "StringBuffer.h" 120 #include "StyleSheetList.h" 121 #include "TextEvent.h" 122 #include "TextIterator.h" 123 #include "TextResourceDecoder.h" 124 #include "Timer.h" 125 #include "TransformSource.h" 126 #include "TreeWalker.h" 127 #include "UIEvent.h" 128 #include "UserContentURLPattern.h" 129 #include "WebKitAnimationEvent.h" 130 #include "WebKitTransitionEvent.h" 131 #include "WheelEvent.h" 132 #include "XMLHttpRequest.h" 133 #include "XMLNSNames.h" 134 #include "XMLNames.h" 135 #include "XMLTokenizer.h" 136 #include "htmlediting.h" 137 #include <wtf/CurrentTime.h> 138 #include <wtf/HashFunctions.h> 139 #include <wtf/MainThread.h> 140 #include <wtf/PassRefPtr.h> 141 #include <wtf/StdLibExtras.h> 142 143 #if ENABLE(SHARED_WORKERS) 144 #include "SharedWorkerRepository.h" 145 #endif 146 147 #if ENABLE(DOM_STORAGE) 148 #include "StorageEvent.h" 149 #endif 150 151 #if ENABLE(XPATH) 152 #include "XPathEvaluator.h" 153 #include "XPathExpression.h" 154 #include "XPathNSResolver.h" 155 #include "XPathResult.h" 156 #endif 157 158 #if ENABLE(XSLT) 159 #include "XSLTProcessor.h" 160 #endif 161 162 #if ENABLE(XBL) 163 #include "XBLBindingManager.h" 164 #endif 165 166 #if ENABLE(SVG) 167 #include "SVGDocumentExtensions.h" 168 #include "SVGElementFactory.h" 169 #include "SVGNames.h" 170 #include "SVGZoomEvent.h" 171 #include "SVGStyleElement.h" 172 #endif 173 174 #if PLATFORM(ANDROID) 175 // FIXME: We shouldn't be including this from WebCore! 176 #include "WebViewCore.h" 177 #endif 178 179 #ifdef ANDROID_META_SUPPORT 180 #include "Settings.h" 181 #endif 182 183 #ifdef ANDROID_RESET_SELECTION 184 #include "CacheBuilder.h" 185 #include "HTMLTextAreaElement.h" 186 #endif 187 188 #ifdef ANDROID_INSTRUMENT 189 #include "TimeCounter.h" 190 #endif 191 192 #if ENABLE(TOUCH_EVENTS) 193 #include "TouchEvent.h" 194 #endif 195 196 #if ENABLE(WML) 197 #include "WMLDocument.h" 198 #include "WMLElement.h" 199 #include "WMLElementFactory.h" 200 #include "WMLNames.h" 201 #endif 202 203 #if ENABLE(MATHML) 204 #include "MathMLElement.h" 205 #include "MathMLElementFactory.h" 206 #include "MathMLNames.h" 207 #endif 208 209 #if ENABLE(XHTMLMP) 210 #include "HTMLNoScriptElement.h" 211 #endif 212 213 using namespace std; 214 using namespace WTF; 215 using namespace Unicode; 216 217 namespace WebCore { 218 219 using namespace HTMLNames; 220 221 // #define INSTRUMENT_LAYOUT_SCHEDULING 1 222 223 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. 224 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high 225 // for dual G5s. :) 226 static const int cLayoutScheduleThreshold = 250; 227 228 // Use 1 to represent the document's default form. 229 static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1); 230 231 // DOM Level 2 says (letters added): 232 // 233 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. 234 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd. 235 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names. 236 // d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed. 237 // e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6. 238 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14). 239 // g) Character #x00B7 is classified as an extender, because the property list so identifies it. 240 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent. 241 // i) Characters ':' and '_' are allowed as name-start characters. 242 // j) Characters '-' and '.' are allowed as name characters. 243 // 244 // It also contains complete tables. If we decide it's better, we could include those instead of the following code. 245 246 static inline bool isValidNameStart(UChar32 c) 247 { 248 // rule (e) above 249 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6) 250 return true; 251 252 // rule (i) above 253 if (c == ':' || c == '_') 254 return true; 255 256 // rules (a) and (f) above 257 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter; 258 if (!(Unicode::category(c) & nameStartMask)) 259 return false; 260 261 // rule (c) above 262 if (c >= 0xF900 && c < 0xFFFE) 263 return false; 264 265 // rule (d) above 266 DecompositionType decompType = decompositionType(c); 267 if (decompType == DecompositionFont || decompType == DecompositionCompat) 268 return false; 269 270 return true; 271 } 272 273 static inline bool isValidNamePart(UChar32 c) 274 { 275 // rules (a), (e), and (i) above 276 if (isValidNameStart(c)) 277 return true; 278 279 // rules (g) and (h) above 280 if (c == 0x00B7 || c == 0x0387) 281 return true; 282 283 // rule (j) above 284 if (c == '-' || c == '.') 285 return true; 286 287 // rules (b) and (f) above 288 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit; 289 if (!(Unicode::category(c) & otherNamePartMask)) 290 return false; 291 292 // rule (c) above 293 if (c >= 0xF900 && c < 0xFFFE) 294 return false; 295 296 // rule (d) above 297 DecompositionType decompType = decompositionType(c); 298 if (decompType == DecompositionFont || decompType == DecompositionCompat) 299 return false; 300 301 return true; 302 } 303 304 static Widget* widgetForNode(Node* focusedNode) 305 { 306 if (!focusedNode) 307 return 0; 308 RenderObject* renderer = focusedNode->renderer(); 309 if (!renderer || !renderer->isWidget()) 310 return 0; 311 return toRenderWidget(renderer)->widget(); 312 } 313 314 static bool acceptsEditingFocus(Node *node) 315 { 316 ASSERT(node); 317 ASSERT(node->isContentEditable()); 318 319 Node *root = node->rootEditableElement(); 320 Frame* frame = node->document()->frame(); 321 if (!frame || !root) 322 return false; 323 324 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get()); 325 } 326 327 static bool disableRangeMutation(Page* page) 328 { 329 #if PLATFORM(MAC) 330 // Disable Range mutation on document modifications in Tiger and Leopard Mail 331 // See <rdar://problem/5865171> 332 return page && (page->settings()->needsLeopardMailQuirks() || page->settings()->needsTigerMailQuirks()); 333 #else 334 return false; 335 #endif 336 } 337 338 static HashSet<Document*>* documentsThatNeedStyleRecalc = 0; 339 340 class DocumentWeakReference : public ThreadSafeShared<DocumentWeakReference> { 341 public: 342 static PassRefPtr<DocumentWeakReference> create(Document* document) 343 { 344 return adoptRef(new DocumentWeakReference(document)); 345 } 346 347 Document* document() 348 { 349 ASSERT(isMainThread()); 350 return m_document; 351 } 352 353 void clear() 354 { 355 ASSERT(isMainThread()); 356 m_document = 0; 357 } 358 359 private: 360 DocumentWeakReference(Document* document) 361 : m_document(document) 362 { 363 ASSERT(isMainThread()); 364 } 365 366 Document* m_document; 367 }; 368 369 Document::Document(Frame* frame, bool isXHTML, bool isHTML) 370 : ContainerNode(0) 371 , m_domtree_version(0) 372 , m_styleSheets(StyleSheetList::create(this)) 373 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired) 374 , m_frameElementsShouldIgnoreScrolling(false) 375 , m_containsValidityStyleRules(false) 376 , m_updateFocusAppearanceRestoresSelection(false) 377 , m_title("") 378 , m_rawTitle("") 379 , m_titleSetExplicitly(false) 380 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) 381 , m_startTime(currentTime()) 382 , m_overMinimumLayoutThreshold(false) 383 , m_extraLayoutDelay(0) 384 , m_executeScriptSoonTimer(this, &Document::executeScriptSoonTimerFired) 385 , m_xmlVersion("1.0") 386 , m_xmlStandalone(false) 387 #if ENABLE(XBL) 388 , m_bindingManager(new XBLBindingManager(this)) 389 #endif 390 , m_savedRenderer(0) 391 , m_designMode(inherit) 392 , m_selfOnlyRefCount(0) 393 #if ENABLE(SVG) 394 , m_svgExtensions(0) 395 #endif 396 #if ENABLE(DASHBOARD_SUPPORT) 397 , m_hasDashboardRegions(false) 398 , m_dashboardRegionsDirty(false) 399 #endif 400 , m_accessKeyMapValid(false) 401 , m_createRenderers(true) 402 , m_inPageCache(false) 403 , m_useSecureKeyboardEntryWhenActive(false) 404 , m_isXHTML(isXHTML) 405 , m_isHTML(isHTML) 406 , m_numNodeListCaches(0) 407 #if USE(JSC) 408 , m_normalWorldWrapperCache(0) 409 #endif 410 , m_usingGeolocation(false) 411 , m_storageEventTimer(this, &Document::storageEventTimerFired) 412 #if ENABLE(WML) 413 , m_containsWMLContent(false) 414 #endif 415 , m_weakReference(DocumentWeakReference::create(this)) 416 { 417 m_document = this; 418 419 m_pageGroupUserSheetCacheValid = false; 420 421 m_printing = false; 422 423 m_ignoreAutofocus = false; 424 425 m_frame = frame; 426 427 #if !PLATFORM(ANDROID) 428 m_axObjectCache = 0; 429 #endif 430 431 m_docLoader = new DocLoader(this); 432 433 m_visuallyOrdered = false; 434 m_bParsing = false; 435 m_wellFormed = false; 436 437 setParseMode(Strict); 438 439 m_textColor = Color::black; 440 m_listenerTypes = 0; 441 m_inDocument = true; 442 m_inStyleRecalc = false; 443 m_closeAfterStyleRecalc = false; 444 445 m_usesDescendantRules = false; 446 m_usesSiblingRules = false; 447 m_usesFirstLineRules = false; 448 m_usesFirstLetterRules = false; 449 m_usesBeforeAfterRules = false; 450 m_usesRemUnits = false; 451 452 m_gotoAnchorNeededAfterStylesheetsLoad = false; 453 454 m_didCalculateStyleSelector = false; 455 m_pendingStylesheets = 0; 456 m_ignorePendingStylesheets = false; 457 m_hasNodesWithPlaceholderStyle = false; 458 m_pendingSheetLayout = NoLayoutWithPendingSheets; 459 460 m_cssTarget = 0; 461 462 resetLinkColor(); 463 resetVisitedLinkColor(); 464 resetActiveLinkColor(); 465 466 m_processingLoadEvent = false; 467 468 initSecurityContext(); 469 initDNSPrefetch(); 470 471 static int docID = 0; 472 m_docID = docID++; 473 #if ENABLE(XHTMLMP) 474 m_shouldProcessNoScriptElement = settings() && !settings()->isJavaScriptEnabled(); 475 #endif 476 } 477 478 void Document::removedLastRef() 479 { 480 ASSERT(!m_deletionHasBegun); 481 if (m_selfOnlyRefCount) { 482 // If removing a child removes the last self-only ref, we don't 483 // want the document to be destructed until after 484 // removeAllChildren returns, so we guard ourselves with an 485 // extra self-only ref. 486 selfOnlyRef(); 487 488 // We must make sure not to be retaining any of our children through 489 // these extra pointers or we will create a reference cycle. 490 m_docType = 0; 491 m_focusedNode = 0; 492 m_hoverNode = 0; 493 m_activeNode = 0; 494 m_titleElement = 0; 495 m_documentElement = 0; 496 497 // removeAllChildren() doesn't always unregister IDs, do it upfront to avoid having stale references in the map. 498 m_elementsById.clear(); 499 500 removeAllChildren(); 501 502 deleteAllValues(m_markers); 503 m_markers.clear(); 504 505 m_tokenizer.clear(); 506 507 m_cssCanvasElements.clear(); 508 509 #ifndef NDEBUG 510 m_inRemovedLastRefFunction = false; 511 #endif 512 513 selfOnlyDeref(); 514 } else { 515 #ifndef NDEBUG 516 m_deletionHasBegun = true; 517 #endif 518 delete this; 519 } 520 } 521 522 Document::~Document() 523 { 524 ASSERT(!renderer()); 525 ASSERT(!m_inPageCache); 526 ASSERT(!m_savedRenderer); 527 ASSERT(m_ranges.isEmpty()); 528 ASSERT(!m_styleRecalcTimer.isActive()); 529 530 for (size_t i = 0; i < m_scriptsToExecuteSoon.size(); ++i) 531 m_scriptsToExecuteSoon[i].first->element()->deref(); // Balances ref() in executeScriptSoon(). 532 533 removeAllEventListeners(); 534 535 #if USE(JSC) 536 forgetAllDOMNodesForDocument(this); 537 #endif 538 539 m_tokenizer.clear(); 540 m_document = 0; 541 m_docLoader.clear(); 542 543 m_renderArena.clear(); 544 545 #if ENABLE(XBL) 546 m_bindingManager.clear(); 547 #endif 548 549 deleteAllValues(m_markers); 550 551 clearAXObjectCache(); 552 553 m_decoder = 0; 554 555 unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]); 556 for (unsigned i = 0; i < count; i++) 557 deleteAllValues(m_nameCollectionInfo[i]); 558 559 if (m_styleSheets) 560 m_styleSheets->documentDestroyed(); 561 562 m_weakReference->clear(); 563 } 564 565 #if USE(JSC) 566 Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world) 567 { 568 JSWrapperCache* wrapperCache = new JSWrapperCache(); 569 m_wrapperCacheMap.set(world, wrapperCache); 570 if (world->isNormal()) { 571 ASSERT(!m_normalWorldWrapperCache); 572 m_normalWorldWrapperCache = wrapperCache; 573 } 574 world->rememberDocument(this); 575 return wrapperCache; 576 } 577 #endif 578 579 void Document::resetLinkColor() 580 { 581 m_linkColor = Color(0, 0, 238); 582 } 583 584 void Document::resetVisitedLinkColor() 585 { 586 m_visitedLinkColor = Color(85, 26, 139); 587 } 588 589 void Document::resetActiveLinkColor() 590 { 591 m_activeLinkColor.setNamedColor("red"); 592 } 593 594 void Document::setDocType(PassRefPtr<DocumentType> docType) 595 { 596 // This should never be called more than once. 597 // Note: This is not a public DOM method and can only be called by the parser. 598 ASSERT(!m_docType || !docType); 599 if (m_docType && docType) 600 return; 601 m_docType = docType; 602 if (m_docType) 603 m_docType->setDocument(this); 604 #ifdef ANDROID_META_SUPPORT 605 if (m_docType && !ownerElement() 606 && m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", false)) { 607 // fit mobile sites directly in the screen 608 if (Frame *f = frame()) 609 f->settings()->setMetadataSettings("width", "device-width"); 610 if (FrameView* frameView = view()) 611 android::WebViewCore::getWebViewCore(frameView)->updateViewport(); 612 } 613 #endif 614 determineParseMode(); 615 } 616 617 DOMImplementation* Document::implementation() const 618 { 619 if (!m_implementation) 620 m_implementation = DOMImplementation::create(); 621 return m_implementation.get(); 622 } 623 624 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 625 { 626 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 627 628 // Invalidate the document element we have cached in case it was replaced. 629 m_documentElement = 0; 630 } 631 632 void Document::cacheDocumentElement() const 633 { 634 ASSERT(!m_documentElement); 635 Node* n = firstChild(); 636 while (n && !n->isElementNode()) 637 n = n->nextSibling(); 638 m_documentElement = static_cast<Element*>(n); 639 } 640 641 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec) 642 { 643 if (!isValidName(name)) { 644 ec = INVALID_CHARACTER_ERR; 645 return 0; 646 } 647 648 if (m_isXHTML) 649 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name, xhtmlNamespaceURI), this, 0, false); 650 651 return createElement(QualifiedName(nullAtom, name, nullAtom), false); 652 } 653 654 PassRefPtr<DocumentFragment> Document::createDocumentFragment() 655 { 656 return DocumentFragment::create(document()); 657 } 658 659 PassRefPtr<Text> Document::createTextNode(const String& data) 660 { 661 return Text::create(this, data); 662 } 663 664 PassRefPtr<Comment> Document::createComment(const String& data) 665 { 666 return Comment::create(this, data); 667 } 668 669 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionCode& ec) 670 { 671 if (isHTMLDocument()) { 672 ec = NOT_SUPPORTED_ERR; 673 return 0; 674 } 675 return CDATASection::create(this, data); 676 } 677 678 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec) 679 { 680 if (!isValidName(target)) { 681 ec = INVALID_CHARACTER_ERR; 682 return 0; 683 } 684 if (isHTMLDocument()) { 685 ec = NOT_SUPPORTED_ERR; 686 return 0; 687 } 688 return ProcessingInstruction::create(this, target, data); 689 } 690 691 PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec) 692 { 693 if (!isValidName(name)) { 694 ec = INVALID_CHARACTER_ERR; 695 return 0; 696 } 697 if (isHTMLDocument()) { 698 ec = NOT_SUPPORTED_ERR; 699 return 0; 700 } 701 return EntityReference::create(this, name); 702 } 703 704 PassRefPtr<EditingText> Document::createEditingTextNode(const String& text) 705 { 706 return EditingText::create(this, text); 707 } 708 709 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration() 710 { 711 return CSSMutableStyleDeclaration::create(); 712 } 713 714 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec) 715 { 716 ec = 0; 717 718 if (!importedNode 719 #if ENABLE(SVG) && ENABLE(DASHBOARD_SUPPORT) 720 || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode()) 721 #endif 722 ) { 723 ec = NOT_SUPPORTED_ERR; 724 return 0; 725 } 726 727 switch (importedNode->nodeType()) { 728 case TEXT_NODE: 729 return createTextNode(importedNode->nodeValue()); 730 case CDATA_SECTION_NODE: 731 return createCDATASection(importedNode->nodeValue(), ec); 732 case ENTITY_REFERENCE_NODE: 733 return createEntityReference(importedNode->nodeName(), ec); 734 case PROCESSING_INSTRUCTION_NODE: 735 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec); 736 case COMMENT_NODE: 737 return createComment(importedNode->nodeValue()); 738 case ELEMENT_NODE: { 739 Element* oldElement = static_cast<Element*>(importedNode); 740 RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec); 741 742 if (ec) 743 return 0; 744 745 NamedNodeMap* attrs = oldElement->attributes(true); 746 if (attrs) { 747 unsigned length = attrs->length(); 748 for (unsigned i = 0; i < length; i++) { 749 Attribute* attr = attrs->attributeItem(i); 750 newElement->setAttribute(attr->name(), attr->value().impl(), ec); 751 if (ec) 752 return 0; 753 } 754 } 755 756 newElement->copyNonAttributeProperties(oldElement); 757 758 if (deep) { 759 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 760 RefPtr<Node> newChild = importNode(oldChild, true, ec); 761 if (ec) 762 return 0; 763 newElement->appendChild(newChild.release(), ec); 764 if (ec) 765 return 0; 766 } 767 } 768 769 return newElement.release(); 770 } 771 case ATTRIBUTE_NODE: 772 return Attr::create(0, this, static_cast<Attr*>(importedNode)->attr()->clone()); 773 case DOCUMENT_FRAGMENT_NODE: { 774 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode); 775 RefPtr<DocumentFragment> newFragment = createDocumentFragment(); 776 if (deep) { 777 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 778 RefPtr<Node> newChild = importNode(oldChild, true, ec); 779 if (ec) 780 return 0; 781 newFragment->appendChild(newChild.release(), ec); 782 if (ec) 783 return 0; 784 } 785 } 786 787 return newFragment.release(); 788 } 789 case ENTITY_NODE: 790 case NOTATION_NODE: 791 // FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that. 792 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM. 793 case DOCUMENT_NODE: 794 case DOCUMENT_TYPE_NODE: 795 case XPATH_NAMESPACE_NODE: 796 break; 797 } 798 799 ec = NOT_SUPPORTED_ERR; 800 return 0; 801 } 802 803 804 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec) 805 { 806 if (!source) { 807 ec = NOT_SUPPORTED_ERR; 808 return 0; 809 } 810 811 if (source->isReadOnlyNode()) { 812 ec = NO_MODIFICATION_ALLOWED_ERR; 813 return 0; 814 } 815 816 switch (source->nodeType()) { 817 case ENTITY_NODE: 818 case NOTATION_NODE: 819 case DOCUMENT_NODE: 820 case DOCUMENT_TYPE_NODE: 821 case XPATH_NAMESPACE_NODE: 822 ec = NOT_SUPPORTED_ERR; 823 return 0; 824 case ATTRIBUTE_NODE: { 825 Attr* attr = static_cast<Attr*>(source.get()); 826 if (attr->ownerElement()) 827 attr->ownerElement()->removeAttributeNode(attr, ec); 828 attr->setSpecified(true); 829 break; 830 } 831 default: 832 if (source->hasTagName(iframeTag)) 833 static_cast<HTMLIFrameElement*>(source.get())->setRemainsAliveOnRemovalFromTree(attached()); 834 835 if (source->parentNode()) 836 source->parentNode()->removeChild(source.get(), ec); 837 } 838 839 for (Node* node = source.get(); node; node = node->traverseNextNode(source.get())) 840 node->setDocument(this); 841 842 return source; 843 } 844 845 bool Document::hasPrefixNamespaceMismatch(const QualifiedName& qName) 846 { 847 // These checks are from DOM Core Level 2, createElementNS 848 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS 849 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div") 850 return true; 851 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang") 852 return true; 853 854 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core: 855 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS 856 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar") 857 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)) 858 return true; 859 860 return false; 861 } 862 863 // FIXME: This should really be in a possible ElementFactory class 864 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser) 865 { 866 RefPtr<Element> e; 867 868 // FIXME: Use registered namespaces and look up in a hash to find the right factory. 869 if (qName.namespaceURI() == xhtmlNamespaceURI) 870 e = HTMLElementFactory::createHTMLElement(qName, this, 0, createdByParser); 871 #if ENABLE(SVG) 872 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI) 873 e = SVGElementFactory::createSVGElement(qName, this, createdByParser); 874 #endif 875 #if ENABLE(WML) 876 else if (qName.namespaceURI() == WMLNames::wmlNamespaceURI) 877 e = WMLElementFactory::createWMLElement(qName, this, createdByParser); 878 else if (isWMLDocument()) 879 e = WMLElementFactory::createWMLElement(QualifiedName(nullAtom, qName.localName(), WMLNames::wmlNamespaceURI), this, createdByParser); 880 #endif 881 #if ENABLE(MATHML) 882 else if (qName.namespaceURI() == MathMLNames::mathmlNamespaceURI) 883 e = MathMLElementFactory::createMathMLElement(qName, this, createdByParser); 884 #endif 885 886 if (!e) 887 e = Element::create(qName, document()); 888 889 // <image> uses imgTag so we need a special rule. 890 #if ENABLE(WML) 891 if (!isWMLDocument()) 892 #endif 893 ASSERT((qName.matches(imageTag) && e->tagQName().matches(imgTag) && e->tagQName().prefix() == qName.prefix()) || qName == e->tagQName()); 894 895 return e.release(); 896 } 897 898 PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec) 899 { 900 String prefix, localName; 901 if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) 902 return 0; 903 904 QualifiedName qName(prefix, localName, namespaceURI); 905 if (hasPrefixNamespaceMismatch(qName)) { 906 ec = NAMESPACE_ERR; 907 return 0; 908 } 909 910 return createElement(qName, false); 911 } 912 913 Element* Document::getElementById(const AtomicString& elementId) const 914 { 915 if (elementId.isEmpty()) 916 return 0; 917 918 m_elementsById.checkConsistency(); 919 920 Element* element = m_elementsById.get(elementId.impl()); 921 if (element) 922 return element; 923 924 if (m_duplicateIds.contains(elementId.impl())) { 925 // We know there's at least one node with this id, but we don't know what the first one is. 926 for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) { 927 if (n->isElementNode()) { 928 element = static_cast<Element*>(n); 929 if (element->hasID() && element->getAttribute(element->idAttributeName()) == elementId) { 930 m_duplicateIds.remove(elementId.impl()); 931 m_elementsById.set(elementId.impl(), element); 932 return element; 933 } 934 } 935 } 936 ASSERT_NOT_REACHED(); 937 } 938 return 0; 939 } 940 941 String Document::readyState() const 942 { 943 if (Frame* f = frame()) { 944 if (f->loader()->isComplete()) 945 return "complete"; 946 if (parsing()) 947 return "loading"; 948 return "loaded"; 949 // FIXME: What does "interactive" mean? 950 // FIXME: Missing support for "uninitialized". 951 } 952 return String(); 953 } 954 955 String Document::encoding() const 956 { 957 if (TextResourceDecoder* d = decoder()) 958 return d->encoding().domName(); 959 return String(); 960 } 961 962 String Document::defaultCharset() const 963 { 964 if (Settings* settings = this->settings()) 965 return settings->defaultTextEncodingName(); 966 return String(); 967 } 968 969 void Document::setCharset(const String& charset) 970 { 971 if (!decoder()) 972 return; 973 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding); 974 } 975 976 void Document::setXMLVersion(const String& version, ExceptionCode& ec) 977 { 978 if (!implementation()->hasFeature("XML", String())) { 979 ec = NOT_SUPPORTED_ERR; 980 return; 981 } 982 983 // FIXME: Also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document. 984 985 m_xmlVersion = version; 986 } 987 988 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec) 989 { 990 if (!implementation()->hasFeature("XML", String())) { 991 ec = NOT_SUPPORTED_ERR; 992 return; 993 } 994 995 m_xmlStandalone = standalone; 996 } 997 998 void Document::setDocumentURI(const String& uri) 999 { 1000 m_documentURI = uri; 1001 updateBaseURL(); 1002 } 1003 1004 KURL Document::baseURI() const 1005 { 1006 return m_baseURL; 1007 } 1008 1009 Element* Document::elementFromPoint(int x, int y) const 1010 { 1011 // FIXME: Share code between this and caretRangeFromPoint. 1012 if (!renderer()) 1013 return 0; 1014 Frame* frame = this->frame(); 1015 if (!frame) 1016 return 0; 1017 FrameView* frameView = frame->view(); 1018 if (!frameView) 1019 return 0; 1020 1021 float zoomFactor = frame->pageZoomFactor(); 1022 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + view()->scrollX(), y * zoomFactor + view()->scrollY())); 1023 1024 if (!frameView->visibleContentRect().contains(point)) 1025 return 0; 1026 1027 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 1028 HitTestResult result(point); 1029 renderView()->layer()->hitTest(request, result); 1030 1031 Node* n = result.innerNode(); 1032 while (n && !n->isElementNode()) 1033 n = n->parentNode(); 1034 if (n) 1035 n = n->shadowAncestorNode(); 1036 return static_cast<Element*>(n); 1037 } 1038 1039 PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) 1040 { 1041 // FIXME: Share code between this and elementFromPoint. 1042 if (!renderer()) 1043 return 0; 1044 Frame* frame = this->frame(); 1045 if (!frame) 1046 return 0; 1047 FrameView* frameView = frame->view(); 1048 if (!frameView) 1049 return 0; 1050 1051 float zoomFactor = frame->pageZoomFactor(); 1052 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + view()->scrollX(), y * zoomFactor + view()->scrollY())); 1053 1054 if (!frameView->visibleContentRect().contains(point)) 1055 return 0; 1056 1057 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 1058 HitTestResult result(point); 1059 renderView()->layer()->hitTest(request, result); 1060 1061 Node* node = result.innerNode(); 1062 if (!node) 1063 return 0; 1064 1065 Node* shadowAncestorNode = node->shadowAncestorNode(); 1066 if (shadowAncestorNode != node) { 1067 unsigned offset = shadowAncestorNode->nodeIndex(); 1068 Node* container = shadowAncestorNode->parentNode(); 1069 return Range::create(this, container, offset, container, offset); 1070 } 1071 1072 RenderObject* renderer = node->renderer(); 1073 if (!renderer) 1074 return 0; 1075 VisiblePosition visiblePosition = renderer->positionForPoint(result.localPoint()); 1076 if (visiblePosition.isNull()) 1077 return 0; 1078 1079 Position rangeCompliantPosition = rangeCompliantEquivalent(visiblePosition); 1080 return Range::create(this, rangeCompliantPosition, rangeCompliantPosition); 1081 } 1082 1083 void Document::addElementById(const AtomicString& elementId, Element* element) 1084 { 1085 typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator; 1086 if (!m_duplicateIds.contains(elementId.impl())) { 1087 // Fast path. The ID is not already in m_duplicateIds, so we assume that it's 1088 // also not already in m_elementsById and do an add. If that add succeeds, we're done. 1089 pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), element); 1090 if (addResult.second) 1091 return; 1092 // The add failed, so this ID was already cached in m_elementsById. 1093 // There are multiple elements with this ID. Remove the m_elementsById 1094 // cache for this ID so getElementById searches for it next time it is called. 1095 m_elementsById.remove(addResult.first); 1096 m_duplicateIds.add(elementId.impl()); 1097 } else { 1098 // There are multiple elements with this ID. If it exists, remove the m_elementsById 1099 // cache for this ID so getElementById searches for it next time it is called. 1100 iterator cachedItem = m_elementsById.find(elementId.impl()); 1101 if (cachedItem != m_elementsById.end()) { 1102 m_elementsById.remove(cachedItem); 1103 m_duplicateIds.add(elementId.impl()); 1104 } 1105 } 1106 m_duplicateIds.add(elementId.impl()); 1107 } 1108 1109 void Document::removeElementById(const AtomicString& elementId, Element* element) 1110 { 1111 m_elementsById.checkConsistency(); 1112 1113 if (m_elementsById.get(elementId.impl()) == element) 1114 m_elementsById.remove(elementId.impl()); 1115 else { 1116 ASSERT(m_inRemovedLastRefFunction || m_duplicateIds.contains(elementId.impl())); 1117 m_duplicateIds.remove(elementId.impl()); 1118 } 1119 } 1120 1121 Element* Document::getElementByAccessKey(const String& key) const 1122 { 1123 if (key.isEmpty()) 1124 return 0; 1125 if (!m_accessKeyMapValid) { 1126 for (Node* n = firstChild(); n; n = n->traverseNextNode()) { 1127 if (!n->isElementNode()) 1128 continue; 1129 Element* element = static_cast<Element*>(n); 1130 const AtomicString& accessKey = element->getAttribute(accesskeyAttr); 1131 if (!accessKey.isEmpty()) 1132 m_elementsByAccessKey.set(accessKey.impl(), element); 1133 } 1134 m_accessKeyMapValid = true; 1135 } 1136 return m_elementsByAccessKey.get(key.impl()); 1137 } 1138 1139 /* 1140 * Performs three operations: 1141 * 1. Convert control characters to spaces 1142 * 2. Trim leading and trailing spaces 1143 * 3. Collapse internal whitespace. 1144 */ 1145 static inline String canonicalizedTitle(Document* document, const String& title) 1146 { 1147 const UChar* characters = title.characters(); 1148 unsigned length = title.length(); 1149 unsigned i; 1150 1151 StringBuffer buffer(length); 1152 unsigned builderIndex = 0; 1153 1154 // Skip leading spaces and leading characters that would convert to spaces 1155 for (i = 0; i < length; ++i) { 1156 UChar c = characters[i]; 1157 if (!(c <= 0x20 || c == 0x7F)) 1158 break; 1159 } 1160 1161 if (i == length) 1162 return ""; 1163 1164 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace. 1165 bool previousCharWasWS = false; 1166 for (; i < length; ++i) { 1167 UChar c = characters[i]; 1168 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) { 1169 if (previousCharWasWS) 1170 continue; 1171 buffer[builderIndex++] = ' '; 1172 previousCharWasWS = true; 1173 } else { 1174 buffer[builderIndex++] = c; 1175 previousCharWasWS = false; 1176 } 1177 } 1178 1179 // Strip trailing spaces 1180 while (builderIndex > 0) { 1181 --builderIndex; 1182 if (buffer[builderIndex] != ' ') 1183 break; 1184 } 1185 1186 if (!builderIndex && buffer[builderIndex] == ' ') 1187 return ""; 1188 1189 buffer.shrink(builderIndex + 1); 1190 1191 // Replace the backslashes with currency symbols if the encoding requires it. 1192 document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length()); 1193 1194 return String::adopt(buffer); 1195 } 1196 1197 void Document::updateTitle() 1198 { 1199 m_title = canonicalizedTitle(this, m_rawTitle); 1200 if (Frame* f = frame()) 1201 f->loader()->setTitle(m_title); 1202 } 1203 1204 void Document::setTitle(const String& title, Element* titleElement) 1205 { 1206 if (!titleElement) { 1207 // Title set by JavaScript -- overrides any title elements. 1208 m_titleSetExplicitly = true; 1209 if (!isHTMLDocument()) 1210 m_titleElement = 0; 1211 else if (!m_titleElement) { 1212 if (HTMLElement* headElement = head()) { 1213 m_titleElement = createElement(titleTag, false); 1214 ExceptionCode ec = 0; 1215 headElement->appendChild(m_titleElement, ec); 1216 ASSERT(!ec); 1217 } 1218 } 1219 } else if (titleElement != m_titleElement) { 1220 if (m_titleElement || m_titleSetExplicitly) 1221 // Only allow the first title element to change the title -- others have no effect. 1222 return; 1223 m_titleElement = titleElement; 1224 } 1225 1226 if (m_rawTitle == title) 1227 return; 1228 1229 m_rawTitle = title; 1230 updateTitle(); 1231 1232 if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag)) 1233 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title); 1234 } 1235 1236 void Document::removeTitle(Element* titleElement) 1237 { 1238 if (m_titleElement != titleElement) 1239 return; 1240 1241 m_titleElement = 0; 1242 m_titleSetExplicitly = false; 1243 1244 // Update title based on first title element in the head, if one exists. 1245 if (HTMLElement* headElement = head()) { 1246 for (Node* e = headElement->firstChild(); e; e = e->nextSibling()) 1247 if (e->hasTagName(titleTag)) { 1248 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e); 1249 setTitle(titleElement->text(), titleElement); 1250 break; 1251 } 1252 } 1253 1254 if (!m_titleElement && !m_rawTitle.isEmpty()) { 1255 m_rawTitle = ""; 1256 updateTitle(); 1257 } 1258 } 1259 1260 String Document::nodeName() const 1261 { 1262 return "#document"; 1263 } 1264 1265 Node::NodeType Document::nodeType() const 1266 { 1267 return DOCUMENT_NODE; 1268 } 1269 1270 FrameView* Document::view() const 1271 { 1272 return m_frame ? m_frame->view() : 0; 1273 } 1274 1275 Page* Document::page() const 1276 { 1277 return m_frame ? m_frame->page() : 0; 1278 } 1279 1280 Settings* Document::settings() const 1281 { 1282 return m_frame ? m_frame->settings() : 0; 1283 } 1284 1285 PassRefPtr<Range> Document::createRange() 1286 { 1287 return Range::create(this); 1288 } 1289 1290 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, 1291 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) 1292 { 1293 if (!root) { 1294 ec = NOT_SUPPORTED_ERR; 1295 return 0; 1296 } 1297 return NodeIterator::create(root, whatToShow, filter, expandEntityReferences); 1298 } 1299 1300 PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow, 1301 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) 1302 { 1303 if (!root) { 1304 ec = NOT_SUPPORTED_ERR; 1305 return 0; 1306 } 1307 return TreeWalker::create(root, whatToShow, filter, expandEntityReferences); 1308 } 1309 1310 void Document::scheduleStyleRecalc() 1311 { 1312 if (m_styleRecalcTimer.isActive() || inPageCache()) 1313 return; 1314 1315 ASSERT(childNeedsStyleRecalc()); 1316 1317 if (!documentsThatNeedStyleRecalc) 1318 documentsThatNeedStyleRecalc = new HashSet<Document*>; 1319 documentsThatNeedStyleRecalc->add(this); 1320 1321 // FIXME: Why on earth is this here? This is clearly misplaced. 1322 if (m_accessKeyMapValid) { 1323 m_accessKeyMapValid = false; 1324 m_elementsByAccessKey.clear(); 1325 } 1326 1327 m_styleRecalcTimer.startOneShot(0); 1328 } 1329 1330 void Document::unscheduleStyleRecalc() 1331 { 1332 ASSERT(!childNeedsStyleRecalc()); 1333 1334 if (documentsThatNeedStyleRecalc) 1335 documentsThatNeedStyleRecalc->remove(this); 1336 1337 m_styleRecalcTimer.stop(); 1338 } 1339 1340 void Document::styleRecalcTimerFired(Timer<Document>*) 1341 { 1342 updateStyleIfNeeded(); 1343 } 1344 1345 bool Document::childNeedsAndNotInStyleRecalc() 1346 { 1347 return childNeedsStyleRecalc() && !m_inStyleRecalc; 1348 } 1349 1350 void Document::recalcStyle(StyleChange change) 1351 { 1352 // we should not enter style recalc while painting 1353 if (view() && view()->isPainting()) { 1354 ASSERT(!view()->isPainting()); 1355 return; 1356 } 1357 1358 if (m_inStyleRecalc) 1359 return; // Guard against re-entrancy. -dwh 1360 1361 #if ENABLE(INSPECTOR) 1362 if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) 1363 timelineAgent->willRecalculateStyle(); 1364 #endif 1365 1366 m_inStyleRecalc = true; 1367 suspendPostAttachCallbacks(); 1368 RenderWidget::suspendWidgetHierarchyUpdates(); 1369 if (view()) 1370 view()->pauseScheduledEvents(); 1371 1372 #ifdef ANDROID_INSTRUMENT 1373 android::TimeCounter::start(android::TimeCounter::CalculateStyleTimeCounter); 1374 #endif 1375 1376 ASSERT(!renderer() || renderArena()); 1377 if (!renderer() || !renderArena()) 1378 goto bail_out; 1379 1380 if (change == Force) { 1381 // style selector may set this again during recalc 1382 m_hasNodesWithPlaceholderStyle = false; 1383 1384 RefPtr<RenderStyle> documentStyle = CSSStyleSelector::styleForDocument(this); 1385 StyleChange ch = diff(documentStyle.get(), renderer()->style()); 1386 if (renderer() && ch != NoChange) 1387 renderer()->setStyle(documentStyle.release()); 1388 } 1389 1390 for (Node* n = firstChild(); n; n = n->nextSibling()) 1391 if (change >= Inherit || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) 1392 n->recalcStyle(change); 1393 1394 #ifdef ANDROID_INSTRUMENT 1395 android::TimeCounter::record(android::TimeCounter::CalculateStyleTimeCounter, __FUNCTION__); 1396 #endif 1397 1398 #if USE(ACCELERATED_COMPOSITING) 1399 if (view()) { 1400 bool layoutPending = view()->layoutPending() || renderer()->needsLayout(); 1401 // If we didn't update compositing layers because of layout(), we need to do so here. 1402 if (!layoutPending) 1403 view()->updateCompositingLayers(); 1404 } 1405 #endif 1406 1407 bail_out: 1408 setNeedsStyleRecalc(NoStyleChange); 1409 setChildNeedsStyleRecalc(false); 1410 unscheduleStyleRecalc(); 1411 1412 if (view()) 1413 view()->resumeScheduledEvents(); 1414 RenderWidget::resumeWidgetHierarchyUpdates(); 1415 resumePostAttachCallbacks(); 1416 m_inStyleRecalc = false; 1417 1418 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished. 1419 if (m_closeAfterStyleRecalc) { 1420 m_closeAfterStyleRecalc = false; 1421 implicitClose(); 1422 } 1423 1424 #if ENABLE(INSPECTOR) 1425 if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) 1426 timelineAgent->didRecalculateStyle(); 1427 #endif 1428 } 1429 1430 void Document::updateStyleIfNeeded() 1431 { 1432 if (!childNeedsStyleRecalc() || inPageCache()) 1433 return; 1434 1435 if (m_frame) 1436 m_frame->animation()->beginAnimationUpdate(); 1437 1438 recalcStyle(NoChange); 1439 1440 // Tell the animation controller that updateStyleIfNeeded is finished and it can do any post-processing 1441 if (m_frame) 1442 m_frame->animation()->endAnimationUpdate(); 1443 } 1444 1445 void Document::updateStyleForAllDocuments() 1446 { 1447 if (!documentsThatNeedStyleRecalc) 1448 return; 1449 1450 while (documentsThatNeedStyleRecalc->size()) { 1451 HashSet<Document*>::iterator it = documentsThatNeedStyleRecalc->begin(); 1452 Document* doc = *it; 1453 documentsThatNeedStyleRecalc->remove(doc); 1454 ASSERT(doc->childNeedsStyleRecalc() && !doc->inPageCache()); 1455 doc->updateStyleIfNeeded(); 1456 } 1457 } 1458 1459 void Document::updateLayout() 1460 { 1461 if (Element* oe = ownerElement()) 1462 oe->document()->updateLayout(); 1463 1464 updateStyleIfNeeded(); 1465 1466 // Only do a layout if changes have occurred that make it necessary. 1467 FrameView* v = view(); 1468 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout())) 1469 v->layout(); 1470 } 1471 1472 // FIXME: This is a bad idea and needs to be removed eventually. 1473 // Other browsers load stylesheets before they continue parsing the web page. 1474 // Since we don't, we can run JavaScript code that needs answers before the 1475 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets 1476 // lets us get reasonable answers. The long term solution to this problem is 1477 // to instead suspend JavaScript execution. 1478 void Document::updateLayoutIgnorePendingStylesheets() 1479 { 1480 bool oldIgnore = m_ignorePendingStylesheets; 1481 1482 if (!haveStylesheetsLoaded()) { 1483 m_ignorePendingStylesheets = true; 1484 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be 1485 // dangerous to try to stop it a second time, after page content has already been loaded and displayed 1486 // with accurate style information. (Our suppression involves blanking the whole page at the 1487 // moment. If it were more refined, we might be able to do something better.) 1488 // It's worth noting though that this entire method is a hack, since what we really want to do is 1489 // suspend JS instead of doing a layout with inaccurate information. 1490 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { 1491 m_pendingSheetLayout = DidLayoutWithPendingSheets; 1492 updateStyleSelector(); 1493 } else if (m_hasNodesWithPlaceholderStyle) 1494 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes 1495 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive 1496 // but here we need up-to-date style immediately. 1497 recalcStyle(Force); 1498 } 1499 1500 updateLayout(); 1501 1502 m_ignorePendingStylesheets = oldIgnore; 1503 } 1504 1505 void Document::createStyleSelector() 1506 { 1507 bool matchAuthorAndUserStyles = true; 1508 if (Settings* docSettings = settings()) 1509 matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled(); 1510 m_styleSelector.set(new CSSStyleSelector(this, m_styleSheets.get(), m_mappedElementSheet.get(), pageUserSheet(), pageGroupUserSheets(), 1511 !inCompatMode(), matchAuthorAndUserStyles)); 1512 } 1513 1514 void Document::attach() 1515 { 1516 ASSERT(!attached()); 1517 ASSERT(!m_inPageCache); 1518 #if !PLATFORM(ANDROID) 1519 ASSERT(!m_axObjectCache); 1520 #endif 1521 1522 if (!m_renderArena) 1523 m_renderArena = new RenderArena(); 1524 1525 // Create the rendering tree 1526 setRenderer(new (m_renderArena.get()) RenderView(this, view())); 1527 #if USE(ACCELERATED_COMPOSITING) 1528 renderView()->didMoveOnscreen(); 1529 #endif 1530 1531 recalcStyle(Force); 1532 1533 RenderObject* render = renderer(); 1534 setRenderer(0); 1535 1536 ContainerNode::attach(); 1537 1538 setRenderer(render); 1539 } 1540 1541 void Document::detach() 1542 { 1543 ASSERT(attached()); 1544 ASSERT(!m_inPageCache); 1545 1546 clearAXObjectCache(); 1547 stopActiveDOMObjects(); 1548 1549 RenderObject* render = renderer(); 1550 1551 // Send out documentWillBecomeInactive() notifications to registered elements, 1552 // in order to stop media elements 1553 documentWillBecomeInactive(); 1554 1555 #if ENABLE(SHARED_WORKERS) 1556 SharedWorkerRepository::documentDetached(this); 1557 #endif 1558 1559 if (m_frame) { 1560 FrameView* view = m_frame->view(); 1561 if (view) 1562 view->detachCustomScrollbars(); 1563 } 1564 1565 // indicate destruction mode, i.e. attached() but renderer == 0 1566 setRenderer(0); 1567 1568 m_hoverNode = 0; 1569 m_focusedNode = 0; 1570 m_activeNode = 0; 1571 1572 ContainerNode::detach(); 1573 1574 unscheduleStyleRecalc(); 1575 1576 if (render) 1577 render->destroy(); 1578 1579 // This is required, as our Frame might delete itself as soon as it detaches 1580 // us. However, this violates Node::detach() semantics, as it's never 1581 // possible to re-attach. Eventually Document::detach() should be renamed, 1582 // or this setting of the frame to 0 could be made explicit in each of the 1583 // callers of Document::detach(). 1584 m_frame = 0; 1585 m_renderArena.clear(); 1586 } 1587 1588 void Document::removeAllEventListeners() 1589 { 1590 #if ENABLE(TOUCH_EVENTS) 1591 Page* ownerPage = page(); 1592 if (!m_inPageCache && ownerPage && (m_frame == ownerPage->mainFrame()) && hasListenerType(Document::TOUCH_LISTENER)) { 1593 // Inform the Chrome Client that it no longer needs to forward touch 1594 // events to WebCore as the document removes all the event listeners. 1595 ownerPage->chrome()->client()->needTouchEvents(false); 1596 } 1597 #endif 1598 1599 EventTarget::removeAllEventListeners(); 1600 1601 if (DOMWindow* domWindow = this->domWindow()) 1602 domWindow->removeAllEventListeners(); 1603 for (Node* node = firstChild(); node; node = node->traverseNextNode()) 1604 node->removeAllEventListeners(); 1605 } 1606 1607 RenderView* Document::renderView() const 1608 { 1609 return toRenderView(renderer()); 1610 } 1611 1612 void Document::clearAXObjectCache() 1613 { 1614 #if PLATFORM(ANDROID) 1615 return; 1616 #else 1617 // clear cache in top document 1618 if (m_axObjectCache) { 1619 delete m_axObjectCache; 1620 m_axObjectCache = 0; 1621 return; 1622 } 1623 1624 // ask the top-level document to clear its cache 1625 Document* doc = topDocument(); 1626 if (doc != this) 1627 doc->clearAXObjectCache(); 1628 #endif 1629 } 1630 1631 AXObjectCache* Document::axObjectCache() const 1632 { 1633 #if PLATFORM(ANDROID) 1634 return 0; 1635 #else 1636 // The only document that actually has a AXObjectCache is the top-level 1637 // document. This is because we need to be able to get from any WebCoreAXObject 1638 // to any other WebCoreAXObject on the same page. Using a single cache allows 1639 // lookups across nested webareas (i.e. multiple documents). 1640 1641 if (m_axObjectCache) { 1642 // return already known top-level cache 1643 if (!ownerElement()) 1644 return m_axObjectCache; 1645 1646 // In some pages with frames, the cache is created before the sub-webarea is 1647 // inserted into the tree. Here, we catch that case and just toss the old 1648 // cache and start over. 1649 // NOTE: This recovery may no longer be needed. I have been unable to trigger 1650 // it again. See rdar://5794454 1651 // FIXME: Can this be fixed when inserting the subframe instead of now? 1652 // FIXME: If this function was called to get the cache in order to remove 1653 // an AXObject, we are now deleting the cache as a whole and returning a 1654 // new empty cache that does not contain the AXObject! That should actually 1655 // be OK. I am concerned about other cases like this where accessing the 1656 // cache blows away the AXObject being operated on. 1657 delete m_axObjectCache; 1658 m_axObjectCache = 0; 1659 } 1660 1661 // ask the top-level document for its cache 1662 Document* doc = topDocument(); 1663 if (doc != this) 1664 return doc->axObjectCache(); 1665 1666 // this is the top-level document, so install a new cache 1667 m_axObjectCache = new AXObjectCache; 1668 return m_axObjectCache; 1669 #endif // ANDROID 1670 } 1671 1672 void Document::setVisuallyOrdered() 1673 { 1674 m_visuallyOrdered = true; 1675 if (renderer()) 1676 renderer()->style()->setVisuallyOrdered(true); 1677 } 1678 1679 Tokenizer* Document::createTokenizer() 1680 { 1681 // FIXME: this should probably pass the frame instead 1682 return new XMLTokenizer(this, view()); 1683 } 1684 1685 void Document::open(Document* ownerDocument) 1686 { 1687 if (ownerDocument) { 1688 setURL(ownerDocument->url()); 1689 m_cookieURL = ownerDocument->cookieURL(); 1690 ScriptExecutionContext::setSecurityOrigin(ownerDocument->securityOrigin()); 1691 } 1692 1693 if (m_frame) { 1694 if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript())) 1695 return; 1696 1697 if (m_frame->loader()->state() == FrameStateProvisional) 1698 m_frame->loader()->stopAllLoaders(); 1699 } 1700 1701 implicitOpen(); 1702 1703 if (DOMWindow* domWindow = this->domWindow()) 1704 domWindow->removeAllEventListeners(); 1705 1706 if (m_frame) 1707 m_frame->loader()->didExplicitOpen(); 1708 } 1709 1710 void Document::cancelParsing() 1711 { 1712 if (m_tokenizer) { 1713 // We have to clear the tokenizer to avoid possibly triggering 1714 // the onload handler when closing as a side effect of a cancel-style 1715 // change, such as opening a new document or closing the window while 1716 // still parsing 1717 m_tokenizer.clear(); 1718 close(); 1719 } 1720 } 1721 1722 void Document::implicitOpen() 1723 { 1724 cancelParsing(); 1725 1726 m_tokenizer.clear(); 1727 1728 removeChildren(); 1729 1730 m_tokenizer = createTokenizer(); 1731 setParsing(true); 1732 1733 if (m_frame) 1734 m_tokenizer->setXSSAuditor(m_frame->script()->xssAuditor()); 1735 1736 // If we reload, the animation controller sticks around and has 1737 // a stale animation time. We need to update it here. 1738 if (m_frame && m_frame->animation()) 1739 m_frame->animation()->beginAnimationUpdate(); 1740 } 1741 1742 HTMLElement* Document::body() const 1743 { 1744 Node* de = documentElement(); 1745 if (!de) 1746 return 0; 1747 1748 // try to prefer a FRAMESET element over BODY 1749 Node* body = 0; 1750 for (Node* i = de->firstChild(); i; i = i->nextSibling()) { 1751 if (i->hasTagName(framesetTag)) 1752 return static_cast<HTMLElement*>(i); 1753 1754 if (i->hasTagName(bodyTag) && !body) 1755 body = i; 1756 } 1757 return static_cast<HTMLElement*>(body); 1758 } 1759 1760 void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec) 1761 { 1762 if (!newBody || !documentElement()) { 1763 ec = HIERARCHY_REQUEST_ERR; 1764 return; 1765 } 1766 1767 HTMLElement* b = body(); 1768 if (!b) 1769 documentElement()->appendChild(newBody, ec); 1770 else 1771 documentElement()->replaceChild(newBody, b, ec); 1772 } 1773 1774 HTMLHeadElement* Document::head() 1775 { 1776 Node* de = documentElement(); 1777 if (!de) 1778 return 0; 1779 1780 for (Node* e = de->firstChild(); e; e = e->nextSibling()) 1781 if (e->hasTagName(headTag)) 1782 return static_cast<HTMLHeadElement*>(e); 1783 1784 return 0; 1785 } 1786 1787 void Document::close() 1788 { 1789 Frame* frame = this->frame(); 1790 if (frame) { 1791 // This code calls implicitClose() if all loading has completed. 1792 FrameLoader* frameLoader = frame->loader(); 1793 frameLoader->endIfNotLoadingMainResource(); 1794 frameLoader->checkCompleted(); 1795 } else { 1796 // Because we have no frame, we don't know if all loading has completed, 1797 // so we just call implicitClose() immediately. FIXME: This might fire 1798 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>. 1799 implicitClose(); 1800 } 1801 } 1802 1803 void Document::implicitClose() 1804 { 1805 // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached. 1806 if (m_inStyleRecalc) { 1807 m_closeAfterStyleRecalc = true; 1808 return; 1809 } 1810 1811 bool wasLocationChangePending = frame() && frame()->redirectScheduler()->locationChangePending(); 1812 bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending; 1813 1814 if (!doload) 1815 return; 1816 1817 m_processingLoadEvent = true; 1818 1819 m_wellFormed = m_tokenizer && m_tokenizer->wellFormed(); 1820 1821 // We have to clear the tokenizer, in case someone document.write()s from the 1822 // onLoad event handler, as in Radar 3206524. 1823 m_tokenizer.clear(); 1824 1825 // Parser should have picked up all preloads by now 1826 m_docLoader->clearPreloads(); 1827 1828 // Create a head and a body if we don't have those yet (e.g. for about:blank). 1829 if (!this->body() && isHTMLDocument()) { 1830 if (Node* documentElement = this->documentElement()) { 1831 ExceptionCode ec = 0; 1832 1833 // The implicit <head> isn't expected in older versions of Mail - <rdar://problem/6863795> 1834 if (!head() && shouldCreateImplicitHead(this)) { 1835 documentElement->appendChild(new HTMLHeadElement(headTag, this), ec); 1836 ASSERT(!ec); 1837 } 1838 documentElement->appendChild(new HTMLBodyElement(bodyTag, this), ec); 1839 ASSERT(!ec); 1840 } 1841 } 1842 1843 // FIXME: We kick off the icon loader when the Document is done parsing. 1844 // There are earlier opportunities we could start it: 1845 // -When the <head> finishes parsing 1846 // -When any new HTMLLinkElement is inserted into the document 1847 // But those add a dynamic component to the favicon that has UI 1848 // ramifications, and we need to decide what is the Right Thing To Do(tm) 1849 Frame* f = frame(); 1850 if (f) 1851 f->loader()->startIconLoader(); 1852 1853 // Resume the animations (or start them) 1854 if (f) 1855 f->animation()->resumeAnimations(this); 1856 1857 ImageLoader::dispatchPendingBeforeLoadEvents(); 1858 ImageLoader::dispatchPendingLoadEvents(); 1859 dispatchWindowLoadEvent(); 1860 dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, false), this); 1861 if (m_pendingStateObject) 1862 dispatchWindowEvent(PopStateEvent::create(m_pendingStateObject.release())); 1863 1864 if (f) 1865 f->loader()->handledOnloadEvents(); 1866 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 1867 if (!ownerElement()) 1868 printf("onload fired at %d\n", elapsedTime()); 1869 #endif 1870 1871 m_processingLoadEvent = false; 1872 1873 // An event handler may have removed the frame 1874 if (!frame()) 1875 return; 1876 1877 // Make sure both the initial layout and reflow happen after the onload 1878 // fires. This will improve onload scores, and other browsers do it. 1879 // If they wanna cheat, we can too. -dwh 1880 1881 if (frame()->redirectScheduler()->locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) { 1882 // Just bail out. Before or during the onload we were shifted to another page. 1883 // The old i-Bench suite does this. When this happens don't bother painting or laying out. 1884 view()->unscheduleRelayout(); 1885 return; 1886 } 1887 1888 frame()->loader()->checkCallImplicitClose(); 1889 RenderObject* renderObject = renderer(); 1890 1891 // We used to force a synchronous display and flush here. This really isn't 1892 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps 1893 // (if your platform is syncing flushes and limiting them to 60fps). 1894 m_overMinimumLayoutThreshold = true; 1895 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) { 1896 updateStyleIfNeeded(); 1897 1898 // Always do a layout after loading if needed. 1899 if (view() && renderObject && (!renderObject->firstChild() || renderObject->needsLayout())) 1900 view()->layout(); 1901 } 1902 1903 #if PLATFORM(MAC) 1904 if (f && renderObject && this == topDocument() && AXObjectCache::accessibilityEnabled()) { 1905 // The AX cache may have been cleared at this point, but we need to make sure it contains an 1906 // AX object to send the notification to. getOrCreate will make sure that an valid AX object 1907 // exists in the cache (we ignore the return value because we don't need it here). This is 1908 // only safe to call when a layout is not in progress, so it can not be used in postNotification. 1909 axObjectCache()->getOrCreate(renderObject); 1910 axObjectCache()->postNotification(renderObject, AXObjectCache::AXLoadComplete, true); 1911 } 1912 #endif 1913 1914 #if ENABLE(SVG) 1915 // FIXME: Officially, time 0 is when the outermost <svg> receives its 1916 // SVGLoad event, but we don't implement those yet. This is close enough 1917 // for now. In some cases we should have fired earlier. 1918 if (svgExtensions()) 1919 accessSVGExtensions()->startAnimations(); 1920 #endif 1921 } 1922 1923 void Document::setParsing(bool b) 1924 { 1925 m_bParsing = b; 1926 if (!m_bParsing && view()) 1927 view()->scheduleRelayout(); 1928 1929 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 1930 if (!ownerElement() && !m_bParsing) 1931 printf("Parsing finished at %d\n", elapsedTime()); 1932 #endif 1933 } 1934 1935 bool Document::shouldScheduleLayout() 1936 { 1937 // This function will only be called when FrameView thinks a layout is needed. 1938 // This enforces a couple extra rules. 1939 // 1940 // (a) Only schedule a layout once the stylesheets are loaded. 1941 // (b) Only schedule layout once we have a body element. 1942 1943 return (haveStylesheetsLoaded() && body()) || 1944 (documentElement() && !documentElement()->hasTagName(htmlTag)); 1945 } 1946 1947 int Document::minimumLayoutDelay() 1948 { 1949 if (m_overMinimumLayoutThreshold) 1950 return m_extraLayoutDelay; 1951 1952 int elapsed = elapsedTime(); 1953 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold; 1954 1955 // We'll want to schedule the timer to fire at the minimum layout threshold. 1956 return max(0, cLayoutScheduleThreshold - elapsed) + m_extraLayoutDelay; 1957 } 1958 1959 int Document::elapsedTime() const 1960 { 1961 return static_cast<int>((currentTime() - m_startTime) * 1000); 1962 } 1963 1964 void Document::write(const SegmentedString& text, Document* ownerDocument) 1965 { 1966 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 1967 if (!ownerElement()) 1968 printf("Beginning a document.write at %d\n", elapsedTime()); 1969 #endif 1970 1971 if (!m_tokenizer) 1972 open(ownerDocument); 1973 1974 ASSERT(m_tokenizer); 1975 m_tokenizer->write(text, false); 1976 1977 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 1978 if (!ownerElement()) 1979 printf("Ending a document.write at %d\n", elapsedTime()); 1980 #endif 1981 } 1982 1983 void Document::write(const String& text, Document* ownerDocument) 1984 { 1985 write(SegmentedString(text), ownerDocument); 1986 } 1987 1988 void Document::writeln(const String& text, Document* ownerDocument) 1989 { 1990 write(text, ownerDocument); 1991 write("\n", ownerDocument); 1992 } 1993 1994 void Document::finishParsing() 1995 { 1996 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 1997 if (!ownerElement()) 1998 printf("Received all data at %d\n", elapsedTime()); 1999 #endif 2000 2001 // Let the tokenizer go through as much data as it can. There will be three possible outcomes after 2002 // finish() is called: 2003 // (1) All remaining data is parsed, document isn't loaded yet 2004 // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted 2005 // (3) Data is still remaining to be parsed. 2006 if (m_tokenizer) 2007 m_tokenizer->finish(); 2008 } 2009 2010 const KURL& Document::virtualURL() const 2011 { 2012 return m_url; 2013 } 2014 2015 KURL Document::virtualCompleteURL(const String& url) const 2016 { 2017 return completeURL(url); 2018 } 2019 2020 void Document::setURL(const KURL& url) 2021 { 2022 const KURL& newURL = url.isEmpty() ? blankURL() : url; 2023 if (newURL == m_url) 2024 return; 2025 2026 m_url = newURL; 2027 m_documentURI = m_url.string(); 2028 updateBaseURL(); 2029 } 2030 2031 void Document::setBaseElementURL(const KURL& baseElementURL) 2032 { 2033 m_baseElementURL = baseElementURL; 2034 updateBaseURL(); 2035 } 2036 2037 void Document::updateBaseURL() 2038 { 2039 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using 2040 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute 2041 // from the Document interface otherwise. 2042 if (m_baseElementURL.isEmpty()) { 2043 // The documentURI attribute is an arbitrary string. DOM 3 Core does not specify how it should be resolved, 2044 // so we use a null base URL. 2045 m_baseURL = KURL(KURL(), documentURI()); 2046 } else 2047 m_baseURL = m_baseElementURL; 2048 if (!m_baseURL.isValid()) 2049 m_baseURL = KURL(); 2050 2051 if (m_elemSheet) 2052 m_elemSheet->setFinalURL(m_baseURL); 2053 if (m_mappedElementSheet) 2054 m_mappedElementSheet->setFinalURL(m_baseURL); 2055 } 2056 2057 String Document::userAgent(const KURL& url) const 2058 { 2059 return frame() ? frame()->loader()->userAgent(url) : String(); 2060 } 2061 2062 CSSStyleSheet* Document::pageUserSheet() 2063 { 2064 if (m_pageUserSheet) 2065 return m_pageUserSheet.get(); 2066 2067 Page* owningPage = page(); 2068 if (!owningPage) 2069 return 0; 2070 2071 String userSheetText = owningPage->userStyleSheet(); 2072 if (userSheetText.isEmpty()) 2073 return 0; 2074 2075 // Parse the sheet and cache it. 2076 m_pageUserSheet = CSSStyleSheet::createInline(this, settings()->userStyleSheetLocation()); 2077 m_pageUserSheet->setIsUserStyleSheet(true); 2078 m_pageUserSheet->parseString(userSheetText, !inCompatMode()); 2079 return m_pageUserSheet.get(); 2080 } 2081 2082 void Document::clearPageUserSheet() 2083 { 2084 m_pageUserSheet = 0; 2085 updateStyleSelector(); 2086 } 2087 2088 const Vector<RefPtr<CSSStyleSheet> >* Document::pageGroupUserSheets() const 2089 { 2090 if (m_pageGroupUserSheetCacheValid) 2091 return m_pageGroupUserSheets.get(); 2092 2093 m_pageGroupUserSheetCacheValid = true; 2094 2095 Page* owningPage = page(); 2096 if (!owningPage) 2097 return 0; 2098 2099 const PageGroup& pageGroup = owningPage->group(); 2100 const UserStyleSheetMap* sheetsMap = pageGroup.userStyleSheets(); 2101 if (!sheetsMap) 2102 return 0; 2103 2104 UserStyleSheetMap::const_iterator end = sheetsMap->end(); 2105 for (UserStyleSheetMap::const_iterator it = sheetsMap->begin(); it != end; ++it) { 2106 const UserStyleSheetVector* sheets = it->second; 2107 for (unsigned i = 0; i < sheets->size(); ++i) { 2108 const UserStyleSheet* sheet = sheets->at(i).get(); 2109 if (!UserContentURLPattern::matchesPatterns(url(), sheet->whitelist(), sheet->blacklist())) 2110 continue; 2111 RefPtr<CSSStyleSheet> parsedSheet = CSSStyleSheet::createInline(const_cast<Document*>(this), sheet->url()); 2112 parsedSheet->setIsUserStyleSheet(true); 2113 parsedSheet->parseString(sheet->source(), !inCompatMode()); 2114 if (!m_pageGroupUserSheets) 2115 m_pageGroupUserSheets.set(new Vector<RefPtr<CSSStyleSheet> >); 2116 m_pageGroupUserSheets->append(parsedSheet.release()); 2117 } 2118 } 2119 2120 return m_pageGroupUserSheets.get(); 2121 } 2122 2123 void Document::clearPageGroupUserSheets() 2124 { 2125 m_pageGroupUserSheets.clear(); 2126 m_pageGroupUserSheetCacheValid = false; 2127 updateStyleSelector(); 2128 } 2129 2130 CSSStyleSheet* Document::elementSheet() 2131 { 2132 if (!m_elemSheet) 2133 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL); 2134 return m_elemSheet.get(); 2135 } 2136 2137 CSSStyleSheet* Document::mappedElementSheet() 2138 { 2139 if (!m_mappedElementSheet) 2140 m_mappedElementSheet = CSSStyleSheet::createInline(this, m_baseURL); 2141 return m_mappedElementSheet.get(); 2142 } 2143 2144 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2145 { 2146 // Search is inclusive of start 2147 for (Node* n = start; n; n = n->traverseNextNode()) 2148 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) 2149 return n; 2150 2151 return 0; 2152 } 2153 2154 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2155 { 2156 // Search is inclusive of start 2157 for (Node* n = start; n; n = n->traversePreviousNode()) 2158 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) 2159 return n; 2160 2161 return 0; 2162 } 2163 2164 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2165 { 2166 // Search is inclusive of start 2167 int winningTabIndex = SHRT_MAX + 1; 2168 Node* winner = 0; 2169 for (Node* n = start; n; n = n->traverseNextNode()) 2170 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) { 2171 winner = n; 2172 winningTabIndex = n->tabIndex(); 2173 } 2174 2175 return winner; 2176 } 2177 2178 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2179 { 2180 // Search is inclusive of start 2181 int winningTabIndex = 0; 2182 Node* winner = 0; 2183 for (Node* n = start; n; n = n->traversePreviousNode()) 2184 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) { 2185 winner = n; 2186 winningTabIndex = n->tabIndex(); 2187 } 2188 2189 return winner; 2190 } 2191 2192 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event) 2193 { 2194 if (start) { 2195 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order 2196 if (start->tabIndex() < 0) { 2197 for (Node* n = start->traverseNextNode(); n; n = n->traverseNextNode()) 2198 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) 2199 return n; 2200 } 2201 2202 // First try to find a node with the same tabindex as start that comes after start in the document. 2203 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event)) 2204 return winner; 2205 2206 if (start->tabIndex() == 0) 2207 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. 2208 return 0; 2209 } 2210 2211 // Look for the first node in the document that: 2212 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and 2213 // 2) comes first in the document, if there's a tie. 2214 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event)) 2215 return winner; 2216 2217 // There are no nodes with a tabindex greater than start's tabindex, 2218 // so find the first node with a tabindex of 0. 2219 return nextNodeWithExactTabIndex(this, 0, event); 2220 } 2221 2222 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event) 2223 { 2224 Node* last; 2225 for (last = this; last->lastChild(); last = last->lastChild()) 2226 ; // Empty loop. 2227 2228 // First try to find the last node in the document that comes before start and has the same tabindex as start. 2229 // If start is null, find the last node in the document with a tabindex of 0. 2230 Node* startingNode; 2231 int startingTabIndex; 2232 if (start) { 2233 startingNode = start->traversePreviousNode(); 2234 startingTabIndex = start->tabIndex(); 2235 } else { 2236 startingNode = last; 2237 startingTabIndex = 0; 2238 } 2239 2240 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order 2241 if (startingTabIndex < 0) { 2242 for (Node* n = startingNode; n; n = n->traversePreviousNode()) 2243 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) 2244 return n; 2245 } 2246 2247 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event)) 2248 return winner; 2249 2250 // There are no nodes before start with the same tabindex as start, so look for a node that: 2251 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and 2252 // 2) comes last in the document, if there's a tie. 2253 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX; 2254 return previousNodeWithLowerTabIndex(last, startingTabIndex, event); 2255 } 2256 2257 int Document::nodeAbsIndex(Node *node) 2258 { 2259 ASSERT(node->document() == this); 2260 2261 int absIndex = 0; 2262 for (Node *n = node; n && n != this; n = n->traversePreviousNode()) 2263 absIndex++; 2264 return absIndex; 2265 } 2266 2267 Node *Document::nodeWithAbsIndex(int absIndex) 2268 { 2269 Node *n = this; 2270 for (int i = 0; n && (i < absIndex); i++) { 2271 n = n->traverseNextNode(); 2272 } 2273 return n; 2274 } 2275 2276 #ifdef ANDROID_META_SUPPORT 2277 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't. 2278 static bool isSeparator(::UChar c) 2279 { 2280 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == ';' || c == '\0'; 2281 } 2282 2283 void Document::processMetadataSettings(const String& content) 2284 { 2285 ASSERT(!content.isNull()); 2286 2287 int keyBegin, keyEnd, valueBegin, valueEnd; 2288 int i = 0; 2289 int length = content.length(); 2290 String buffer = content.lower(); 2291 while (i < length) { 2292 // skip to first non-separator, but don't skip past the end of the string 2293 while (isSeparator(buffer[i])) { 2294 if (i >= length) 2295 break; 2296 i++; 2297 } 2298 keyBegin = i; 2299 2300 // skip to first separator 2301 while (!isSeparator(buffer[i])) 2302 i++; 2303 keyEnd = i; 2304 2305 // skip to first '=', but don't skip past a ',', ';' or the end of the string 2306 while (buffer[i] != '=') { 2307 if (buffer[i] == ',' || buffer[i] == ';' || i >= length) 2308 break; 2309 i++; 2310 } 2311 2312 // skip to first non-separator, but don't skip past a ',', ';' or the end of the string 2313 while (isSeparator(buffer[i])) { 2314 if (buffer[i] == ',' || buffer[i] == ';' || i >= length) 2315 break; 2316 i++; 2317 } 2318 valueBegin = i; 2319 2320 // skip to first separator 2321 while (!isSeparator(buffer[i])) 2322 i++; 2323 valueEnd = i; 2324 2325 ASSERT(i <= length); 2326 2327 String key(buffer.substring(keyBegin, keyEnd - keyBegin)); 2328 String value(buffer.substring(valueBegin, valueEnd - valueBegin)); 2329 if (frame()) 2330 frame()->settings()->setMetadataSettings(key, value); 2331 } 2332 } 2333 #endif 2334 2335 void Document::processHttpEquiv(const String& equiv, const String& content) 2336 { 2337 ASSERT(!equiv.isNull() && !content.isNull()); 2338 2339 Frame* frame = this->frame(); 2340 2341 if (equalIgnoringCase(equiv, "default-style")) { 2342 // The preferred style set has been overridden as per section 2343 // 14.3.2 of the HTML4.0 specification. We need to update the 2344 // sheet used variable and then update our style selector. 2345 // For more info, see the test at: 2346 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html 2347 // -dwh 2348 m_selectedStylesheetSet = content; 2349 m_preferredStylesheetSet = content; 2350 updateStyleSelector(); 2351 } else if (equalIgnoringCase(equiv, "refresh")) { 2352 double delay; 2353 String url; 2354 if (frame && parseHTTPRefresh(content, true, delay, url)) { 2355 if (url.isEmpty()) 2356 url = frame->loader()->url().string(); 2357 else 2358 url = completeURL(url).string(); 2359 frame->redirectScheduler()->scheduleRedirect(delay, url); 2360 } 2361 } else if (equalIgnoringCase(equiv, "set-cookie")) { 2362 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....> 2363 if (isHTMLDocument()) { 2364 ExceptionCode ec; // Exception (for sandboxed documents) ignored. 2365 static_cast<HTMLDocument*>(this)->setCookie(content, ec); 2366 } 2367 } else if (equalIgnoringCase(equiv, "content-language")) 2368 setContentLanguage(content); 2369 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) 2370 parseDNSPrefetchControlHeader(content); 2371 else if (equalIgnoringCase(equiv, "x-frame-options")) { 2372 FrameLoader* frameLoader = frame->loader(); 2373 if (frameLoader->shouldInterruptLoadForXFrameOptions(content, url())) { 2374 frameLoader->stopAllLoaders(); 2375 frame->redirectScheduler()->scheduleLocationChange(blankURL(), String()); 2376 } 2377 } 2378 } 2379 2380 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event) 2381 { 2382 ASSERT(!renderer() || renderer()->isRenderView()); 2383 2384 if (!renderer()) 2385 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint())); 2386 2387 HitTestResult result(documentPoint); 2388 renderView()->layer()->hitTest(request, result); 2389 2390 if (!request.readOnly()) 2391 updateStyleIfNeeded(); 2392 2393 return MouseEventWithHitTestResults(event, result); 2394 } 2395 2396 // DOM Section 1.1.1 2397 bool Document::childTypeAllowed(NodeType type) 2398 { 2399 switch (type) { 2400 case ATTRIBUTE_NODE: 2401 case CDATA_SECTION_NODE: 2402 case DOCUMENT_FRAGMENT_NODE: 2403 case DOCUMENT_NODE: 2404 case ENTITY_NODE: 2405 case ENTITY_REFERENCE_NODE: 2406 case NOTATION_NODE: 2407 case TEXT_NODE: 2408 case XPATH_NAMESPACE_NODE: 2409 return false; 2410 case COMMENT_NODE: 2411 case PROCESSING_INSTRUCTION_NODE: 2412 return true; 2413 case DOCUMENT_TYPE_NODE: 2414 case ELEMENT_NODE: 2415 // Documents may contain no more than one of each of these. 2416 // (One Element and one DocumentType.) 2417 for (Node* c = firstChild(); c; c = c->nextSibling()) 2418 if (c->nodeType() == type) 2419 return false; 2420 return true; 2421 } 2422 return false; 2423 } 2424 2425 bool Document::canReplaceChild(Node* newChild, Node* oldChild) 2426 { 2427 if (!oldChild) 2428 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR. 2429 return true; 2430 2431 if (oldChild->nodeType() == newChild->nodeType()) 2432 return true; 2433 2434 int numDoctypes = 0; 2435 int numElements = 0; 2436 2437 // First, check how many doctypes and elements we have, not counting 2438 // the child we're about to remove. 2439 for (Node* c = firstChild(); c; c = c->nextSibling()) { 2440 if (c == oldChild) 2441 continue; 2442 2443 switch (c->nodeType()) { 2444 case DOCUMENT_TYPE_NODE: 2445 numDoctypes++; 2446 break; 2447 case ELEMENT_NODE: 2448 numElements++; 2449 break; 2450 default: 2451 break; 2452 } 2453 } 2454 2455 // Then, see how many doctypes and elements might be added by the new child. 2456 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) { 2457 for (Node* c = firstChild(); c; c = c->nextSibling()) { 2458 switch (c->nodeType()) { 2459 case ATTRIBUTE_NODE: 2460 case CDATA_SECTION_NODE: 2461 case DOCUMENT_FRAGMENT_NODE: 2462 case DOCUMENT_NODE: 2463 case ENTITY_NODE: 2464 case ENTITY_REFERENCE_NODE: 2465 case NOTATION_NODE: 2466 case TEXT_NODE: 2467 case XPATH_NAMESPACE_NODE: 2468 return false; 2469 case COMMENT_NODE: 2470 case PROCESSING_INSTRUCTION_NODE: 2471 break; 2472 case DOCUMENT_TYPE_NODE: 2473 numDoctypes++; 2474 break; 2475 case ELEMENT_NODE: 2476 numElements++; 2477 break; 2478 } 2479 } 2480 } else { 2481 switch (newChild->nodeType()) { 2482 case ATTRIBUTE_NODE: 2483 case CDATA_SECTION_NODE: 2484 case DOCUMENT_FRAGMENT_NODE: 2485 case DOCUMENT_NODE: 2486 case ENTITY_NODE: 2487 case ENTITY_REFERENCE_NODE: 2488 case NOTATION_NODE: 2489 case TEXT_NODE: 2490 case XPATH_NAMESPACE_NODE: 2491 return false; 2492 case COMMENT_NODE: 2493 case PROCESSING_INSTRUCTION_NODE: 2494 return true; 2495 case DOCUMENT_TYPE_NODE: 2496 numDoctypes++; 2497 break; 2498 case ELEMENT_NODE: 2499 numElements++; 2500 break; 2501 } 2502 } 2503 2504 if (numElements > 1 || numDoctypes > 1) 2505 return false; 2506 2507 return true; 2508 } 2509 2510 PassRefPtr<Node> Document::cloneNode(bool /*deep*/) 2511 { 2512 // Spec says cloning Document nodes is "implementation dependent" 2513 // so we do not support it... 2514 return 0; 2515 } 2516 2517 StyleSheetList* Document::styleSheets() 2518 { 2519 return m_styleSheets.get(); 2520 } 2521 2522 String Document::preferredStylesheetSet() const 2523 { 2524 return m_preferredStylesheetSet; 2525 } 2526 2527 String Document::selectedStylesheetSet() const 2528 { 2529 return m_selectedStylesheetSet; 2530 } 2531 2532 void Document::setSelectedStylesheetSet(const String& aString) 2533 { 2534 m_selectedStylesheetSet = aString; 2535 updateStyleSelector(); 2536 if (renderer()) 2537 renderer()->repaint(); 2538 } 2539 2540 // This method is called whenever a top-level stylesheet has finished loading. 2541 void Document::removePendingSheet() 2542 { 2543 // Make sure we knew this sheet was pending, and that our count isn't out of sync. 2544 ASSERT(m_pendingStylesheets > 0); 2545 2546 m_pendingStylesheets--; 2547 2548 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2549 if (!ownerElement()) 2550 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets); 2551 #endif 2552 2553 updateStyleSelector(); 2554 2555 if (!m_pendingStylesheets && m_tokenizer) 2556 m_tokenizer->executeScriptsWaitingForStylesheets(); 2557 2558 if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && view()) 2559 view()->scrollToFragment(m_frame->loader()->url()); 2560 } 2561 2562 void Document::updateStyleSelector() 2563 { 2564 // Don't bother updating, since we haven't loaded all our style info yet 2565 // and haven't calculated the style selector for the first time. 2566 if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded()) 2567 return; 2568 2569 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) { 2570 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; 2571 if (renderer()) 2572 renderer()->repaint(); 2573 } 2574 2575 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2576 if (!ownerElement()) 2577 printf("Beginning update of style selector at time %d.\n", elapsedTime()); 2578 #endif 2579 2580 recalcStyleSelector(); 2581 recalcStyle(Force); 2582 2583 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2584 if (!ownerElement()) 2585 printf("Finished update of style selector at time %d\n", elapsedTime()); 2586 #endif 2587 2588 if (renderer()) { 2589 renderer()->setNeedsLayoutAndPrefWidthsRecalc(); 2590 if (view()) 2591 view()->scheduleRelayout(); 2592 } 2593 } 2594 2595 void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser) 2596 { 2597 // Until the <body> exists, we have no choice but to compare document positions, 2598 // since styles outside of the body and head continue to be shunted into the head 2599 // (and thus can shift to end up before dynamically added DOM content that is also 2600 // outside the body). 2601 if ((createdByParser && body()) || m_styleSheetCandidateNodes.isEmpty()) { 2602 m_styleSheetCandidateNodes.add(node); 2603 return; 2604 } 2605 2606 // Determine an appropriate insertion point. 2607 ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin(); 2608 ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end(); 2609 ListHashSet<Node*>::iterator it = end; 2610 Node* followingNode = 0; 2611 do { 2612 --it; 2613 Node* n = *it; 2614 unsigned short position = n->compareDocumentPosition(node); 2615 if (position == DOCUMENT_POSITION_FOLLOWING) { 2616 m_styleSheetCandidateNodes.insertBefore(followingNode, node); 2617 return; 2618 } 2619 followingNode = n; 2620 } while (it != begin); 2621 2622 m_styleSheetCandidateNodes.insertBefore(followingNode, node); 2623 } 2624 2625 void Document::removeStyleSheetCandidateNode(Node* node) 2626 { 2627 m_styleSheetCandidateNodes.remove(node); 2628 } 2629 2630 void Document::recalcStyleSelector() 2631 { 2632 if (!renderer() || !attached()) 2633 return; 2634 2635 StyleSheetVector sheets; 2636 2637 bool matchAuthorAndUserStyles = true; 2638 if (Settings* settings = this->settings()) 2639 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled(); 2640 2641 ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin(); 2642 ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end(); 2643 if (!matchAuthorAndUserStyles) 2644 end = begin; 2645 for (ListHashSet<Node*>::iterator it = begin; it != end; ++it) { 2646 Node* n = *it; 2647 2648 StyleSheet* sheet = 0; 2649 2650 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) { 2651 // Processing instruction (XML documents only) 2652 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n); 2653 sheet = pi->sheet(); 2654 #if ENABLE(XSLT) 2655 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> 2656 if (pi->isXSL() && !transformSourceDocument()) { 2657 // Don't apply XSL transforms until loading is finished. 2658 if (!parsing()) 2659 applyXSLTransform(pi); 2660 return; 2661 } 2662 #endif 2663 if (!sheet && !pi->localHref().isEmpty()) { 2664 // Processing instruction with reference to an element in this document - e.g. 2665 // <?xml-stylesheet href="#mystyle">, with the element 2666 // <foo id="mystyle">heading { color: red; }</foo> at some location in 2667 // the document 2668 Element* elem = getElementById(pi->localHref().impl()); 2669 if (elem) { 2670 String sheetText(""); 2671 for (Node* c = elem->firstChild(); c; c = c->nextSibling()) { 2672 if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE) 2673 sheetText += c->nodeValue(); 2674 } 2675 2676 RefPtr<CSSStyleSheet> cssSheet = CSSStyleSheet::create(this); 2677 cssSheet->parseString(sheetText); 2678 pi->setCSSStyleSheet(cssSheet); 2679 sheet = cssSheet.get(); 2680 } 2681 } 2682 } else if ((n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))) 2683 #if ENABLE(SVG) 2684 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) 2685 #endif 2686 ) { 2687 Element* e = static_cast<Element*>(n); 2688 AtomicString title = e->getAttribute(titleAttr); 2689 bool enabledViaScript = false; 2690 if (e->hasLocalName(linkTag)) { 2691 // <LINK> element 2692 HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n); 2693 if (l->isDisabled()) 2694 continue; 2695 enabledViaScript = l->isEnabledViaScript(); 2696 if (l->isLoading()) { 2697 // it is loading but we should still decide which style sheet set to use 2698 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) { 2699 const AtomicString& rel = e->getAttribute(relAttr); 2700 if (!rel.contains("alternate")) { 2701 m_preferredStylesheetSet = title; 2702 m_selectedStylesheetSet = title; 2703 } 2704 } 2705 continue; 2706 } 2707 if (!l->sheet()) 2708 title = nullAtom; 2709 } 2710 2711 // Get the current preferred styleset. This is the 2712 // set of sheets that will be enabled. 2713 #if ENABLE(SVG) 2714 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) 2715 sheet = static_cast<SVGStyleElement*>(n)->sheet(); 2716 else 2717 #endif 2718 if (e->hasLocalName(linkTag)) 2719 sheet = static_cast<HTMLLinkElement*>(n)->sheet(); 2720 else 2721 // <STYLE> element 2722 sheet = static_cast<HTMLStyleElement*>(n)->sheet(); 2723 2724 // Check to see if this sheet belongs to a styleset 2725 // (thus making it PREFERRED or ALTERNATE rather than 2726 // PERSISTENT). 2727 if (!enabledViaScript && !title.isEmpty()) { 2728 // Yes, we have a title. 2729 if (m_preferredStylesheetSet.isEmpty()) { 2730 // No preferred set has been established. If 2731 // we are NOT an alternate sheet, then establish 2732 // us as the preferred set. Otherwise, just ignore 2733 // this sheet. 2734 AtomicString rel = e->getAttribute(relAttr); 2735 if (e->hasLocalName(styleTag) || !rel.contains("alternate")) 2736 m_preferredStylesheetSet = m_selectedStylesheetSet = title; 2737 } 2738 2739 if (title != m_preferredStylesheetSet) 2740 sheet = 0; 2741 } 2742 } 2743 2744 if (sheet) 2745 sheets.append(sheet); 2746 } 2747 2748 m_styleSheets->swap(sheets); 2749 2750 m_styleSelector.clear(); 2751 m_didCalculateStyleSelector = true; 2752 } 2753 2754 void Document::setHoverNode(PassRefPtr<Node> newHoverNode) 2755 { 2756 m_hoverNode = newHoverNode; 2757 } 2758 2759 void Document::setActiveNode(PassRefPtr<Node> newActiveNode) 2760 { 2761 m_activeNode = newActiveNode; 2762 } 2763 2764 void Document::focusedNodeRemoved() 2765 { 2766 setFocusedNode(0); 2767 } 2768 2769 void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly) 2770 { 2771 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node. 2772 return; 2773 2774 bool nodeInSubtree = false; 2775 if (amongChildrenOnly) 2776 nodeInSubtree = m_focusedNode->isDescendantOf(node); 2777 else 2778 nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node); 2779 2780 if (nodeInSubtree) 2781 document()->focusedNodeRemoved(); 2782 } 2783 2784 void Document::hoveredNodeDetached(Node* node) 2785 { 2786 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parent()))) 2787 return; 2788 2789 m_hoverNode = node->parent(); 2790 while (m_hoverNode && !m_hoverNode->renderer()) 2791 m_hoverNode = m_hoverNode->parent(); 2792 if (frame()) 2793 frame()->eventHandler()->scheduleHoverStateUpdate(); 2794 } 2795 2796 void Document::activeChainNodeDetached(Node* node) 2797 { 2798 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parent()))) 2799 return; 2800 2801 m_activeNode = node->parent(); 2802 while (m_activeNode && !m_activeNode->renderer()) 2803 m_activeNode = m_activeNode->parent(); 2804 } 2805 2806 #if ENABLE(DASHBOARD_SUPPORT) 2807 const Vector<DashboardRegionValue>& Document::dashboardRegions() const 2808 { 2809 return m_dashboardRegions; 2810 } 2811 2812 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions) 2813 { 2814 m_dashboardRegions = regions; 2815 setDashboardRegionsDirty(false); 2816 } 2817 #endif 2818 2819 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) 2820 { 2821 // Make sure newFocusedNode is actually in this document 2822 if (newFocusedNode && (newFocusedNode->document() != this)) 2823 return true; 2824 2825 if (m_focusedNode == newFocusedNode) 2826 return true; 2827 2828 if (m_inPageCache) 2829 return false; 2830 2831 bool focusChangeBlocked = false; 2832 RefPtr<Node> oldFocusedNode = m_focusedNode; 2833 m_focusedNode = 0; 2834 2835 // Remove focus from the existing focus node (if any) 2836 if (oldFocusedNode && !oldFocusedNode->m_inDetach) { 2837 if (oldFocusedNode->active()) 2838 oldFocusedNode->setActive(false); 2839 2840 oldFocusedNode->setFocus(false); 2841 2842 // Dispatch a change event for text fields or textareas that have been edited 2843 RenderObject* r = oldFocusedNode->renderer(); 2844 if (r && r->isTextControl() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) { 2845 static_cast<Element*>(oldFocusedNode.get())->dispatchFormControlChangeEvent(); 2846 r = oldFocusedNode->renderer(); 2847 if (r && r->isTextControl()) 2848 toRenderTextControl(r)->setChangedSinceLastChangeEvent(false); 2849 } 2850 2851 // Dispatch the blur event and let the node do any other blur related activities (important for text fields) 2852 oldFocusedNode->dispatchBlurEvent(); 2853 2854 if (m_focusedNode) { 2855 // handler shifted focus 2856 focusChangeBlocked = true; 2857 newFocusedNode = 0; 2858 } 2859 oldFocusedNode->dispatchUIEvent(eventNames().DOMFocusOutEvent, 0, 0); 2860 if (m_focusedNode) { 2861 // handler shifted focus 2862 focusChangeBlocked = true; 2863 newFocusedNode = 0; 2864 } 2865 if (oldFocusedNode == this && oldFocusedNode->hasOneRef()) 2866 return true; 2867 2868 if (oldFocusedNode == oldFocusedNode->rootEditableElement()) 2869 frame()->editor()->didEndEditing(); 2870 } 2871 2872 if (newFocusedNode) { 2873 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) { 2874 // delegate blocks focus change 2875 focusChangeBlocked = true; 2876 goto SetFocusedNodeDone; 2877 } 2878 // Set focus on the new node 2879 m_focusedNode = newFocusedNode.get(); 2880 2881 // Dispatch the focus event and let the node do any other focus related activities (important for text fields) 2882 m_focusedNode->dispatchFocusEvent(); 2883 2884 if (m_focusedNode != newFocusedNode) { 2885 // handler shifted focus 2886 focusChangeBlocked = true; 2887 goto SetFocusedNodeDone; 2888 } 2889 m_focusedNode->dispatchUIEvent(eventNames().DOMFocusInEvent, 0, 0); 2890 if (m_focusedNode != newFocusedNode) { 2891 // handler shifted focus 2892 focusChangeBlocked = true; 2893 goto SetFocusedNodeDone; 2894 } 2895 m_focusedNode->setFocus(); 2896 2897 if (m_focusedNode == m_focusedNode->rootEditableElement()) 2898 frame()->editor()->didBeginEditing(); 2899 2900 // eww, I suck. set the qt focus correctly 2901 // ### find a better place in the code for this 2902 if (view()) { 2903 Widget *focusWidget = widgetForNode(m_focusedNode.get()); 2904 if (focusWidget) { 2905 // Make sure a widget has the right size before giving it focus. 2906 // Otherwise, we are testing edge cases of the Widget code. 2907 // Specifically, in WebCore this does not work well for text fields. 2908 updateLayout(); 2909 // Re-get the widget in case updating the layout changed things. 2910 focusWidget = widgetForNode(m_focusedNode.get()); 2911 } 2912 if (focusWidget) 2913 focusWidget->setFocus(); 2914 else 2915 view()->setFocus(); 2916 } 2917 } 2918 2919 #if ((PLATFORM(MAC) || PLATFORM(WIN)) && !PLATFORM(CHROMIUM)) || PLATFORM(GTK) 2920 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled()) { 2921 RenderObject* oldFocusedRenderer = 0; 2922 RenderObject* newFocusedRenderer = 0; 2923 2924 if (oldFocusedNode) 2925 oldFocusedRenderer = oldFocusedNode->renderer(); 2926 if (newFocusedNode) 2927 newFocusedRenderer = newFocusedNode->renderer(); 2928 2929 axObjectCache()->handleFocusedUIElementChanged(oldFocusedRenderer, newFocusedRenderer); 2930 } 2931 #endif 2932 if (!focusChangeBlocked) 2933 page()->chrome()->focusedNodeChanged(m_focusedNode.get()); 2934 2935 SetFocusedNodeDone: 2936 updateStyleIfNeeded(); 2937 return !focusChangeBlocked; 2938 } 2939 2940 void Document::getFocusableNodes(Vector<RefPtr<Node> >& nodes) 2941 { 2942 updateLayout(); 2943 2944 for (Node* node = firstChild(); node; node = node->traverseNextNode()) { 2945 if (node->isFocusable()) 2946 nodes.append(node); 2947 } 2948 } 2949 2950 void Document::setCSSTarget(Element* n) 2951 { 2952 if (m_cssTarget) 2953 m_cssTarget->setNeedsStyleRecalc(); 2954 m_cssTarget = n; 2955 if (n) 2956 n->setNeedsStyleRecalc(); 2957 } 2958 2959 void Document::attachNodeIterator(NodeIterator *ni) 2960 { 2961 m_nodeIterators.add(ni); 2962 } 2963 2964 void Document::detachNodeIterator(NodeIterator *ni) 2965 { 2966 m_nodeIterators.remove(ni); 2967 } 2968 2969 void Document::nodeChildrenChanged(ContainerNode* container) 2970 { 2971 if (!disableRangeMutation(page())) { 2972 HashSet<Range*>::const_iterator end = m_ranges.end(); 2973 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 2974 (*it)->nodeChildrenChanged(container); 2975 } 2976 } 2977 2978 void Document::nodeWillBeRemoved(Node* n) 2979 { 2980 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); 2981 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) 2982 (*it)->nodeWillBeRemoved(n); 2983 2984 if (!disableRangeMutation(page())) { 2985 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end(); 2986 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it) 2987 (*it)->nodeWillBeRemoved(n); 2988 } 2989 2990 if (Frame* frame = this->frame()) { 2991 frame->selection()->nodeWillBeRemoved(n); 2992 frame->dragCaretController()->nodeWillBeRemoved(n); 2993 } 2994 } 2995 2996 void Document::textInserted(Node* text, unsigned offset, unsigned length) 2997 { 2998 if (!disableRangeMutation(page())) { 2999 HashSet<Range*>::const_iterator end = m_ranges.end(); 3000 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3001 (*it)->textInserted(text, offset, length); 3002 } 3003 3004 // Update the markers for spelling and grammar checking. 3005 shiftMarkers(text, offset, length); 3006 } 3007 3008 void Document::textRemoved(Node* text, unsigned offset, unsigned length) 3009 { 3010 if (!disableRangeMutation(page())) { 3011 HashSet<Range*>::const_iterator end = m_ranges.end(); 3012 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3013 (*it)->textRemoved(text, offset, length); 3014 } 3015 3016 // Update the markers for spelling and grammar checking. 3017 removeMarkers(text, offset, length); 3018 shiftMarkers(text, offset + length, 0 - length); 3019 } 3020 3021 void Document::textNodesMerged(Text* oldNode, unsigned offset) 3022 { 3023 if (!disableRangeMutation(page())) { 3024 NodeWithIndex oldNodeWithIndex(oldNode); 3025 HashSet<Range*>::const_iterator end = m_ranges.end(); 3026 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3027 (*it)->textNodesMerged(oldNodeWithIndex, offset); 3028 } 3029 3030 // FIXME: This should update markers for spelling and grammar checking. 3031 } 3032 3033 void Document::textNodeSplit(Text* oldNode) 3034 { 3035 if (!disableRangeMutation(page())) { 3036 HashSet<Range*>::const_iterator end = m_ranges.end(); 3037 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3038 (*it)->textNodeSplit(oldNode); 3039 } 3040 3041 // FIXME: This should update markers for spelling and grammar checking. 3042 } 3043 3044 // FIXME: eventually, this should return a DOMWindow stored in the document. 3045 DOMWindow* Document::domWindow() const 3046 { 3047 if (!frame()) 3048 return 0; 3049 3050 // The m_frame pointer is not (not always?) zeroed out when the document is put into b/f cache, so the frame can hold an unrelated document/window pair. 3051 // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content. 3052 if (m_frame->document() != this) 3053 return 0; 3054 3055 return frame()->domWindow(); 3056 } 3057 3058 void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener) 3059 { 3060 DOMWindow* domWindow = this->domWindow(); 3061 if (!domWindow) 3062 return; 3063 domWindow->setAttributeEventListener(eventType, listener); 3064 } 3065 3066 EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType) 3067 { 3068 DOMWindow* domWindow = this->domWindow(); 3069 if (!domWindow) 3070 return 0; 3071 return domWindow->getAttributeEventListener(eventType); 3072 } 3073 3074 void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTarget> target) 3075 { 3076 ASSERT(!eventDispatchForbidden()); 3077 DOMWindow* domWindow = this->domWindow(); 3078 if (!domWindow) 3079 return; 3080 domWindow->dispatchEvent(event, target); 3081 } 3082 3083 void Document::dispatchWindowLoadEvent() 3084 { 3085 ASSERT(!eventDispatchForbidden()); 3086 DOMWindow* domWindow = this->domWindow(); 3087 if (!domWindow) 3088 return; 3089 domWindow->dispatchLoadEvent(); 3090 } 3091 3092 void Document::enqueueStorageEvent(PassRefPtr<Event> storageEvent) 3093 { 3094 m_storageEventQueue.append(storageEvent); 3095 if (!m_storageEventTimer.isActive()) 3096 m_storageEventTimer.startOneShot(0); 3097 } 3098 3099 void Document::storageEventTimerFired(Timer<Document>*) 3100 { 3101 ASSERT(!m_storageEventTimer.isActive()); 3102 Vector<RefPtr<Event> > storageEventQueue; 3103 storageEventQueue.swap(m_storageEventQueue); 3104 3105 typedef Vector<RefPtr<Event> >::const_iterator Iterator; 3106 Iterator end = storageEventQueue.end(); 3107 for (Iterator it = storageEventQueue.begin(); it != end; ++it) 3108 dispatchWindowEvent(*it); 3109 } 3110 3111 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec) 3112 { 3113 RefPtr<Event> event; 3114 if (eventType == "Event" || eventType == "Events" || eventType == "HTMLEvents") 3115 event = Event::create(); 3116 else if (eventType == "KeyboardEvent" || eventType == "KeyboardEvents") 3117 event = KeyboardEvent::create(); 3118 else if (eventType == "MessageEvent") 3119 event = MessageEvent::create(); 3120 else if (eventType == "MouseEvent" || eventType == "MouseEvents") 3121 event = MouseEvent::create(); 3122 else if (eventType == "MutationEvent" || eventType == "MutationEvents") 3123 event = MutationEvent::create(); 3124 else if (eventType == "OverflowEvent") 3125 event = OverflowEvent::create(); 3126 else if (eventType == "PageTransitionEvent") 3127 event = PageTransitionEvent::create(); 3128 else if (eventType == "ProgressEvent") 3129 event = ProgressEvent::create(); 3130 #if ENABLE(DOM_STORAGE) 3131 else if (eventType == "StorageEvent") 3132 event = StorageEvent::create(); 3133 #endif 3134 else if (eventType == "TextEvent") 3135 event = TextEvent::create(); 3136 else if (eventType == "UIEvent" || eventType == "UIEvents") 3137 event = UIEvent::create(); 3138 else if (eventType == "WebKitAnimationEvent") 3139 event = WebKitAnimationEvent::create(); 3140 else if (eventType == "WebKitTransitionEvent") 3141 event = WebKitTransitionEvent::create(); 3142 else if (eventType == "WheelEvent") 3143 event = WheelEvent::create(); 3144 #if ENABLE(SVG) 3145 else if (eventType == "SVGEvents") 3146 event = Event::create(); 3147 else if (eventType == "SVGZoomEvents") 3148 event = SVGZoomEvent::create(); 3149 #endif 3150 #if ENABLE(TOUCH_EVENTS) 3151 else if (eventType == "TouchEvent") 3152 event = TouchEvent::create(); 3153 #endif 3154 if (event) { 3155 event->setCreatedByDOM(true); 3156 return event.release(); 3157 } 3158 ec = NOT_SUPPORTED_ERR; 3159 return 0; 3160 } 3161 3162 void Document::addListenerTypeIfNeeded(const AtomicString& eventType) 3163 { 3164 if (eventType == eventNames().DOMSubtreeModifiedEvent) 3165 addListenerType(DOMSUBTREEMODIFIED_LISTENER); 3166 else if (eventType == eventNames().DOMNodeInsertedEvent) 3167 addListenerType(DOMNODEINSERTED_LISTENER); 3168 else if (eventType == eventNames().DOMNodeRemovedEvent) 3169 addListenerType(DOMNODEREMOVED_LISTENER); 3170 else if (eventType == eventNames().DOMNodeRemovedFromDocumentEvent) 3171 addListenerType(DOMNODEREMOVEDFROMDOCUMENT_LISTENER); 3172 else if (eventType == eventNames().DOMNodeInsertedIntoDocumentEvent) 3173 addListenerType(DOMNODEINSERTEDINTODOCUMENT_LISTENER); 3174 else if (eventType == eventNames().DOMAttrModifiedEvent) 3175 addListenerType(DOMATTRMODIFIED_LISTENER); 3176 else if (eventType == eventNames().DOMCharacterDataModifiedEvent) 3177 addListenerType(DOMCHARACTERDATAMODIFIED_LISTENER); 3178 else if (eventType == eventNames().overflowchangedEvent) 3179 addListenerType(OVERFLOWCHANGED_LISTENER); 3180 else if (eventType == eventNames().webkitAnimationStartEvent) 3181 addListenerType(ANIMATIONSTART_LISTENER); 3182 else if (eventType == eventNames().webkitAnimationEndEvent) 3183 addListenerType(ANIMATIONEND_LISTENER); 3184 else if (eventType == eventNames().webkitAnimationIterationEvent) 3185 addListenerType(ANIMATIONITERATION_LISTENER); 3186 else if (eventType == eventNames().webkitTransitionEndEvent) 3187 addListenerType(TRANSITIONEND_LISTENER); 3188 else if (eventType == eventNames().beforeloadEvent) 3189 addListenerType(BEFORELOAD_LISTENER); 3190 #if ENABLE(TOUCH_EVENTS) 3191 else if (eventType == eventNames().touchstartEvent 3192 || eventType == eventNames().touchmoveEvent 3193 || eventType == eventNames().touchendEvent 3194 || eventType == eventNames().touchcancelEvent) { 3195 addListenerType(TOUCH_LISTENER); 3196 if (Page* page = this->page()) 3197 page->chrome()->client()->needTouchEvents(true); 3198 } 3199 #endif 3200 } 3201 3202 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) 3203 { 3204 return 0; 3205 } 3206 3207 Element* Document::ownerElement() const 3208 { 3209 if (!frame()) 3210 return 0; 3211 return frame()->ownerElement(); 3212 } 3213 3214 String Document::cookie(ExceptionCode& ec) const 3215 { 3216 if (page() && !page()->cookieEnabled()) 3217 return String(); 3218 3219 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3220 // INVALID_STATE_ERR exception on getting if the Document has no 3221 // browsing context. 3222 3223 if (!securityOrigin()->canAccessCookies()) { 3224 ec = SECURITY_ERR; 3225 return String(); 3226 } 3227 3228 KURL cookieURL = this->cookieURL(); 3229 if (cookieURL.isEmpty()) 3230 return String(); 3231 3232 return cookies(this, cookieURL); 3233 } 3234 3235 void Document::setCookie(const String& value, ExceptionCode& ec) 3236 { 3237 if (page() && !page()->cookieEnabled()) 3238 return; 3239 3240 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3241 // INVALID_STATE_ERR exception on setting if the Document has no 3242 // browsing context. 3243 3244 if (!securityOrigin()->canAccessCookies()) { 3245 ec = SECURITY_ERR; 3246 return; 3247 } 3248 3249 KURL cookieURL = this->cookieURL(); 3250 if (cookieURL.isEmpty()) 3251 return; 3252 3253 setCookies(this, cookieURL, value); 3254 } 3255 3256 String Document::referrer() const 3257 { 3258 if (frame()) 3259 return frame()->loader()->referrer(); 3260 return String(); 3261 } 3262 3263 String Document::domain() const 3264 { 3265 return securityOrigin()->domain(); 3266 } 3267 3268 void Document::setDomain(const String& newDomain, ExceptionCode& ec) 3269 { 3270 if (SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) { 3271 ec = SECURITY_ERR; 3272 return; 3273 } 3274 3275 // Both NS and IE specify that changing the domain is only allowed when 3276 // the new domain is a suffix of the old domain. 3277 3278 // FIXME: We should add logging indicating why a domain was not allowed. 3279 3280 // If the new domain is the same as the old domain, still call 3281 // securityOrigin()->setDomainForDOM. This will change the 3282 // security check behavior. For example, if a page loaded on port 8000 3283 // assigns its current domain using document.domain, the page will 3284 // allow other pages loaded on different ports in the same domain that 3285 // have also assigned to access this page. 3286 if (equalIgnoringCase(domain(), newDomain)) { 3287 securityOrigin()->setDomainFromDOM(newDomain); 3288 if (m_frame) 3289 m_frame->script()->updateSecurityOrigin(); 3290 return; 3291 } 3292 3293 int oldLength = domain().length(); 3294 int newLength = newDomain.length(); 3295 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14) 3296 if (newLength >= oldLength) { 3297 ec = SECURITY_ERR; 3298 return; 3299 } 3300 3301 String test = domain(); 3302 // Check that it's a subdomain, not e.g. "ebkit.org" 3303 if (test[oldLength - newLength - 1] != '.') { 3304 ec = SECURITY_ERR; 3305 return; 3306 } 3307 3308 // Now test is "webkit.org" from domain() 3309 // and we check that it's the same thing as newDomain 3310 test.remove(0, oldLength - newLength); 3311 if (test != newDomain) { 3312 ec = SECURITY_ERR; 3313 return; 3314 } 3315 3316 securityOrigin()->setDomainFromDOM(newDomain); 3317 if (m_frame) 3318 m_frame->script()->updateSecurityOrigin(); 3319 } 3320 3321 String Document::lastModified() const 3322 { 3323 Frame* f = frame(); 3324 if (!f) 3325 return String(); 3326 DocumentLoader* loader = f->loader()->documentLoader(); 3327 if (!loader) 3328 return String(); 3329 return loader->response().httpHeaderField("Last-Modified"); 3330 } 3331 3332 static bool isValidNameNonASCII(const UChar* characters, unsigned length) 3333 { 3334 unsigned i = 0; 3335 3336 UChar32 c; 3337 U16_NEXT(characters, i, length, c) 3338 if (!isValidNameStart(c)) 3339 return false; 3340 3341 while (i < length) { 3342 U16_NEXT(characters, i, length, c) 3343 if (!isValidNamePart(c)) 3344 return false; 3345 } 3346 3347 return true; 3348 } 3349 3350 static inline bool isValidNameASCII(const UChar* characters, unsigned length) 3351 { 3352 UChar c = characters[0]; 3353 if (!(isASCIIAlpha(c) || c == ':' || c == '_')) 3354 return false; 3355 3356 for (unsigned i = 1; i < length; ++i) { 3357 c = characters[i]; 3358 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.')) 3359 return false; 3360 } 3361 3362 return true; 3363 } 3364 3365 bool Document::isValidName(const String& name) 3366 { 3367 unsigned length = name.length(); 3368 if (!length) 3369 return false; 3370 3371 const UChar* characters = name.characters(); 3372 return isValidNameASCII(characters, length) || isValidNameNonASCII(characters, length); 3373 } 3374 3375 bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec) 3376 { 3377 unsigned length = qualifiedName.length(); 3378 3379 if (length == 0) { 3380 ec = INVALID_CHARACTER_ERR; 3381 return false; 3382 } 3383 3384 bool nameStart = true; 3385 bool sawColon = false; 3386 int colonPos = 0; 3387 3388 const UChar* s = qualifiedName.characters(); 3389 for (unsigned i = 0; i < length;) { 3390 UChar32 c; 3391 U16_NEXT(s, i, length, c) 3392 if (c == ':') { 3393 if (sawColon) { 3394 ec = NAMESPACE_ERR; 3395 return false; // multiple colons: not allowed 3396 } 3397 nameStart = true; 3398 sawColon = true; 3399 colonPos = i - 1; 3400 } else if (nameStart) { 3401 if (!isValidNameStart(c)) { 3402 ec = INVALID_CHARACTER_ERR; 3403 return false; 3404 } 3405 nameStart = false; 3406 } else { 3407 if (!isValidNamePart(c)) { 3408 ec = INVALID_CHARACTER_ERR; 3409 return false; 3410 } 3411 } 3412 } 3413 3414 if (!sawColon) { 3415 prefix = String(); 3416 localName = qualifiedName; 3417 } else { 3418 prefix = qualifiedName.substring(0, colonPos); 3419 if (prefix.isEmpty()) { 3420 ec = NAMESPACE_ERR; 3421 return false; 3422 } 3423 localName = qualifiedName.substring(colonPos + 1); 3424 } 3425 3426 if (localName.isEmpty()) { 3427 ec = NAMESPACE_ERR; 3428 return false; 3429 } 3430 3431 return true; 3432 } 3433 3434 void Document::addImageMap(HTMLMapElement* imageMap) 3435 { 3436 const AtomicString& name = imageMap->getName(); 3437 if (!name.impl()) 3438 return; 3439 3440 // Add the image map, unless there's already another with that name. 3441 // "First map wins" is the rule other browsers seem to implement. 3442 m_imageMapsByName.add(name.impl(), imageMap); 3443 } 3444 3445 void Document::removeImageMap(HTMLMapElement* imageMap) 3446 { 3447 // Remove the image map by name. 3448 // But don't remove some other image map that just happens to have the same name. 3449 // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map 3450 // once a map has been removed. 3451 const AtomicString& name = imageMap->getName(); 3452 if (!name.impl()) 3453 return; 3454 3455 m_imageMapsByName.checkConsistency(); 3456 3457 ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl()); 3458 if (it != m_imageMapsByName.end() && it->second == imageMap) 3459 m_imageMapsByName.remove(it); 3460 } 3461 3462 HTMLMapElement *Document::getImageMap(const String& url) const 3463 { 3464 if (url.isNull()) 3465 return 0; 3466 int hashPos = url.find('#'); 3467 String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl(); 3468 AtomicString mapName = isHTMLDocument() ? name.lower() : name; 3469 m_imageMapsByName.checkConsistency(); 3470 return m_imageMapsByName.get(mapName.impl()); 3471 } 3472 3473 void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) 3474 { 3475 m_decoder = decoder; 3476 } 3477 3478 KURL Document::completeURL(const String& url) const 3479 { 3480 // Always return a null URL when passed a null string. 3481 // FIXME: Should we change the KURL constructor to have this behavior? 3482 // See also [CSS]StyleSheet::completeURL(const String&) 3483 if (url.isNull()) 3484 return KURL(); 3485 const KURL& baseURL = ((m_baseURL.isEmpty() || m_baseURL == blankURL()) && parentDocument()) ? parentDocument()->baseURL() : m_baseURL; 3486 if (!m_decoder) 3487 return KURL(baseURL, url); 3488 return KURL(baseURL, url, m_decoder->encoding()); 3489 } 3490 3491 void Document::setInPageCache(bool flag) 3492 { 3493 if (m_inPageCache == flag) 3494 return; 3495 3496 m_inPageCache = flag; 3497 if (flag) { 3498 ASSERT(m_savedRenderer == 0); 3499 m_savedRenderer = renderer(); 3500 if (FrameView* v = view()) 3501 v->resetScrollbars(); 3502 unscheduleStyleRecalc(); 3503 } else { 3504 ASSERT(renderer() == 0 || renderer() == m_savedRenderer); 3505 ASSERT(m_renderArena); 3506 setRenderer(m_savedRenderer); 3507 m_savedRenderer = 0; 3508 if (childNeedsStyleRecalc()) 3509 scheduleStyleRecalc(); 3510 } 3511 } 3512 3513 void Document::documentWillBecomeInactive() 3514 { 3515 #if USE(ACCELERATED_COMPOSITING) 3516 if (renderer()) 3517 renderView()->willMoveOffscreen(); 3518 #endif 3519 3520 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end(); 3521 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i) 3522 (*i)->documentWillBecomeInactive(); 3523 } 3524 3525 void Document::documentDidBecomeActive() 3526 { 3527 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end(); 3528 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i) 3529 (*i)->documentDidBecomeActive(); 3530 3531 #if USE(ACCELERATED_COMPOSITING) 3532 if (renderer()) 3533 renderView()->didMoveOnscreen(); 3534 #endif 3535 } 3536 3537 void Document::registerForDocumentActivationCallbacks(Element* e) 3538 { 3539 m_documentActivationCallbackElements.add(e); 3540 } 3541 3542 void Document::unregisterForDocumentActivationCallbacks(Element* e) 3543 { 3544 m_documentActivationCallbackElements.remove(e); 3545 } 3546 3547 void Document::mediaVolumeDidChange() 3548 { 3549 HashSet<Element*>::iterator end = m_mediaVolumeCallbackElements.end(); 3550 for (HashSet<Element*>::iterator i = m_mediaVolumeCallbackElements.begin(); i != end; ++i) 3551 (*i)->mediaVolumeDidChange(); 3552 } 3553 3554 void Document::registerForMediaVolumeCallbacks(Element* e) 3555 { 3556 m_mediaVolumeCallbackElements.add(e); 3557 } 3558 3559 void Document::unregisterForMediaVolumeCallbacks(Element* e) 3560 { 3561 m_mediaVolumeCallbackElements.remove(e); 3562 } 3563 3564 void Document::setShouldCreateRenderers(bool f) 3565 { 3566 m_createRenderers = f; 3567 } 3568 3569 bool Document::shouldCreateRenderers() 3570 { 3571 return m_createRenderers; 3572 } 3573 3574 // Support for Javascript execCommand, and related methods 3575 3576 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false) 3577 { 3578 Frame* frame = document->frame(); 3579 if (!frame || frame->document() != document) 3580 return Editor::Command(); 3581 return frame->editor()->command(commandName, 3582 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM); 3583 } 3584 3585 bool Document::execCommand(const String& commandName, bool userInterface, const String& value) 3586 { 3587 return command(this, commandName, userInterface).execute(value); 3588 } 3589 3590 bool Document::queryCommandEnabled(const String& commandName) 3591 { 3592 return command(this, commandName).isEnabled(); 3593 } 3594 3595 bool Document::queryCommandIndeterm(const String& commandName) 3596 { 3597 return command(this, commandName).state() == MixedTriState; 3598 } 3599 3600 bool Document::queryCommandState(const String& commandName) 3601 { 3602 return command(this, commandName).state() != FalseTriState; 3603 } 3604 3605 bool Document::queryCommandSupported(const String& commandName) 3606 { 3607 return command(this, commandName).isSupported(); 3608 } 3609 3610 String Document::queryCommandValue(const String& commandName) 3611 { 3612 return command(this, commandName).value(); 3613 } 3614 3615 static IntRect placeholderRectForMarker() 3616 { 3617 return IntRect(-1, -1, -1, -1); 3618 } 3619 3620 void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String description) 3621 { 3622 // Use a TextIterator to visit the potentially multiple nodes the range covers. 3623 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 3624 RefPtr<Range> textPiece = markedText.range(); 3625 int exception = 0; 3626 DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description, false}; 3627 addMarker(textPiece->startContainer(exception), marker); 3628 } 3629 } 3630 3631 void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType) 3632 { 3633 if (m_markers.isEmpty()) 3634 return; 3635 3636 ExceptionCode ec = 0; 3637 Node* startContainer = range->startContainer(ec); 3638 Node* endContainer = range->endContainer(ec); 3639 3640 Node* pastLastNode = range->pastLastNode(); 3641 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 3642 int startOffset = node == startContainer ? range->startOffset(ec) : 0; 3643 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX; 3644 int length = endOffset - startOffset; 3645 removeMarkers(node, startOffset, length, markerType); 3646 } 3647 } 3648 3649 // Markers are stored in order sorted by their start offset. 3650 // Markers of the same type do not overlap each other. 3651 3652 void Document::addMarker(Node* node, DocumentMarker newMarker) 3653 { 3654 ASSERT(newMarker.endOffset >= newMarker.startOffset); 3655 if (newMarker.endOffset == newMarker.startOffset) 3656 return; 3657 3658 MarkerMapVectorPair* vectorPair = m_markers.get(node); 3659 3660 if (!vectorPair) { 3661 vectorPair = new MarkerMapVectorPair; 3662 vectorPair->first.append(newMarker); 3663 vectorPair->second.append(placeholderRectForMarker()); 3664 m_markers.set(node, vectorPair); 3665 } else { 3666 Vector<DocumentMarker>& markers = vectorPair->first; 3667 Vector<IntRect>& rects = vectorPair->second; 3668 size_t numMarkers = markers.size(); 3669 ASSERT(numMarkers == rects.size()); 3670 size_t i; 3671 // Iterate over all markers whose start offset is less than or equal to the new marker's. 3672 // If one of them is of the same type as the new marker and touches it or intersects with it 3673 // (there is at most one), remove it and adjust the new marker's start offset to encompass it. 3674 for (i = 0; i < numMarkers; ++i) { 3675 DocumentMarker marker = markers[i]; 3676 if (marker.startOffset > newMarker.startOffset) 3677 break; 3678 if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) { 3679 newMarker.startOffset = marker.startOffset; 3680 markers.remove(i); 3681 rects.remove(i); 3682 numMarkers--; 3683 break; 3684 } 3685 } 3686 size_t j = i; 3687 // Iterate over all markers whose end offset is less than or equal to the new marker's, 3688 // removing markers of the same type as the new marker which touch it or intersect with it, 3689 // adjusting the new marker's end offset to cover them if necessary. 3690 while (j < numMarkers) { 3691 DocumentMarker marker = markers[j]; 3692 if (marker.startOffset > newMarker.endOffset) 3693 break; 3694 if (marker.type == newMarker.type) { 3695 markers.remove(j); 3696 rects.remove(j); 3697 if (newMarker.endOffset <= marker.endOffset) { 3698 newMarker.endOffset = marker.endOffset; 3699 break; 3700 } 3701 numMarkers--; 3702 } else 3703 j++; 3704 } 3705 // At this point i points to the node before which we want to insert. 3706 markers.insert(i, newMarker); 3707 rects.insert(i, placeholderRectForMarker()); 3708 } 3709 3710 // repaint the affected node 3711 if (node->renderer()) 3712 node->renderer()->repaint(); 3713 } 3714 3715 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is 3716 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode. 3717 void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType) 3718 { 3719 if (length <= 0) 3720 return; 3721 3722 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode); 3723 if (!vectorPair) 3724 return; 3725 3726 ASSERT(vectorPair->first.size() == vectorPair->second.size()); 3727 3728 bool docDirty = false; 3729 unsigned endOffset = startOffset + length - 1; 3730 Vector<DocumentMarker>& markers = vectorPair->first; 3731 for (size_t i = 0; i != markers.size(); ++i) { 3732 DocumentMarker marker = markers[i]; 3733 3734 // stop if we are now past the specified range 3735 if (marker.startOffset > endOffset) 3736 break; 3737 3738 // skip marker that is before the specified range or is the wrong type 3739 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) 3740 continue; 3741 3742 // pin the marker to the specified range and apply the shift delta 3743 docDirty = true; 3744 if (marker.startOffset < startOffset) 3745 marker.startOffset = startOffset; 3746 if (marker.endOffset > endOffset) 3747 marker.endOffset = endOffset; 3748 marker.startOffset += delta; 3749 marker.endOffset += delta; 3750 3751 addMarker(dstNode, marker); 3752 } 3753 3754 // repaint the affected node 3755 if (docDirty && dstNode->renderer()) 3756 dstNode->renderer()->repaint(); 3757 } 3758 3759 void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType) 3760 { 3761 if (length <= 0) 3762 return; 3763 3764 MarkerMapVectorPair* vectorPair = m_markers.get(node); 3765 if (!vectorPair) 3766 return; 3767 3768 Vector<DocumentMarker>& markers = vectorPair->first; 3769 Vector<IntRect>& rects = vectorPair->second; 3770 ASSERT(markers.size() == rects.size()); 3771 bool docDirty = false; 3772 unsigned endOffset = startOffset + length; 3773 for (size_t i = 0; i < markers.size();) { 3774 DocumentMarker marker = markers[i]; 3775 3776 // markers are returned in order, so stop if we are now past the specified range 3777 if (marker.startOffset >= endOffset) 3778 break; 3779 3780 // skip marker that is wrong type or before target 3781 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) { 3782 i++; 3783 continue; 3784 } 3785 3786 // at this point we know that marker and target intersect in some way 3787 docDirty = true; 3788 3789 // pitch the old marker and any associated rect 3790 markers.remove(i); 3791 rects.remove(i); 3792 3793 // add either of the resulting slices that are left after removing target 3794 if (startOffset > marker.startOffset) { 3795 DocumentMarker newLeft = marker; 3796 newLeft.endOffset = startOffset; 3797 markers.insert(i, newLeft); 3798 rects.insert(i, placeholderRectForMarker()); 3799 // i now points to the newly-inserted node, but we want to skip that one 3800 i++; 3801 } 3802 if (marker.endOffset > endOffset) { 3803 DocumentMarker newRight = marker; 3804 newRight.startOffset = endOffset; 3805 markers.insert(i, newRight); 3806 rects.insert(i, placeholderRectForMarker()); 3807 // i now points to the newly-inserted node, but we want to skip that one 3808 i++; 3809 } 3810 } 3811 3812 if (markers.isEmpty()) { 3813 ASSERT(rects.isEmpty()); 3814 m_markers.remove(node); 3815 delete vectorPair; 3816 } 3817 3818 // repaint the affected node 3819 if (docDirty && node->renderer()) 3820 node->renderer()->repaint(); 3821 } 3822 3823 DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType) 3824 { 3825 // outer loop: process each node that contains any markers 3826 MarkerMap::iterator end = m_markers.end(); 3827 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 3828 // inner loop; process each marker in this node 3829 MarkerMapVectorPair* vectorPair = nodeIterator->second; 3830 Vector<DocumentMarker>& markers = vectorPair->first; 3831 Vector<IntRect>& rects = vectorPair->second; 3832 ASSERT(markers.size() == rects.size()); 3833 unsigned markerCount = markers.size(); 3834 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 3835 DocumentMarker& marker = markers[markerIndex]; 3836 3837 // skip marker that is wrong type 3838 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) 3839 continue; 3840 3841 IntRect& r = rects[markerIndex]; 3842 3843 // skip placeholder rects 3844 if (r == placeholderRectForMarker()) 3845 continue; 3846 3847 if (r.contains(point)) 3848 return ▮ 3849 } 3850 } 3851 3852 return 0; 3853 } 3854 3855 Vector<DocumentMarker> Document::markersForNode(Node* node) 3856 { 3857 MarkerMapVectorPair* vectorPair = m_markers.get(node); 3858 if (vectorPair) 3859 return vectorPair->first; 3860 return Vector<DocumentMarker>(); 3861 } 3862 3863 Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) 3864 { 3865 Vector<IntRect> result; 3866 3867 // outer loop: process each node 3868 MarkerMap::iterator end = m_markers.end(); 3869 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 3870 // inner loop; process each marker in this node 3871 MarkerMapVectorPair* vectorPair = nodeIterator->second; 3872 Vector<DocumentMarker>& markers = vectorPair->first; 3873 Vector<IntRect>& rects = vectorPair->second; 3874 ASSERT(markers.size() == rects.size()); 3875 unsigned markerCount = markers.size(); 3876 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 3877 DocumentMarker marker = markers[markerIndex]; 3878 3879 // skip marker that is wrong type 3880 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) 3881 continue; 3882 3883 IntRect r = rects[markerIndex]; 3884 // skip placeholder rects 3885 if (r == placeholderRectForMarker()) 3886 continue; 3887 3888 result.append(r); 3889 } 3890 } 3891 3892 return result; 3893 } 3894 3895 void Document::removeMarkers(Node* node) 3896 { 3897 MarkerMap::iterator i = m_markers.find(node); 3898 if (i != m_markers.end()) { 3899 delete i->second; 3900 m_markers.remove(i); 3901 if (RenderObject* renderer = node->renderer()) 3902 renderer->repaint(); 3903 } 3904 } 3905 3906 void Document::removeMarkers(DocumentMarker::MarkerType markerType) 3907 { 3908 // outer loop: process each markered node in the document 3909 MarkerMap markerMapCopy = m_markers; 3910 MarkerMap::iterator end = markerMapCopy.end(); 3911 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) { 3912 Node* node = i->first.get(); 3913 bool nodeNeedsRepaint = false; 3914 3915 // inner loop: process each marker in the current node 3916 MarkerMapVectorPair* vectorPair = i->second; 3917 Vector<DocumentMarker>& markers = vectorPair->first; 3918 Vector<IntRect>& rects = vectorPair->second; 3919 ASSERT(markers.size() == rects.size()); 3920 for (size_t i = 0; i != markers.size();) { 3921 DocumentMarker marker = markers[i]; 3922 3923 // skip nodes that are not of the specified type 3924 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) { 3925 ++i; 3926 continue; 3927 } 3928 3929 // pitch the old marker 3930 markers.remove(i); 3931 rects.remove(i); 3932 nodeNeedsRepaint = true; 3933 // markerIterator now points to the next node 3934 } 3935 3936 // Redraw the node if it changed. Do this before the node is removed from m_markers, since 3937 // m_markers might contain the last reference to the node. 3938 if (nodeNeedsRepaint) { 3939 RenderObject* renderer = node->renderer(); 3940 if (renderer) 3941 renderer->repaint(); 3942 } 3943 3944 // delete the node's list if it is now empty 3945 if (markers.isEmpty()) { 3946 ASSERT(rects.isEmpty()); 3947 m_markers.remove(node); 3948 delete vectorPair; 3949 } 3950 } 3951 } 3952 3953 void Document::repaintMarkers(DocumentMarker::MarkerType markerType) 3954 { 3955 // outer loop: process each markered node in the document 3956 MarkerMap::iterator end = m_markers.end(); 3957 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 3958 Node* node = i->first.get(); 3959 3960 // inner loop: process each marker in the current node 3961 MarkerMapVectorPair* vectorPair = i->second; 3962 Vector<DocumentMarker>& markers = vectorPair->first; 3963 bool nodeNeedsRepaint = false; 3964 for (size_t i = 0; i != markers.size(); ++i) { 3965 DocumentMarker marker = markers[i]; 3966 3967 // skip nodes that are not of the specified type 3968 if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) { 3969 nodeNeedsRepaint = true; 3970 break; 3971 } 3972 } 3973 3974 if (!nodeNeedsRepaint) 3975 continue; 3976 3977 // cause the node to be redrawn 3978 if (RenderObject* renderer = node->renderer()) 3979 renderer->repaint(); 3980 } 3981 } 3982 3983 void Document::setRenderedRectForMarker(Node* node, const DocumentMarker& marker, const IntRect& r) 3984 { 3985 MarkerMapVectorPair* vectorPair = m_markers.get(node); 3986 if (!vectorPair) { 3987 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about 3988 return; 3989 } 3990 3991 Vector<DocumentMarker>& markers = vectorPair->first; 3992 ASSERT(markers.size() == vectorPair->second.size()); 3993 unsigned markerCount = markers.size(); 3994 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 3995 DocumentMarker m = markers[markerIndex]; 3996 if (m == marker) { 3997 vectorPair->second[markerIndex] = r; 3998 return; 3999 } 4000 } 4001 4002 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about 4003 } 4004 4005 void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r) 4006 { 4007 // outer loop: process each markered node in the document 4008 MarkerMap::iterator end = m_markers.end(); 4009 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 4010 4011 // inner loop: process each rect in the current node 4012 MarkerMapVectorPair* vectorPair = i->second; 4013 Vector<IntRect>& rects = vectorPair->second; 4014 4015 unsigned rectCount = rects.size(); 4016 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex) 4017 if (rects[rectIndex].intersects(r)) 4018 rects[rectIndex] = placeholderRectForMarker(); 4019 } 4020 } 4021 4022 void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType) 4023 { 4024 MarkerMapVectorPair* vectorPair = m_markers.get(node); 4025 if (!vectorPair) 4026 return; 4027 4028 Vector<DocumentMarker>& markers = vectorPair->first; 4029 Vector<IntRect>& rects = vectorPair->second; 4030 ASSERT(markers.size() == rects.size()); 4031 4032 bool docDirty = false; 4033 for (size_t i = 0; i != markers.size(); ++i) { 4034 DocumentMarker &marker = markers[i]; 4035 if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) { 4036 ASSERT((int)marker.startOffset + delta >= 0); 4037 marker.startOffset += delta; 4038 marker.endOffset += delta; 4039 docDirty = true; 4040 4041 // Marker moved, so previously-computed rendered rectangle is now invalid 4042 rects[i] = placeholderRectForMarker(); 4043 } 4044 } 4045 4046 // repaint the affected node 4047 if (docDirty && node->renderer()) 4048 node->renderer()->repaint(); 4049 } 4050 4051 void Document::setMarkersActive(Range* range, bool active) 4052 { 4053 if (m_markers.isEmpty()) 4054 return; 4055 4056 ExceptionCode ec = 0; 4057 Node* startContainer = range->startContainer(ec); 4058 Node* endContainer = range->endContainer(ec); 4059 4060 Node* pastLastNode = range->pastLastNode(); 4061 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 4062 int startOffset = node == startContainer ? range->startOffset(ec) : 0; 4063 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX; 4064 setMarkersActive(node, startOffset, endOffset, active); 4065 } 4066 } 4067 4068 void Document::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active) 4069 { 4070 MarkerMapVectorPair* vectorPair = m_markers.get(node); 4071 if (!vectorPair) 4072 return; 4073 4074 Vector<DocumentMarker>& markers = vectorPair->first; 4075 ASSERT(markers.size() == vectorPair->second.size()); 4076 4077 bool docDirty = false; 4078 for (size_t i = 0; i != markers.size(); ++i) { 4079 DocumentMarker &marker = markers[i]; 4080 4081 // Markers are returned in order, so stop if we are now past the specified range. 4082 if (marker.startOffset >= endOffset) 4083 break; 4084 4085 // Skip marker that is wrong type or before target. 4086 if (marker.endOffset < startOffset || marker.type != DocumentMarker::TextMatch) 4087 continue; 4088 4089 marker.activeMatch = active; 4090 docDirty = true; 4091 } 4092 4093 // repaint the affected node 4094 if (docDirty && node->renderer()) 4095 node->renderer()->repaint(); 4096 } 4097 4098 #if ENABLE(XSLT) 4099 4100 void Document::applyXSLTransform(ProcessingInstruction* pi) 4101 { 4102 RefPtr<XSLTProcessor> processor = XSLTProcessor::create(); 4103 processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet())); 4104 String resultMIMEType; 4105 String newSource; 4106 String resultEncoding; 4107 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding)) 4108 return; 4109 // FIXME: If the transform failed we should probably report an error (like Mozilla does). 4110 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame()); 4111 } 4112 4113 void Document::setTransformSource(PassOwnPtr<TransformSource> source) 4114 { 4115 if (m_transformSource == source) 4116 return; 4117 m_transformSource = source; 4118 } 4119 4120 #endif 4121 4122 void Document::setDesignMode(InheritedBool value) 4123 { 4124 m_designMode = value; 4125 } 4126 4127 Document::InheritedBool Document::getDesignMode() const 4128 { 4129 return m_designMode; 4130 } 4131 4132 bool Document::inDesignMode() const 4133 { 4134 for (const Document* d = this; d; d = d->parentDocument()) { 4135 if (d->m_designMode != inherit) 4136 return d->m_designMode; 4137 } 4138 return false; 4139 } 4140 4141 Document *Document::parentDocument() const 4142 { 4143 Frame *childPart = frame(); 4144 if (!childPart) 4145 return 0; 4146 Frame *parent = childPart->tree()->parent(); 4147 if (!parent) 4148 return 0; 4149 return parent->document(); 4150 } 4151 4152 Document *Document::topDocument() const 4153 { 4154 Document *doc = const_cast<Document *>(this); 4155 Element *element; 4156 while ((element = doc->ownerElement())) 4157 doc = element->document(); 4158 4159 return doc; 4160 } 4161 4162 PassRefPtr<Attr> Document::createAttribute(const String& name, ExceptionCode& ec) 4163 { 4164 return createAttributeNS(String(), name, ec, true); 4165 } 4166 4167 PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks) 4168 { 4169 String prefix, localName; 4170 if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) 4171 return 0; 4172 4173 QualifiedName qName(prefix, localName, namespaceURI); 4174 if (!shouldIgnoreNamespaceChecks && hasPrefixNamespaceMismatch(qName)) { 4175 ec = NAMESPACE_ERR; 4176 return 0; 4177 } 4178 4179 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrAttrNS 4180 if (!shouldIgnoreNamespaceChecks && qName.localName() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { 4181 ec = NAMESPACE_ERR; 4182 return 0; 4183 } 4184 4185 // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML 4186 // documents if we're wrong. 4187 return Attr::create(0, this, MappedAttribute::create(qName, StringImpl::empty())); 4188 } 4189 4190 #if ENABLE(SVG) 4191 const SVGDocumentExtensions* Document::svgExtensions() 4192 { 4193 return m_svgExtensions.get(); 4194 } 4195 4196 SVGDocumentExtensions* Document::accessSVGExtensions() 4197 { 4198 if (!m_svgExtensions) 4199 m_svgExtensions.set(new SVGDocumentExtensions(this)); 4200 return m_svgExtensions.get(); 4201 } 4202 #endif 4203 4204 PassRefPtr<HTMLCollection> Document::images() 4205 { 4206 return HTMLCollection::create(this, DocImages); 4207 } 4208 4209 PassRefPtr<HTMLCollection> Document::applets() 4210 { 4211 return HTMLCollection::create(this, DocApplets); 4212 } 4213 4214 PassRefPtr<HTMLCollection> Document::embeds() 4215 { 4216 return HTMLCollection::create(this, DocEmbeds); 4217 } 4218 4219 PassRefPtr<HTMLCollection> Document::plugins() 4220 { 4221 // This is an alias for embeds() required for the JS DOM bindings. 4222 return HTMLCollection::create(this, DocEmbeds); 4223 } 4224 4225 PassRefPtr<HTMLCollection> Document::objects() 4226 { 4227 return HTMLCollection::create(this, DocObjects); 4228 } 4229 4230 PassRefPtr<HTMLCollection> Document::scripts() 4231 { 4232 return HTMLCollection::create(this, DocScripts); 4233 } 4234 4235 PassRefPtr<HTMLCollection> Document::links() 4236 { 4237 return HTMLCollection::create(this, DocLinks); 4238 } 4239 4240 PassRefPtr<HTMLCollection> Document::forms() 4241 { 4242 return HTMLCollection::create(this, DocForms); 4243 } 4244 4245 PassRefPtr<HTMLCollection> Document::anchors() 4246 { 4247 return HTMLCollection::create(this, DocAnchors); 4248 } 4249 4250 PassRefPtr<HTMLAllCollection> Document::all() 4251 { 4252 return HTMLAllCollection::create(this); 4253 } 4254 4255 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name) 4256 { 4257 return HTMLNameCollection::create(this, WindowNamedItems, name); 4258 } 4259 4260 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name) 4261 { 4262 return HTMLNameCollection::create(this, DocumentNamedItems, name); 4263 } 4264 4265 CollectionCache* Document::nameCollectionInfo(CollectionType type, const AtomicString& name) 4266 { 4267 ASSERT(type >= FirstNamedDocumentCachedType); 4268 unsigned index = type - FirstNamedDocumentCachedType; 4269 ASSERT(index < NumNamedDocumentCachedTypes); 4270 4271 NamedCollectionMap& map = m_nameCollectionInfo[index]; 4272 NamedCollectionMap::iterator iter = map.find(name.impl()); 4273 if (iter == map.end()) 4274 iter = map.add(name.impl(), new CollectionCache).first; 4275 iter->second->checkConsistency(); 4276 return iter->second; 4277 } 4278 4279 void Document::finishedParsing() 4280 { 4281 setParsing(false); 4282 dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false)); 4283 if (Frame* f = frame()) { 4284 f->loader()->finishedParsing(); 4285 4286 #if ENABLE(INSPECTOR) 4287 if (!page()) 4288 return; 4289 4290 if (InspectorController* controller = page()->inspectorController()) 4291 controller->mainResourceFiredDOMContentEvent(f->loader()->documentLoader(), url()); 4292 #endif 4293 } 4294 } 4295 4296 Vector<String> Document::formElementsState() const 4297 { 4298 Vector<String> stateVector; 4299 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3); 4300 typedef ListHashSet<Element*>::const_iterator Iterator; 4301 Iterator end = m_formElementsWithState.end(); 4302 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) { 4303 Element* e = *it; 4304 String value; 4305 if (e->saveFormControlState(value)) { 4306 stateVector.append(e->formControlName().string()); 4307 stateVector.append(e->formControlType().string()); 4308 stateVector.append(value); 4309 } 4310 } 4311 return stateVector; 4312 } 4313 4314 #if ENABLE(XPATH) 4315 4316 PassRefPtr<XPathExpression> Document::createExpression(const String& expression, 4317 XPathNSResolver* resolver, 4318 ExceptionCode& ec) 4319 { 4320 if (!m_xpathEvaluator) 4321 m_xpathEvaluator = XPathEvaluator::create(); 4322 return m_xpathEvaluator->createExpression(expression, resolver, ec); 4323 } 4324 4325 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver) 4326 { 4327 if (!m_xpathEvaluator) 4328 m_xpathEvaluator = XPathEvaluator::create(); 4329 return m_xpathEvaluator->createNSResolver(nodeResolver); 4330 } 4331 4332 PassRefPtr<XPathResult> Document::evaluate(const String& expression, 4333 Node* contextNode, 4334 XPathNSResolver* resolver, 4335 unsigned short type, 4336 XPathResult* result, 4337 ExceptionCode& ec) 4338 { 4339 if (!m_xpathEvaluator) 4340 m_xpathEvaluator = XPathEvaluator::create(); 4341 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); 4342 } 4343 4344 #endif // ENABLE(XPATH) 4345 4346 void Document::setStateForNewFormElements(const Vector<String>& stateVector) 4347 { 4348 // Walk the state vector backwards so that the value to use for each 4349 // name/type pair first is the one at the end of each individual vector 4350 // in the FormElementStateMap. We're using them like stacks. 4351 typedef FormElementStateMap::iterator Iterator; 4352 m_formElementsWithState.clear(); 4353 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) { 4354 AtomicString a = stateVector[i - 3]; 4355 AtomicString b = stateVector[i - 2]; 4356 const String& c = stateVector[i - 1]; 4357 FormElementKey key(a.impl(), b.impl()); 4358 Iterator it = m_stateForNewFormElements.find(key); 4359 if (it != m_stateForNewFormElements.end()) 4360 it->second.append(c); 4361 else { 4362 Vector<String> v(1); 4363 v[0] = c; 4364 m_stateForNewFormElements.set(key, v); 4365 } 4366 } 4367 } 4368 4369 bool Document::hasStateForNewFormElements() const 4370 { 4371 return !m_stateForNewFormElements.isEmpty(); 4372 } 4373 4374 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state) 4375 { 4376 typedef FormElementStateMap::iterator Iterator; 4377 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type)); 4378 if (it == m_stateForNewFormElements.end()) 4379 return false; 4380 ASSERT(it->second.size()); 4381 state = it->second.last(); 4382 if (it->second.size() > 1) 4383 it->second.removeLast(); 4384 else 4385 m_stateForNewFormElements.remove(it); 4386 return true; 4387 } 4388 4389 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type) 4390 : m_name(name), m_type(type) 4391 { 4392 ref(); 4393 } 4394 4395 FormElementKey::~FormElementKey() 4396 { 4397 deref(); 4398 } 4399 4400 FormElementKey::FormElementKey(const FormElementKey& other) 4401 : m_name(other.name()), m_type(other.type()) 4402 { 4403 ref(); 4404 } 4405 4406 FormElementKey& FormElementKey::operator=(const FormElementKey& other) 4407 { 4408 other.ref(); 4409 deref(); 4410 m_name = other.name(); 4411 m_type = other.type(); 4412 return *this; 4413 } 4414 4415 void FormElementKey::ref() const 4416 { 4417 if (name()) 4418 name()->ref(); 4419 if (type()) 4420 type()->ref(); 4421 } 4422 4423 void FormElementKey::deref() const 4424 { 4425 if (name()) 4426 name()->deref(); 4427 if (type()) 4428 type()->deref(); 4429 } 4430 4431 unsigned FormElementKeyHash::hash(const FormElementKey& k) 4432 { 4433 ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0); 4434 4435 unsigned l = sizeof(k) / (sizeof(uint16_t) * 2); 4436 const uint16_t* s = reinterpret_cast<const uint16_t*>(&k); 4437 uint32_t hash = WTF::stringHashingStartValue; 4438 4439 // Main loop 4440 for (; l > 0; l--) { 4441 hash += s[0]; 4442 uint32_t tmp = (s[1] << 11) ^ hash; 4443 hash = (hash << 16) ^ tmp; 4444 s += 2; 4445 hash += hash >> 11; 4446 } 4447 4448 // Force "avalanching" of final 127 bits 4449 hash ^= hash << 3; 4450 hash += hash >> 5; 4451 hash ^= hash << 2; 4452 hash += hash >> 15; 4453 hash ^= hash << 10; 4454 4455 // this avoids ever returning a hash code of 0, since that is used to 4456 // signal "hash not computed yet", using a value that is likely to be 4457 // effectively the same as 0 when the low bits are masked 4458 if (hash == 0) 4459 hash = 0x80000000; 4460 4461 return hash; 4462 } 4463 4464 void Document::setIconURL(const String& iconURL, const String& type) 4465 { 4466 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type" 4467 if (m_iconURL.isEmpty()) 4468 m_iconURL = iconURL; 4469 else if (!type.isEmpty()) 4470 m_iconURL = iconURL; 4471 } 4472 4473 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard) 4474 { 4475 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard) 4476 return; 4477 4478 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard; 4479 m_frame->updateSecureKeyboardEntryIfActive(); 4480 } 4481 4482 bool Document::useSecureKeyboardEntryWhenActive() const 4483 { 4484 return m_useSecureKeyboardEntryWhenActive; 4485 } 4486 4487 void Document::initSecurityContext() 4488 { 4489 if (securityOrigin() && !securityOrigin()->isEmpty()) 4490 return; // m_securityOrigin has already been initialized. 4491 4492 if (!m_frame) { 4493 // No source for a security context. 4494 // This can occur via document.implementation.createDocument(). 4495 m_cookieURL = KURL(ParsedURLString, ""); 4496 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createEmpty()); 4497 return; 4498 } 4499 4500 // In the common case, create the security context from the currently 4501 // loading URL. 4502 const KURL& url = m_frame->loader()->url(); 4503 m_cookieURL = url; 4504 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(url, m_frame->loader()->sandboxFlags())); 4505 4506 if (SecurityOrigin::allowSubstituteDataAccessToLocal()) { 4507 // If this document was loaded with substituteData, then the document can 4508 // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756 4509 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further 4510 // discussion. 4511 DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); 4512 if (documentLoader && documentLoader->substituteData().isValid()) 4513 securityOrigin()->grantLoadLocalResources(); 4514 } 4515 4516 if (Settings* settings = this->settings()) { 4517 if (!settings->isWebSecurityEnabled()) { 4518 // Web security is turned off. We should let this document access every 4519 // other document. This is used primary by testing harnesses for web 4520 // sites. 4521 securityOrigin()->grantUniversalAccess(); 4522 4523 } else if (settings->allowUniversalAccessFromFileURLs() && securityOrigin()->isLocal()) { 4524 // Some clients want file:// URLs to have universal access, but that 4525 // setting is dangerous for other clients. 4526 securityOrigin()->grantUniversalAccess(); 4527 } 4528 } 4529 4530 if (!securityOrigin()->isEmpty()) 4531 return; 4532 4533 // If we do not obtain a meaningful origin from the URL, then we try to 4534 // find one via the frame hierarchy. 4535 4536 Frame* ownerFrame = m_frame->tree()->parent(); 4537 if (!ownerFrame) 4538 ownerFrame = m_frame->loader()->opener(); 4539 4540 if (ownerFrame) { 4541 m_cookieURL = ownerFrame->document()->cookieURL(); 4542 // We alias the SecurityOrigins to match Firefox, see Bug 15313 4543 // https://bugs.webkit.org/show_bug.cgi?id=15313 4544 ScriptExecutionContext::setSecurityOrigin(ownerFrame->document()->securityOrigin()); 4545 } 4546 } 4547 4548 void Document::setSecurityOrigin(SecurityOrigin* securityOrigin) 4549 { 4550 ScriptExecutionContext::setSecurityOrigin(securityOrigin); 4551 // FIXME: Find a better place to enable DNS prefetch, which is a loader concept, 4552 // not applicable to arbitrary documents. 4553 initDNSPrefetch(); 4554 } 4555 4556 #if ENABLE(DATABASE) 4557 4558 bool Document::isDatabaseReadOnly() const 4559 { 4560 if (!page() || page()->settings()->privateBrowsingEnabled()) 4561 return true; 4562 return false; 4563 } 4564 4565 void Document::databaseExceededQuota(const String& name) 4566 { 4567 Page* currentPage = page(); 4568 if (currentPage) 4569 currentPage->chrome()->client()->exceededDatabaseQuota(document()->frame(), name); 4570 } 4571 4572 #endif 4573 4574 bool Document::isContextThread() const 4575 { 4576 return isMainThread(); 4577 } 4578 4579 void Document::updateURLForPushOrReplaceState(const KURL& url) 4580 { 4581 Frame* f = frame(); 4582 if (!f) 4583 return; 4584 4585 setURL(url); 4586 f->loader()->documentLoader()->replaceRequestURLForSameDocumentNavigation(url); 4587 } 4588 4589 void Document::statePopped(SerializedScriptValue* stateObject) 4590 { 4591 Frame* f = frame(); 4592 if (!f) 4593 return; 4594 4595 if (f->loader()->isComplete()) 4596 dispatchWindowEvent(PopStateEvent::create(stateObject)); 4597 else 4598 m_pendingStateObject = stateObject; 4599 } 4600 4601 void Document::updateFocusAppearanceSoon(bool restorePreviousSelection) 4602 { 4603 m_updateFocusAppearanceRestoresSelection = restorePreviousSelection; 4604 if (!m_updateFocusAppearanceTimer.isActive()) 4605 m_updateFocusAppearanceTimer.startOneShot(0); 4606 } 4607 4608 void Document::cancelFocusAppearanceUpdate() 4609 { 4610 m_updateFocusAppearanceTimer.stop(); 4611 } 4612 4613 void Document::updateFocusAppearanceTimerFired(Timer<Document>*) 4614 { 4615 Node* node = focusedNode(); 4616 if (!node) 4617 return; 4618 if (!node->isElementNode()) 4619 return; 4620 4621 updateLayout(); 4622 4623 Element* element = static_cast<Element*>(node); 4624 if (element->isFocusable()) 4625 element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection); 4626 } 4627 4628 void Document::executeScriptSoonTimerFired(Timer<Document>* timer) 4629 { 4630 ASSERT_UNUSED(timer, timer == &m_executeScriptSoonTimer); 4631 4632 Vector<pair<ScriptElementData*, CachedResourceHandle<CachedScript> > > scripts; 4633 scripts.swap(m_scriptsToExecuteSoon); 4634 size_t size = scripts.size(); 4635 for (size_t i = 0; i < size; ++i) { 4636 scripts[i].first->execute(scripts[i].second.get()); 4637 scripts[i].first->element()->deref(); // Balances ref() in executeScriptSoon(). 4638 } 4639 } 4640 4641 void Document::executeScriptSoon(ScriptElementData* data, CachedResourceHandle<CachedScript> cachedScript) 4642 { 4643 ASSERT_ARG(data, data); 4644 4645 Element* element = data->element(); 4646 ASSERT(element); 4647 ASSERT(element->document() == this); 4648 ASSERT(element->inDocument()); 4649 4650 m_scriptsToExecuteSoon.append(make_pair(data, cachedScript)); 4651 element->ref(); // Balanced by deref()s in executeScriptSoonTimerFired() and ~Document(). 4652 if (!m_executeScriptSoonTimer.isActive()) 4653 m_executeScriptSoonTimer.startOneShot(0); 4654 } 4655 4656 // FF method for accessing the selection added for compatibility. 4657 DOMSelection* Document::getSelection() const 4658 { 4659 return frame() ? frame()->domWindow()->getSelection() : 0; 4660 } 4661 4662 #if ENABLE(WML) 4663 void Document::resetWMLPageState() 4664 { 4665 if (WMLPageState* pageState = wmlPageStateForDocument(this)) 4666 pageState->reset(); 4667 } 4668 4669 void Document::initializeWMLPageState() 4670 { 4671 if (!isWMLDocument()) 4672 return; 4673 4674 static_cast<WMLDocument*>(this)->initialize(); 4675 } 4676 #endif 4677 4678 void Document::attachRange(Range* range) 4679 { 4680 ASSERT(!m_ranges.contains(range)); 4681 m_ranges.add(range); 4682 } 4683 4684 void Document::detachRange(Range* range) 4685 { 4686 // We don't ASSERT m_ranges.contains(range) to allow us to call this 4687 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044 4688 m_ranges.remove(range); 4689 } 4690 4691 CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height) 4692 { 4693 HTMLCanvasElement* result = getCSSCanvasElement(name); 4694 if (!result) 4695 return 0; 4696 result->setSize(IntSize(width, height)); 4697 return result->getContext(type); 4698 } 4699 4700 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name) 4701 { 4702 RefPtr<HTMLCanvasElement> result = m_cssCanvasElements.get(name).get(); 4703 if (!result) { 4704 result = new HTMLCanvasElement(canvasTag, this); 4705 m_cssCanvasElements.set(name, result); 4706 } 4707 return result.get(); 4708 } 4709 4710 void Document::initDNSPrefetch() 4711 { 4712 m_haveExplicitlyDisabledDNSPrefetch = false; 4713 m_isDNSPrefetchEnabled = securityOrigin()->protocol() == "http"; 4714 4715 // Inherit DNS prefetch opt-out from parent frame 4716 if (Document* parent = parentDocument()) { 4717 if (!parent->isDNSPrefetchEnabled()) 4718 m_isDNSPrefetchEnabled = false; 4719 } 4720 } 4721 4722 void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl) 4723 { 4724 if (equalIgnoringCase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) { 4725 m_isDNSPrefetchEnabled = true; 4726 return; 4727 } 4728 4729 m_isDNSPrefetchEnabled = false; 4730 m_haveExplicitlyDisabledDNSPrefetch = true; 4731 } 4732 4733 void Document::reportException(const String& errorMessage, int lineNumber, const String& sourceURL) 4734 { 4735 if (DOMWindow* window = domWindow()) 4736 window->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, errorMessage, lineNumber, sourceURL); 4737 } 4738 4739 void Document::addMessage(MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) 4740 { 4741 switch (destination) { 4742 #if ENABLE(INSPECTOR) 4743 case InspectorControllerDestination: 4744 if (page()) 4745 page()->inspectorController()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL); 4746 return; 4747 #endif 4748 case ConsoleDestination: 4749 if (DOMWindow* window = domWindow()) 4750 window->console()->addMessage(source, type, level, message, lineNumber, sourceURL); 4751 return; 4752 } 4753 ASSERT_NOT_REACHED(); 4754 } 4755 4756 void Document::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString) 4757 { 4758 #if ENABLE(INSPECTOR) 4759 if (page()) 4760 page()->inspectorController()->resourceRetrievedByXMLHttpRequest(identifier, sourceString); 4761 #endif 4762 Frame* frame = this->frame(); 4763 if (frame) { 4764 FrameLoader* frameLoader = frame->loader(); 4765 frameLoader->notifier()->didLoadResourceByXMLHttpRequest(identifier, sourceString); 4766 } 4767 } 4768 4769 void Document::scriptImported(unsigned long identifier, const String& sourceString) 4770 { 4771 #if ENABLE(INSPECTOR) 4772 if (page()) 4773 page()->inspectorController()->scriptImported(identifier, sourceString); 4774 #else 4775 UNUSED_PARAM(identifier); 4776 UNUSED_PARAM(sourceString); 4777 #endif 4778 } 4779 4780 class ScriptExecutionContextTaskTimer : public TimerBase { 4781 public: 4782 ScriptExecutionContextTaskTimer(PassRefPtr<Document> context, PassOwnPtr<ScriptExecutionContext::Task> task) 4783 : m_context(context) 4784 , m_task(task) 4785 { 4786 } 4787 4788 private: 4789 virtual void fired() 4790 { 4791 m_task->performTask(m_context.get()); 4792 delete this; 4793 } 4794 4795 RefPtr<Document> m_context; 4796 OwnPtr<ScriptExecutionContext::Task> m_task; 4797 }; 4798 4799 struct PerformTaskContext : Noncopyable { 4800 PerformTaskContext(PassRefPtr<DocumentWeakReference> documentReference, PassOwnPtr<ScriptExecutionContext::Task> task) 4801 : documentReference(documentReference) 4802 , task(task) 4803 { 4804 } 4805 4806 RefPtr<DocumentWeakReference> documentReference; 4807 OwnPtr<ScriptExecutionContext::Task> task; 4808 }; 4809 4810 static void performTask(void* ctx) 4811 { 4812 ASSERT(isMainThread()); 4813 4814 PerformTaskContext* context = reinterpret_cast<PerformTaskContext*>(ctx); 4815 ASSERT(context); 4816 4817 if (Document* document = context->documentReference->document()) 4818 context->task->performTask(document); 4819 4820 delete context; 4821 } 4822 4823 void Document::postTask(PassOwnPtr<Task> task) 4824 { 4825 if (isMainThread()) { 4826 ScriptExecutionContextTaskTimer* timer = new ScriptExecutionContextTaskTimer(static_cast<Document*>(this), task); 4827 timer->startOneShot(0); 4828 } else { 4829 callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task)); 4830 } 4831 } 4832 4833 Element* Document::findAnchor(const String& name) 4834 { 4835 if (name.isEmpty()) 4836 return 0; 4837 if (Element* element = getElementById(name)) 4838 return element; 4839 for (Node* node = this; node; node = node->traverseNextNode()) { 4840 if (node->hasTagName(aTag)) { 4841 HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); 4842 if (inCompatMode()) { 4843 // Quirks mode, case insensitive comparison of names. 4844 if (equalIgnoringCase(anchor->name(), name)) 4845 return anchor; 4846 } else { 4847 // Strict mode, names need to match exactly. 4848 if (anchor->name() == name) 4849 return anchor; 4850 } 4851 } 4852 } 4853 return 0; 4854 } 4855 4856 String Document::displayStringModifiedByEncoding(const String& str) const 4857 { 4858 if (m_decoder) 4859 return m_decoder->encoding().displayString(str.impl()); 4860 return str; 4861 } 4862 4863 PassRefPtr<StringImpl> Document::displayStringModifiedByEncoding(PassRefPtr<StringImpl> str) const 4864 { 4865 if (m_decoder) 4866 return m_decoder->encoding().displayString(str); 4867 return str; 4868 } 4869 4870 void Document::displayBufferModifiedByEncoding(UChar* buffer, unsigned len) const 4871 { 4872 if (m_decoder) 4873 m_decoder->encoding().displayBuffer(buffer, len); 4874 } 4875 4876 #if ENABLE(XHTMLMP) 4877 bool Document::isXHTMLMPDocument() const 4878 { 4879 if (!frame() || !frame()->loader()) 4880 return false; 4881 // As per section 7.2 of OMA-WAP-XHTMLMP-V1_1-20061020-A.pdf, a conforming user agent 4882 // MUST accept XHTMLMP document identified as "application/vnd.wap.xhtml+xml" 4883 // and SHOULD accept it identified as "application/xhtml+xml" 4884 return frame()->loader()->responseMIMEType() == "application/vnd.wap.xhtml+xml" || frame()->loader()->responseMIMEType() == "application/xhtml+xml"; 4885 } 4886 #endif 4887 4888 #if ENABLE(INSPECTOR) 4889 InspectorTimelineAgent* Document::inspectorTimelineAgent() const 4890 { 4891 return page() ? page()->inspectorTimelineAgent() : 0; 4892 } 4893 #endif 4894 4895 #if ENABLE(TOUCH_EVENTS) 4896 PassRefPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, int pageX, int pageY, int screenX, int screenY, ExceptionCode&) const 4897 { 4898 // FIXME: It's not clear from the documentation at 4899 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html 4900 // when this method should throw and nor is it by inspection of iOS behavior. It would be nice to verify any cases where it throws under iOS 4901 // and implement them here. See https://bugs.webkit.org/show_bug.cgi?id=47819 4902 // Ditto for the createTouchList method below. 4903 Frame* frame = window ? window->frame() : this->frame(); 4904 return Touch::create(frame, target, identifier, screenX, screenY, pageX, pageY); 4905 } 4906 4907 PassRefPtr<TouchList> Document::createTouchList(ExceptionCode&) const 4908 { 4909 return TouchList::create(); 4910 } 4911 #endif 4912 4913 } // namespace WebCore 4914