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, 2012 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, 2011, 2012 Google Inc. All rights reserved. 9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Library General Public 14 * License as published by the Free Software Foundation; either 15 * version 2 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Library General Public License for more details. 21 * 22 * You should have received a copy of the GNU Library General Public License 23 * along with this library; see the file COPYING.LIB. If not, write to 24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 * Boston, MA 02110-1301, USA. 26 */ 27 28 #include "config.h" 29 #include "core/dom/Document.h" 30 31 #include "HTMLElementFactory.h" 32 #include "HTMLNames.h" 33 #include "RuntimeEnabledFeatures.h" 34 #include "SVGElementFactory.h" 35 #include "SVGNames.h" 36 #include "XMLNSNames.h" 37 #include "XMLNames.h" 38 #include "bindings/v8/CustomElementConstructorBuilder.h" 39 #include "bindings/v8/Dictionary.h" 40 #include "bindings/v8/ExceptionMessages.h" 41 #include "bindings/v8/ExceptionState.h" 42 #include "bindings/v8/ExceptionStatePlaceholder.h" 43 #include "bindings/v8/ScriptController.h" 44 #include "core/accessibility/AXObjectCache.h" 45 #include "core/animation/AnimationClock.h" 46 #include "core/animation/DocumentAnimations.h" 47 #include "core/animation/DocumentTimeline.h" 48 #include "core/animation/css/TransitionTimeline.h" 49 #include "core/css/CSSDefaultStyleSheets.h" 50 #include "core/css/CSSFontSelector.h" 51 #include "core/css/CSSStyleDeclaration.h" 52 #include "core/css/CSSStyleSheet.h" 53 #include "core/css/MediaQueryMatcher.h" 54 #include "core/css/StylePropertySet.h" 55 #include "core/css/StyleSheetContents.h" 56 #include "core/css/StyleSheetList.h" 57 #include "core/css/resolver/FontBuilder.h" 58 #include "core/css/resolver/StyleResolver.h" 59 #include "core/css/resolver/StyleResolverStats.h" 60 #include "core/dom/AddConsoleMessageTask.h" 61 #include "core/dom/Attr.h" 62 #include "core/dom/CDATASection.h" 63 #include "core/dom/Comment.h" 64 #include "core/dom/ContextFeatures.h" 65 #include "core/dom/DOMImplementation.h" 66 #include "core/dom/DOMNamedFlowCollection.h" 67 #include "core/dom/DocumentFragment.h" 68 #include "core/dom/DocumentLifecycleNotifier.h" 69 #include "core/dom/DocumentLifecycleObserver.h" 70 #include "core/dom/DocumentMarkerController.h" 71 #include "core/dom/DocumentSharedObjectPool.h" 72 #include "core/dom/DocumentType.h" 73 #include "core/dom/Element.h" 74 #include "core/dom/ElementTraversal.h" 75 #include "core/dom/ExceptionCode.h" 76 #include "core/dom/ExecutionContextTask.h" 77 #include "core/dom/MainThreadTaskRunner.h" 78 #include "core/dom/NamedFlowCollection.h" 79 #include "core/dom/NodeChildRemovalTracker.h" 80 #include "core/dom/NodeFilter.h" 81 #include "core/dom/NodeIterator.h" 82 #include "core/dom/NodeRareData.h" 83 #include "core/dom/NodeRenderStyle.h" 84 #include "core/dom/NodeRenderingTraversal.h" 85 #include "core/dom/NodeTraversal.h" 86 #include "core/dom/NodeWithIndex.h" 87 #include "core/dom/PostAttachCallbacks.h" 88 #include "core/dom/ProcessingInstruction.h" 89 #include "core/dom/RequestAnimationFrameCallback.h" 90 #include "core/dom/ScriptRunner.h" 91 #include "core/dom/ScriptedAnimationController.h" 92 #include "core/dom/SelectorQuery.h" 93 #include "core/dom/StyleEngine.h" 94 #include "core/dom/TouchList.h" 95 #include "core/dom/TransformSource.h" 96 #include "core/dom/TreeWalker.h" 97 #include "core/dom/VisitedLinkState.h" 98 #include "core/dom/custom/CustomElementRegistrationContext.h" 99 #include "core/dom/shadow/ElementShadow.h" 100 #include "core/dom/shadow/ShadowRoot.h" 101 #include "core/editing/Editor.h" 102 #include "core/editing/FrameSelection.h" 103 #include "core/editing/SpellChecker.h" 104 #include "core/events/BeforeUnloadEvent.h" 105 #include "core/events/Event.h" 106 #include "core/events/EventFactory.h" 107 #include "core/events/EventListener.h" 108 #include "core/events/HashChangeEvent.h" 109 #include "core/events/PageTransitionEvent.h" 110 #include "core/events/ScopedEventQueue.h" 111 #include "core/events/ThreadLocalEventNames.h" 112 #include "core/fetch/ResourceFetcher.h" 113 #include "core/fetch/TextResourceDecoder.h" 114 #include "core/frame/ContentSecurityPolicy.h" 115 #include "core/frame/DOMSecurityPolicy.h" 116 #include "core/frame/DOMWindow.h" 117 #include "core/frame/Frame.h" 118 #include "core/frame/FrameView.h" 119 #include "core/frame/History.h" 120 #include "core/frame/animation/AnimationController.h" 121 #include "core/html/HTMLAllCollection.h" 122 #include "core/html/HTMLAnchorElement.h" 123 #include "core/html/HTMLCanvasElement.h" 124 #include "core/html/HTMLCollection.h" 125 #include "core/html/HTMLDialogElement.h" 126 #include "core/html/HTMLDocument.h" 127 #include "core/html/HTMLFrameOwnerElement.h" 128 #include "core/html/HTMLHeadElement.h" 129 #include "core/html/HTMLHtmlElement.h" 130 #include "core/html/HTMLIFrameElement.h" 131 #include "core/html/HTMLImport.h" 132 #include "core/html/HTMLInputElement.h" 133 #include "core/html/HTMLLinkElement.h" 134 #include "core/html/HTMLNameCollection.h" 135 #include "core/html/HTMLScriptElement.h" 136 #include "core/html/HTMLStyleElement.h" 137 #include "core/html/HTMLTitleElement.h" 138 #include "core/html/PluginDocument.h" 139 #include "core/html/forms/FormController.h" 140 #include "core/html/parser/HTMLDocumentParser.h" 141 #include "core/html/parser/HTMLParserIdioms.h" 142 #include "core/html/parser/NestingLevelIncrementer.h" 143 #include "core/inspector/InspectorCounters.h" 144 #include "core/inspector/InspectorInstrumentation.h" 145 #include "core/inspector/ScriptCallStack.h" 146 #include "core/loader/CookieJar.h" 147 #include "core/loader/DocumentLoader.h" 148 #include "core/loader/FrameLoader.h" 149 #include "core/loader/FrameLoaderClient.h" 150 #include "core/loader/ImageLoader.h" 151 #include "core/loader/appcache/ApplicationCacheHost.h" 152 #include "core/page/Chrome.h" 153 #include "core/page/ChromeClient.h" 154 #include "core/page/EventHandler.h" 155 #include "core/page/FrameTree.h" 156 #include "core/page/MouseEventWithHitTestResults.h" 157 #include "core/page/Page.h" 158 #include "core/page/PageConsole.h" 159 #include "core/page/PointerLockController.h" 160 #include "core/frame/Settings.h" 161 #include "core/page/scrolling/ScrollingCoordinator.h" 162 #include "core/rendering/FastTextAutosizer.h" 163 #include "core/rendering/HitTestResult.h" 164 #include "core/rendering/RenderView.h" 165 #include "core/rendering/RenderWidget.h" 166 #include "core/rendering/TextAutosizer.h" 167 #include "core/svg/SVGDocumentExtensions.h" 168 #include "core/svg/SVGFontFaceElement.h" 169 #include "core/svg/SVGStyleElement.h" 170 #include "core/xml/XSLTProcessor.h" 171 #include "core/xml/parser/XMLDocumentParser.h" 172 #include "platform/DateComponents.h" 173 #include "platform/Language.h" 174 #include "platform/TraceEvent.h" 175 #include "platform/network/HTTPParsers.h" 176 #include "platform/scroll/ScrollbarTheme.h" 177 #include "platform/text/PlatformLocale.h" 178 #include "platform/text/SegmentedString.h" 179 #include "platform/weborigin/OriginAccessEntry.h" 180 #include "platform/weborigin/SchemeRegistry.h" 181 #include "platform/weborigin/SecurityOrigin.h" 182 #include "wtf/CurrentTime.h" 183 #include "wtf/HashFunctions.h" 184 #include "wtf/MainThread.h" 185 #include "wtf/StdLibExtras.h" 186 #include "wtf/TemporaryChange.h" 187 #include "wtf/text/StringBuffer.h" 188 #include "wtf/text/TextEncodingRegistry.h" 189 190 using namespace std; 191 using namespace WTF; 192 using namespace Unicode; 193 194 namespace WebCore { 195 196 using namespace HTMLNames; 197 198 static const unsigned cMaxWriteRecursionDepth = 21; 199 200 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. 201 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high 202 // for dual G5s. :) 203 static const int cLayoutScheduleThreshold = 250; 204 205 // DOM Level 2 says (letters added): 206 // 207 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. 208 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd. 209 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names. 210 // 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. 211 // 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. 212 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14). 213 // g) Character #x00B7 is classified as an extender, because the property list so identifies it. 214 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent. 215 // i) Characters ':' and '_' are allowed as name-start characters. 216 // j) Characters '-' and '.' are allowed as name characters. 217 // 218 // It also contains complete tables. If we decide it's better, we could include those instead of the following code. 219 220 static inline bool isValidNameStart(UChar32 c) 221 { 222 // rule (e) above 223 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6) 224 return true; 225 226 // rule (i) above 227 if (c == ':' || c == '_') 228 return true; 229 230 // rules (a) and (f) above 231 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter; 232 if (!(Unicode::category(c) & nameStartMask)) 233 return false; 234 235 // rule (c) above 236 if (c >= 0xF900 && c < 0xFFFE) 237 return false; 238 239 // rule (d) above 240 DecompositionType decompType = decompositionType(c); 241 if (decompType == DecompositionFont || decompType == DecompositionCompat) 242 return false; 243 244 return true; 245 } 246 247 static inline bool isValidNamePart(UChar32 c) 248 { 249 // rules (a), (e), and (i) above 250 if (isValidNameStart(c)) 251 return true; 252 253 // rules (g) and (h) above 254 if (c == 0x00B7 || c == 0x0387) 255 return true; 256 257 // rule (j) above 258 if (c == '-' || c == '.') 259 return true; 260 261 // rules (b) and (f) above 262 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit; 263 if (!(Unicode::category(c) & otherNamePartMask)) 264 return false; 265 266 // rule (c) above 267 if (c >= 0xF900 && c < 0xFFFE) 268 return false; 269 270 // rule (d) above 271 DecompositionType decompType = decompositionType(c); 272 if (decompType == DecompositionFont || decompType == DecompositionCompat) 273 return false; 274 275 return true; 276 } 277 278 static bool shouldInheritSecurityOriginFromOwner(const KURL& url) 279 { 280 // http://www.whatwg.org/specs/web-apps/current-work/#origin-0 281 // 282 // If a Document has the address "about:blank" 283 // The origin of the Document is the origin it was assigned when its browsing context was created. 284 // 285 // Note: We generalize this to all "blank" URLs and invalid URLs because we 286 // treat all of these URLs as about:blank. 287 // 288 return url.isEmpty() || url.isBlankURL(); 289 } 290 291 static Widget* widgetForElement(const Element& focusedElement) 292 { 293 RenderObject* renderer = focusedElement.renderer(); 294 if (!renderer || !renderer->isWidget()) 295 return 0; 296 return toRenderWidget(renderer)->widget(); 297 } 298 299 static bool acceptsEditingFocus(const Element& element) 300 { 301 ASSERT(element.rendererIsEditable()); 302 303 return element.document().frame() && element.rootEditableElement(); 304 } 305 306 static bool canAccessAncestor(const SecurityOrigin& activeSecurityOrigin, Frame* targetFrame) 307 { 308 // targetFrame can be 0 when we're trying to navigate a top-level frame 309 // that has a 0 opener. 310 if (!targetFrame) 311 return false; 312 313 const bool isLocalActiveOrigin = activeSecurityOrigin.isLocal(); 314 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree().parent()) { 315 Document* ancestorDocument = ancestorFrame->document(); 316 // FIXME: Should be an ASSERT? Frames should alway have documents. 317 if (!ancestorDocument) 318 return true; 319 320 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin(); 321 if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin)) 322 return true; 323 324 // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false. 325 // FIXME: It's a bit strange to special-case local origins here. Should we be doing 326 // something more general instead? 327 if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal()) 328 return true; 329 } 330 331 return false; 332 } 333 334 static void printNavigationErrorMessage(const Frame& frame, const KURL& activeURL, const char* reason) 335 { 336 String message = "Unsafe JavaScript attempt to initiate navigation for frame with URL '" + frame.document()->url().string() + "' from frame with URL '" + activeURL.string() + "'. " + reason + "\n"; 337 338 // FIXME: should we print to the console of the document performing the navigation instead? 339 frame.domWindow()->printErrorMessage(message); 340 } 341 342 uint64_t Document::s_globalTreeVersion = 0; 343 344 // This class should be passed only to Document::postTask. 345 class CheckFocusedElementTask FINAL : public ExecutionContextTask { 346 public: 347 static PassOwnPtr<CheckFocusedElementTask> create() 348 { 349 return adoptPtr(new CheckFocusedElementTask()); 350 } 351 virtual ~CheckFocusedElementTask() { } 352 353 private: 354 CheckFocusedElementTask() { } 355 virtual void performTask(ExecutionContext* context) OVERRIDE 356 { 357 ASSERT(context->isDocument()); 358 Document* document = toDocument(context); 359 document->didRunCheckFocusedElementTask(); 360 Element* element = document->focusedElement(); 361 if (!element) 362 return; 363 if (document->childNeedsStyleRecalc()) { 364 document->setNeedsFocusedElementCheck(); 365 return; 366 } 367 if (element->renderer() && element->renderer()->needsLayout()) 368 return; 369 if (!element->isFocusable()) 370 document->setFocusedElement(0); 371 } 372 }; 373 374 Document::Document(const DocumentInit& initializer, DocumentClassFlags documentClasses) 375 : ContainerNode(0, CreateDocument) 376 , TreeScope(this) 377 , m_hasNodesWithPlaceholderStyle(false) 378 , m_needsNotifyRemoveAllPendingStylesheet(false) 379 , m_evaluateMediaQueriesOnStyleRecalc(false) 380 , m_pendingSheetLayout(NoLayoutWithPendingSheets) 381 , m_frame(initializer.frame()) 382 , m_domWindow(m_frame ? m_frame->domWindow() : 0) 383 , m_import(initializer.import()) 384 , m_activeParserCount(0) 385 , m_contextFeatures(ContextFeatures::defaultSwitch()) 386 , m_wellFormed(false) 387 , m_printing(false) 388 , m_paginatedForScreen(false) 389 , m_compatibilityMode(NoQuirksMode) 390 , m_compatibilityModeLocked(false) 391 , m_didPostCheckFocusedElementTask(false) 392 , m_domTreeVersion(++s_globalTreeVersion) 393 , m_listenerTypes(0) 394 , m_mutationObserverTypes(0) 395 , m_visitedLinkState(VisitedLinkState::create(*this)) 396 , m_visuallyOrdered(false) 397 , m_readyState(Complete) 398 , m_bParsing(false) 399 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired) 400 , m_inStyleRecalc(false) 401 , m_gotoAnchorNeededAfterStylesheetsLoad(false) 402 , m_containsValidityStyleRules(false) 403 , m_updateFocusAppearanceRestoresSelection(false) 404 , m_containsPlugins(false) 405 , m_ignoreDestructiveWriteCount(0) 406 , m_titleSetExplicitly(false) 407 , m_markers(adoptPtr(new DocumentMarkerController)) 408 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) 409 , m_cssTarget(0) 410 , m_loadEventProgress(LoadEventNotRun) 411 , m_startTime(currentTime()) 412 , m_overMinimumLayoutThreshold(false) 413 , m_scriptRunner(ScriptRunner::create(this)) 414 , m_xmlVersion("1.0") 415 , m_xmlStandalone(StandaloneUnspecified) 416 , m_hasXMLDeclaration(0) 417 , m_designMode(inherit) 418 , m_hasAnnotatedRegions(false) 419 , m_annotatedRegionsDirty(false) 420 , m_useSecureKeyboardEntryWhenActive(false) 421 , m_documentClasses(documentClasses) 422 , m_isViewSource(false) 423 , m_sawElementsInKnownNamespaces(false) 424 , m_isSrcdocDocument(false) 425 , m_isMobileDocument(false) 426 , m_mayDisplaySeamlesslyWithParent(false) 427 , m_renderView(0) 428 , m_weakFactory(this) 429 , m_contextDocument(initializer.contextDocument()) 430 , m_idAttributeName(idAttr) 431 , m_hasFullscreenElementStack(false) 432 , m_loadEventDelayCount(0) 433 , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired) 434 , m_referrerPolicy(ReferrerPolicyDefault) 435 , m_directionSetOnDocumentElement(false) 436 , m_writingModeSetOnDocumentElement(false) 437 , m_writeRecursionIsTooDeep(false) 438 , m_writeRecursionDepth(0) 439 , m_lastHandledUserGestureTimestamp(0) 440 , m_taskRunner(MainThreadTaskRunner::create(this)) 441 , m_registrationContext(initializer.registrationContext(this)) 442 , m_sharedObjectPoolClearTimer(this, &Document::sharedObjectPoolClearTimerFired) 443 #ifndef NDEBUG 444 , m_didDispatchViewportPropertiesChanged(false) 445 #endif 446 , m_animationClock(AnimationClock::create()) 447 , m_timeline(DocumentTimeline::create(this)) 448 , m_transitionTimeline(TransitionTimeline::create(this)) 449 , m_templateDocumentHost(0) 450 , m_didAssociateFormControlsTimer(this, &Document::didAssociateFormControlsTimerFired) 451 { 452 setClient(this); 453 ScriptWrappable::init(this); 454 455 if (m_frame) { 456 provideContextFeaturesToDocumentFrom(this, m_frame->page()); 457 458 m_fetcher = m_frame->loader().activeDocumentLoader()->fetcher(); 459 } 460 461 if (!m_fetcher) 462 m_fetcher = ResourceFetcher::create(0); 463 m_fetcher->setDocument(this); 464 465 // We depend on the url getting immediately set in subframes, but we 466 // also depend on the url NOT getting immediately set in opened windows. 467 // See fast/dom/early-frame-url.html 468 // and fast/dom/location-new-window-no-crash.html, respectively. 469 // FIXME: Can/should we unify this behavior? 470 if (initializer.shouldSetURL()) 471 setURL(initializer.url()); 472 473 initSecurityContext(initializer); 474 initDNSPrefetch(); 475 476 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++) 477 m_nodeListCounts[i] = 0; 478 479 InspectorCounters::incrementCounter(InspectorCounters::DocumentCounter); 480 481 m_lifecyle.advanceTo(DocumentLifecycle::Inactive); 482 483 // Since CSSFontSelector requires Document::m_fetcher and StyleEngine owns 484 // CSSFontSelector, need to initialize m_styleEngine after initializing 485 // m_fetcher. 486 m_styleEngine = StyleEngine::create(*this); 487 } 488 489 Document::~Document() 490 { 491 ASSERT(!renderView()); 492 ASSERT(m_ranges.isEmpty()); 493 ASSERT(!m_parentTreeScope); 494 ASSERT(!hasGuardRefCount()); 495 496 if (m_templateDocument) 497 m_templateDocument->setTemplateDocumentHost(0); // balanced in templateDocument(). 498 499 if (Document* ownerDocument = this->ownerDocument()) 500 ownerDocument->didRemoveEventTargetNode(this); 501 502 m_scriptRunner.clear(); 503 504 removeAllEventListeners(); 505 506 // Currently we believe that Document can never outlive the parser. 507 // Although the Document may be replaced synchronously, DocumentParsers 508 // generally keep at least one reference to an Element which would in turn 509 // has a reference to the Document. If you hit this ASSERT, then that 510 // assumption is wrong. DocumentParser::detach() should ensure that even 511 // if the DocumentParser outlives the Document it won't cause badness. 512 ASSERT(!m_parser || m_parser->refCount() == 1); 513 detachParser(); 514 515 if (this == topDocument()) 516 clearAXObjectCache(); 517 518 if (m_styleSheetList) 519 m_styleSheetList->detachFromDocument(); 520 521 if (m_import) { 522 m_import->wasDetachedFromDocument(); 523 m_import = 0; 524 } 525 526 m_styleEngine.clear(); // We need to destory CSSFontSelector before destroying m_fetcher. 527 528 if (m_elemSheet) 529 m_elemSheet->clearOwnerNode(); 530 531 // It's possible for multiple Documents to end up referencing the same ResourceFetcher (e.g., SVGImages 532 // load the initial empty document and the SVGDocument with the same DocumentLoader). 533 if (m_fetcher->document() == this) 534 m_fetcher->setDocument(0); 535 m_fetcher.clear(); 536 537 // We must call clearRareData() here since a Document class inherits TreeScope 538 // as well as Node. See a comment on TreeScope.h for the reason. 539 if (hasRareData()) 540 clearRareData(); 541 542 ASSERT(!m_listsInvalidatedAtDocument.size()); 543 544 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++) 545 ASSERT(!m_nodeListCounts[i]); 546 547 clearDocumentScope(); 548 setClient(0); 549 550 InspectorCounters::decrementCounter(InspectorCounters::DocumentCounter); 551 } 552 553 void Document::dispose() 554 { 555 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun); 556 // We must make sure not to be retaining any of our children through 557 // these extra pointers or we will create a reference cycle. 558 m_docType = 0; 559 m_focusedElement = 0; 560 m_hoverNode = 0; 561 m_activeElement = 0; 562 m_titleElement = 0; 563 m_documentElement = 0; 564 m_contextFeatures = ContextFeatures::defaultSwitch(); 565 m_userActionElements.documentDidRemoveLastRef(); 566 m_associatedFormControls.clear(); 567 568 detachParser(); 569 570 m_registrationContext.clear(); 571 572 if (m_import) { 573 m_import->wasDetachedFromDocument(); 574 m_import = 0; 575 } 576 577 // removeDetachedChildren() doesn't always unregister IDs, 578 // so tear down scope information upfront to avoid having stale references in the map. 579 destroyTreeScopeData(); 580 removeDetachedChildren(); 581 // removeDetachedChildren() can access FormController. 582 m_formController.clear(); 583 584 m_markers->clear(); 585 586 m_cssCanvasElements.clear(); 587 588 // FIXME: consider using ActiveDOMObject. 589 if (m_scriptedAnimationController) 590 m_scriptedAnimationController->clearDocumentPointer(); 591 m_scriptedAnimationController.clear(); 592 593 if (svgExtensions()) 594 accessSVGExtensions()->pauseAnimations(); 595 596 m_lifecyle.advanceTo(DocumentLifecycle::Disposed); 597 lifecycleNotifier().notifyDocumentWasDisposed(); 598 } 599 600 SelectorQueryCache& Document::selectorQueryCache() 601 { 602 if (!m_selectorQueryCache) 603 m_selectorQueryCache = adoptPtr(new SelectorQueryCache()); 604 return *m_selectorQueryCache; 605 } 606 607 MediaQueryMatcher& Document::mediaQueryMatcher() 608 { 609 if (!m_mediaQueryMatcher) 610 m_mediaQueryMatcher = MediaQueryMatcher::create(this); 611 return *m_mediaQueryMatcher; 612 } 613 614 void Document::mediaQueryAffectingValueChanged() 615 { 616 styleEngine()->clearMediaQueryRuleSetStyleSheets(); 617 } 618 619 void Document::setCompatibilityMode(CompatibilityMode mode) 620 { 621 if (m_compatibilityModeLocked || mode == m_compatibilityMode) 622 return; 623 bool wasInQuirksMode = inQuirksMode(); 624 m_compatibilityMode = mode; 625 selectorQueryCache().invalidate(); 626 if (inQuirksMode() != wasInQuirksMode) { 627 // All injected stylesheets have to reparse using the different mode. 628 m_styleEngine->invalidateInjectedStyleSheetCache(); 629 } 630 } 631 632 String Document::compatMode() const 633 { 634 return inQuirksMode() ? "BackCompat" : "CSS1Compat"; 635 } 636 637 void Document::setDoctype(PassRefPtr<DocumentType> docType) 638 { 639 // This should never be called more than once. 640 ASSERT(!m_docType || !docType); 641 m_docType = docType; 642 if (m_docType) { 643 this->adoptIfNeeded(*m_docType); 644 if (m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", /* caseSensitive */ false)) 645 m_isMobileDocument = true; 646 } 647 // Doctype affects the interpretation of the stylesheets. 648 clearStyleResolver(); 649 } 650 651 DOMImplementation* Document::implementation() 652 { 653 if (!m_implementation) 654 m_implementation = DOMImplementation::create(*this); 655 return m_implementation.get(); 656 } 657 658 bool Document::hasManifest() const 659 { 660 return documentElement() && isHTMLHtmlElement(documentElement()) && documentElement()->hasAttribute(manifestAttr); 661 } 662 663 Location* Document::location() const 664 { 665 if (!frame()) 666 return 0; 667 668 return domWindow()->location(); 669 } 670 671 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 672 { 673 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 674 675 Element* newDocumentElement = ElementTraversal::firstWithin(*this); 676 if (newDocumentElement == m_documentElement) 677 return; 678 m_documentElement = newDocumentElement; 679 // The root style used for media query matching depends on the document element. 680 clearStyleResolver(); 681 } 682 683 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionState& exceptionState) 684 { 685 if (!isValidName(name)) { 686 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError); 687 return 0; 688 } 689 690 if (isXHTMLDocument() || isHTMLDocument()) 691 return HTMLElementFactory::createHTMLElement(isHTMLDocument() ? name.lower() : name, document(), 0, false); 692 693 return createElement(QualifiedName(nullAtom, name, nullAtom), false); 694 } 695 696 PassRefPtr<Element> Document::createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState& exceptionState) 697 { 698 if (!isValidName(localName)) { 699 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError); 700 return 0; 701 } 702 703 RefPtr<Element> element; 704 705 if (RuntimeEnabledFeatures::customElementsEnabled() && CustomElement::isValidName(localName) && registrationContext()) 706 element = registrationContext()->createCustomTagElement(*this, QualifiedName(nullAtom, localName, xhtmlNamespaceURI)); 707 else 708 element = createElement(localName, exceptionState); 709 710 if (RuntimeEnabledFeatures::customElementsEnabled() && !typeExtension.isNull() && !typeExtension.isEmpty()) 711 CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension); 712 713 return element; 714 } 715 716 PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& typeExtension, ExceptionState& exceptionState) 717 { 718 AtomicString prefix, localName; 719 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState)) 720 return 0; 721 722 QualifiedName qName(prefix, localName, namespaceURI); 723 if (!hasValidNamespaceForElements(qName)) { 724 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 725 return 0; 726 } 727 728 RefPtr<Element> element; 729 if (CustomElement::isValidName(qName.localName()) && registrationContext()) 730 element = registrationContext()->createCustomTagElement(*this, qName); 731 else 732 element = createElementNS(namespaceURI, qualifiedName, exceptionState); 733 734 if (!typeExtension.isNull() && !typeExtension.isEmpty()) 735 CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension); 736 737 return element; 738 } 739 740 ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, ExceptionState& exceptionState) 741 { 742 return registerElement(state, name, Dictionary(), exceptionState); 743 } 744 745 ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& exceptionState, CustomElement::NameSet validNames) 746 { 747 if (!registrationContext()) { 748 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 749 return ScriptValue(); 750 } 751 752 CustomElementConstructorBuilder constructorBuilder(state, &options); 753 registrationContext()->registerElement(this, &constructorBuilder, name, validNames, exceptionState); 754 return constructorBuilder.bindingsReturnValue(); 755 } 756 757 void Document::setImport(HTMLImport* import) 758 { 759 ASSERT(!m_import || !import); 760 m_import = import; 761 } 762 763 void Document::didLoadAllImports() 764 { 765 executeScriptsWaitingForResourcesIfNeeded(); 766 } 767 768 bool Document::haveImportsLoaded() const 769 { 770 return !m_import || !m_import->isBlocked(); 771 } 772 773 PassRefPtr<DocumentFragment> Document::createDocumentFragment() 774 { 775 return DocumentFragment::create(document()); 776 } 777 778 PassRefPtr<Text> Document::createTextNode(const String& data) 779 { 780 return Text::create(*this, data); 781 } 782 783 PassRefPtr<Comment> Document::createComment(const String& data) 784 { 785 return Comment::create(*this, data); 786 } 787 788 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionState& exceptionState) 789 { 790 if (isHTMLDocument()) { 791 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 792 return 0; 793 } 794 if (data.contains("]]>")) { 795 exceptionState.throwDOMException(InvalidCharacterError, "String cannot contain ']]>' since that is the end delimiter of a CData section."); 796 return 0; 797 } 798 return CDATASection::create(*this, data); 799 } 800 801 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionState& exceptionState) 802 { 803 if (!isValidName(target)) { 804 exceptionState.throwDOMException(InvalidCharacterError, "The target provided ('" + target + "') is not a valid name."); 805 return 0; 806 } 807 if (data.contains("?>")) { 808 exceptionState.throwDOMException(InvalidCharacterError, "The data provided ('" + data + "') contains '?>'."); 809 return 0; 810 } 811 return ProcessingInstruction::create(*this, target, data); 812 } 813 814 PassRefPtr<Text> Document::createEditingTextNode(const String& text) 815 { 816 return Text::createEditingText(*this, text); 817 } 818 819 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration() 820 { 821 return MutableStylePropertySet::create()->ensureCSSStyleDeclaration(); 822 } 823 824 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionState& exceptionState) 825 { 826 if (!importedNode) { 827 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 828 return 0; 829 } 830 831 switch (importedNode->nodeType()) { 832 case TEXT_NODE: 833 return createTextNode(importedNode->nodeValue()); 834 case CDATA_SECTION_NODE: 835 return createCDATASection(importedNode->nodeValue(), exceptionState); 836 case PROCESSING_INSTRUCTION_NODE: 837 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), exceptionState); 838 case COMMENT_NODE: 839 return createComment(importedNode->nodeValue()); 840 case ELEMENT_NODE: { 841 Element* oldElement = toElement(importedNode); 842 // FIXME: The following check might be unnecessary. Is it possible that 843 // oldElement has mismatched prefix/namespace? 844 if (!hasValidNamespaceForElements(oldElement->tagQName())) { 845 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 846 return 0; 847 } 848 RefPtr<Element> newElement = createElement(oldElement->tagQName(), false); 849 850 newElement->cloneDataFromElement(*oldElement); 851 852 if (deep) { 853 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 854 RefPtr<Node> newChild = importNode(oldChild, true, exceptionState); 855 if (exceptionState.hadException()) 856 return 0; 857 newElement->appendChild(newChild.release(), exceptionState); 858 if (exceptionState.hadException()) 859 return 0; 860 } 861 } 862 863 return newElement.release(); 864 } 865 case ATTRIBUTE_NODE: 866 return Attr::create(*this, QualifiedName(nullAtom, toAttr(importedNode)->name(), nullAtom), toAttr(importedNode)->value()); 867 case DOCUMENT_FRAGMENT_NODE: { 868 if (importedNode->isShadowRoot()) { 869 // ShadowRoot nodes should not be explicitly importable. 870 // Either they are imported along with their host node, or created implicitly. 871 break; 872 } 873 DocumentFragment* oldFragment = toDocumentFragment(importedNode); 874 RefPtr<DocumentFragment> newFragment = createDocumentFragment(); 875 if (deep) { 876 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 877 RefPtr<Node> newChild = importNode(oldChild, true, exceptionState); 878 if (exceptionState.hadException()) 879 return 0; 880 newFragment->appendChild(newChild.release(), exceptionState); 881 if (exceptionState.hadException()) 882 return 0; 883 } 884 } 885 886 return newFragment.release(); 887 } 888 case ENTITY_NODE: 889 case NOTATION_NODE: 890 // 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. 891 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM. 892 case DOCUMENT_NODE: 893 case DOCUMENT_TYPE_NODE: 894 case XPATH_NAMESPACE_NODE: 895 break; 896 } 897 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 898 return 0; 899 } 900 901 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionState& exceptionState) 902 { 903 if (!source) { 904 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 905 return 0; 906 } 907 908 EventQueueScope scope; 909 910 switch (source->nodeType()) { 911 case ENTITY_NODE: 912 case NOTATION_NODE: 913 case DOCUMENT_NODE: 914 case DOCUMENT_TYPE_NODE: 915 case XPATH_NAMESPACE_NODE: 916 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 917 return 0; 918 case ATTRIBUTE_NODE: { 919 Attr* attr = toAttr(source.get()); 920 if (attr->ownerElement()) 921 attr->ownerElement()->removeAttributeNode(attr, exceptionState); 922 break; 923 } 924 default: 925 if (source->isShadowRoot()) { 926 // ShadowRoot cannot disconnect itself from the host node. 927 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError); 928 return 0; 929 } 930 931 if (source->isFrameOwnerElement()) { 932 HTMLFrameOwnerElement* frameOwnerElement = toHTMLFrameOwnerElement(source.get()); 933 if (frame() && frame()->tree().isDescendantOf(frameOwnerElement->contentFrame())) { 934 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError); 935 return 0; 936 } 937 } 938 if (source->parentNode()) { 939 source->parentNode()->removeChild(source.get(), exceptionState); 940 if (exceptionState.hadException()) 941 return 0; 942 } 943 } 944 945 this->adoptIfNeeded(*source); 946 947 return source; 948 } 949 950 bool Document::hasValidNamespaceForElements(const QualifiedName& qName) 951 { 952 // These checks are from DOM Core Level 2, createElementNS 953 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS 954 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div") 955 return false; 956 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang") 957 return false; 958 959 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core: 960 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS 961 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar") 962 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)) 963 return false; 964 965 return true; 966 } 967 968 bool Document::hasValidNamespaceForAttributes(const QualifiedName& qName) 969 { 970 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-ElSetAttrNS 971 if (qName.prefix().isEmpty() && qName.localName() == xmlnsAtom) { 972 // Note: The case of an "xmlns" qualified name with a namespace of 973 // xmlnsNamespaceURI is specifically allowed (See <http://www.w3.org/2000/xmlns/>). 974 return qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI; 975 } 976 return hasValidNamespaceForElements(qName); 977 } 978 979 // FIXME: This should really be in a possible ElementFactory class 980 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser) 981 { 982 RefPtr<Element> e; 983 984 // FIXME: Use registered namespaces and look up in a hash to find the right factory. 985 if (qName.namespaceURI() == xhtmlNamespaceURI) 986 e = HTMLElementFactory::createHTMLElement(qName.localName(), document(), 0, createdByParser); 987 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI) 988 e = SVGElementFactory::createSVGElement(qName.localName(), document(), createdByParser); 989 990 if (e) 991 m_sawElementsInKnownNamespaces = true; 992 else 993 e = Element::create(qName, &document()); 994 995 if (e->prefix() != qName.prefix()) 996 e->setTagNameForCreateElementNS(qName); 997 998 ASSERT(qName == e->tagQName()); 999 1000 return e.release(); 1001 } 1002 1003 bool Document::regionBasedColumnsEnabled() const 1004 { 1005 return settings() && settings()->regionBasedColumnsEnabled(); 1006 } 1007 1008 PassRefPtr<DOMNamedFlowCollection> Document::webkitGetNamedFlows() 1009 { 1010 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderView()) 1011 return 0; 1012 1013 updateStyleIfNeeded(); 1014 1015 return namedFlows()->createCSSOMSnapshot(); 1016 } 1017 1018 NamedFlowCollection* Document::namedFlows() 1019 { 1020 if (!m_namedFlows) 1021 m_namedFlows = NamedFlowCollection::create(this); 1022 1023 return m_namedFlows.get(); 1024 } 1025 1026 PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState) 1027 { 1028 AtomicString prefix, localName; 1029 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState)) 1030 return 0; 1031 1032 QualifiedName qName(prefix, localName, namespaceURI); 1033 if (!hasValidNamespaceForElements(qName)) { 1034 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 1035 return 0; 1036 } 1037 1038 return createElement(qName, false); 1039 } 1040 1041 String Document::readyState() const 1042 { 1043 DEFINE_STATIC_LOCAL(const String, loading, ("loading")); 1044 DEFINE_STATIC_LOCAL(const String, interactive, ("interactive")); 1045 DEFINE_STATIC_LOCAL(const String, complete, ("complete")); 1046 1047 switch (m_readyState) { 1048 case Loading: 1049 return loading; 1050 case Interactive: 1051 return interactive; 1052 case Complete: 1053 return complete; 1054 } 1055 1056 ASSERT_NOT_REACHED(); 1057 return String(); 1058 } 1059 1060 void Document::setReadyState(ReadyState readyState) 1061 { 1062 if (readyState == m_readyState) 1063 return; 1064 1065 switch (readyState) { 1066 case Loading: 1067 if (!m_documentTiming.domLoading) { 1068 m_documentTiming.domLoading = monotonicallyIncreasingTime(); 1069 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) 1070 m_timeline->setZeroTime(m_documentTiming.domLoading); 1071 } 1072 break; 1073 case Interactive: 1074 if (!m_documentTiming.domInteractive) 1075 m_documentTiming.domInteractive = monotonicallyIncreasingTime(); 1076 break; 1077 case Complete: 1078 if (!m_documentTiming.domComplete) 1079 m_documentTiming.domComplete = monotonicallyIncreasingTime(); 1080 break; 1081 } 1082 1083 m_readyState = readyState; 1084 dispatchEvent(Event::create(EventTypeNames::readystatechange)); 1085 } 1086 1087 bool Document::isLoadCompleted() 1088 { 1089 return m_readyState == Complete; 1090 } 1091 1092 AtomicString Document::encodingName() const 1093 { 1094 // TextEncoding::name() returns a char*, no need to allocate a new 1095 // String for it each time. 1096 // FIXME: We should fix TextEncoding to speak AtomicString anyway. 1097 return AtomicString(encoding().name()); 1098 } 1099 1100 String Document::defaultCharset() const 1101 { 1102 if (Settings* settings = this->settings()) 1103 return settings->defaultTextEncodingName(); 1104 return String(); 1105 } 1106 1107 void Document::setCharset(const String& charset) 1108 { 1109 if (DocumentLoader* documentLoader = loader()) 1110 documentLoader->setUserChosenEncoding(charset); 1111 WTF::TextEncoding encoding(charset); 1112 // In case the encoding didn't exist, we keep the old one (helps some sites specifying invalid encodings). 1113 if (!encoding.isValid()) 1114 return; 1115 DocumentEncodingData newEncodingData = m_encodingData; 1116 newEncodingData.encoding = encoding; 1117 setEncodingData(newEncodingData); 1118 } 1119 1120 void Document::setContentLanguage(const AtomicString& language) 1121 { 1122 if (m_contentLanguage == language) 1123 return; 1124 m_contentLanguage = language; 1125 1126 // Document's style depends on the content language. 1127 setNeedsStyleRecalc(); 1128 } 1129 1130 void Document::setXMLVersion(const String& version, ExceptionState& exceptionState) 1131 { 1132 if (!implementation()->hasFeature("XML", String())) { 1133 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1134 return; 1135 } 1136 1137 if (!XMLDocumentParser::supportsXMLVersion(version)) { 1138 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1139 return; 1140 } 1141 1142 m_xmlVersion = version; 1143 } 1144 1145 void Document::setXMLStandalone(bool standalone, ExceptionState& exceptionState) 1146 { 1147 if (!implementation()->hasFeature("XML", String())) { 1148 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1149 return; 1150 } 1151 1152 m_xmlStandalone = standalone ? Standalone : NotStandalone; 1153 } 1154 1155 KURL Document::baseURI() const 1156 { 1157 return m_baseURL; 1158 } 1159 1160 void Document::setContent(const String& content) 1161 { 1162 open(); 1163 // FIXME: This should probably use insert(), but that's (intentionally) 1164 // not implemented for the XML parser as it's normally synonymous with 1165 // document.write(). append() will end up yielding, but close() will 1166 // pump the tokenizer syncrhonously and finish the parse. 1167 m_parser->pinToMainThread(); 1168 m_parser->append(content.impl()); 1169 close(); 1170 } 1171 1172 String Document::suggestedMIMEType() const 1173 { 1174 if (isXHTMLDocument()) 1175 return "application/xhtml+xml"; 1176 if (isSVGDocument()) 1177 return "image/svg+xml"; 1178 if (xmlStandalone()) 1179 return "text/xml"; 1180 if (isHTMLDocument()) 1181 return "text/html"; 1182 1183 if (DocumentLoader* documentLoader = loader()) 1184 return documentLoader->responseMIMEType(); 1185 return String(); 1186 } 1187 1188 Element* Document::elementFromPoint(int x, int y) const 1189 { 1190 if (!renderView()) 1191 return 0; 1192 1193 return TreeScope::elementFromPoint(x, y); 1194 } 1195 1196 PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) 1197 { 1198 if (!renderView()) 1199 return 0; 1200 LayoutPoint localPoint; 1201 RenderObject* renderer = rendererFromPoint(this, x, y, &localPoint); 1202 if (!renderer) 1203 return 0; 1204 1205 Node* node = renderer->node(); 1206 Node* shadowAncestorNode = ancestorInThisScope(node); 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 PositionWithAffinity positionWithAffinity = renderer->positionForPoint(localPoint); 1214 if (positionWithAffinity.position().isNull()) 1215 return 0; 1216 1217 Position rangeCompliantPosition = positionWithAffinity.position().parentAnchoredEquivalent(); 1218 return Range::create(*this, rangeCompliantPosition, rangeCompliantPosition); 1219 } 1220 1221 /* 1222 * Performs three operations: 1223 * 1. Convert control characters to spaces 1224 * 2. Trim leading and trailing spaces 1225 * 3. Collapse internal whitespace. 1226 */ 1227 template <typename CharacterType> 1228 static inline String canonicalizedTitle(Document* document, const String& title) 1229 { 1230 const CharacterType* characters = title.getCharacters<CharacterType>(); 1231 unsigned length = title.length(); 1232 unsigned i; 1233 1234 StringBuffer<CharacterType> buffer(length); 1235 unsigned builderIndex = 0; 1236 1237 // Skip leading spaces and leading characters that would convert to spaces 1238 for (i = 0; i < length; ++i) { 1239 CharacterType c = characters[i]; 1240 if (!(c <= 0x20 || c == 0x7F)) 1241 break; 1242 } 1243 1244 if (i == length) 1245 return String(); 1246 1247 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace. 1248 bool previousCharWasWS = false; 1249 for (; i < length; ++i) { 1250 CharacterType c = characters[i]; 1251 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) { 1252 if (previousCharWasWS) 1253 continue; 1254 buffer[builderIndex++] = ' '; 1255 previousCharWasWS = true; 1256 } else { 1257 buffer[builderIndex++] = c; 1258 previousCharWasWS = false; 1259 } 1260 } 1261 1262 // Strip trailing spaces 1263 while (builderIndex > 0) { 1264 --builderIndex; 1265 if (buffer[builderIndex] != ' ') 1266 break; 1267 } 1268 1269 if (!builderIndex && buffer[builderIndex] == ' ') 1270 return String(); 1271 1272 buffer.shrink(builderIndex + 1); 1273 1274 return String::adopt(buffer); 1275 } 1276 1277 void Document::updateTitle(const String& title) 1278 { 1279 if (m_rawTitle == title) 1280 return; 1281 1282 m_rawTitle = title; 1283 1284 String oldTitle = m_title; 1285 if (m_rawTitle.isEmpty()) 1286 m_title = String(); 1287 else if (m_rawTitle.is8Bit()) 1288 m_title = canonicalizedTitle<LChar>(this, m_rawTitle); 1289 else 1290 m_title = canonicalizedTitle<UChar>(this, m_rawTitle); 1291 1292 if (!m_frame || oldTitle == m_title) 1293 return; 1294 m_frame->loader().client()->dispatchDidReceiveTitle(m_title); 1295 } 1296 1297 void Document::setTitle(const String& title) 1298 { 1299 // Title set by JavaScript -- overrides any title elements. 1300 m_titleSetExplicitly = true; 1301 if (!isHTMLDocument() && !isXHTMLDocument()) 1302 m_titleElement = 0; 1303 else if (!m_titleElement) { 1304 if (HTMLElement* headElement = head()) { 1305 m_titleElement = createElement(titleTag, false); 1306 headElement->appendChild(m_titleElement); 1307 } 1308 } 1309 1310 updateTitle(title); 1311 1312 if (m_titleElement && isHTMLTitleElement(m_titleElement.get())) 1313 toHTMLTitleElement(m_titleElement)->setText(title); 1314 } 1315 1316 void Document::setTitleElement(const String& title, Element* titleElement) 1317 { 1318 if (titleElement != m_titleElement) { 1319 if (m_titleElement || m_titleSetExplicitly) 1320 // Only allow the first title element to change the title -- others have no effect. 1321 return; 1322 m_titleElement = titleElement; 1323 } 1324 1325 updateTitle(title); 1326 } 1327 1328 void Document::removeTitle(Element* titleElement) 1329 { 1330 if (m_titleElement != titleElement) 1331 return; 1332 1333 m_titleElement = 0; 1334 m_titleSetExplicitly = false; 1335 1336 // FIXME: This is broken for SVG. 1337 // Update title based on first title element in the head, if one exists. 1338 if (HTMLElement* headElement = head()) { 1339 for (Element* element = headElement->firstElementChild(); element; element = element->nextElementSibling()) { 1340 if (!isHTMLTitleElement(element)) 1341 continue; 1342 HTMLTitleElement* title = toHTMLTitleElement(element); 1343 setTitleElement(title->text(), title); 1344 break; 1345 } 1346 } 1347 1348 if (!m_titleElement) 1349 updateTitle(String()); 1350 } 1351 1352 PageVisibilityState Document::pageVisibilityState() const 1353 { 1354 // The visibility of the document is inherited from the visibility of the 1355 // page. If there is no page associated with the document, we will assume 1356 // that the page is hidden, as specified by the spec: 1357 // http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#dom-document-hidden 1358 if (!m_frame || !m_frame->page()) 1359 return PageVisibilityStateHidden; 1360 return m_frame->page()->visibilityState(); 1361 } 1362 1363 String Document::visibilityState() const 1364 { 1365 return pageVisibilityStateString(pageVisibilityState()); 1366 } 1367 1368 bool Document::hidden() const 1369 { 1370 return pageVisibilityState() != PageVisibilityStateVisible; 1371 } 1372 1373 void Document::dispatchVisibilityStateChangeEvent() 1374 { 1375 dispatchEvent(Event::create(EventTypeNames::visibilitychange)); 1376 // Also send out the deprecated version until it can be removed. 1377 dispatchEvent(Event::create(EventTypeNames::webkitvisibilitychange)); 1378 } 1379 1380 DOMSecurityPolicy* Document::securityPolicy() 1381 { 1382 if (!m_domSecurityPolicy) 1383 m_domSecurityPolicy = DOMSecurityPolicy::create(this); 1384 return m_domSecurityPolicy.get(); 1385 } 1386 1387 String Document::nodeName() const 1388 { 1389 return "#document"; 1390 } 1391 1392 Node::NodeType Document::nodeType() const 1393 { 1394 return DOCUMENT_NODE; 1395 } 1396 1397 FormController* Document::formController() 1398 { 1399 if (!m_formController) 1400 m_formController = FormController::create(); 1401 return m_formController.get(); 1402 } 1403 1404 Vector<String> Document::formElementsState() const 1405 { 1406 if (!m_formController) 1407 return Vector<String>(); 1408 return m_formController->formElementsState(); 1409 } 1410 1411 void Document::setStateForNewFormElements(const Vector<String>& stateVector) 1412 { 1413 if (!stateVector.size() && !m_formController) 1414 return; 1415 formController()->setStateForNewFormElements(stateVector); 1416 } 1417 1418 FrameView* Document::view() const 1419 { 1420 return m_frame ? m_frame->view() : 0; 1421 } 1422 1423 Page* Document::page() const 1424 { 1425 return m_frame ? m_frame->page() : 0; 1426 } 1427 1428 Settings* Document::settings() const 1429 { 1430 return m_frame ? m_frame->settings() : 0; 1431 } 1432 1433 PassRefPtr<Range> Document::createRange() 1434 { 1435 return Range::create(*this); 1436 } 1437 1438 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, ExceptionState& exceptionState) 1439 { 1440 // FIXME: Probably this should be handled within the bindings layer and TypeError should be thrown. 1441 if (!root) { 1442 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1443 return 0; 1444 } 1445 return NodeIterator::create(root, NodeFilter::SHOW_ALL, PassRefPtr<NodeFilter>()); 1446 } 1447 1448 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, ExceptionState& exceptionState) 1449 { 1450 if (!root) { 1451 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1452 return 0; 1453 } 1454 // FIXME: It might be a good idea to emit a warning if |whatToShow| contains a bit that is not defined in 1455 // NodeFilter. 1456 return NodeIterator::create(root, whatToShow, PassRefPtr<NodeFilter>()); 1457 } 1458 1459 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, PassRefPtr<NodeFilter> filter, ExceptionState& exceptionState) 1460 { 1461 if (!root) { 1462 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1463 return 0; 1464 } 1465 // FIXME: Ditto. 1466 return NodeIterator::create(root, whatToShow, filter); 1467 } 1468 1469 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, ExceptionState& exceptionState) 1470 { 1471 if (!root) { 1472 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1473 return 0; 1474 } 1475 return TreeWalker::create(root, NodeFilter::SHOW_ALL, PassRefPtr<NodeFilter>()); 1476 } 1477 1478 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, ExceptionState& exceptionState) 1479 { 1480 if (!root) { 1481 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1482 return 0; 1483 } 1484 return TreeWalker::create(root, whatToShow, PassRefPtr<NodeFilter>()); 1485 } 1486 1487 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, PassRefPtr<NodeFilter> filter, ExceptionState& exceptionState) 1488 { 1489 if (!root) { 1490 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 1491 return 0; 1492 } 1493 return TreeWalker::create(root, whatToShow, filter); 1494 } 1495 1496 void Document::scheduleStyleRecalc() 1497 { 1498 if (shouldDisplaySeamlesslyWithParent()) { 1499 // When we're seamless, our parent document manages our style recalcs. 1500 ownerElement()->setNeedsStyleRecalc(); 1501 ownerElement()->document().scheduleStyleRecalc(); 1502 return; 1503 } 1504 1505 if (m_styleRecalcTimer.isActive()) 1506 return; 1507 1508 ASSERT(needsStyleRecalc() || childNeedsStyleRecalc() || childNeedsDistributionRecalc()); 1509 1510 m_styleRecalcTimer.startOneShot(0); 1511 1512 InspectorInstrumentation::didScheduleStyleRecalculation(this); 1513 } 1514 1515 void Document::unscheduleStyleRecalc() 1516 { 1517 ASSERT(!isActive() || (!needsStyleRecalc() && !childNeedsStyleRecalc())); 1518 m_styleRecalcTimer.stop(); 1519 } 1520 1521 bool Document::hasPendingStyleRecalc() const 1522 { 1523 return m_styleRecalcTimer.isActive() && !m_inStyleRecalc; 1524 } 1525 1526 bool Document::hasPendingForcedStyleRecalc() const 1527 { 1528 return hasPendingStyleRecalc() && styleChangeType() >= SubtreeStyleChange; 1529 } 1530 1531 void Document::styleRecalcTimerFired(Timer<Document>*) 1532 { 1533 updateStyleIfNeeded(); 1534 } 1535 1536 void Document::updateDistributionIfNeeded() 1537 { 1538 if (!childNeedsDistributionRecalc()) 1539 return; 1540 TRACE_EVENT0("webkit", "Document::recalcDistribution"); 1541 recalcDistribution(); 1542 } 1543 1544 void Document::updateDistributionForNodeIfNeeded(Node* node) 1545 { 1546 if (node->inDocument()) { 1547 updateDistributionIfNeeded(); 1548 return; 1549 } 1550 Node* root = node; 1551 while (Node* host = root->shadowHost()) 1552 root = host; 1553 while (Node* ancestor = root->parentOrShadowHostNode()) 1554 root = ancestor; 1555 if (root->childNeedsDistributionRecalc()) 1556 root->recalcDistribution(); 1557 } 1558 1559 void Document::setStyleDependentState(RenderStyle* documentStyle) 1560 { 1561 const Pagination& pagination = view()->pagination(); 1562 if (pagination.mode != Pagination::Unpaginated) { 1563 Pagination::setStylesForPaginationMode(pagination.mode, documentStyle); 1564 documentStyle->setColumnGap(pagination.gap); 1565 if (renderView()->hasColumns()) 1566 renderView()->updateColumnInfoFromStyle(documentStyle); 1567 } 1568 1569 // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font. 1570 if (shouldDisplaySeamlesslyWithParent()) 1571 return; 1572 1573 FontBuilder fontBuilder; 1574 fontBuilder.initForStyleResolve(*this, documentStyle, isSVGDocument()); 1575 RefPtr<CSSFontSelector> selector = m_styleEngine->fontSelector(); 1576 fontBuilder.createFontForDocument(selector, documentStyle); 1577 } 1578 1579 void Document::inheritHtmlAndBodyElementStyles(StyleRecalcChange change) 1580 { 1581 ASSERT(inStyleRecalc()); 1582 ASSERT(documentElement()); 1583 1584 RefPtr<RenderStyle> documentElementStyle = documentElement()->renderStyle(); 1585 if (!documentElementStyle || documentElement()->needsStyleRecalc() || change == Force) 1586 documentElementStyle = ensureStyleResolver().styleForElement(documentElement()); 1587 1588 WritingMode rootWritingMode = documentElementStyle->writingMode(); 1589 TextDirection rootDirection = documentElementStyle->direction(); 1590 HTMLElement* body = this->body(); 1591 1592 if (body) { 1593 RefPtr<RenderStyle> bodyStyle = body->renderStyle(); 1594 if (!bodyStyle || body->needsStyleRecalc() || documentElement()->needsStyleRecalc() || change == Force) 1595 bodyStyle = ensureStyleResolver().styleForElement(body, documentElementStyle.get()); 1596 if (!writingModeSetOnDocumentElement()) 1597 rootWritingMode = bodyStyle->writingMode(); 1598 if (!directionSetOnDocumentElement()) 1599 rootDirection = bodyStyle->direction(); 1600 } 1601 1602 RefPtr<RenderStyle> documentStyle = renderView()->style(); 1603 if (documentStyle->writingMode() != rootWritingMode || documentStyle->direction() != rootDirection) { 1604 RefPtr<RenderStyle> newStyle = RenderStyle::clone(documentStyle.get()); 1605 newStyle->setWritingMode(rootWritingMode); 1606 newStyle->setDirection(rootDirection); 1607 renderView()->setStyle(newStyle); 1608 setStyleDependentState(newStyle.get()); 1609 } 1610 1611 if (body) { 1612 if (RenderStyle* style = body->renderStyle()) { 1613 if (style->direction() != rootDirection || style->writingMode() != rootWritingMode) 1614 body->setNeedsStyleRecalc(); 1615 } 1616 } 1617 1618 if (RenderStyle* style = documentElement()->renderStyle()) { 1619 if (style->direction() != rootDirection || style->writingMode() != rootWritingMode) 1620 documentElement()->setNeedsStyleRecalc(); 1621 } 1622 } 1623 1624 void Document::recalcStyle(StyleRecalcChange change) 1625 { 1626 // we should not enter style recalc while painting 1627 RELEASE_ASSERT(!view() || !view()->isPainting()); 1628 1629 // FIXME: We should never enter here without a FrameView or with an inactive document. 1630 if (!isActive() || !view()) 1631 return; 1632 1633 if (m_inStyleRecalc) 1634 return; 1635 1636 TRACE_EVENT0("webkit", "Document::recalcStyle"); 1637 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "RecalcStyle"); 1638 1639 updateDistributionIfNeeded(); 1640 1641 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this); 1642 1643 if (m_evaluateMediaQueriesOnStyleRecalc) { 1644 m_evaluateMediaQueriesOnStyleRecalc = false; 1645 evaluateMediaQueryList(); 1646 } 1647 1648 // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless), 1649 // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach 1650 // before setting the DOMWindow on the Frame, or the SecurityOrigin on the document. The attach, in turn 1651 // resolves style (here) and then when we resolve style on the parent chain, we may end up 1652 // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed 1653 // hits a null-dereference due to security code always assuming the document has a SecurityOrigin. 1654 1655 if (m_styleEngine->needsUpdateActiveStylesheetsOnStyleRecalc()) 1656 m_styleEngine->updateActiveStyleSheets(FullStyleUpdate); 1657 1658 if (m_elemSheet && m_elemSheet->contents()->usesRemUnits()) 1659 m_styleEngine->setUsesRemUnit(true); 1660 1661 { 1662 PostAttachCallbacks::SuspendScope suspendPostAttachCallbacks; 1663 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates; 1664 FrameView::DeferredRepaintScope deferRepaints(*view()); 1665 TemporaryChange<bool> changeInStyleRecalc(m_inStyleRecalc, true); 1666 1667 if (styleChangeType() >= SubtreeStyleChange) 1668 change = Force; 1669 1670 // FIXME: Cannot access the ensureStyleResolver() before calling styleForDocument below because 1671 // apparently the StyleResolver's constructor has side effects. We should fix it. 1672 // See printing/setPrinting.html, printing/width-overflow.html though they only fail on 1673 // mac when accessing the resolver by what appears to be a viewport size difference. 1674 1675 if (change == Force || (change >= Inherit && shouldDisplaySeamlesslyWithParent())) { 1676 m_hasNodesWithPlaceholderStyle = false; 1677 RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(*this, m_styleEngine->fontSelector()); 1678 StyleRecalcChange localChange = RenderStyle::compare(documentStyle.get(), renderView()->style()); 1679 if (localChange != NoChange) 1680 renderView()->setStyle(documentStyle.release()); 1681 } 1682 1683 clearNeedsStyleRecalc(); 1684 1685 // Uncomment to enable printing of statistics about style sharing and the matched property cache. 1686 // Optionally pass StyleResolver::ReportSlowStats to print numbers that require crawling the 1687 // entire DOM (where collecting them is very slow). 1688 // FIXME: Expose this as a runtime flag. 1689 // ensureStyleResolver().enableStats(/*StyleResolver::ReportSlowStats*/); 1690 1691 if (StyleResolverStats* stats = ensureStyleResolver().stats()) 1692 stats->reset(); 1693 1694 if (Element* documentElement = this->documentElement()) { 1695 inheritHtmlAndBodyElementStyles(change); 1696 if (shouldRecalcStyle(change, documentElement)) 1697 documentElement->recalcStyle(change); 1698 } 1699 1700 ensureStyleResolver().printStats(); 1701 1702 view()->updateCompositingLayersAfterStyleChange(); 1703 1704 clearChildNeedsStyleRecalc(); 1705 unscheduleStyleRecalc(); 1706 1707 // FIXME: SVG <use> element can schedule a recalc in the middle of an already running one. 1708 // See StyleEngine::updateActiveStyleSheets. 1709 if (m_styleEngine->needsUpdateActiveStylesheetsOnStyleRecalc()) 1710 setNeedsStyleRecalc(); 1711 1712 if (m_styleEngine->hasResolver()) { 1713 // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc. 1714 StyleResolver& resolver = m_styleEngine->ensureResolver(); 1715 m_styleEngine->resetCSSFeatureFlags(resolver.ensureRuleFeatureSet()); 1716 resolver.clearStyleSharingList(); 1717 } 1718 } 1719 1720 InspectorInstrumentation::didRecalculateStyle(cookie); 1721 1722 // As a result of the style recalculation, the currently hovered element might have been 1723 // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event 1724 // to check if any other elements ended up under the mouse pointer due to re-layout. 1725 if (hoverNode() && !hoverNode()->renderer() && frame()) 1726 frame()->eventHandler().dispatchFakeMouseMoveEventSoon(); 1727 } 1728 1729 void Document::updateStyleIfNeeded() 1730 { 1731 ASSERT(isMainThread()); 1732 ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting())); 1733 1734 if (!needsStyleRecalc() && !childNeedsStyleRecalc() && !childNeedsDistributionRecalc()) 1735 return; 1736 1737 RefPtr<Frame> holder(m_frame); 1738 AnimationUpdateBlock animationUpdateBlock(m_frame ? &m_frame->animation() : 0); 1739 recalcStyle(NoChange); 1740 DocumentAnimations::serviceAfterStyleRecalc(*this); 1741 } 1742 1743 void Document::updateStyleForNodeIfNeeded(Node* node) 1744 { 1745 if (!hasPendingForcedStyleRecalc() && !childNeedsStyleRecalc() && !needsStyleRecalc()) 1746 return; 1747 1748 bool needsStyleRecalc = hasPendingForcedStyleRecalc(); 1749 for (Node* ancestor = node; ancestor && !needsStyleRecalc; ancestor = ancestor->parentOrShadowHostNode()) 1750 needsStyleRecalc = ancestor->needsStyleRecalc(); 1751 if (needsStyleRecalc) 1752 updateStyleIfNeeded(); 1753 } 1754 1755 void Document::updateLayout() 1756 { 1757 ASSERT(isMainThread()); 1758 1759 RefPtr<FrameView> frameView = view(); 1760 if (frameView && frameView->isInLayout()) { 1761 // View layout should not be re-entrant. 1762 ASSERT_NOT_REACHED(); 1763 return; 1764 } 1765 1766 if (Element* oe = ownerElement()) 1767 oe->document().updateLayout(); 1768 1769 updateStyleIfNeeded(); 1770 1771 // Only do a layout if changes have occurred that make it necessary. 1772 if (isActive() && frameView && renderView() && (frameView->layoutPending() || renderView()->needsLayout())) 1773 frameView->layout(); 1774 1775 if (isActive() && frameView) 1776 frameView->partialLayout().reset(); 1777 1778 setNeedsFocusedElementCheck(); 1779 } 1780 1781 void Document::setNeedsFocusedElementCheck() 1782 { 1783 // FIXME: Using a Task doesn't look a good idea. 1784 if (!m_focusedElement || m_didPostCheckFocusedElementTask) 1785 return; 1786 m_taskRunner->postTask(CheckFocusedElementTask::create()); 1787 m_didPostCheckFocusedElementTask = true; 1788 } 1789 1790 void Document::recalcStyleForLayoutIgnoringPendingStylesheets() 1791 { 1792 ASSERT(m_styleEngine->ignoringPendingStylesheets()); 1793 1794 if (!m_styleEngine->hasPendingSheets()) 1795 return; 1796 1797 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. 1798 // Our assumption is that it would be dangerous to try to stop it a second time, after page 1799 // content has already been loaded and displayed with accurate style information. (Our 1800 // suppression involves blanking the whole page at the moment. If it were more refined, we 1801 // might be able to do something better.) It's worth noting though that this entire method 1802 // is a hack, since what we really want to do is suspend JS instead of doing a layout with 1803 // inaccurate information. 1804 HTMLElement* bodyElement = body(); 1805 if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { 1806 m_pendingSheetLayout = DidLayoutWithPendingSheets; 1807 styleResolverChanged(RecalcStyleImmediately); 1808 } else if (m_hasNodesWithPlaceholderStyle) { 1809 // If new nodes have been added or style recalc has been done with style sheets still 1810 // pending, some nodes may not have had their real style calculated yet. Normally this 1811 // gets cleaned when style sheets arrive but here we need up-to-date style immediately. 1812 recalcStyle(Force); 1813 } 1814 } 1815 1816 // FIXME: This is a bad idea and needs to be removed eventually. 1817 // Other browsers load stylesheets before they continue parsing the web page. 1818 // Since we don't, we can run JavaScript code that needs answers before the 1819 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets 1820 // lets us get reasonable answers. The long term solution to this problem is 1821 // to instead suspend JavaScript execution. 1822 void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks) 1823 { 1824 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get()); 1825 recalcStyleForLayoutIgnoringPendingStylesheets(); 1826 updateLayout(); 1827 if (runPostLayoutTasks == RunPostLayoutTasksSynchronously && view()) 1828 view()->flushAnyPendingPostLayoutTasks(); 1829 } 1830 1831 void Document::partialUpdateLayoutIgnorePendingStylesheets(Node* stopLayoutAtNode) 1832 { 1833 // Non-overlay scrollbars can cause a second layout that is dependent 1834 // on a first layout. This is disabled for partial layout for now. 1835 if (!RuntimeEnabledFeatures::partialLayoutEnabled() || !ScrollbarTheme::theme()->usesOverlayScrollbars()) { 1836 updateLayoutIgnorePendingStylesheets(); 1837 return; 1838 } 1839 1840 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get()); 1841 recalcStyleForLayoutIgnoringPendingStylesheets(); 1842 1843 if (stopLayoutAtNode) { 1844 RenderObject* renderer = stopLayoutAtNode->renderer(); 1845 bool canPartialLayout = renderer; 1846 while (renderer) { 1847 if (!renderer->supportsPartialLayout()) { 1848 canPartialLayout = false; 1849 break; 1850 } 1851 renderer = renderer->parent(); 1852 } 1853 if (canPartialLayout && view()) 1854 view()->partialLayout().setStopAtRenderer(stopLayoutAtNode->renderer()); 1855 } 1856 1857 updateLayout(); 1858 1859 if (view()) 1860 view()->partialLayout().reset(); 1861 } 1862 1863 PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element* element) 1864 { 1865 ASSERT_ARG(element, element->document() == this); 1866 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get()); 1867 return ensureStyleResolver().styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0); 1868 } 1869 1870 PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex) 1871 { 1872 return ensureStyleResolver().styleForPage(pageIndex); 1873 } 1874 1875 bool Document::isPageBoxVisible(int pageIndex) 1876 { 1877 return styleForPage(pageIndex)->visibility() != HIDDEN; // display property doesn't apply to @page. 1878 } 1879 1880 void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) 1881 { 1882 RefPtr<RenderStyle> style = styleForPage(pageIndex); 1883 RenderView* view = renderView(); 1884 1885 int width = pageSize.width(); 1886 int height = pageSize.height(); 1887 switch (style->pageSizeType()) { 1888 case PAGE_SIZE_AUTO: 1889 break; 1890 case PAGE_SIZE_AUTO_LANDSCAPE: 1891 if (width < height) 1892 std::swap(width, height); 1893 break; 1894 case PAGE_SIZE_AUTO_PORTRAIT: 1895 if (width > height) 1896 std::swap(width, height); 1897 break; 1898 case PAGE_SIZE_RESOLVED: { 1899 LengthSize size = style->pageSize(); 1900 ASSERT(size.width().isFixed()); 1901 ASSERT(size.height().isFixed()); 1902 width = valueForLength(size.width(), 0, view); 1903 height = valueForLength(size.height(), 0, view); 1904 break; 1905 } 1906 default: 1907 ASSERT_NOT_REACHED(); 1908 } 1909 pageSize = IntSize(width, height); 1910 1911 // The percentage is calculated with respect to the width even for margin top and bottom. 1912 // http://www.w3.org/TR/CSS2/box.html#margin-properties 1913 marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width, view); 1914 marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width, view); 1915 marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view); 1916 marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view); 1917 } 1918 1919 void Document::setIsViewSource(bool isViewSource) 1920 { 1921 m_isViewSource = isViewSource; 1922 if (!m_isViewSource) 1923 return; 1924 1925 setSecurityOrigin(SecurityOrigin::createUnique()); 1926 didUpdateSecurityOrigin(); 1927 } 1928 1929 StyleResolver* Document::styleResolver() const 1930 { 1931 return m_styleEngine->resolver(); 1932 } 1933 1934 StyleResolver& Document::ensureStyleResolver() const 1935 { 1936 return m_styleEngine->ensureResolver(); 1937 } 1938 1939 void Document::clearStyleResolver() 1940 { 1941 m_styleEngine->clearResolver(); 1942 } 1943 1944 void Document::attach(const AttachContext& context) 1945 { 1946 ASSERT(m_lifecyle.state() == DocumentLifecycle::Inactive); 1947 ASSERT(!m_axObjectCache || this != topDocument()); 1948 1949 m_renderView = new RenderView(this); 1950 setRenderer(m_renderView); 1951 1952 m_renderView->setIsInWindow(true); 1953 m_renderView->setStyle(StyleResolver::styleForDocument(*this)); 1954 view()->updateCompositingLayersAfterStyleChange(); 1955 1956 m_styleEngine->didAttach(); 1957 1958 ContainerNode::attach(context); 1959 1960 m_lifecyle.advanceTo(DocumentLifecycle::Active); 1961 } 1962 1963 void Document::detach(const AttachContext& context) 1964 { 1965 ASSERT(isActive()); 1966 m_lifecyle.advanceTo(DocumentLifecycle::Stopping); 1967 1968 if (page()) 1969 page()->documentDetached(this); 1970 1971 if (this == topDocument()) 1972 clearAXObjectCache(); 1973 1974 stopActiveDOMObjects(); 1975 1976 // FIXME: consider using ActiveDOMObject. 1977 if (m_scriptedAnimationController) 1978 m_scriptedAnimationController->clearDocumentPointer(); 1979 m_scriptedAnimationController.clear(); 1980 1981 if (svgExtensions()) 1982 accessSVGExtensions()->pauseAnimations(); 1983 1984 // FIXME: This shouldn't be needed once DOMWindow becomes ExecutionContext. 1985 if (m_domWindow) 1986 m_domWindow->clearEventQueue(); 1987 1988 RenderView* renderView = m_renderView; 1989 1990 if (renderView) 1991 renderView->setIsInWindow(false); 1992 1993 if (m_frame) { 1994 FrameView* view = m_frame->view(); 1995 if (view) 1996 view->detachCustomScrollbars(); 1997 } 1998 1999 // Indicate destruction mode by setting the renderer to null. 2000 // FIXME: Don't do this and use m_lifecycle.state() == Stopping instead. 2001 setRenderer(0); 2002 m_renderView = 0; 2003 2004 m_hoverNode = 0; 2005 m_focusedElement = 0; 2006 m_activeElement = 0; 2007 2008 ContainerNode::detach(context); 2009 2010 unscheduleStyleRecalc(); 2011 2012 m_styleEngine->didDetach(); 2013 2014 if (renderView) 2015 renderView->destroy(); 2016 2017 if (m_touchEventTargets && m_touchEventTargets->size() && parentDocument()) 2018 parentDocument()->didRemoveEventTargetNode(this); 2019 2020 // This is required, as our Frame might delete itself as soon as it detaches 2021 // us. However, this violates Node::detach() semantics, as it's never 2022 // possible to re-attach. Eventually Document::detach() should be renamed, 2023 // or this setting of the frame to 0 could be made explicit in each of the 2024 // callers of Document::detach(). 2025 m_frame = 0; 2026 2027 if (m_mediaQueryMatcher) 2028 m_mediaQueryMatcher->documentDestroyed(); 2029 2030 lifecycleNotifier().notifyDocumentWasDetached(); 2031 m_lifecyle.advanceTo(DocumentLifecycle::Stopped); 2032 } 2033 2034 void Document::prepareForDestruction() 2035 { 2036 m_markers->prepareForDestruction(); 2037 disconnectDescendantFrames(); 2038 2039 // The process of disconnecting descendant frames could have already detached us. 2040 if (!isActive()) 2041 return; 2042 2043 if (DOMWindow* window = this->domWindow()) 2044 window->willDetachDocumentFromFrame(); 2045 detach(); 2046 } 2047 2048 void Document::removeAllEventListeners() 2049 { 2050 EventTarget::removeAllEventListeners(); 2051 2052 if (DOMWindow* domWindow = this->domWindow()) 2053 domWindow->removeAllEventListeners(); 2054 for (Node* node = firstChild(); node; node = NodeTraversal::next(*node)) 2055 node->removeAllEventListeners(); 2056 } 2057 2058 void Document::clearAXObjectCache() 2059 { 2060 ASSERT(topDocument() == this); 2061 // Clear the cache member variable before calling delete because attempts 2062 // are made to access it during destruction. 2063 m_axObjectCache.clear(); 2064 } 2065 2066 AXObjectCache* Document::existingAXObjectCache() const 2067 { 2068 if (!AXObjectCache::accessibilityEnabled()) 2069 return 0; 2070 2071 // If the renderer is gone then we are in the process of destruction. 2072 // This method will be called before m_frame = 0. 2073 if (!topDocument()->renderView()) 2074 return 0; 2075 2076 return topDocument()->m_axObjectCache.get(); 2077 } 2078 2079 AXObjectCache* Document::axObjectCache() const 2080 { 2081 if (!AXObjectCache::accessibilityEnabled()) 2082 return 0; 2083 2084 // The only document that actually has a AXObjectCache is the top-level 2085 // document. This is because we need to be able to get from any WebCoreAXObject 2086 // to any other WebCoreAXObject on the same page. Using a single cache allows 2087 // lookups across nested webareas (i.e. multiple documents). 2088 Document* topDocument = this->topDocument(); 2089 2090 // If the document has already been detached, do not make a new axObjectCache. 2091 if (!topDocument->renderView()) 2092 return 0; 2093 2094 ASSERT(topDocument == this || !m_axObjectCache); 2095 if (!topDocument->m_axObjectCache) 2096 topDocument->m_axObjectCache = adoptPtr(new AXObjectCache(topDocument)); 2097 return topDocument->m_axObjectCache.get(); 2098 } 2099 2100 void Document::setVisuallyOrdered() 2101 { 2102 m_visuallyOrdered = true; 2103 // FIXME: How is possible to not have a renderer here? 2104 if (renderView()) 2105 renderView()->style()->setRTLOrdering(VisualOrder); 2106 setNeedsStyleRecalc(); 2107 } 2108 2109 PassRefPtr<DocumentParser> Document::createParser() 2110 { 2111 if (isHTMLDocument()) { 2112 bool reportErrors = InspectorInstrumentation::collectingHTMLParseErrors(this->page()); 2113 return HTMLDocumentParser::create(toHTMLDocument(this), reportErrors); 2114 } 2115 // FIXME: this should probably pass the frame instead 2116 return XMLDocumentParser::create(this, view()); 2117 } 2118 2119 bool Document::isFrameSet() const 2120 { 2121 if (!isHTMLDocument()) 2122 return false; 2123 HTMLElement* bodyElement = body(); 2124 return bodyElement && bodyElement->hasTagName(framesetTag); 2125 } 2126 2127 ScriptableDocumentParser* Document::scriptableDocumentParser() const 2128 { 2129 return parser() ? parser()->asScriptableDocumentParser() : 0; 2130 } 2131 2132 void Document::open(Document* ownerDocument) 2133 { 2134 if (ownerDocument) { 2135 setURL(ownerDocument->url()); 2136 m_cookieURL = ownerDocument->cookieURL(); 2137 setSecurityOrigin(ownerDocument->securityOrigin()); 2138 } 2139 2140 if (m_frame) { 2141 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) { 2142 if (parser->isParsing()) { 2143 // FIXME: HTML5 doesn't tell us to check this, it might not be correct. 2144 if (parser->isExecutingScript()) 2145 return; 2146 2147 if (!parser->wasCreatedByScript() && parser->hasInsertionPoint()) 2148 return; 2149 } 2150 } 2151 2152 if (m_frame->loader().state() == FrameStateProvisional) 2153 m_frame->loader().stopAllLoaders(); 2154 } 2155 2156 removeAllEventListeners(); 2157 implicitOpen(); 2158 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) 2159 parser->setWasCreatedByScript(true); 2160 2161 if (m_frame) 2162 m_frame->loader().didExplicitOpen(); 2163 if (m_loadEventProgress != LoadEventInProgress && m_loadEventProgress != UnloadEventInProgress) 2164 m_loadEventProgress = LoadEventNotRun; 2165 } 2166 2167 void Document::detachParser() 2168 { 2169 if (!m_parser) 2170 return; 2171 m_parser->detach(); 2172 m_parser.clear(); 2173 } 2174 2175 void Document::cancelParsing() 2176 { 2177 if (!m_parser) 2178 return; 2179 2180 // We have to clear the parser to avoid possibly triggering 2181 // the onload handler when closing as a side effect of a cancel-style 2182 // change, such as opening a new document or closing the window while 2183 // still parsing. 2184 detachParser(); 2185 explicitClose(); 2186 } 2187 2188 PassRefPtr<DocumentParser> Document::implicitOpen() 2189 { 2190 cancelParsing(); 2191 2192 removeChildren(); 2193 ASSERT(!m_focusedElement); 2194 2195 setCompatibilityMode(NoQuirksMode); 2196 2197 // Documents rendered seamlessly should start out requiring a stylesheet 2198 // collection update in order to ensure they inherit all the relevant data 2199 // from their parent. 2200 if (shouldDisplaySeamlesslyWithParent()) 2201 styleResolverChanged(RecalcStyleDeferred); 2202 2203 m_parser = createParser(); 2204 setParsing(true); 2205 setReadyState(Loading); 2206 2207 return m_parser; 2208 } 2209 2210 HTMLElement* Document::body() const 2211 { 2212 if (!documentElement()) 2213 return 0; 2214 2215 for (Node* child = documentElement()->firstChild(); child; child = child->nextSibling()) { 2216 if (child->hasTagName(framesetTag) || child->hasTagName(bodyTag)) 2217 return toHTMLElement(child); 2218 } 2219 2220 return 0; 2221 } 2222 2223 void Document::setBody(PassRefPtr<HTMLElement> prpNewBody, ExceptionState& exceptionState) 2224 { 2225 RefPtr<HTMLElement> newBody = prpNewBody; 2226 2227 if (!newBody || !documentElement()) { 2228 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError); 2229 return; 2230 } 2231 2232 if (!newBody->hasTagName(bodyTag) && !newBody->hasTagName(framesetTag)) { 2233 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError); 2234 return; 2235 } 2236 2237 HTMLElement* oldBody = body(); 2238 if (oldBody == newBody) 2239 return; 2240 2241 if (oldBody) 2242 documentElement()->replaceChild(newBody.release(), oldBody, exceptionState); 2243 else 2244 documentElement()->appendChild(newBody.release(), exceptionState); 2245 } 2246 2247 HTMLHeadElement* Document::head() 2248 { 2249 Node* de = documentElement(); 2250 if (!de) 2251 return 0; 2252 2253 for (Node* node = de->firstChild(); node; node = node->nextSibling()) { 2254 if (node->hasTagName(headTag)) 2255 return toHTMLHeadElement(node); 2256 } 2257 return 0; 2258 } 2259 2260 void Document::close() 2261 { 2262 // FIXME: We should follow the specification more closely: 2263 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close 2264 2265 if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript() || !scriptableDocumentParser()->isParsing()) 2266 return; 2267 2268 explicitClose(); 2269 } 2270 2271 void Document::explicitClose() 2272 { 2273 if (RefPtr<DocumentParser> parser = m_parser) 2274 parser->finish(); 2275 2276 if (!m_frame) { 2277 // Because we have no frame, we don't know if all loading has completed, 2278 // so we just call implicitClose() immediately. FIXME: This might fire 2279 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>. 2280 implicitClose(); 2281 return; 2282 } 2283 2284 m_frame->loader().checkCompleted(); 2285 } 2286 2287 void Document::implicitClose() 2288 { 2289 ASSERT(!inStyleRecalc()); 2290 2291 bool wasLocationChangePending = frame() && frame()->navigationScheduler().locationChangePending(); 2292 bool doload = !parsing() && m_parser && !processingLoadEvent() && !wasLocationChangePending; 2293 2294 // If the load was blocked because of a pending location change and the location change triggers a same document 2295 // navigation, don't fire load events after the same document navigation completes (unless there's an explicit open). 2296 m_loadEventProgress = LoadEventTried; 2297 2298 if (!doload) 2299 return; 2300 2301 // The call to dispatchWindowLoadEvent can detach the DOMWindow and cause it (and its 2302 // attached Document) to be destroyed. 2303 RefPtr<DOMWindow> protectedWindow(this->domWindow()); 2304 2305 m_loadEventProgress = LoadEventInProgress; 2306 2307 ScriptableDocumentParser* parser = scriptableDocumentParser(); 2308 m_wellFormed = parser && parser->wellFormed(); 2309 2310 // We have to clear the parser, in case someone document.write()s from the 2311 // onLoad event handler, as in Radar 3206524. 2312 detachParser(); 2313 2314 if (frame() && frame()->script().canExecuteScripts(NotAboutToExecuteScript)) { 2315 ImageLoader::dispatchPendingBeforeLoadEvents(); 2316 ImageLoader::dispatchPendingLoadEvents(); 2317 ImageLoader::dispatchPendingErrorEvents(); 2318 2319 HTMLLinkElement::dispatchPendingLoadEvents(); 2320 HTMLStyleElement::dispatchPendingLoadEvents(); 2321 } 2322 2323 // JS running below could remove the frame or destroy the RenderView so we call 2324 // those two functions repeatedly and don't save them on the stack. 2325 2326 // To align the HTML load event and the SVGLoad event for the outermost <svg> element, fire it from 2327 // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false", 2328 // which is the default, for ='true' its fired at a later time, once all external resources finished loading). 2329 if (svgExtensions()) 2330 accessSVGExtensions()->dispatchSVGLoadEventToOutermostSVGElements(); 2331 2332 if (protectedWindow) 2333 protectedWindow->documentWasClosed(); 2334 2335 if (frame()) { 2336 frame()->loader().client()->dispatchDidHandleOnloadEvents(); 2337 loader()->applicationCacheHost()->stopDeferringEvents(); 2338 } 2339 2340 if (!frame()) { 2341 m_loadEventProgress = LoadEventCompleted; 2342 return; 2343 } 2344 2345 // Make sure both the initial layout and reflow happen after the onload 2346 // fires. This will improve onload scores, and other browsers do it. 2347 // If they wanna cheat, we can too. -dwh 2348 2349 if (frame()->navigationScheduler().locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) { 2350 // Just bail out. Before or during the onload we were shifted to another page. 2351 // The old i-Bench suite does this. When this happens don't bother painting or laying out. 2352 m_loadEventProgress = LoadEventCompleted; 2353 view()->unscheduleRelayout(); 2354 return; 2355 } 2356 2357 // We used to force a synchronous display and flush here. This really isn't 2358 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps 2359 // (if your platform is syncing flushes and limiting them to 60fps). 2360 m_overMinimumLayoutThreshold = true; 2361 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) { 2362 updateStyleIfNeeded(); 2363 2364 // Always do a layout after loading if needed. 2365 if (view() && renderView() && (!renderView()->firstChild() || renderView()->needsLayout())) 2366 view()->layout(); 2367 } 2368 2369 m_loadEventProgress = LoadEventCompleted; 2370 2371 if (frame() && renderView() && AXObjectCache::accessibilityEnabled()) { 2372 // The AX cache may have been cleared at this point, but we need to make sure it contains an 2373 // AX object to send the notification to. getOrCreate will make sure that an valid AX object 2374 // exists in the cache (we ignore the return value because we don't need it here). This is 2375 // only safe to call when a layout is not in progress, so it can not be used in postNotification. 2376 if (AXObjectCache* cache = axObjectCache()) { 2377 cache->getOrCreate(renderView()); 2378 if (this == topDocument()) { 2379 cache->postNotification(renderView(), AXObjectCache::AXLoadComplete, true); 2380 } else { 2381 // AXLoadComplete can only be posted on the top document, so if it's a document 2382 // in an iframe that just finished loading, post AXLayoutComplete instead. 2383 cache->postNotification(renderView(), AXObjectCache::AXLayoutComplete, true); 2384 } 2385 } 2386 } 2387 2388 if (svgExtensions()) 2389 accessSVGExtensions()->startAnimations(); 2390 } 2391 2392 bool Document::dispatchBeforeUnloadEvent(Chrome& chrome, bool& didAllowNavigation) 2393 { 2394 if (!m_domWindow) 2395 return true; 2396 2397 if (!body()) 2398 return true; 2399 2400 RefPtr<Document> protect(this); 2401 2402 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); 2403 m_loadEventProgress = BeforeUnloadEventInProgress; 2404 m_domWindow->dispatchEvent(beforeUnloadEvent.get(), this); 2405 m_loadEventProgress = BeforeUnloadEventCompleted; 2406 if (!beforeUnloadEvent->defaultPrevented()) 2407 defaultEventHandler(beforeUnloadEvent.get()); 2408 if (beforeUnloadEvent->returnValue().isNull()) 2409 return true; 2410 2411 if (didAllowNavigation) { 2412 addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation."); 2413 return true; 2414 } 2415 2416 String text = beforeUnloadEvent->returnValue(); 2417 if (chrome.runBeforeUnloadConfirmPanel(text, m_frame)) { 2418 didAllowNavigation = true; 2419 return true; 2420 } 2421 return false; 2422 } 2423 2424 void Document::dispatchUnloadEvents() 2425 { 2426 RefPtr<Document> protect(this); 2427 if (m_parser) 2428 m_parser->stopParsing(); 2429 2430 if (m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress) { 2431 Element* currentFocusedElement = focusedElement(); 2432 if (currentFocusedElement && currentFocusedElement->hasTagName(inputTag)) 2433 toHTMLInputElement(currentFocusedElement)->endEditing(); 2434 if (m_loadEventProgress < PageHideInProgress) { 2435 m_loadEventProgress = PageHideInProgress; 2436 if (DOMWindow* window = domWindow()) 2437 window->dispatchEvent(PageTransitionEvent::create(EventTypeNames::pagehide, false), this); 2438 if (!m_frame) 2439 return; 2440 2441 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed 2442 // while dispatching the event, so protect it to prevent writing the end 2443 // time into freed memory. 2444 RefPtr<DocumentLoader> documentLoader = m_frame->loader().provisionalDocumentLoader(); 2445 m_loadEventProgress = UnloadEventInProgress; 2446 RefPtr<Event> unloadEvent(Event::create(EventTypeNames::unload)); 2447 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) { 2448 DocumentLoadTiming* timing = documentLoader->timing(); 2449 ASSERT(timing->navigationStart()); 2450 timing->markUnloadEventStart(); 2451 m_frame->domWindow()->dispatchEvent(unloadEvent, this); 2452 timing->markUnloadEventEnd(); 2453 } else { 2454 m_frame->domWindow()->dispatchEvent(unloadEvent, m_frame->document()); 2455 } 2456 } 2457 m_loadEventProgress = UnloadEventHandled; 2458 } 2459 2460 if (!m_frame) 2461 return; 2462 2463 // Don't remove event listeners from a transitional empty document (see https://bugs.webkit.org/show_bug.cgi?id=28716 for more information). 2464 bool keepEventListeners = m_frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader().provisionalDocumentLoader() 2465 && isSecureTransitionTo(m_frame->loader().provisionalDocumentLoader()->url()); 2466 if (!keepEventListeners) 2467 removeAllEventListeners(); 2468 } 2469 2470 Document::PageDismissalType Document::pageDismissalEventBeingDispatched() const 2471 { 2472 if (m_loadEventProgress == BeforeUnloadEventInProgress) 2473 return BeforeUnloadDismissal; 2474 if (m_loadEventProgress == PageHideInProgress) 2475 return PageHideDismissal; 2476 if (m_loadEventProgress == UnloadEventInProgress) 2477 return UnloadDismissal; 2478 return NoDismissal; 2479 } 2480 2481 void Document::setParsing(bool b) 2482 { 2483 m_bParsing = b; 2484 2485 if (m_bParsing && !m_sharedObjectPool) 2486 m_sharedObjectPool = DocumentSharedObjectPool::create(); 2487 2488 if (!m_bParsing && view()) 2489 view()->scheduleRelayout(); 2490 } 2491 2492 bool Document::shouldScheduleLayout() 2493 { 2494 // This function will only be called when FrameView thinks a layout is needed. 2495 // This enforces a couple extra rules. 2496 // 2497 // (a) Only schedule a layout once the stylesheets are loaded. 2498 // (b) Only schedule layout once we have a body element. 2499 2500 return (haveStylesheetsLoaded() && body()) 2501 || (documentElement() && !isHTMLHtmlElement(documentElement())); 2502 } 2503 2504 bool Document::shouldParserYieldAgressivelyBeforeScriptExecution() 2505 { 2506 return view() && view()->layoutPending() && !minimumLayoutDelay(); 2507 } 2508 2509 int Document::minimumLayoutDelay() 2510 { 2511 if (m_overMinimumLayoutThreshold) 2512 return 0; 2513 2514 int elapsed = elapsedTime(); 2515 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold; 2516 2517 // We'll want to schedule the timer to fire at the minimum layout threshold. 2518 return max(0, cLayoutScheduleThreshold - elapsed); 2519 } 2520 2521 int Document::elapsedTime() const 2522 { 2523 return static_cast<int>((currentTime() - m_startTime) * 1000); 2524 } 2525 2526 void Document::write(const SegmentedString& text, Document* ownerDocument) 2527 { 2528 NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth); 2529 2530 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep; 2531 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep; 2532 2533 if (m_writeRecursionIsTooDeep) 2534 return; 2535 2536 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint(); 2537 if (!hasInsertionPoint && m_ignoreDestructiveWriteCount) 2538 return; 2539 2540 if (!hasInsertionPoint) 2541 open(ownerDocument); 2542 2543 ASSERT(m_parser); 2544 m_parser->insert(text); 2545 } 2546 2547 void Document::write(const String& text, Document* ownerDocument) 2548 { 2549 write(SegmentedString(text), ownerDocument); 2550 } 2551 2552 void Document::writeln(const String& text, Document* ownerDocument) 2553 { 2554 write(text, ownerDocument); 2555 write("\n", ownerDocument); 2556 } 2557 2558 const KURL& Document::virtualURL() const 2559 { 2560 return m_url; 2561 } 2562 2563 KURL Document::virtualCompleteURL(const String& url) const 2564 { 2565 return completeURL(url); 2566 } 2567 2568 double Document::timerAlignmentInterval() const 2569 { 2570 Page* p = page(); 2571 if (!p) 2572 return DOMTimer::visiblePageAlignmentInterval(); 2573 return p->timerAlignmentInterval(); 2574 } 2575 2576 EventTarget* Document::errorEventTarget() 2577 { 2578 return domWindow(); 2579 } 2580 2581 void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack) 2582 { 2583 internalAddMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack, 0); 2584 } 2585 2586 void Document::setURL(const KURL& url) 2587 { 2588 const KURL& newURL = url.isEmpty() ? blankURL() : url; 2589 if (newURL == m_url) 2590 return; 2591 2592 m_url = newURL; 2593 m_documentURI = m_url.string(); 2594 updateBaseURL(); 2595 contextFeatures()->urlDidChange(this); 2596 } 2597 2598 void Document::updateBaseURL() 2599 { 2600 KURL oldBaseURL = m_baseURL; 2601 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using 2602 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute 2603 // from the Document interface otherwise. 2604 if (!m_baseElementURL.isEmpty()) 2605 m_baseURL = m_baseElementURL; 2606 else if (!m_baseURLOverride.isEmpty()) 2607 m_baseURL = m_baseURLOverride; 2608 else { 2609 // The documentURI attribute is read-only from JavaScript, but writable from Objective C, so we need to retain 2610 // this fallback behavior. We use a null base URL, since the documentURI attribute is an arbitrary string 2611 // and DOM 3 Core does not specify how it should be resolved. 2612 // FIXME: Now that we don't support Objective-C this can probably be removed. 2613 m_baseURL = KURL(ParsedURLString, documentURI()); 2614 } 2615 selectorQueryCache().invalidate(); 2616 2617 if (!m_baseURL.isValid()) 2618 m_baseURL = KURL(); 2619 2620 if (m_elemSheet) { 2621 // Element sheet is silly. It never contains anything. 2622 ASSERT(!m_elemSheet->contents()->ruleCount()); 2623 bool usesRemUnits = m_elemSheet->contents()->usesRemUnits(); 2624 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL); 2625 // FIXME: So we are not really the parser. The right fix is to eliminate the element sheet completely. 2626 m_elemSheet->contents()->parserSetUsesRemUnits(usesRemUnits); 2627 } 2628 2629 if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) { 2630 // Base URL change changes any relative visited links. 2631 // FIXME: There are other URLs in the tree that would need to be re-evaluated on dynamic base URL change. Style should be invalidated too. 2632 for (Element* element = ElementTraversal::firstWithin(*this); element; element = ElementTraversal::next(*element)) { 2633 if (isHTMLAnchorElement(element)) 2634 toHTMLAnchorElement(element)->invalidateCachedVisitedLinkHash(); 2635 } 2636 } 2637 } 2638 2639 void Document::setBaseURLOverride(const KURL& url) 2640 { 2641 m_baseURLOverride = url; 2642 updateBaseURL(); 2643 } 2644 2645 void Document::processBaseElement() 2646 { 2647 // Find the first href attribute in a base element and the first target attribute in a base element. 2648 const AtomicString* href = 0; 2649 const AtomicString* target = 0; 2650 for (Element* element = ElementTraversal::firstWithin(*this); element && (!href || !target); element = ElementTraversal::next(*element)) { 2651 if (element->hasTagName(baseTag)) { 2652 if (!href) { 2653 const AtomicString& value = element->fastGetAttribute(hrefAttr); 2654 if (!value.isNull()) 2655 href = &value; 2656 } 2657 if (!target) { 2658 const AtomicString& value = element->fastGetAttribute(targetAttr); 2659 if (!value.isNull()) 2660 target = &value; 2661 } 2662 if (contentSecurityPolicy()->isActive()) 2663 UseCounter::count(*this, UseCounter::ContentSecurityPolicyWithBaseElement); 2664 } 2665 } 2666 2667 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly. 2668 KURL baseElementURL; 2669 if (href) { 2670 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href); 2671 if (!strippedHref.isEmpty()) 2672 baseElementURL = KURL(url(), strippedHref); 2673 } 2674 if (m_baseElementURL != baseElementURL && contentSecurityPolicy()->allowBaseURI(baseElementURL)) { 2675 m_baseElementURL = baseElementURL; 2676 updateBaseURL(); 2677 } 2678 2679 m_baseTarget = target ? *target : nullAtom; 2680 } 2681 2682 String Document::userAgent(const KURL& url) const 2683 { 2684 return frame() ? frame()->loader().userAgent(url) : String(); 2685 } 2686 2687 void Document::disableEval(const String& errorMessage) 2688 { 2689 if (!frame()) 2690 return; 2691 2692 frame()->script().disableEval(errorMessage); 2693 } 2694 2695 bool Document::canNavigate(Frame* targetFrame) 2696 { 2697 if (!m_frame) 2698 return false; 2699 2700 // FIXME: We shouldn't call this function without a target frame, but 2701 // fast/forms/submit-to-blank-multiple-times.html depends on this function 2702 // returning true when supplied with a 0 targetFrame. 2703 if (!targetFrame) 2704 return true; 2705 2706 // Frame-busting is generally allowed, but blocked for sandboxed frames lacking the 'allow-top-navigation' flag. 2707 if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree().top()) 2708 return true; 2709 2710 if (isSandboxed(SandboxNavigation)) { 2711 if (targetFrame->tree().isDescendantOf(m_frame)) 2712 return true; 2713 2714 const char* reason = "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors."; 2715 if (isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree().top()) 2716 reason = "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set."; 2717 2718 printNavigationErrorMessage(*targetFrame, url(), reason); 2719 return false; 2720 } 2721 2722 ASSERT(securityOrigin()); 2723 SecurityOrigin& origin = *securityOrigin(); 2724 2725 // This is the normal case. A document can navigate its decendant frames, 2726 // or, more generally, a document can navigate a frame if the document is 2727 // in the same origin as any of that frame's ancestors (in the frame 2728 // hierarchy). 2729 // 2730 // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for 2731 // historical information about this security check. 2732 if (canAccessAncestor(origin, targetFrame)) 2733 return true; 2734 2735 // Top-level frames are easier to navigate than other frames because they 2736 // display their URLs in the address bar (in most browsers). However, there 2737 // are still some restrictions on navigation to avoid nuisance attacks. 2738 // Specifically, a document can navigate a top-level frame if that frame 2739 // opened the document or if the document is the same-origin with any of 2740 // the top-level frame's opener's ancestors (in the frame hierarchy). 2741 // 2742 // In both of these cases, the document performing the navigation is in 2743 // some way related to the frame being navigate (e.g., by the "opener" 2744 // and/or "parent" relation). Requiring some sort of relation prevents a 2745 // document from navigating arbitrary, unrelated top-level frames. 2746 if (!targetFrame->tree().parent()) { 2747 if (targetFrame == m_frame->loader().opener()) 2748 return true; 2749 2750 if (canAccessAncestor(origin, targetFrame->loader().opener())) 2751 return true; 2752 } 2753 2754 printNavigationErrorMessage(*targetFrame, url(), "The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener."); 2755 return false; 2756 } 2757 2758 Frame* Document::findUnsafeParentScrollPropagationBoundary() 2759 { 2760 Frame* currentFrame = m_frame; 2761 Frame* ancestorFrame = currentFrame->tree().parent(); 2762 2763 while (ancestorFrame) { 2764 if (!ancestorFrame->document()->securityOrigin()->canAccess(securityOrigin())) 2765 return currentFrame; 2766 currentFrame = ancestorFrame; 2767 ancestorFrame = ancestorFrame->tree().parent(); 2768 } 2769 return 0; 2770 } 2771 2772 2773 void Document::seamlessParentUpdatedStylesheets() 2774 { 2775 m_styleEngine->didModifySeamlessParentStyleSheet(); 2776 styleResolverChanged(RecalcStyleImmediately); 2777 } 2778 2779 void Document::didRemoveAllPendingStylesheet() 2780 { 2781 m_needsNotifyRemoveAllPendingStylesheet = false; 2782 2783 styleResolverChanged(RecalcStyleDeferred, AnalyzedStyleUpdate); 2784 executeScriptsWaitingForResourcesIfNeeded(); 2785 2786 if (m_gotoAnchorNeededAfterStylesheetsLoad && view()) 2787 view()->scrollToFragment(m_url); 2788 } 2789 2790 void Document::executeScriptsWaitingForResourcesIfNeeded() 2791 { 2792 if (!haveStylesheetsAndImportsLoaded()) 2793 return; 2794 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) 2795 parser->executeScriptsWaitingForResources(); 2796 } 2797 2798 2799 CSSStyleSheet* Document::elementSheet() 2800 { 2801 if (!m_elemSheet) 2802 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL); 2803 return m_elemSheet.get(); 2804 } 2805 2806 void Document::processHttpEquiv(const AtomicString& equiv, const AtomicString& content) 2807 { 2808 ASSERT(!equiv.isNull() && !content.isNull()); 2809 2810 if (equalIgnoringCase(equiv, "default-style")) 2811 processHttpEquivDefaultStyle(content); 2812 else if (equalIgnoringCase(equiv, "refresh")) 2813 processHttpEquivRefresh(content); 2814 else if (equalIgnoringCase(equiv, "set-cookie")) 2815 processHttpEquivSetCookie(content); 2816 else if (equalIgnoringCase(equiv, "content-language")) 2817 setContentLanguage(content); 2818 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) 2819 parseDNSPrefetchControlHeader(content); 2820 else if (equalIgnoringCase(equiv, "x-frame-options")) 2821 processHttpEquivXFrameOptions(content); 2822 else if (equalIgnoringCase(equiv, "content-security-policy") 2823 || equalIgnoringCase(equiv, "content-security-policy-report-only") 2824 || equalIgnoringCase(equiv, "x-webkit-csp") 2825 || equalIgnoringCase(equiv, "x-webkit-csp-report-only")) 2826 processHttpEquivContentSecurityPolicy(equiv, content); 2827 } 2828 2829 void Document::processHttpEquivContentSecurityPolicy(const AtomicString& equiv, const AtomicString& content) 2830 { 2831 if (equalIgnoringCase(equiv, "content-security-policy")) 2832 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Enforce); 2833 else if (equalIgnoringCase(equiv, "content-security-policy-report-only")) 2834 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Report); 2835 // FIXME: Remove deprecation messages after the next release branch. 2836 else if (equalIgnoringCase(equiv, "x-webkit-csp")) 2837 UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicy); 2838 else if (equalIgnoringCase(equiv, "x-webkit-csp-report-only")) 2839 UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicyReportOnly); 2840 else 2841 ASSERT_NOT_REACHED(); 2842 } 2843 2844 void Document::processHttpEquivDefaultStyle(const AtomicString& content) 2845 { 2846 // The preferred style set has been overridden as per section 2847 // 14.3.2 of the HTML4.0 specification. We need to update the 2848 // sheet used variable and then update our style selector. 2849 // For more info, see the test at: 2850 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html 2851 // -dwh 2852 m_styleEngine->setSelectedStylesheetSetName(content); 2853 m_styleEngine->setPreferredStylesheetSetName(content); 2854 styleResolverChanged(RecalcStyleDeferred); 2855 } 2856 2857 void Document::processHttpEquivRefresh(const AtomicString& content) 2858 { 2859 maybeHandleHttpRefresh(content, HttpRefreshFromMetaTag); 2860 } 2861 2862 void Document::maybeHandleHttpRefresh(const String& content, HttpRefreshType httpRefreshType) 2863 { 2864 if (m_isViewSource || !m_frame) 2865 return; 2866 2867 double delay; 2868 String refreshURL; 2869 if (!parseHTTPRefresh(content, httpRefreshType == HttpRefreshFromMetaTag, delay, refreshURL)) 2870 return; 2871 if (refreshURL.isEmpty()) 2872 refreshURL = url().string(); 2873 else 2874 refreshURL = completeURL(refreshURL).string(); 2875 2876 if (protocolIsJavaScript(refreshURL)) { 2877 String message = "Refused to refresh " + m_url.elidedString() + " to a javascript: URL"; 2878 addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message); 2879 return; 2880 } 2881 2882 if (httpRefreshType == HttpRefreshFromMetaTag && isSandboxed(SandboxAutomaticFeatures)) { 2883 String message = "Refused to execute the redirect specified via '<meta http-equiv='refresh' content='...'>'. The document is sandboxed, and the 'allow-scripts' keyword is not set."; 2884 addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message); 2885 return; 2886 } 2887 m_frame->navigationScheduler().scheduleRedirect(delay, refreshURL); 2888 } 2889 2890 void Document::processHttpEquivSetCookie(const AtomicString& content) 2891 { 2892 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....> 2893 if (!isHTMLDocument()) 2894 return; 2895 2896 // Exception (for sandboxed documents) ignored. 2897 toHTMLDocument(this)->setCookie(content, IGNORE_EXCEPTION); 2898 } 2899 2900 void Document::processHttpEquivXFrameOptions(const AtomicString& content) 2901 { 2902 Frame* frame = this->frame(); 2903 if (!frame) 2904 return; 2905 2906 FrameLoader& frameLoader = frame->loader(); 2907 unsigned long requestIdentifier = loader()->mainResourceIdentifier(); 2908 if (frameLoader.shouldInterruptLoadForXFrameOptions(content, url(), requestIdentifier)) { 2909 String message = "Refused to display '" + url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'."; 2910 frameLoader.stopAllLoaders(); 2911 // Stopping the loader isn't enough, as we're already parsing the document; to honor the header's 2912 // intent, we must navigate away from the possibly partially-rendered document to a location that 2913 // doesn't inherit the parent's SecurityOrigin. 2914 frame->navigationScheduler().scheduleLocationChange(this, SecurityOrigin::urlWithUniqueSecurityOrigin(), String()); 2915 addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier); 2916 } 2917 } 2918 2919 bool Document::shouldMergeWithLegacyDescription(ViewportDescription::Type origin) 2920 { 2921 return settings() && settings()->viewportMetaMergeContentQuirk() && m_legacyViewportDescription.isMetaViewportType() && m_legacyViewportDescription.type == origin; 2922 } 2923 2924 void Document::setViewportDescription(const ViewportDescription& viewportDescription) 2925 { 2926 if (viewportDescription.isLegacyViewportType()) { 2927 if (settings() && !settings()->viewportMetaEnabled()) 2928 return; 2929 2930 m_legacyViewportDescription = viewportDescription; 2931 2932 // When no author style for @viewport is present, and a meta tag for defining 2933 // the viewport is, apply the meta tag viewport instead of the UA styles. 2934 if (m_viewportDescription.type == ViewportDescription::AuthorStyleSheet) 2935 return; 2936 m_viewportDescription = viewportDescription; 2937 } else { 2938 // If the legacy viewport tag has higher priority than the cascaded @viewport 2939 // descriptors, use the values from the legacy tag. 2940 if (!shouldOverrideLegacyDescription(viewportDescription.type)) 2941 m_viewportDescription = m_legacyViewportDescription; 2942 else 2943 m_viewportDescription = viewportDescription; 2944 } 2945 2946 updateViewportDescription(); 2947 } 2948 2949 void Document::updateViewportDescription() 2950 { 2951 if (frame() && frame()->isMainFrame()) { 2952 #ifndef NDEBUG 2953 m_didDispatchViewportPropertiesChanged = true; 2954 #endif 2955 page()->chrome().dispatchViewportPropertiesDidChange(m_viewportDescription); 2956 } 2957 } 2958 2959 void Document::processReferrerPolicy(const String& policy) 2960 { 2961 ASSERT(!policy.isNull()); 2962 2963 m_referrerPolicy = ReferrerPolicyDefault; 2964 2965 if (equalIgnoringCase(policy, "never")) 2966 m_referrerPolicy = ReferrerPolicyNever; 2967 else if (equalIgnoringCase(policy, "always")) 2968 m_referrerPolicy = ReferrerPolicyAlways; 2969 else if (equalIgnoringCase(policy, "origin")) 2970 m_referrerPolicy = ReferrerPolicyOrigin; 2971 } 2972 2973 String Document::outgoingReferrer() 2974 { 2975 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources 2976 // for why we walk the parent chain for srcdoc documents. 2977 Document* referrerDocument = this; 2978 if (Frame* frame = m_frame) { 2979 while (frame->document()->isSrcdocDocument()) { 2980 frame = frame->tree().parent(); 2981 // Srcdoc documents cannot be top-level documents, by definition, 2982 // because they need to be contained in iframes with the srcdoc. 2983 ASSERT(frame); 2984 } 2985 referrerDocument = frame->document(); 2986 } 2987 return referrerDocument->m_url.strippedForUseAsReferrer(); 2988 } 2989 2990 String Document::outgoingOrigin() const 2991 { 2992 return securityOrigin()->toString(); 2993 } 2994 2995 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event) 2996 { 2997 ASSERT(!renderView() || renderView()->isRenderView()); 2998 2999 // RenderView::hitTest causes a layout, and we don't want to hit that until the first 3000 // layout because until then, there is nothing shown on the screen - the user can't 3001 // have intentionally clicked on something belonging to this page. Furthermore, 3002 // mousemove events before the first layout should not lead to a premature layout() 3003 // happening, which could show a flash of white. 3004 // See also the similar code in EventHandler::hitTestResultAtPoint. 3005 if (!renderView() || !view() || !view()->didFirstLayout()) 3006 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint())); 3007 3008 HitTestResult result(documentPoint); 3009 renderView()->hitTest(request, result); 3010 3011 if (!request.readOnly()) 3012 updateHoverActiveState(request, result.innerElement(), &event); 3013 3014 return MouseEventWithHitTestResults(event, result); 3015 } 3016 3017 // DOM Section 1.1.1 3018 bool Document::childTypeAllowed(NodeType type) const 3019 { 3020 switch (type) { 3021 case ATTRIBUTE_NODE: 3022 case CDATA_SECTION_NODE: 3023 case DOCUMENT_FRAGMENT_NODE: 3024 case DOCUMENT_NODE: 3025 case ENTITY_NODE: 3026 case NOTATION_NODE: 3027 case TEXT_NODE: 3028 case XPATH_NAMESPACE_NODE: 3029 return false; 3030 case COMMENT_NODE: 3031 case PROCESSING_INSTRUCTION_NODE: 3032 return true; 3033 case DOCUMENT_TYPE_NODE: 3034 case ELEMENT_NODE: 3035 // Documents may contain no more than one of each of these. 3036 // (One Element and one DocumentType.) 3037 for (Node* c = firstChild(); c; c = c->nextSibling()) 3038 if (c->nodeType() == type) 3039 return false; 3040 return true; 3041 } 3042 return false; 3043 } 3044 3045 bool Document::canReplaceChild(const Node& newChild, const Node& oldChild) const 3046 { 3047 if (oldChild.nodeType() == newChild.nodeType()) 3048 return true; 3049 3050 int numDoctypes = 0; 3051 int numElements = 0; 3052 3053 // First, check how many doctypes and elements we have, not counting 3054 // the child we're about to remove. 3055 for (Node* c = firstChild(); c; c = c->nextSibling()) { 3056 if (c == oldChild) 3057 continue; 3058 3059 switch (c->nodeType()) { 3060 case DOCUMENT_TYPE_NODE: 3061 numDoctypes++; 3062 break; 3063 case ELEMENT_NODE: 3064 numElements++; 3065 break; 3066 default: 3067 break; 3068 } 3069 } 3070 3071 // Then, see how many doctypes and elements might be added by the new child. 3072 if (newChild.nodeType() == DOCUMENT_FRAGMENT_NODE) { 3073 for (Node* c = newChild.firstChild(); c; c = c->nextSibling()) { 3074 switch (c->nodeType()) { 3075 case ATTRIBUTE_NODE: 3076 case CDATA_SECTION_NODE: 3077 case DOCUMENT_FRAGMENT_NODE: 3078 case DOCUMENT_NODE: 3079 case ENTITY_NODE: 3080 case NOTATION_NODE: 3081 case TEXT_NODE: 3082 case XPATH_NAMESPACE_NODE: 3083 return false; 3084 case COMMENT_NODE: 3085 case PROCESSING_INSTRUCTION_NODE: 3086 break; 3087 case DOCUMENT_TYPE_NODE: 3088 numDoctypes++; 3089 break; 3090 case ELEMENT_NODE: 3091 numElements++; 3092 break; 3093 } 3094 } 3095 } else { 3096 switch (newChild.nodeType()) { 3097 case ATTRIBUTE_NODE: 3098 case CDATA_SECTION_NODE: 3099 case DOCUMENT_FRAGMENT_NODE: 3100 case DOCUMENT_NODE: 3101 case ENTITY_NODE: 3102 case NOTATION_NODE: 3103 case TEXT_NODE: 3104 case XPATH_NAMESPACE_NODE: 3105 return false; 3106 case COMMENT_NODE: 3107 case PROCESSING_INSTRUCTION_NODE: 3108 return true; 3109 case DOCUMENT_TYPE_NODE: 3110 numDoctypes++; 3111 break; 3112 case ELEMENT_NODE: 3113 numElements++; 3114 break; 3115 } 3116 } 3117 3118 if (numElements > 1 || numDoctypes > 1) 3119 return false; 3120 3121 return true; 3122 } 3123 3124 PassRefPtr<Node> Document::cloneNode(bool deep) 3125 { 3126 RefPtr<Document> clone = cloneDocumentWithoutChildren(); 3127 clone->cloneDataFromDocument(*this); 3128 if (deep) 3129 cloneChildNodes(clone.get()); 3130 return clone.release(); 3131 } 3132 3133 PassRefPtr<Document> Document::cloneDocumentWithoutChildren() 3134 { 3135 DocumentInit init(url()); 3136 if (isXHTMLDocument()) 3137 return createXHTML(init.withRegistrationContext(registrationContext())); 3138 return create(init); 3139 } 3140 3141 void Document::cloneDataFromDocument(const Document& other) 3142 { 3143 setCompatibilityMode(other.compatibilityMode()); 3144 setEncodingData(other.m_encodingData); 3145 setContextFeatures(other.contextFeatures()); 3146 setSecurityOrigin(other.securityOrigin()->isolatedCopy()); 3147 } 3148 3149 StyleSheetList* Document::styleSheets() 3150 { 3151 if (!m_styleSheetList) 3152 m_styleSheetList = StyleSheetList::create(this); 3153 return m_styleSheetList.get(); 3154 } 3155 3156 String Document::preferredStylesheetSet() const 3157 { 3158 return m_styleEngine->preferredStylesheetSetName(); 3159 } 3160 3161 String Document::selectedStylesheetSet() const 3162 { 3163 return m_styleEngine->selectedStylesheetSetName(); 3164 } 3165 3166 void Document::setSelectedStylesheetSet(const String& aString) 3167 { 3168 m_styleEngine->setSelectedStylesheetSetName(aString); 3169 styleResolverChanged(RecalcStyleDeferred); 3170 } 3171 3172 void Document::evaluateMediaQueryList() 3173 { 3174 if (m_mediaQueryMatcher) 3175 m_mediaQueryMatcher->styleResolverChanged(); 3176 } 3177 3178 void Document::styleResolverChanged(RecalcStyleTime updateTime, StyleResolverUpdateMode updateMode) 3179 { 3180 // styleResolverChanged() can be invoked during Document destruction. 3181 // We just skip that case. 3182 if (!m_styleEngine) 3183 return; 3184 3185 StyleResolverChange change = m_styleEngine->resolverChanged(updateTime, updateMode); 3186 if (change.needsRepaint()) { 3187 // We need to manually repaint because we avoid doing all repaints in layout or style 3188 // recalc while sheets are still loading to avoid FOUC. 3189 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; 3190 renderView()->repaintViewAndCompositedLayers(); 3191 } 3192 3193 if (!change.needsStyleRecalc()) 3194 return; 3195 3196 m_evaluateMediaQueriesOnStyleRecalc = true; 3197 setNeedsStyleRecalc(); 3198 3199 if (updateTime == RecalcStyleImmediately) 3200 updateStyleIfNeeded(); 3201 } 3202 3203 void Document::notifySeamlessChildDocumentsOfStylesheetUpdate() const 3204 { 3205 // If we're not in a frame yet any potential child documents won't have a StyleResolver to update. 3206 if (!frame()) 3207 return; 3208 3209 // Seamless child frames are expected to notify their seamless children recursively, so we only do direct children. 3210 for (Frame* child = frame()->tree().firstChild(); child; child = child->tree().nextSibling()) { 3211 Document* childDocument = child->document(); 3212 if (childDocument->shouldDisplaySeamlesslyWithParent()) { 3213 ASSERT(childDocument->seamlessParentIFrame()->document() == this); 3214 childDocument->seamlessParentUpdatedStylesheets(); 3215 } 3216 } 3217 } 3218 3219 void Document::setHoverNode(PassRefPtr<Node> newHoverNode) 3220 { 3221 m_hoverNode = newHoverNode; 3222 } 3223 3224 void Document::setActiveElement(PassRefPtr<Element> newActiveElement) 3225 { 3226 if (!newActiveElement) { 3227 m_activeElement.clear(); 3228 return; 3229 } 3230 3231 m_activeElement = newActiveElement; 3232 } 3233 3234 void Document::removeFocusedElementOfSubtree(Node* node, bool amongChildrenOnly) 3235 { 3236 if (!m_focusedElement) 3237 return; 3238 3239 // We can't be focused if we're not in the document. 3240 if (!node->inDocument()) 3241 return; 3242 bool contains = node->containsIncludingShadowDOM(m_focusedElement.get()); 3243 if (contains && (m_focusedElement != node || !amongChildrenOnly)) 3244 setFocusedElement(0); 3245 } 3246 3247 void Document::hoveredNodeDetached(Node* node) 3248 { 3249 if (!m_hoverNode) 3250 return; 3251 3252 if (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != NodeRenderingTraversal::parent(m_hoverNode.get()))) 3253 return; 3254 3255 m_hoverNode = NodeRenderingTraversal::parent(node); 3256 while (m_hoverNode && !m_hoverNode->renderer()) 3257 m_hoverNode = NodeRenderingTraversal::parent(m_hoverNode.get()); 3258 3259 // If the mouse cursor is not visible, do not clear existing 3260 // hover effects on the ancestors of |node| and do not invoke 3261 // new hover effects on any other element. 3262 if (!page()->isCursorVisible()) 3263 return; 3264 3265 if (frame()) 3266 frame()->eventHandler().scheduleHoverStateUpdate(); 3267 } 3268 3269 void Document::activeChainNodeDetached(Node* node) 3270 { 3271 if (!m_activeElement) 3272 return; 3273 3274 if (node != m_activeElement && (!m_activeElement->isTextNode() || node != NodeRenderingTraversal::parent(m_activeElement.get()))) 3275 return; 3276 3277 Node* activeNode = NodeRenderingTraversal::parent(node); 3278 while (activeNode && activeNode->isElementNode() && !activeNode->renderer()) 3279 activeNode = NodeRenderingTraversal::parent(activeNode); 3280 3281 m_activeElement = activeNode && activeNode->isElementNode() ? toElement(activeNode) : 0; 3282 } 3283 3284 const Vector<AnnotatedRegionValue>& Document::annotatedRegions() const 3285 { 3286 return m_annotatedRegions; 3287 } 3288 3289 void Document::setAnnotatedRegions(const Vector<AnnotatedRegionValue>& regions) 3290 { 3291 m_annotatedRegions = regions; 3292 setAnnotatedRegionsDirty(false); 3293 } 3294 3295 bool Document::setFocusedElement(PassRefPtr<Element> prpNewFocusedElement, FocusDirection direction) 3296 { 3297 RefPtr<Element> newFocusedElement = prpNewFocusedElement; 3298 3299 // Make sure newFocusedNode is actually in this document 3300 if (newFocusedElement && (newFocusedElement->document() != this)) 3301 return true; 3302 3303 if (NodeChildRemovalTracker::isBeingRemoved(newFocusedElement.get())) 3304 return true; 3305 3306 if (m_focusedElement == newFocusedElement) 3307 return true; 3308 3309 bool focusChangeBlocked = false; 3310 RefPtr<Element> oldFocusedElement = m_focusedElement; 3311 m_focusedElement = 0; 3312 3313 // Remove focus from the existing focus node (if any) 3314 if (oldFocusedElement) { 3315 ASSERT(!oldFocusedElement->inDetach()); 3316 3317 if (oldFocusedElement->active()) 3318 oldFocusedElement->setActive(false); 3319 3320 oldFocusedElement->setFocus(false); 3321 3322 // Dispatch a change event for text fields or textareas that have been edited 3323 if (oldFocusedElement->wasChangedSinceLastFormControlChangeEvent()) 3324 oldFocusedElement->dispatchFormControlChangeEvent(); 3325 3326 // Dispatch the blur event and let the node do any other blur related activities (important for text fields) 3327 oldFocusedElement->dispatchBlurEvent(newFocusedElement.get()); 3328 3329 if (m_focusedElement) { 3330 // handler shifted focus 3331 focusChangeBlocked = true; 3332 newFocusedElement = 0; 3333 } 3334 3335 oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, newFocusedElement.get()); // DOM level 3 name for the bubbling blur event. 3336 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends 3337 // on it, probably when <rdar://problem/8503958> is resolved. 3338 oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, newFocusedElement.get()); // DOM level 2 name for compatibility. 3339 3340 if (m_focusedElement) { 3341 // handler shifted focus 3342 focusChangeBlocked = true; 3343 newFocusedElement = 0; 3344 } 3345 3346 if (view()) { 3347 Widget* oldWidget = widgetForElement(*oldFocusedElement); 3348 if (oldWidget) 3349 oldWidget->setFocus(false); 3350 else 3351 view()->setFocus(false); 3352 } 3353 } 3354 3355 if (newFocusedElement && newFocusedElement->isFocusable()) { 3356 if (newFocusedElement->isRootEditableElement() && !acceptsEditingFocus(*newFocusedElement)) { 3357 // delegate blocks focus change 3358 focusChangeBlocked = true; 3359 goto SetFocusedElementDone; 3360 } 3361 // Set focus on the new node 3362 m_focusedElement = newFocusedElement; 3363 3364 // Dispatch the focus event and let the node do any other focus related activities (important for text fields) 3365 m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), direction); 3366 3367 if (m_focusedElement != newFocusedElement) { 3368 // handler shifted focus 3369 focusChangeBlocked = true; 3370 goto SetFocusedElementDone; 3371 } 3372 3373 m_focusedElement->dispatchFocusInEvent(EventTypeNames::focusin, oldFocusedElement.get()); // DOM level 3 bubbling focus event. 3374 3375 if (m_focusedElement != newFocusedElement) { 3376 // handler shifted focus 3377 focusChangeBlocked = true; 3378 goto SetFocusedElementDone; 3379 } 3380 3381 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends 3382 // on it, probably when <rdar://problem/8503958> is m. 3383 m_focusedElement->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, oldFocusedElement.get()); // DOM level 2 for compatibility. 3384 3385 if (m_focusedElement != newFocusedElement) { 3386 // handler shifted focus 3387 focusChangeBlocked = true; 3388 goto SetFocusedElementDone; 3389 } 3390 m_focusedElement->setFocus(true); 3391 3392 if (m_focusedElement->isRootEditableElement()) 3393 frame()->spellChecker().didBeginEditing(m_focusedElement.get()); 3394 3395 // eww, I suck. set the qt focus correctly 3396 // ### find a better place in the code for this 3397 if (view()) { 3398 Widget* focusWidget = widgetForElement(*m_focusedElement); 3399 if (focusWidget) { 3400 // Make sure a widget has the right size before giving it focus. 3401 // Otherwise, we are testing edge cases of the Widget code. 3402 // Specifically, in WebCore this does not work well for text fields. 3403 updateLayout(); 3404 // Re-get the widget in case updating the layout changed things. 3405 focusWidget = widgetForElement(*m_focusedElement); 3406 } 3407 if (focusWidget) 3408 focusWidget->setFocus(true); 3409 else 3410 view()->setFocus(true); 3411 } 3412 } 3413 3414 if (!focusChangeBlocked && m_focusedElement) { 3415 // Create the AXObject cache in a focus change because Chromium relies on it. 3416 if (AXObjectCache* cache = axObjectCache()) 3417 cache->handleFocusedUIElementChanged(oldFocusedElement.get(), newFocusedElement.get()); 3418 } 3419 3420 if (!focusChangeBlocked && page()) 3421 page()->chrome().focusedNodeChanged(m_focusedElement.get()); 3422 3423 SetFocusedElementDone: 3424 updateStyleIfNeeded(); 3425 if (Frame* frame = this->frame()) 3426 frame->selection().didChangeFocus(); 3427 return !focusChangeBlocked; 3428 } 3429 3430 void Document::setCSSTarget(Element* n) 3431 { 3432 if (m_cssTarget) 3433 m_cssTarget->didAffectSelector(AffectedSelectorTarget); 3434 m_cssTarget = n; 3435 if (n) 3436 n->didAffectSelector(AffectedSelectorTarget); 3437 } 3438 3439 void Document::registerNodeList(LiveNodeListBase* list) 3440 { 3441 if (list->hasIdNameCache()) 3442 m_nodeListCounts[InvalidateOnIdNameAttrChange]++; 3443 m_nodeListCounts[list->invalidationType()]++; 3444 if (list->isRootedAtDocument()) 3445 m_listsInvalidatedAtDocument.add(list); 3446 } 3447 3448 void Document::unregisterNodeList(LiveNodeListBase* list) 3449 { 3450 if (list->hasIdNameCache()) 3451 m_nodeListCounts[InvalidateOnIdNameAttrChange]--; 3452 m_nodeListCounts[list->invalidationType()]--; 3453 if (list->isRootedAtDocument()) { 3454 ASSERT(m_listsInvalidatedAtDocument.contains(list)); 3455 m_listsInvalidatedAtDocument.remove(list); 3456 } 3457 } 3458 3459 void Document::attachNodeIterator(NodeIterator* ni) 3460 { 3461 m_nodeIterators.add(ni); 3462 } 3463 3464 void Document::detachNodeIterator(NodeIterator* ni) 3465 { 3466 // The node iterator can be detached without having been attached if its root node didn't have a document 3467 // when the iterator was created, but has it now. 3468 m_nodeIterators.remove(ni); 3469 } 3470 3471 void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument) 3472 { 3473 HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators; 3474 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = nodeIteratorsList.end(); 3475 for (HashSet<NodeIterator*>::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) { 3476 if ((*it)->root() == node) { 3477 detachNodeIterator(*it); 3478 newDocument->attachNodeIterator(*it); 3479 } 3480 } 3481 } 3482 3483 void Document::updateRangesAfterChildrenChanged(ContainerNode* container) 3484 { 3485 if (!m_ranges.isEmpty()) { 3486 HashSet<Range*>::const_iterator end = m_ranges.end(); 3487 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3488 (*it)->nodeChildrenChanged(container); 3489 } 3490 } 3491 3492 void Document::nodeChildrenWillBeRemoved(ContainerNode* container) 3493 { 3494 NoEventDispatchAssertion assertNoEventDispatch; 3495 if (!m_ranges.isEmpty()) { 3496 HashSet<Range*>::const_iterator end = m_ranges.end(); 3497 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3498 (*it)->nodeChildrenWillBeRemoved(container); 3499 } 3500 3501 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); 3502 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) { 3503 for (Node* n = container->firstChild(); n; n = n->nextSibling()) 3504 (*it)->nodeWillBeRemoved(*n); 3505 } 3506 3507 if (Frame* frame = this->frame()) { 3508 for (Node* n = container->firstChild(); n; n = n->nextSibling()) { 3509 frame->eventHandler().nodeWillBeRemoved(*n); 3510 frame->selection().nodeWillBeRemoved(*n); 3511 frame->page()->dragCaretController().nodeWillBeRemoved(*n); 3512 } 3513 } 3514 } 3515 3516 void Document::nodeWillBeRemoved(Node& n) 3517 { 3518 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); 3519 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) 3520 (*it)->nodeWillBeRemoved(n); 3521 3522 if (!m_ranges.isEmpty()) { 3523 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end(); 3524 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it) 3525 (*it)->nodeWillBeRemoved(n); 3526 } 3527 3528 if (Frame* frame = this->frame()) { 3529 frame->eventHandler().nodeWillBeRemoved(n); 3530 frame->selection().nodeWillBeRemoved(n); 3531 frame->page()->dragCaretController().nodeWillBeRemoved(n); 3532 } 3533 } 3534 3535 void Document::didInsertText(Node* text, unsigned offset, unsigned length) 3536 { 3537 if (!m_ranges.isEmpty()) { 3538 HashSet<Range*>::const_iterator end = m_ranges.end(); 3539 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3540 (*it)->didInsertText(text, offset, length); 3541 } 3542 3543 // Update the markers for spelling and grammar checking. 3544 m_markers->shiftMarkers(text, offset, length); 3545 } 3546 3547 void Document::didRemoveText(Node* text, unsigned offset, unsigned length) 3548 { 3549 if (!m_ranges.isEmpty()) { 3550 HashSet<Range*>::const_iterator end = m_ranges.end(); 3551 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3552 (*it)->didRemoveText(text, offset, length); 3553 } 3554 3555 // Update the markers for spelling and grammar checking. 3556 m_markers->removeMarkers(text, offset, length); 3557 m_markers->shiftMarkers(text, offset + length, 0 - length); 3558 } 3559 3560 void Document::didMergeTextNodes(Text* oldNode, unsigned offset) 3561 { 3562 if (!m_ranges.isEmpty()) { 3563 NodeWithIndex oldNodeWithIndex(oldNode); 3564 HashSet<Range*>::const_iterator end = m_ranges.end(); 3565 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3566 (*it)->didMergeTextNodes(oldNodeWithIndex, offset); 3567 } 3568 3569 if (m_frame) 3570 m_frame->selection().didMergeTextNodes(*oldNode, offset); 3571 3572 // FIXME: This should update markers for spelling and grammar checking. 3573 } 3574 3575 void Document::didSplitTextNode(Text* oldNode) 3576 { 3577 if (!m_ranges.isEmpty()) { 3578 HashSet<Range*>::const_iterator end = m_ranges.end(); 3579 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3580 (*it)->didSplitTextNode(oldNode); 3581 } 3582 3583 if (m_frame) 3584 m_frame->selection().didSplitTextNode(*oldNode); 3585 3586 // FIXME: This should update markers for spelling and grammar checking. 3587 } 3588 3589 void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld) 3590 { 3591 DOMWindow* domWindow = this->domWindow(); 3592 if (!domWindow) 3593 return; 3594 domWindow->setAttributeEventListener(eventType, listener, isolatedWorld); 3595 } 3596 3597 EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld) 3598 { 3599 DOMWindow* domWindow = this->domWindow(); 3600 if (!domWindow) 3601 return 0; 3602 return domWindow->getAttributeEventListener(eventType, isolatedWorld); 3603 } 3604 3605 EventQueue* Document::eventQueue() const 3606 { 3607 if (!m_domWindow) 3608 return 0; 3609 return m_domWindow->eventQueue(); 3610 } 3611 3612 void Document::enqueueAnimationFrameEvent(PassRefPtr<Event> event) 3613 { 3614 ensureScriptedAnimationController().enqueueEvent(event); 3615 } 3616 3617 void Document::enqueueScrollEventForNode(Node* target) 3618 { 3619 // Per the W3C CSSOM View Module only scroll events fired at the document should bubble. 3620 RefPtr<Event> scrollEvent = target->isDocumentNode() ? Event::createBubble(EventTypeNames::scroll) : Event::create(EventTypeNames::scroll); 3621 scrollEvent->setTarget(target); 3622 ensureScriptedAnimationController().enqueuePerFrameEvent(scrollEvent.release()); 3623 } 3624 3625 void Document::enqueueResizeEvent() 3626 { 3627 RefPtr<Event> event = Event::create(EventTypeNames::resize); 3628 event->setTarget(domWindow()); 3629 ensureScriptedAnimationController().enqueuePerFrameEvent(event.release()); 3630 } 3631 3632 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionState& exceptionState) 3633 { 3634 RefPtr<Event> event = EventFactory::create(eventType); 3635 if (event) 3636 return event.release(); 3637 3638 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 3639 return 0; 3640 } 3641 3642 void Document::addMutationEventListenerTypeIfEnabled(ListenerType listenerType) 3643 { 3644 if (ContextFeatures::mutationEventsEnabled(this)) 3645 addListenerType(listenerType); 3646 } 3647 3648 void Document::addListenerTypeIfNeeded(const AtomicString& eventType) 3649 { 3650 if (eventType == EventTypeNames::DOMSubtreeModified) { 3651 UseCounter::count(*this, UseCounter::DOMSubtreeModifiedEvent); 3652 addMutationEventListenerTypeIfEnabled(DOMSUBTREEMODIFIED_LISTENER); 3653 } else if (eventType == EventTypeNames::DOMNodeInserted) { 3654 UseCounter::count(*this, UseCounter::DOMNodeInsertedEvent); 3655 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTED_LISTENER); 3656 } else if (eventType == EventTypeNames::DOMNodeRemoved) { 3657 UseCounter::count(*this, UseCounter::DOMNodeRemovedEvent); 3658 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVED_LISTENER); 3659 } else if (eventType == EventTypeNames::DOMNodeRemovedFromDocument) { 3660 UseCounter::count(*this, UseCounter::DOMNodeRemovedFromDocumentEvent); 3661 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVEDFROMDOCUMENT_LISTENER); 3662 } else if (eventType == EventTypeNames::DOMNodeInsertedIntoDocument) { 3663 UseCounter::count(*this, UseCounter::DOMNodeInsertedIntoDocumentEvent); 3664 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTEDINTODOCUMENT_LISTENER); 3665 } else if (eventType == EventTypeNames::DOMCharacterDataModified) { 3666 UseCounter::count(*this, UseCounter::DOMCharacterDataModifiedEvent); 3667 addMutationEventListenerTypeIfEnabled(DOMCHARACTERDATAMODIFIED_LISTENER); 3668 } else if (eventType == EventTypeNames::overflowchanged) { 3669 UseCounter::count(*this, UseCounter::OverflowChangedEvent); 3670 addListenerType(OVERFLOWCHANGED_LISTENER); 3671 } else if (eventType == EventTypeNames::webkitAnimationStart || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationstart)) { 3672 addListenerType(ANIMATIONSTART_LISTENER); 3673 } else if (eventType == EventTypeNames::webkitAnimationEnd || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationend)) { 3674 addListenerType(ANIMATIONEND_LISTENER); 3675 } else if (eventType == EventTypeNames::webkitAnimationIteration || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationiteration)) { 3676 addListenerType(ANIMATIONITERATION_LISTENER); 3677 } else if (eventType == EventTypeNames::webkitTransitionEnd || eventType == EventTypeNames::transitionend) { 3678 addListenerType(TRANSITIONEND_LISTENER); 3679 } else if (eventType == EventTypeNames::beforeload) { 3680 if (m_frame && m_frame->script().shouldBypassMainWorldContentSecurityPolicy()) { 3681 UseCounter::count(*this, UseCounter::BeforeLoadEventInIsolatedWorld); 3682 } else { 3683 UseCounter::count(*this, UseCounter::BeforeLoadEvent); 3684 } 3685 addListenerType(BEFORELOAD_LISTENER); 3686 } else if (eventType == EventTypeNames::scroll) { 3687 addListenerType(SCROLL_LISTENER); 3688 } else if (eventType == EventTypeNames::DOMFocusIn || eventType == EventTypeNames::DOMFocusOut) { 3689 UseCounter::count(*this, UseCounter::DOMFocusInOutEvent); 3690 } 3691 } 3692 3693 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) 3694 { 3695 return 0; 3696 } 3697 3698 HTMLFrameOwnerElement* Document::ownerElement() const 3699 { 3700 if (!frame()) 3701 return 0; 3702 return frame()->ownerElement(); 3703 } 3704 3705 String Document::cookie(ExceptionState& exceptionState) const 3706 { 3707 if (settings() && !settings()->cookieEnabled()) 3708 return String(); 3709 3710 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3711 // InvalidStateError exception on getting if the Document has no 3712 // browsing context. 3713 3714 if (!securityOrigin()->canAccessCookies()) { 3715 if (isSandboxed(SandboxOrigin)) 3716 exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag."); 3717 else if (url().protocolIs("data")) 3718 exceptionState.throwSecurityError("Cookies are disabled inside 'data:' URLs."); 3719 else 3720 exceptionState.throwSecurityError("Access is denied for this document."); 3721 return String(); 3722 } 3723 3724 KURL cookieURL = this->cookieURL(); 3725 if (cookieURL.isEmpty()) 3726 return String(); 3727 3728 return cookies(this, cookieURL); 3729 } 3730 3731 void Document::setCookie(const String& value, ExceptionState& exceptionState) 3732 { 3733 if (settings() && !settings()->cookieEnabled()) 3734 return; 3735 3736 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3737 // InvalidStateError exception on setting if the Document has no 3738 // browsing context. 3739 3740 if (!securityOrigin()->canAccessCookies()) { 3741 if (isSandboxed(SandboxOrigin)) 3742 exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag."); 3743 else if (url().protocolIs("data")) 3744 exceptionState.throwSecurityError("Cookies are disabled inside 'data:' URLs."); 3745 else 3746 exceptionState.throwSecurityError("Access is denied for this document."); 3747 return; 3748 } 3749 3750 KURL cookieURL = this->cookieURL(); 3751 if (cookieURL.isEmpty()) 3752 return; 3753 3754 setCookies(this, cookieURL, value); 3755 } 3756 3757 const AtomicString& Document::referrer() const 3758 { 3759 if (loader()) 3760 return loader()->request().httpReferrer(); 3761 return nullAtom; 3762 } 3763 3764 String Document::domain() const 3765 { 3766 return securityOrigin()->domain(); 3767 } 3768 3769 void Document::setDomain(const String& newDomain, ExceptionState& exceptionState) 3770 { 3771 if (isSandboxed(SandboxDocumentDomain)) { 3772 exceptionState.throwSecurityError("Assignment is forbidden for sandboxed iframes."); 3773 return; 3774 } 3775 3776 if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) { 3777 exceptionState.throwSecurityError("Assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme."); 3778 return; 3779 } 3780 3781 if (newDomain.isEmpty()) { 3782 exceptionState.throwSecurityError("'" + newDomain + "' is an empty domain."); 3783 return; 3784 } 3785 3786 OriginAccessEntry::IPAddressSetting ipAddressSetting = settings() && settings()->treatIPAddressAsDomain() ? OriginAccessEntry::TreatIPAddressAsDomain : OriginAccessEntry::TreatIPAddressAsIPAddress; 3787 OriginAccessEntry accessEntry(securityOrigin()->protocol(), newDomain, OriginAccessEntry::AllowSubdomains, ipAddressSetting); 3788 OriginAccessEntry::MatchResult result = accessEntry.matchesOrigin(*securityOrigin()); 3789 if (result == OriginAccessEntry::DoesNotMatchOrigin) { 3790 exceptionState.throwSecurityError("'" + newDomain + "' is not a suffix of '" + domain() + "'."); 3791 return; 3792 } 3793 3794 if (result == OriginAccessEntry::MatchesOriginButIsPublicSuffix) { 3795 exceptionState.throwSecurityError("'" + newDomain + "' is a top-level domain."); 3796 return; 3797 } 3798 3799 securityOrigin()->setDomainFromDOM(newDomain); 3800 if (m_frame) 3801 m_frame->script().updateSecurityOrigin(); 3802 } 3803 3804 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified 3805 String Document::lastModified() const 3806 { 3807 DateComponents date; 3808 bool foundDate = false; 3809 if (m_frame) { 3810 if (DocumentLoader* documentLoader = loader()) { 3811 const AtomicString& httpLastModified = documentLoader->response().httpHeaderField("Last-Modified"); 3812 if (!httpLastModified.isEmpty()) { 3813 date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified)); 3814 foundDate = true; 3815 } 3816 } 3817 } 3818 // FIXME: If this document came from the file system, the HTML5 3819 // specificiation tells us to read the last modification date from the file 3820 // system. 3821 if (!foundDate) 3822 date.setMillisecondsSinceEpochForDateTime(currentTimeMS()); 3823 return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second()); 3824 } 3825 3826 const KURL& Document::firstPartyForCookies() const 3827 { 3828 return topDocument()->url(); 3829 } 3830 3831 static bool isValidNameNonASCII(const LChar* characters, unsigned length) 3832 { 3833 if (!isValidNameStart(characters[0])) 3834 return false; 3835 3836 for (unsigned i = 1; i < length; ++i) { 3837 if (!isValidNamePart(characters[i])) 3838 return false; 3839 } 3840 3841 return true; 3842 } 3843 3844 static bool isValidNameNonASCII(const UChar* characters, unsigned length) 3845 { 3846 unsigned i = 0; 3847 3848 UChar32 c; 3849 U16_NEXT(characters, i, length, c) 3850 if (!isValidNameStart(c)) 3851 return false; 3852 3853 while (i < length) { 3854 U16_NEXT(characters, i, length, c) 3855 if (!isValidNamePart(c)) 3856 return false; 3857 } 3858 3859 return true; 3860 } 3861 3862 template<typename CharType> 3863 static inline bool isValidNameASCII(const CharType* characters, unsigned length) 3864 { 3865 CharType c = characters[0]; 3866 if (!(isASCIIAlpha(c) || c == ':' || c == '_')) 3867 return false; 3868 3869 for (unsigned i = 1; i < length; ++i) { 3870 c = characters[i]; 3871 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.')) 3872 return false; 3873 } 3874 3875 return true; 3876 } 3877 3878 bool Document::isValidName(const String& name) 3879 { 3880 unsigned length = name.length(); 3881 if (!length) 3882 return false; 3883 3884 if (name.is8Bit()) { 3885 const LChar* characters = name.characters8(); 3886 3887 if (isValidNameASCII(characters, length)) 3888 return true; 3889 3890 return isValidNameNonASCII(characters, length); 3891 } 3892 3893 const UChar* characters = name.characters16(); 3894 3895 if (isValidNameASCII(characters, length)) 3896 return true; 3897 3898 return isValidNameNonASCII(characters, length); 3899 } 3900 3901 template<typename CharType> 3902 static bool parseQualifiedNameInternal(const AtomicString& qualifiedName, const CharType* characters, unsigned length, AtomicString& prefix, AtomicString& localName, ExceptionState& exceptionState) 3903 { 3904 bool nameStart = true; 3905 bool sawColon = false; 3906 int colonPos = 0; 3907 3908 for (unsigned i = 0; i < length;) { 3909 UChar32 c; 3910 U16_NEXT(characters, i, length, c) 3911 if (c == ':') { 3912 if (sawColon) { 3913 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 3914 return false; // multiple colons: not allowed 3915 } 3916 nameStart = true; 3917 sawColon = true; 3918 colonPos = i - 1; 3919 } else if (nameStart) { 3920 if (!isValidNameStart(c)) { 3921 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError); 3922 return false; 3923 } 3924 nameStart = false; 3925 } else { 3926 if (!isValidNamePart(c)) { 3927 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError); 3928 return false; 3929 } 3930 } 3931 } 3932 3933 if (!sawColon) { 3934 prefix = nullAtom; 3935 localName = qualifiedName; 3936 } else { 3937 prefix = AtomicString(characters, colonPos); 3938 if (prefix.isEmpty()) { 3939 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 3940 return false; 3941 } 3942 int prefixStart = colonPos + 1; 3943 localName = AtomicString(characters + prefixStart, length - prefixStart); 3944 } 3945 3946 if (localName.isEmpty()) { 3947 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 3948 return false; 3949 } 3950 3951 return true; 3952 } 3953 3954 bool Document::parseQualifiedName(const AtomicString& qualifiedName, AtomicString& prefix, AtomicString& localName, ExceptionState& exceptionState) 3955 { 3956 unsigned length = qualifiedName.length(); 3957 3958 if (!length) { 3959 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError); 3960 return false; 3961 } 3962 3963 if (qualifiedName.is8Bit()) 3964 return parseQualifiedNameInternal(qualifiedName, qualifiedName.characters8(), length, prefix, localName, exceptionState); 3965 return parseQualifiedNameInternal(qualifiedName, qualifiedName.characters16(), length, prefix, localName, exceptionState); 3966 } 3967 3968 void Document::setEncodingData(const DocumentEncodingData& newData) 3969 { 3970 // It's possible for the encoding of the document to change while we're decoding 3971 // data. That can only occur while we're processing the <head> portion of the 3972 // document. There isn't much user-visible content in the <head>, but there is 3973 // the <title> element. This function detects that situation and re-decodes the 3974 // document's title so that the user doesn't see an incorrectly decoded title 3975 // in the title bar. 3976 if (m_titleElement 3977 && encoding() != newData.encoding 3978 && !m_titleElement->firstElementChild() 3979 && encoding() == Latin1Encoding() 3980 && m_titleElement->textContent().containsOnlyLatin1()) { 3981 3982 CString originalBytes = m_titleElement->textContent().latin1(); 3983 OwnPtr<TextCodec> codec = newTextCodec(newData.encoding); 3984 String correctlyDecodedTitle = codec->decode(originalBytes.data(), originalBytes.length(), true); 3985 m_titleElement->setTextContent(correctlyDecodedTitle); 3986 } 3987 3988 m_encodingData = newData; 3989 } 3990 3991 KURL Document::completeURL(const String& url, const KURL& baseURLOverride) const 3992 { 3993 // Always return a null URL when passed a null string. 3994 // FIXME: Should we change the KURL constructor to have this behavior? 3995 // See also [CSS]StyleSheet::completeURL(const String&) 3996 if (url.isNull()) 3997 return KURL(); 3998 const KURL* baseURLFromParent = 0; 3999 if (baseURLOverride.isEmpty() || baseURLOverride == blankURL()) { 4000 if (Document* parent = parentDocument()) 4001 baseURLFromParent = &parent->baseURL(); 4002 } 4003 const KURL& baseURL = baseURLFromParent ? *baseURLFromParent : baseURLOverride; 4004 if (!encoding().isValid()) 4005 return KURL(baseURL, url); 4006 return KURL(baseURL, url, encoding()); 4007 } 4008 4009 KURL Document::completeURL(const String& url) const 4010 { 4011 return completeURL(url, m_baseURL); 4012 } 4013 4014 // Support for Javascript execCommand, and related methods 4015 4016 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false) 4017 { 4018 Frame* frame = document->frame(); 4019 if (!frame || frame->document() != document) 4020 return Editor::Command(); 4021 4022 document->updateStyleIfNeeded(); 4023 return frame->editor().command(commandName, userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM); 4024 } 4025 4026 bool Document::execCommand(const String& commandName, bool userInterface, const String& value) 4027 { 4028 return command(this, commandName, userInterface).execute(value); 4029 } 4030 4031 bool Document::queryCommandEnabled(const String& commandName) 4032 { 4033 return command(this, commandName).isEnabled(); 4034 } 4035 4036 bool Document::queryCommandIndeterm(const String& commandName) 4037 { 4038 return command(this, commandName).state() == MixedTriState; 4039 } 4040 4041 bool Document::queryCommandState(const String& commandName) 4042 { 4043 return command(this, commandName).state() == TrueTriState; 4044 } 4045 4046 bool Document::queryCommandSupported(const String& commandName) 4047 { 4048 return command(this, commandName).isSupported(); 4049 } 4050 4051 String Document::queryCommandValue(const String& commandName) 4052 { 4053 return command(this, commandName).value(); 4054 } 4055 4056 KURL Document::openSearchDescriptionURL() 4057 { 4058 static const char openSearchMIMEType[] = "application/opensearchdescription+xml"; 4059 static const char openSearchRelation[] = "search"; 4060 4061 // FIXME: Why do only top-level frames have openSearchDescriptionURLs? 4062 if (!frame() || frame()->tree().parent()) 4063 return KURL(); 4064 4065 // FIXME: Why do we need to wait for FrameStateComplete? 4066 if (frame()->loader().state() != FrameStateComplete) 4067 return KURL(); 4068 4069 if (!head()) 4070 return KURL(); 4071 4072 RefPtr<HTMLCollection> children = head()->children(); 4073 for (unsigned i = 0; Node* child = children->item(i); i++) { 4074 if (!child->hasTagName(linkTag)) 4075 continue; 4076 HTMLLinkElement* linkElement = toHTMLLinkElement(child); 4077 if (!equalIgnoringCase(linkElement->type(), openSearchMIMEType) || !equalIgnoringCase(linkElement->rel(), openSearchRelation)) 4078 continue; 4079 if (linkElement->href().isEmpty()) 4080 continue; 4081 return linkElement->href(); 4082 } 4083 4084 return KURL(); 4085 } 4086 4087 void Document::pushCurrentScript(PassRefPtr<HTMLScriptElement> newCurrentScript) 4088 { 4089 ASSERT(newCurrentScript); 4090 m_currentScriptStack.append(newCurrentScript); 4091 } 4092 4093 void Document::popCurrentScript() 4094 { 4095 ASSERT(!m_currentScriptStack.isEmpty()); 4096 m_currentScriptStack.removeLast(); 4097 } 4098 4099 void Document::applyXSLTransform(ProcessingInstruction* pi) 4100 { 4101 ASSERT(!pi->isLoading()); 4102 UseCounter::count(*this, UseCounter::XSLProcessingInstruction); 4103 RefPtr<XSLTProcessor> processor = XSLTProcessor::create(); 4104 processor->setXSLStyleSheet(toXSLStyleSheet(pi->sheet())); 4105 String resultMIMEType; 4106 String newSource; 4107 String resultEncoding; 4108 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding)) 4109 return; 4110 // FIXME: If the transform failed we should probably report an error (like Mozilla does). 4111 Frame* ownerFrame = frame(); 4112 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, ownerFrame); 4113 InspectorInstrumentation::frameDocumentUpdated(ownerFrame); 4114 } 4115 4116 void Document::setTransformSource(PassOwnPtr<TransformSource> source) 4117 { 4118 m_transformSource = source; 4119 } 4120 4121 void Document::setDesignMode(InheritedBool value) 4122 { 4123 m_designMode = value; 4124 for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree().traverseNext(m_frame)) 4125 frame->document()->setNeedsStyleRecalc(); 4126 } 4127 4128 Document::InheritedBool Document::getDesignMode() const 4129 { 4130 return m_designMode; 4131 } 4132 4133 bool Document::inDesignMode() const 4134 { 4135 for (const Document* d = this; d; d = d->parentDocument()) { 4136 if (d->m_designMode != inherit) 4137 return d->m_designMode; 4138 } 4139 return false; 4140 } 4141 4142 Document* Document::parentDocument() const 4143 { 4144 if (!m_frame) 4145 return 0; 4146 Frame* parent = m_frame->tree().parent(); 4147 if (!parent) 4148 return 0; 4149 return parent->document(); 4150 } 4151 4152 Document* Document::topDocument() const 4153 { 4154 Document* doc = const_cast<Document*>(this); 4155 Element* element; 4156 while ((element = doc->ownerElement())) 4157 doc = &element->document(); 4158 4159 return doc; 4160 } 4161 4162 WeakPtr<Document> Document::contextDocument() 4163 { 4164 if (m_contextDocument) 4165 return m_contextDocument; 4166 if (m_frame) 4167 return m_weakFactory.createWeakPtr(); 4168 return WeakPtr<Document>(0); 4169 } 4170 4171 PassRefPtr<Attr> Document::createAttribute(const AtomicString& name, ExceptionState& exceptionState) 4172 { 4173 return createAttributeNS(nullAtom, name, exceptionState, true); 4174 } 4175 4176 PassRefPtr<Attr> Document::createAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState, bool shouldIgnoreNamespaceChecks) 4177 { 4178 AtomicString prefix, localName; 4179 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState)) 4180 return 0; 4181 4182 QualifiedName qName(prefix, localName, namespaceURI); 4183 4184 if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(qName)) { 4185 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError); 4186 return 0; 4187 } 4188 4189 return Attr::create(*this, qName, emptyString()); 4190 } 4191 4192 const SVGDocumentExtensions* Document::svgExtensions() 4193 { 4194 return m_svgExtensions.get(); 4195 } 4196 4197 SVGDocumentExtensions* Document::accessSVGExtensions() 4198 { 4199 if (!m_svgExtensions) 4200 m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this)); 4201 return m_svgExtensions.get(); 4202 } 4203 4204 bool Document::hasSVGRootNode() const 4205 { 4206 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag); 4207 } 4208 4209 PassRefPtr<HTMLCollection> Document::ensureCachedCollection(CollectionType type) 4210 { 4211 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type); 4212 } 4213 4214 PassRefPtr<HTMLCollection> Document::images() 4215 { 4216 return ensureCachedCollection(DocImages); 4217 } 4218 4219 PassRefPtr<HTMLCollection> Document::applets() 4220 { 4221 return ensureCachedCollection(DocApplets); 4222 } 4223 4224 PassRefPtr<HTMLCollection> Document::embeds() 4225 { 4226 return ensureCachedCollection(DocEmbeds); 4227 } 4228 4229 PassRefPtr<HTMLCollection> Document::scripts() 4230 { 4231 return ensureCachedCollection(DocScripts); 4232 } 4233 4234 PassRefPtr<HTMLCollection> Document::links() 4235 { 4236 return ensureCachedCollection(DocLinks); 4237 } 4238 4239 PassRefPtr<HTMLCollection> Document::forms() 4240 { 4241 return ensureCachedCollection(DocForms); 4242 } 4243 4244 PassRefPtr<HTMLCollection> Document::anchors() 4245 { 4246 return ensureCachedCollection(DocAnchors); 4247 } 4248 4249 PassRefPtr<HTMLCollection> Document::allForBinding() 4250 { 4251 UseCounter::count(*this, UseCounter::DocumentAll); 4252 return all(); 4253 } 4254 4255 PassRefPtr<HTMLCollection> Document::all() 4256 { 4257 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLAllCollection>(this, DocAll); 4258 } 4259 4260 PassRefPtr<HTMLCollection> Document::windowNamedItems(const AtomicString& name) 4261 { 4262 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, WindowNamedItems, name); 4263 } 4264 4265 PassRefPtr<HTMLCollection> Document::documentNamedItems(const AtomicString& name) 4266 { 4267 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, DocumentNamedItems, name); 4268 } 4269 4270 void Document::finishedParsing() 4271 { 4272 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing()); 4273 ASSERT(!scriptableDocumentParser() || m_readyState != Loading); 4274 setParsing(false); 4275 if (!m_documentTiming.domContentLoadedEventStart) 4276 m_documentTiming.domContentLoadedEventStart = monotonicallyIncreasingTime(); 4277 dispatchEvent(Event::createBubble(EventTypeNames::DOMContentLoaded)); 4278 if (!m_documentTiming.domContentLoadedEventEnd) 4279 m_documentTiming.domContentLoadedEventEnd = monotonicallyIncreasingTime(); 4280 4281 // The loader's finishedParsing() method may invoke script that causes this object to 4282 // be dereferenced (when this document is in an iframe and the onload causes the iframe's src to change). 4283 // Keep it alive until we are done. 4284 RefPtr<Document> protect(this); 4285 4286 if (RefPtr<Frame> f = frame()) { 4287 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all 4288 // resource loads are complete. HTMLObjectElements can start loading their resources from 4289 // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object> 4290 // tag and then reach the end of the document without updating styles, we might not have yet 4291 // started the resource load and might fire the window load event too early. To avoid this 4292 // we force the styles to be up to date before calling FrameLoader::finishedParsing(). 4293 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35. 4294 updateStyleIfNeeded(); 4295 4296 f->loader().finishedParsing(); 4297 4298 InspectorInstrumentation::domContentLoadedEventFired(f.get()); 4299 } 4300 4301 // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes 4302 // so that dynamically inserted content can also benefit from sharing optimizations. 4303 // Note that we don't refresh the timer on pool access since that could lead to huge caches being kept 4304 // alive indefinitely by something innocuous like JS setting .innerHTML repeatedly on a timer. 4305 static const int timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds = 10; 4306 m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds); 4307 4308 // Parser should have picked up all preloads by now 4309 m_fetcher->clearPreloads(); 4310 4311 if (m_import) 4312 m_import->didFinishParsing(); 4313 } 4314 4315 void Document::sharedObjectPoolClearTimerFired(Timer<Document>*) 4316 { 4317 m_sharedObjectPool.clear(); 4318 } 4319 4320 Vector<IconURL> Document::iconURLs(int iconTypesMask) 4321 { 4322 IconURL firstFavicon; 4323 IconURL firstTouchIcon; 4324 IconURL firstTouchPrecomposedIcon; 4325 Vector<IconURL> secondaryIcons; 4326 4327 // Start from the last child node so that icons seen later take precedence as required by the spec. 4328 RefPtr<HTMLCollection> children = head() ? head()->children() : 0; 4329 unsigned length = children ? children->length() : 0; 4330 for (unsigned i = 0; i < length; i++) { 4331 Node* child = children->item(i); 4332 if (!child->hasTagName(linkTag)) 4333 continue; 4334 HTMLLinkElement* linkElement = toHTMLLinkElement(child); 4335 if (!(linkElement->iconType() & iconTypesMask)) 4336 continue; 4337 if (linkElement->href().isEmpty()) 4338 continue; 4339 #if !ENABLE(TOUCH_ICON_LOADING) 4340 if (linkElement->iconType() != Favicon) 4341 continue; 4342 #endif 4343 4344 IconURL newURL(linkElement->href(), linkElement->iconSizes(), linkElement->type(), linkElement->iconType()); 4345 if (linkElement->iconType() == Favicon) { 4346 if (firstFavicon.m_iconType != InvalidIcon) 4347 secondaryIcons.append(firstFavicon); 4348 firstFavicon = newURL; 4349 } else if (linkElement->iconType() == TouchIcon) { 4350 if (firstTouchIcon.m_iconType != InvalidIcon) 4351 secondaryIcons.append(firstTouchIcon); 4352 firstTouchIcon = newURL; 4353 } else if (linkElement->iconType() == TouchPrecomposedIcon) { 4354 if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon) 4355 secondaryIcons.append(firstTouchPrecomposedIcon); 4356 firstTouchPrecomposedIcon = newURL; 4357 } else { 4358 ASSERT_NOT_REACHED(); 4359 } 4360 } 4361 4362 Vector<IconURL> iconURLs; 4363 if (firstFavicon.m_iconType != InvalidIcon) 4364 iconURLs.append(firstFavicon); 4365 else if (m_url.protocolIsInHTTPFamily() && iconTypesMask & Favicon) 4366 iconURLs.append(IconURL::defaultFavicon(m_url)); 4367 4368 if (firstTouchIcon.m_iconType != InvalidIcon) 4369 iconURLs.append(firstTouchIcon); 4370 if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon) 4371 iconURLs.append(firstTouchPrecomposedIcon); 4372 for (int i = secondaryIcons.size() - 1; i >= 0; --i) 4373 iconURLs.append(secondaryIcons[i]); 4374 return iconURLs; 4375 } 4376 4377 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard) 4378 { 4379 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard) 4380 return; 4381 4382 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard; 4383 m_frame->selection().updateSecureKeyboardEntryIfActive(); 4384 } 4385 4386 bool Document::useSecureKeyboardEntryWhenActive() const 4387 { 4388 return m_useSecureKeyboardEntryWhenActive; 4389 } 4390 4391 void Document::initSecurityContext() 4392 { 4393 initSecurityContext(DocumentInit(m_url, m_frame, contextDocument(), m_import)); 4394 } 4395 4396 void Document::initSecurityContext(const DocumentInit& initializer) 4397 { 4398 if (haveInitializedSecurityOrigin()) { 4399 ASSERT(securityOrigin()); 4400 return; 4401 } 4402 4403 if (!initializer.hasSecurityContext()) { 4404 // No source for a security context. 4405 // This can occur via document.implementation.createDocument(). 4406 m_cookieURL = KURL(ParsedURLString, emptyString()); 4407 setSecurityOrigin(SecurityOrigin::createUnique()); 4408 setContentSecurityPolicy(ContentSecurityPolicy::create(this)); 4409 return; 4410 } 4411 4412 // In the common case, create the security context from the currently 4413 // loading URL with a fresh content security policy. 4414 m_cookieURL = m_url; 4415 enforceSandboxFlags(initializer.sandboxFlags()); 4416 setSecurityOrigin(isSandboxed(SandboxOrigin) ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url)); 4417 setContentSecurityPolicy(ContentSecurityPolicy::create(this)); 4418 4419 if (Settings* settings = initializer.settings()) { 4420 if (!settings->webSecurityEnabled()) { 4421 // Web security is turned off. We should let this document access every other document. This is used primary by testing 4422 // harnesses for web sites. 4423 securityOrigin()->grantUniversalAccess(); 4424 } else if (securityOrigin()->isLocal()) { 4425 if (settings->allowUniversalAccessFromFileURLs()) { 4426 // Some clients want local URLs to have universal access, but that setting is dangerous for other clients. 4427 securityOrigin()->grantUniversalAccess(); 4428 } else if (!settings->allowFileAccessFromFileURLs()) { 4429 // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files. 4430 // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files 4431 // still can have other privileges that can be remembered, thereby not making them unique origins. 4432 securityOrigin()->enforceFilePathSeparation(); 4433 } 4434 } 4435 } 4436 4437 if (initializer.shouldTreatURLAsSrcdocDocument()) { 4438 m_isSrcdocDocument = true; 4439 setBaseURLOverride(initializer.parentBaseURL()); 4440 } 4441 4442 // FIXME: What happens if we inherit the security origin? This check may need to be later. 4443 // <iframe seamless src="about:blank"> likely won't work as-is. 4444 m_mayDisplaySeamlesslyWithParent = initializer.isSeamlessAllowedFor(this); 4445 4446 if (!shouldInheritSecurityOriginFromOwner(m_url)) 4447 return; 4448 4449 // If we do not obtain a meaningful origin from the URL, then we try to 4450 // find one via the frame hierarchy. 4451 4452 if (!initializer.owner()) { 4453 didFailToInitializeSecurityOrigin(); 4454 return; 4455 } 4456 4457 if (isSandboxed(SandboxOrigin)) { 4458 // If we're supposed to inherit our security origin from our owner, 4459 // but we're also sandboxed, the only thing we inherit is the ability 4460 // to load local resources. This lets about:blank iframes in file:// 4461 // URL documents load images and other resources from the file system. 4462 if (initializer.owner()->securityOrigin()->canLoadLocalResources()) 4463 securityOrigin()->grantLoadLocalResources(); 4464 return; 4465 } 4466 4467 m_cookieURL = initializer.owner()->cookieURL(); 4468 // We alias the SecurityOrigins to match Firefox, see Bug 15313 4469 // https://bugs.webkit.org/show_bug.cgi?id=15313 4470 setSecurityOrigin(initializer.owner()->securityOrigin()); 4471 } 4472 4473 void Document::initContentSecurityPolicy(const ContentSecurityPolicyResponseHeaders& headers) 4474 { 4475 if (m_frame && m_frame->tree().parent() && (shouldInheritSecurityOriginFromOwner(m_url) || isPluginDocument())) 4476 contentSecurityPolicy()->copyStateFrom(m_frame->tree().parent()->document()->contentSecurityPolicy()); 4477 contentSecurityPolicy()->didReceiveHeaders(headers); 4478 } 4479 4480 bool Document::allowInlineEventHandlers(Node* node, EventListener* listener, const String& contextURL, const WTF::OrdinalNumber& contextLine) 4481 { 4482 if (!contentSecurityPolicy()->allowInlineEventHandlers(contextURL, contextLine)) 4483 return false; 4484 4485 // HTML says that inline script needs browsing context to create its execution environment. 4486 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-handler-attributes 4487 // Also, if the listening node came from other document, which happens on context-less event dispatching, 4488 // we also need to ask the owner document of the node. 4489 if (!m_frame) 4490 return false; 4491 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript)) 4492 return false; 4493 if (node && node->document() != this && !node->document().allowInlineEventHandlers(node, listener, contextURL, contextLine)) 4494 return false; 4495 4496 return true; 4497 } 4498 4499 bool Document::allowExecutingScripts(Node* node) 4500 { 4501 // FIXME: Eventually we'd like to evaluate scripts which are inserted into a 4502 // viewless document but this'll do for now. 4503 // See http://bugs.webkit.org/show_bug.cgi?id=5727 4504 if (!frame() && !import()) 4505 return false; 4506 if (!node->document().frame() && !node->document().import()) 4507 return false; 4508 if (!contextDocument().get()->frame()->script().canExecuteScripts(AboutToExecuteScript)) 4509 return false; 4510 return true; 4511 } 4512 4513 void Document::updateSecurityOrigin(PassRefPtr<SecurityOrigin> origin) 4514 { 4515 setSecurityOrigin(origin); 4516 didUpdateSecurityOrigin(); 4517 } 4518 4519 void Document::didUpdateSecurityOrigin() 4520 { 4521 if (!m_frame) 4522 return; 4523 m_frame->script().updateSecurityOrigin(); 4524 } 4525 4526 bool Document::isContextThread() const 4527 { 4528 return isMainThread(); 4529 } 4530 4531 void Document::updateFocusAppearanceSoon(bool restorePreviousSelection) 4532 { 4533 m_updateFocusAppearanceRestoresSelection = restorePreviousSelection; 4534 if (!m_updateFocusAppearanceTimer.isActive()) 4535 m_updateFocusAppearanceTimer.startOneShot(0); 4536 } 4537 4538 void Document::cancelFocusAppearanceUpdate() 4539 { 4540 m_updateFocusAppearanceTimer.stop(); 4541 } 4542 4543 void Document::updateFocusAppearanceTimerFired(Timer<Document>*) 4544 { 4545 Element* element = focusedElement(); 4546 if (!element) 4547 return; 4548 updateLayout(); 4549 if (element->isFocusable()) 4550 element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection); 4551 } 4552 4553 void Document::attachRange(Range* range) 4554 { 4555 ASSERT(!m_ranges.contains(range)); 4556 m_ranges.add(range); 4557 } 4558 4559 void Document::detachRange(Range* range) 4560 { 4561 // We don't ASSERT m_ranges.contains(range) to allow us to call this 4562 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044 4563 m_ranges.remove(range); 4564 } 4565 4566 CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height) 4567 { 4568 HTMLCanvasElement* element = getCSSCanvasElement(name); 4569 if (!element) 4570 return 0; 4571 element->setSize(IntSize(width, height)); 4572 return element->getContext(type); 4573 } 4574 4575 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name) 4576 { 4577 RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).iterator->value; 4578 if (!element) { 4579 element = HTMLCanvasElement::create(*this); 4580 element->setAccelerationDisabled(true); 4581 } 4582 return element.get(); 4583 } 4584 4585 void Document::initDNSPrefetch() 4586 { 4587 Settings* settings = this->settings(); 4588 4589 m_haveExplicitlyDisabledDNSPrefetch = false; 4590 m_isDNSPrefetchEnabled = settings && settings->dnsPrefetchingEnabled() && securityOrigin()->protocol() == "http"; 4591 4592 // Inherit DNS prefetch opt-out from parent frame 4593 if (Document* parent = parentDocument()) { 4594 if (!parent->isDNSPrefetchEnabled()) 4595 m_isDNSPrefetchEnabled = false; 4596 } 4597 } 4598 4599 void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl) 4600 { 4601 if (equalIgnoringCase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) { 4602 m_isDNSPrefetchEnabled = true; 4603 return; 4604 } 4605 4606 m_isDNSPrefetchEnabled = false; 4607 m_haveExplicitlyDisabledDNSPrefetch = true; 4608 } 4609 4610 void Document::reportBlockedScriptExecutionToInspector(const String& directiveText) 4611 { 4612 InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText); 4613 } 4614 4615 void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state) 4616 { 4617 internalAddMessage(source, level, message, sourceURL, lineNumber, 0, state); 4618 } 4619 4620 void Document::internalAddMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state) 4621 { 4622 if (!isContextThread()) { 4623 m_taskRunner->postTask(AddConsoleMessageTask::create(source, level, message)); 4624 return; 4625 } 4626 Page* page = this->page(); 4627 if (!page) 4628 return; 4629 4630 String messageURL = sourceURL; 4631 if (!state && sourceURL.isNull() && !lineNumber) { 4632 messageURL = url().string(); 4633 if (parsing() && !isInDocumentWrite() && scriptableDocumentParser()) { 4634 ScriptableDocumentParser* parser = scriptableDocumentParser(); 4635 if (!parser->isWaitingForScripts() && !parser->isExecutingScript()) 4636 lineNumber = parser->lineNumber().oneBasedInt(); 4637 } 4638 } 4639 page->console().addMessage(source, level, message, messageURL, lineNumber, 0, callStack, state, 0); 4640 } 4641 4642 void Document::addConsoleMessageWithRequestIdentifier(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier) 4643 { 4644 if (!isContextThread()) { 4645 m_taskRunner->postTask(AddConsoleMessageTask::create(source, level, message)); 4646 return; 4647 } 4648 4649 if (Page* page = this->page()) 4650 page->console().addMessage(source, level, message, String(), 0, 0, 0, 0, requestIdentifier); 4651 } 4652 4653 // FIXME(crbug.com/305497): This should be removed after ExecutionContext-DOMWindow migration. 4654 void Document::postTask(PassOwnPtr<ExecutionContextTask> task) 4655 { 4656 m_taskRunner->postTask(task); 4657 } 4658 4659 void Document::tasksWereSuspended() 4660 { 4661 scriptRunner()->suspend(); 4662 4663 if (m_parser) 4664 m_parser->suspendScheduledTasks(); 4665 if (m_scriptedAnimationController) 4666 m_scriptedAnimationController->suspend(); 4667 } 4668 4669 void Document::tasksWereResumed() 4670 { 4671 scriptRunner()->resume(); 4672 4673 if (m_parser) 4674 m_parser->resumeScheduledTasks(); 4675 if (m_scriptedAnimationController) 4676 m_scriptedAnimationController->resume(); 4677 } 4678 4679 // FIXME: suspendScheduledTasks(), resumeScheduledTasks(), tasksNeedSuspension() 4680 // should be moved to DOMWindow once it inherits ExecutionContext 4681 void Document::suspendScheduledTasks() 4682 { 4683 ExecutionContext::suspendScheduledTasks(); 4684 m_taskRunner->suspend(); 4685 } 4686 4687 void Document::resumeScheduledTasks() 4688 { 4689 ExecutionContext::resumeScheduledTasks(); 4690 m_taskRunner->resume(); 4691 } 4692 4693 bool Document::tasksNeedSuspension() 4694 { 4695 Page* page = this->page(); 4696 return page && page->defersLoading(); 4697 } 4698 4699 void Document::addToTopLayer(Element* element, const Element* before) 4700 { 4701 if (element->isInTopLayer()) 4702 return; 4703 4704 ASSERT(!m_topLayerElements.contains(element)); 4705 ASSERT(!before || m_topLayerElements.contains(before)); 4706 if (before) { 4707 size_t beforePosition = m_topLayerElements.find(before); 4708 m_topLayerElements.insert(beforePosition, element); 4709 } else { 4710 m_topLayerElements.append(element); 4711 } 4712 element->setIsInTopLayer(true); 4713 } 4714 4715 void Document::removeFromTopLayer(Element* element) 4716 { 4717 if (!element->isInTopLayer()) 4718 return; 4719 size_t position = m_topLayerElements.find(element); 4720 ASSERT(position != kNotFound); 4721 m_topLayerElements.remove(position); 4722 element->setIsInTopLayer(false); 4723 } 4724 4725 HTMLDialogElement* Document::activeModalDialog() const 4726 { 4727 if (m_topLayerElements.isEmpty()) 4728 return 0; 4729 return toHTMLDialogElement(m_topLayerElements.last().get()); 4730 } 4731 4732 void Document::webkitExitPointerLock() 4733 { 4734 if (!page()) 4735 return; 4736 if (Element* target = page()->pointerLockController().element()) { 4737 if (target->document() != this) 4738 return; 4739 } 4740 page()->pointerLockController().requestPointerUnlock(); 4741 } 4742 4743 Element* Document::webkitPointerLockElement() const 4744 { 4745 if (!page() || page()->pointerLockController().lockPending()) 4746 return 0; 4747 if (Element* element = page()->pointerLockController().element()) { 4748 if (element->document() == this) 4749 return element; 4750 } 4751 return 0; 4752 } 4753 4754 void Document::decrementLoadEventDelayCount() 4755 { 4756 ASSERT(m_loadEventDelayCount); 4757 --m_loadEventDelayCount; 4758 4759 if (frame() && !m_loadEventDelayCount && !m_loadEventDelayTimer.isActive()) 4760 m_loadEventDelayTimer.startOneShot(0); 4761 } 4762 4763 void Document::loadEventDelayTimerFired(Timer<Document>*) 4764 { 4765 if (frame()) 4766 frame()->loader().checkCompleted(); 4767 } 4768 4769 ScriptedAnimationController& Document::ensureScriptedAnimationController() 4770 { 4771 if (!m_scriptedAnimationController) { 4772 m_scriptedAnimationController = ScriptedAnimationController::create(this); 4773 // We need to make sure that we don't start up the animation controller on a background tab, for example. 4774 if (!page()) 4775 m_scriptedAnimationController->suspend(); 4776 } 4777 return *m_scriptedAnimationController; 4778 } 4779 4780 int Document::requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback) 4781 { 4782 return ensureScriptedAnimationController().registerCallback(callback); 4783 } 4784 4785 void Document::cancelAnimationFrame(int id) 4786 { 4787 if (!m_scriptedAnimationController) 4788 return; 4789 m_scriptedAnimationController->cancelCallback(id); 4790 } 4791 4792 void Document::serviceScriptedAnimations(double monotonicAnimationStartTime) 4793 { 4794 if (!m_scriptedAnimationController) 4795 return; 4796 m_scriptedAnimationController->serviceScriptedAnimations(monotonicAnimationStartTime); 4797 } 4798 4799 PassRefPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, int pageX, int pageY, int screenX, int screenY, int radiusX, int radiusY, float rotationAngle, float force) const 4800 { 4801 // FIXME: It's not clear from the documentation at 4802 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html 4803 // 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 4804 // and implement them here. See https://bugs.webkit.org/show_bug.cgi?id=47819 4805 Frame* frame = window ? window->frame() : this->frame(); 4806 return Touch::create(frame, target, identifier, screenX, screenY, pageX, pageY, radiusX, radiusY, rotationAngle, force); 4807 } 4808 4809 PassRefPtr<TouchList> Document::createTouchList(Vector<RefPtr<Touch> >& touches) const 4810 { 4811 return TouchList::create(touches); 4812 } 4813 4814 void Document::didAddTouchEventHandler(Node* handler) 4815 { 4816 if (!m_touchEventTargets.get()) 4817 m_touchEventTargets = adoptPtr(new TouchEventTargetSet); 4818 m_touchEventTargets->add(handler); 4819 if (Document* parent = parentDocument()) { 4820 parent->didAddTouchEventHandler(this); 4821 return; 4822 } 4823 if (Page* page = this->page()) { 4824 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 4825 scrollingCoordinator->touchEventTargetRectsDidChange(this); 4826 if (m_touchEventTargets->size() == 1) 4827 page->chrome().client().needTouchEvents(true); 4828 } 4829 } 4830 4831 void Document::didRemoveTouchEventHandler(Node* handler) 4832 { 4833 if (!m_touchEventTargets.get()) 4834 return; 4835 ASSERT(m_touchEventTargets->contains(handler)); 4836 m_touchEventTargets->remove(handler); 4837 if (Document* parent = parentDocument()) { 4838 parent->didRemoveTouchEventHandler(this); 4839 return; 4840 } 4841 4842 Page* page = this->page(); 4843 if (!page) 4844 return; 4845 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 4846 scrollingCoordinator->touchEventTargetRectsDidChange(this); 4847 if (m_touchEventTargets->size()) 4848 return; 4849 for (const Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) { 4850 if (frame->document() && frame->document()->hasTouchEventHandlers()) 4851 return; 4852 } 4853 page->chrome().client().needTouchEvents(false); 4854 } 4855 4856 void Document::didRemoveEventTargetNode(Node* handler) 4857 { 4858 if (m_touchEventTargets && !m_touchEventTargets->isEmpty()) { 4859 if (handler == this) 4860 m_touchEventTargets->clear(); 4861 else 4862 m_touchEventTargets->removeAll(handler); 4863 if (m_touchEventTargets->isEmpty() && parentDocument()) 4864 parentDocument()->didRemoveEventTargetNode(this); 4865 } 4866 } 4867 4868 void Document::resetLastHandledUserGestureTimestamp() 4869 { 4870 m_lastHandledUserGestureTimestamp = currentTime(); 4871 } 4872 4873 HTMLIFrameElement* Document::seamlessParentIFrame() const 4874 { 4875 if (!shouldDisplaySeamlesslyWithParent()) 4876 return 0; 4877 4878 return toHTMLIFrameElement(this->ownerElement()); 4879 } 4880 4881 bool Document::shouldDisplaySeamlesslyWithParent() const 4882 { 4883 if (!RuntimeEnabledFeatures::seamlessIFramesEnabled()) 4884 return false; 4885 HTMLFrameOwnerElement* ownerElement = this->ownerElement(); 4886 if (!ownerElement) 4887 return false; 4888 return m_mayDisplaySeamlesslyWithParent && ownerElement->hasTagName(iframeTag) && ownerElement->fastHasAttribute(seamlessAttr); 4889 } 4890 4891 DocumentLoader* Document::loader() const 4892 { 4893 if (!m_frame) 4894 return 0; 4895 4896 DocumentLoader* loader = m_frame->loader().documentLoader(); 4897 if (!loader) 4898 return 0; 4899 4900 if (m_frame->document() != this) 4901 return 0; 4902 4903 return loader; 4904 } 4905 4906 IntSize Document::initialViewportSize() const 4907 { 4908 if (!view()) 4909 return IntSize(); 4910 return view()->unscaledVisibleContentSize(ScrollableArea::IncludeScrollbars); 4911 } 4912 4913 Node* eventTargetNodeForDocument(Document* doc) 4914 { 4915 if (!doc) 4916 return 0; 4917 Node* node = doc->focusedElement(); 4918 if (!node && doc->isPluginDocument()) { 4919 PluginDocument* pluginDocument = toPluginDocument(doc); 4920 node = pluginDocument->pluginNode(); 4921 } 4922 if (!node && doc->isHTMLDocument()) 4923 node = doc->body(); 4924 if (!node) 4925 node = doc->documentElement(); 4926 return node; 4927 } 4928 4929 void Document::adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>& quads, RenderObject& renderer) 4930 { 4931 if (!view()) 4932 return; 4933 4934 LayoutRect visibleContentRect = view()->visibleContentRect(); 4935 for (size_t i = 0; i < quads.size(); ++i) { 4936 quads[i].move(-visibleContentRect.x(), -visibleContentRect.y()); 4937 adjustFloatQuadForAbsoluteZoom(quads[i], renderer); 4938 } 4939 } 4940 4941 void Document::adjustFloatRectForScrollAndAbsoluteZoom(FloatRect& rect, RenderObject& renderer) 4942 { 4943 if (!view()) 4944 return; 4945 4946 LayoutRect visibleContentRect = view()->visibleContentRect(); 4947 rect.move(-visibleContentRect.x(), -visibleContentRect.y()); 4948 adjustFloatRectForAbsoluteZoom(rect, renderer); 4949 } 4950 4951 bool Document::hasActiveParser() 4952 { 4953 return m_activeParserCount || (m_parser && m_parser->processingData()); 4954 } 4955 4956 void Document::decrementActiveParserCount() 4957 { 4958 --m_activeParserCount; 4959 if (!frame()) 4960 return; 4961 // FIXME: This should always be enabled, but it seems to cause 4962 // http/tests/security/feed-urls-from-remote.html to timeout on Mac WK1 4963 // see http://webkit.org/b/110554 and http://webkit.org/b/110401 4964 loader()->checkLoadComplete(); 4965 frame()->loader().checkLoadComplete(); 4966 } 4967 4968 void Document::setContextFeatures(PassRefPtr<ContextFeatures> features) 4969 { 4970 m_contextFeatures = features; 4971 } 4972 4973 static RenderObject* nearestCommonHoverAncestor(RenderObject* obj1, RenderObject* obj2) 4974 { 4975 if (!obj1 || !obj2) 4976 return 0; 4977 4978 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) { 4979 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) { 4980 if (currObj1 == currObj2) 4981 return currObj1; 4982 } 4983 } 4984 4985 return 0; 4986 } 4987 4988 void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement, const PlatformMouseEvent* event) 4989 { 4990 ASSERT(!request.readOnly()); 4991 4992 if (request.active() && m_frame) 4993 m_frame->eventHandler().notifyElementActivated(); 4994 4995 Element* innerElementInDocument = innerElement; 4996 while (innerElementInDocument && innerElementInDocument->document() != this) { 4997 innerElementInDocument->document().updateHoverActiveState(request, innerElementInDocument, event); 4998 innerElementInDocument = innerElementInDocument->document().ownerElement(); 4999 } 5000 5001 Element* oldActiveElement = activeElement(); 5002 if (oldActiveElement && !request.active()) { 5003 // We are clearing the :active chain because the mouse has been released. 5004 for (RenderObject* curr = oldActiveElement->renderer(); curr; curr = curr->parent()) { 5005 if (curr->node()) { 5006 ASSERT(!curr->node()->isTextNode()); 5007 curr->node()->setActive(false); 5008 m_userActionElements.setInActiveChain(curr->node(), false); 5009 } 5010 } 5011 setActiveElement(0); 5012 } else { 5013 Element* newActiveElement = innerElementInDocument; 5014 if (!oldActiveElement && newActiveElement && request.active() && !request.touchMove()) { 5015 // We are setting the :active chain and freezing it. If future moves happen, they 5016 // will need to reference this chain. 5017 for (RenderObject* curr = newActiveElement->renderer(); curr; curr = curr->parent()) { 5018 if (curr->node() && !curr->isText()) 5019 m_userActionElements.setInActiveChain(curr->node(), true); 5020 } 5021 5022 setActiveElement(newActiveElement); 5023 } 5024 } 5025 // If the mouse has just been pressed, set :active on the chain. Those (and only those) 5026 // nodes should remain :active until the mouse is released. 5027 bool allowActiveChanges = !oldActiveElement && activeElement(); 5028 5029 // If the mouse is down and if this is a mouse move event, we want to restrict changes in 5030 // :hover/:active to only apply to elements that are in the :active chain that we froze 5031 // at the time the mouse went down. 5032 bool mustBeInActiveChain = request.active() && request.move(); 5033 5034 RefPtr<Node> oldHoverNode = hoverNode(); 5035 5036 // Check to see if the hovered node has changed. 5037 // If it hasn't, we do not need to do anything. 5038 Node* newHoverNode = innerElementInDocument; 5039 while (newHoverNode && !newHoverNode->renderer()) 5040 newHoverNode = newHoverNode->parentOrShadowHostNode(); 5041 5042 // Update our current hover node. 5043 setHoverNode(newHoverNode); 5044 5045 // We have two different objects. Fetch their renderers. 5046 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0; 5047 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0; 5048 5049 // Locate the common ancestor render object for the two renderers. 5050 RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj); 5051 RefPtr<Node> ancestorNode(ancestor ? ancestor->node() : 0); 5052 5053 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain; 5054 Vector<RefPtr<Node>, 32> nodesToAddToChain; 5055 5056 if (oldHoverObj != newHoverObj) { 5057 // If the old hovered node is not nil but it's renderer is, it was probably detached as part of the :hover style 5058 // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors) 5059 // must be updated, to ensure it's normal style is re-applied. 5060 if (oldHoverNode && !oldHoverObj) { 5061 for (Node* node = oldHoverNode.get(); node; node = node->parentNode()) { 5062 if (!mustBeInActiveChain || (node->isElementNode() && toElement(node)->inActiveChain())) 5063 nodesToRemoveFromChain.append(node); 5064 } 5065 5066 } 5067 5068 // The old hover path only needs to be cleared up to (and not including) the common ancestor; 5069 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { 5070 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) 5071 nodesToRemoveFromChain.append(curr->node()); 5072 } 5073 } 5074 5075 // Now set the hover state for our new object up to the root. 5076 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { 5077 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) 5078 nodesToAddToChain.append(curr->node()); 5079 } 5080 5081 // mouseenter and mouseleave events do not bubble, so they are dispatched iff there is a capturing 5082 // event handler on an ancestor or a normal event handler on the element itself. This special 5083 // handling is necessary to avoid O(n^2) capturing event handler checks. We'll check the previously 5084 // hovered node's ancestor tree for 'mouseleave' handlers here, then check the newly hovered node's 5085 // ancestor tree for 'mouseenter' handlers after dispatching the 'mouseleave' events (as the handler 5086 // for 'mouseleave' might set a capturing 'mouseenter' handler, odd as that might be). 5087 bool ancestorHasCapturingMouseleaveListener = false; 5088 if (event && newHoverNode != oldHoverNode.get()) { 5089 for (Node* node = oldHoverNode.get(); node; node = node->parentOrShadowHostNode()) { 5090 if (node->hasCapturingEventListeners(EventTypeNames::mouseleave)) { 5091 ancestorHasCapturingMouseleaveListener = true; 5092 break; 5093 } 5094 } 5095 } 5096 5097 size_t removeCount = nodesToRemoveFromChain.size(); 5098 for (size_t i = 0; i < removeCount; ++i) { 5099 nodesToRemoveFromChain[i]->setHovered(false); 5100 if (event && (ancestorHasCapturingMouseleaveListener || nodesToRemoveFromChain[i]->hasEventListeners(EventTypeNames::mouseleave))) 5101 nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, EventTypeNames::mouseleave, 0, newHoverNode); 5102 } 5103 5104 bool ancestorHasCapturingMouseenterListener = false; 5105 if (event && newHoverNode != oldHoverNode.get()) { 5106 for (Node* node = newHoverNode; node; node = node->parentOrShadowHostNode()) { 5107 if (node->hasCapturingEventListeners(EventTypeNames::mouseenter)) { 5108 ancestorHasCapturingMouseenterListener = true; 5109 break; 5110 } 5111 } 5112 } 5113 5114 bool sawCommonAncestor = false; 5115 size_t addCount = nodesToAddToChain.size(); 5116 for (size_t i = 0; i < addCount; ++i) { 5117 // Elements past the common ancestor do not change hover state, but might change active state. 5118 if (ancestorNode && nodesToAddToChain[i] == ancestorNode) 5119 sawCommonAncestor = true; 5120 if (allowActiveChanges) 5121 nodesToAddToChain[i]->setActive(true); 5122 if (!sawCommonAncestor) { 5123 nodesToAddToChain[i]->setHovered(true); 5124 if (event && (ancestorHasCapturingMouseenterListener || nodesToAddToChain[i]->hasEventListeners(EventTypeNames::mouseenter))) 5125 nodesToAddToChain[i]->dispatchMouseEvent(*event, EventTypeNames::mouseenter, 0, oldHoverNode.get()); 5126 } 5127 } 5128 5129 updateStyleIfNeeded(); 5130 } 5131 5132 bool Document::haveStylesheetsLoaded() const 5133 { 5134 return m_styleEngine->haveStylesheetsLoaded(); 5135 } 5136 5137 Locale& Document::getCachedLocale(const AtomicString& locale) 5138 { 5139 AtomicString localeKey = locale; 5140 if (locale.isEmpty() || !RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled()) 5141 return Locale::defaultLocale(); 5142 LocaleIdentifierToLocaleMap::AddResult result = m_localeCache.add(localeKey, nullptr); 5143 if (result.isNewEntry) 5144 result.iterator->value = Locale::create(localeKey); 5145 return *(result.iterator->value); 5146 } 5147 5148 Document& Document::ensureTemplateDocument() 5149 { 5150 if (const Document* document = templateDocument()) 5151 return *const_cast<Document*>(document); 5152 5153 if (isHTMLDocument()) { 5154 DocumentInit init = DocumentInit::fromContext(contextDocument(), blankURL()); 5155 m_templateDocument = HTMLDocument::create(init); 5156 } else { 5157 m_templateDocument = Document::create(DocumentInit(blankURL())); 5158 } 5159 5160 m_templateDocument->setTemplateDocumentHost(this); // balanced in dtor. 5161 5162 return *m_templateDocument.get(); 5163 } 5164 5165 void Document::didAssociateFormControl(Element* element) 5166 { 5167 if (!frame() || !frame()->page()) 5168 return; 5169 m_associatedFormControls.add(element); 5170 if (!m_didAssociateFormControlsTimer.isActive()) 5171 m_didAssociateFormControlsTimer.startOneShot(0); 5172 } 5173 5174 void Document::didAssociateFormControlsTimerFired(Timer<Document>* timer) 5175 { 5176 ASSERT_UNUSED(timer, timer == &m_didAssociateFormControlsTimer); 5177 if (!frame() || !frame()->page()) 5178 return; 5179 5180 Vector<RefPtr<Element> > associatedFormControls; 5181 copyToVector(m_associatedFormControls, associatedFormControls); 5182 5183 frame()->page()->chrome().client().didAssociateFormControls(associatedFormControls); 5184 m_associatedFormControls.clear(); 5185 } 5186 5187 float Document::devicePixelRatio() const 5188 { 5189 return m_frame ? m_frame->devicePixelRatio() : 1.0; 5190 } 5191 5192 PassOwnPtr<LifecycleNotifier<Document> > Document::createLifecycleNotifier() 5193 { 5194 return DocumentLifecycleNotifier::create(this); 5195 } 5196 5197 DocumentLifecycleNotifier& Document::lifecycleNotifier() 5198 { 5199 return static_cast<DocumentLifecycleNotifier&>(LifecycleContext<Document>::lifecycleNotifier()); 5200 } 5201 5202 void Document::removedStyleSheet(StyleSheet* sheet, RecalcStyleTime when, StyleResolverUpdateMode updateMode) 5203 { 5204 // If we're in document teardown, then we don't need this notification of our sheet's removal. 5205 // styleResolverChanged() is needed even when the document is inactive so that 5206 // imported docuements (which is inactive) notifies the change to the master document. 5207 if (isActive()) 5208 styleEngine()->modifiedStyleSheet(sheet); 5209 styleResolverChanged(when, updateMode); 5210 } 5211 5212 void Document::modifiedStyleSheet(StyleSheet* sheet, RecalcStyleTime when, StyleResolverUpdateMode updateMode) 5213 { 5214 // If we're in document teardown, then we don't need this notification of our sheet's removal. 5215 // styleResolverChanged() is needed even when the document is inactive so that 5216 // imported docuements (which is inactive) notifies the change to the master document. 5217 if (isActive()) 5218 styleEngine()->modifiedStyleSheet(sheet); 5219 styleResolverChanged(when, updateMode); 5220 } 5221 5222 TextAutosizer* Document::textAutosizer() 5223 { 5224 if (!m_textAutosizer && !RuntimeEnabledFeatures::fastTextAutosizingEnabled()) 5225 m_textAutosizer = TextAutosizer::create(this); 5226 return m_textAutosizer.get(); 5227 } 5228 5229 FastTextAutosizer* Document::fastTextAutosizer() 5230 { 5231 if (!m_fastTextAutosizer && RuntimeEnabledFeatures::fastTextAutosizingEnabled()) 5232 m_fastTextAutosizer = FastTextAutosizer::create(this); 5233 return m_fastTextAutosizer.get(); 5234 } 5235 5236 } // namespace WebCore 5237