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