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