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