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