1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004-2019 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 "Document.h"
30
31#include "AXObjectCache.h"
32#include "ApplicationStateChangeListener.h"
33#include "Attr.h"
34#include "BeforeUnloadEvent.h"
35#include "CDATASection.h"
36#include "CSSAnimationController.h"
37#include "CSSFontSelector.h"
38#include "CSSStyleDeclaration.h"
39#include "CSSStyleSheet.h"
40#include "CachedCSSStyleSheet.h"
41#include "CachedFrame.h"
42#include "CachedResourceLoader.h"
43#include "CanvasRenderingContext2D.h"
44#include "Chrome.h"
45#include "ChromeClient.h"
46#include "Comment.h"
47#include "CommonVM.h"
48#include "ComposedTreeIterator.h"
49#include "CompositionEvent.h"
50#include "ConstantPropertyMap.h"
51#include "ContentSecurityPolicy.h"
52#include "CookieJar.h"
53#include "CustomElementReactionQueue.h"
54#include "CustomElementRegistry.h"
55#include "CustomEvent.h"
56#include "DOMImplementation.h"
57#include "DOMWindow.h"
58#include "DateComponents.h"
59#include "DebugPageOverlays.h"
60#include "DocumentLoader.h"
61#include "DocumentMarkerController.h"
62#include "DocumentSharedObjectPool.h"
63#include "DocumentTimeline.h"
64#include "DocumentType.h"
65#include "Editing.h"
66#include "Editor.h"
67#include "ElementIterator.h"
68#include "EventHandler.h"
69#include "ExtensionStyleSheets.h"
70#include "FocusController.h"
71#include "FocusEvent.h"
72#include "FontFaceSet.h"
73#include "FormController.h"
74#include "Frame.h"
75#include "FrameLoader.h"
76#include "FrameLoaderClient.h"
77#include "FrameView.h"
78#include "FullscreenManager.h"
79#include "GenericCachedHTMLCollection.h"
80#include "HTMLAllCollection.h"
81#include "HTMLAnchorElement.h"
82#include "HTMLAttachmentElement.h"
83#include "HTMLBaseElement.h"
84#include "HTMLBodyElement.h"
85#include "HTMLCanvasElement.h"
86#include "HTMLDocument.h"
87#include "HTMLElementFactory.h"
88#include "HTMLFormControlElement.h"
89#include "HTMLFrameOwnerElement.h"
90#include "HTMLFrameSetElement.h"
91#include "HTMLHeadElement.h"
92#include "HTMLHtmlElement.h"
93#include "HTMLImageElement.h"
94#include "HTMLInputElement.h"
95#include "HTMLLinkElement.h"
96#include "HTMLMediaElement.h"
97#include "HTMLNameCollection.h"
98#include "HTMLParserIdioms.h"
99#include "HTMLPictureElement.h"
100#include "HTMLPlugInElement.h"
101#include "HTMLScriptElement.h"
102#include "HTMLStyleElement.h"
103#include "HTMLTitleElement.h"
104#include "HTMLUnknownElement.h"
105#include "HTTPHeaderNames.h"
106#include "HTTPParsers.h"
107#include "HashChangeEvent.h"
108#include "History.h"
109#include "HitTestResult.h"
110#include "ImageBitmapRenderingContext.h"
111#include "ImageLoader.h"
112#include "InspectorInstrumentation.h"
113#include "IntersectionObserver.h"
114#include "JSCustomElementInterface.h"
115#include "JSLazyEventListener.h"
116#include "KeyboardEvent.h"
117#include "KeyframeEffect.h"
118#include "LayoutDisallowedScope.h"
119#include "LibWebRTCProvider.h"
120#include "LoaderStrategy.h"
121#include "Logging.h"
122#include "MediaCanStartListener.h"
123#include "MediaProducer.h"
124#include "MediaQueryList.h"
125#include "MediaQueryMatcher.h"
126#include "MessageEvent.h"
127#include "Microtasks.h"
128#include "MouseEventWithHitTestResults.h"
129#include "MutationEvent.h"
130#include "NameNodeList.h"
131#include "NavigationDisabler.h"
132#include "NavigationScheduler.h"
133#include "NestingLevelIncrementer.h"
134#include "NodeIterator.h"
135#include "NodeRareData.h"
136#include "NodeWithIndex.h"
137#include "OverflowEvent.h"
138#include "PageConsoleClient.h"
139#include "PageGroup.h"
140#include "PageTransitionEvent.h"
141#include "PaintWorkletGlobalScope.h"
142#include "PlatformLocale.h"
143#include "PlatformMediaSessionManager.h"
144#include "PlatformScreen.h"
145#include "PlatformStrategies.h"
146#include "PlugInsResources.h"
147#include "PluginDocument.h"
148#include "PointerLockController.h"
149#include "PolicyChecker.h"
150#include "PopStateEvent.h"
151#include "ProcessingInstruction.h"
152#include "PublicSuffix.h"
153#include "Quirks.h"
154#include "RealtimeMediaSourceCenter.h"
155#include "RenderChildIterator.h"
156#include "RenderInline.h"
157#include "RenderLayerCompositor.h"
158#include "RenderLineBreak.h"
159#include "RenderTreeUpdater.h"
160#include "RenderView.h"
161#include "RenderWidget.h"
162#include "RequestAnimationFrameCallback.h"
163#include "ResizeObserver.h"
164#include "ResourceLoadObserver.h"
165#include "RuntimeApplicationChecks.h"
166#include "RuntimeEnabledFeatures.h"
167#include "SVGDocumentExtensions.h"
168#include "SVGElement.h"
169#include "SVGElementFactory.h"
170#include "SVGNames.h"
171#include "SVGSVGElement.h"
172#include "SVGTitleElement.h"
173#include "SVGUseElement.h"
174#include "SVGZoomEvent.h"
175#include "SWClientConnection.h"
176#include "SchemeRegistry.h"
177#include "ScopedEventQueue.h"
178#include "ScriptController.h"
179#include "ScriptDisallowedScope.h"
180#include "ScriptModuleLoader.h"
181#include "ScriptRunner.h"
182#include "ScriptSourceCode.h"
183#include "ScriptState.h"
184#include "ScriptedAnimationController.h"
185#include "ScrollingCoordinator.h"
186#include "SecurityOrigin.h"
187#include "SecurityOriginData.h"
188#include "SecurityOriginPolicy.h"
189#include "SecurityPolicy.h"
190#include "SegmentedString.h"
191#include "SelectorQuery.h"
192#include "ServiceWorkerClientData.h"
193#include "ServiceWorkerProvider.h"
194#include "Settings.h"
195#include "ShadowRoot.h"
196#include "SocketProvider.h"
197#include "StorageEvent.h"
198#include "StringCallback.h"
199#include "StyleColor.h"
200#include "StyleProperties.h"
201#include "StyleResolveForDocument.h"
202#include "StyleResolver.h"
203#include "StyleScope.h"
204#include "StyleSheetContents.h"
205#include "StyleSheetList.h"
206#include "StyleTreeResolver.h"
207#include "SubresourceLoader.h"
208#include "TextAutoSizing.h"
209#include "TextEvent.h"
210#include "TextNodeTraversal.h"
211#include "TouchAction.h"
212#include "TransformSource.h"
213#include "TreeWalker.h"
214#include "UndoManager.h"
215#include "UserGestureIndicator.h"
216#include "ValidationMessageClient.h"
217#include "VisibilityChangeClient.h"
218#include "VisitedLinkState.h"
219#include "WebAnimation.h"
220#include "WheelEvent.h"
221#include "WindowFeatures.h"
222#include "Worklet.h"
223#include "XMLDocument.h"
224#include "XMLDocumentParser.h"
225#include "XMLNSNames.h"
226#include "XMLNames.h"
227#include "XPathEvaluator.h"
228#include "XPathExpression.h"
229#include "XPathNSResolver.h"
230#include "XPathResult.h"
231#include <JavaScriptCore/ConsoleMessage.h>
232#include <JavaScriptCore/RegularExpression.h>
233#include <JavaScriptCore/ScriptCallStack.h>
234#include <JavaScriptCore/VM.h>
235#include <ctime>
236#include <wtf/IsoMallocInlines.h>
237#include <wtf/Language.h>
238#include <wtf/NeverDestroyed.h>
239#include <wtf/SetForScope.h>
240#include <wtf/SystemTracing.h>
241#include <wtf/UUID.h>
242#include <wtf/text/StringBuffer.h>
243#include <wtf/text/TextStream.h>
244
245#if ENABLE(DEVICE_ORIENTATION)
246#include "DeviceMotionEvent.h"
247#include "DeviceOrientationAndMotionAccessController.h"
248#include "DeviceOrientationEvent.h"
249#endif
250
251#if ENABLE(FULLSCREEN_API)
252#include "RenderFullScreen.h"
253#endif
254
255#if ENABLE(INDEXED_DATABASE)
256#include "IDBConnectionProxy.h"
257#include "IDBOpenDBRequest.h"
258#endif
259
260#if PLATFORM(IOS_FAMILY)
261#include "ContentChangeObserver.h"
262#include "CSSFontSelector.h"
263#include "DeviceMotionClientIOS.h"
264#include "DeviceMotionController.h"
265#include "DeviceOrientationClientIOS.h"
266#include "DeviceOrientationController.h"
267#include "Geolocation.h"
268#include "Navigator.h"
269#include "NavigatorGeolocation.h"
270#endif
271
272#if ENABLE(IOS_GESTURE_EVENTS)
273#include "GestureEvent.h"
274#endif
275
276#if ENABLE(MATHML)
277#include "MathMLElement.h"
278#include "MathMLElementFactory.h"
279#include "MathMLNames.h"
280#endif
281
282#if ENABLE(MEDIA_SESSION)
283#include "MediaSession.h"
284#endif
285
286#if USE(QUICK_LOOK)
287#include "QuickLook.h"
288#endif
289
290#if ENABLE(TOUCH_EVENTS)
291#include "TouchEvent.h"
292#endif
293
294#if ENABLE(VIDEO_TRACK)
295#include "CaptionUserPreferences.h"
296#endif
297
298#if ENABLE(WIRELESS_PLAYBACK_TARGET)
299#include "MediaPlaybackTargetClient.h"
300#endif
301
302#if ENABLE(XSLT)
303#include "XSLTProcessor.h"
304#endif
305
306#if ENABLE(MEDIA_STREAM)
307#include "MediaStream.h"
308#include "MediaStreamRegistry.h"
309#endif
310
311#if ENABLE(WEBGL)
312#include "WebGLRenderingContext.h"
313#endif
314#if ENABLE(WEBGL2)
315#include "WebGL2RenderingContext.h"
316#endif
317#if ENABLE(WEBGPU)
318#include "GPUCanvasContext.h"
319#endif
320
321namespace WebCore {
322
323WTF_MAKE_ISO_ALLOCATED_IMPL(Document);
324
325using namespace HTMLNames;
326using namespace PAL;
327using namespace WTF::Unicode;
328
329static const unsigned cMaxWriteRecursionDepth = 21;
330bool Document::hasEverCreatedAnAXObjectCache = false;
331static const Seconds maxIntervalForUserGestureForwardingAfterMediaFinishesPlaying { 1_s };
332
333// DOM Level 2 says (letters added):
334//
335// a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
336// b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
337// c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
338// 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.
339// 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.
340// f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
341// g) Character #x00B7 is classified as an extender, because the property list so identifies it.
342// h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
343// i) Characters ':' and '_' are allowed as name-start characters.
344// j) Characters '-' and '.' are allowed as name characters.
345//
346// It also contains complete tables. If we decide it's better, we could include those instead of the following code.
347
348static inline bool isValidNameStart(UChar32 c)
349{
350 // rule (e) above
351 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
352 return true;
353
354 // rule (i) above
355 if (c == ':' || c == '_')
356 return true;
357
358 // rules (a) and (f) above
359 if (!(U_GET_GC_MASK(c) & (U_GC_LL_MASK | U_GC_LU_MASK | U_GC_LO_MASK | U_GC_LT_MASK | U_GC_NL_MASK)))
360 return false;
361
362 // rule (c) above
363 if (c >= 0xF900 && c < 0xFFFE)
364 return false;
365
366 // rule (d) above
367 int type = u_getIntPropertyValue(c, UCHAR_DECOMPOSITION_TYPE);
368 if (type == U_DT_FONT || type == U_DT_COMPAT)
369 return false;
370
371 return true;
372}
373
374static inline bool isValidNamePart(UChar32 c)
375{
376 // rules (a), (e), and (i) above
377 if (isValidNameStart(c))
378 return true;
379
380 // rules (g) and (h) above
381 if (c == 0x00B7 || c == 0x0387)
382 return true;
383
384 // rule (j) above
385 if (c == '-' || c == '.')
386 return true;
387
388 // rules (b) and (f) above
389 if (!(U_GET_GC_MASK(c) & (U_GC_M_MASK | U_GC_LM_MASK | U_GC_ND_MASK)))
390 return false;
391
392 // rule (c) above
393 if (c >= 0xF900 && c < 0xFFFE)
394 return false;
395
396 // rule (d) above
397 int type = u_getIntPropertyValue(c, UCHAR_DECOMPOSITION_TYPE);
398 if (type == U_DT_FONT || type == U_DT_COMPAT)
399 return false;
400
401 return true;
402}
403
404static Widget* widgetForElement(Element* focusedElement)
405{
406 if (!focusedElement)
407 return nullptr;
408 auto* renderer = focusedElement->renderer();
409 if (!is<RenderWidget>(renderer))
410 return nullptr;
411 return downcast<RenderWidget>(*renderer).widget();
412}
413
414static bool acceptsEditingFocus(const Element& element)
415{
416 ASSERT(element.hasEditableStyle());
417
418 auto* root = element.rootEditableElement();
419 Frame* frame = element.document().frame();
420 if (!frame || !root)
421 return false;
422
423 return frame->editor().shouldBeginEditing(rangeOfContents(*root).ptr());
424}
425
426static bool canAccessAncestor(const SecurityOrigin& activeSecurityOrigin, Frame* targetFrame)
427{
428 // targetFrame can be 0 when we're trying to navigate a top-level frame
429 // that has a 0 opener.
430 if (!targetFrame)
431 return false;
432
433 const bool isLocalActiveOrigin = activeSecurityOrigin.isLocal();
434 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree().parent()) {
435 Document* ancestorDocument = ancestorFrame->document();
436 // FIXME: Should be an ASSERT? Frames should alway have documents.
437 if (!ancestorDocument)
438 return true;
439
440 const SecurityOrigin& ancestorSecurityOrigin = ancestorDocument->securityOrigin();
441 if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin))
442 return true;
443
444 // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
445 // FIXME: It's a bit strange to special-case local origins here. Should we be doing
446 // something more general instead?
447 if (isLocalActiveOrigin && ancestorSecurityOrigin.isLocal())
448 return true;
449 }
450
451 return false;
452}
453
454static void printNavigationErrorMessage(Frame& frame, const URL& activeURL, const char* reason)
455{
456 String message = "Unsafe JavaScript attempt to initiate navigation for frame with URL '" + frame.document()->url().string() + "' from frame with URL '" + activeURL.string() + "'. " + reason + "\n";
457
458 // FIXME: should we print to the console of the document performing the navigation instead?
459 frame.document()->domWindow()->printErrorMessage(message);
460}
461
462uint64_t Document::s_globalTreeVersion = 0;
463
464auto Document::allDocumentsMap() -> DocumentsMap&
465{
466 static NeverDestroyed<DocumentsMap> documents;
467 return documents;
468}
469
470auto Document::allDocuments() -> DocumentsMap::ValuesIteratorRange
471{
472 return allDocumentsMap().values();
473}
474
475static inline int currentOrientation(Frame* frame)
476{
477#if ENABLE(ORIENTATION_EVENTS)
478 if (frame)
479 return frame->orientation();
480#else
481 UNUSED_PARAM(frame);
482#endif
483 return 0;
484}
485
486Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsigned constructionFlags)
487 : ContainerNode(*this, CreateDocument)
488 , TreeScope(*this)
489 , FrameDestructionObserver(frame)
490#if ENABLE(IOS_TOUCH_EVENTS)
491 , m_touchEventsChangedTimer(*this, &Document::touchEventsChangedTimerFired)
492#endif
493 , m_settings(frame ? Ref<Settings>(frame->settings()) : Settings::create(nullptr))
494 , m_quirks(makeUniqueRef<Quirks>(*this))
495 , m_cachedResourceLoader(m_frame ? Ref<CachedResourceLoader>(m_frame->loader().activeDocumentLoader()->cachedResourceLoader()) : CachedResourceLoader::create(nullptr))
496 , m_domTreeVersion(++s_globalTreeVersion)
497 , m_styleScope(std::make_unique<Style::Scope>(*this))
498 , m_extensionStyleSheets(std::make_unique<ExtensionStyleSheets>(*this))
499 , m_visitedLinkState(std::make_unique<VisitedLinkState>(*this))
500 , m_markers(std::make_unique<DocumentMarkerController>(*this))
501 , m_styleRecalcTimer([this] { updateStyleIfNeeded(); })
502 , m_documentCreationTime(MonotonicTime::now())
503 , m_scriptRunner(std::make_unique<ScriptRunner>(*this))
504 , m_moduleLoader(std::make_unique<ScriptModuleLoader>(*this))
505#if ENABLE(XSLT)
506 , m_applyPendingXSLTransformsTimer(*this, &Document::applyPendingXSLTransformsTimerFired)
507#endif
508 , m_xmlVersion("1.0"_s)
509 , m_constantPropertyMap(std::make_unique<ConstantPropertyMap>(*this))
510 , m_documentClasses(documentClasses)
511 , m_eventQueue(*this)
512#if ENABLE(FULLSCREEN_API)
513 , m_fullscreenManager { makeUniqueRef<FullscreenManager>(*this) }
514#endif
515#if ENABLE(INTERSECTION_OBSERVER)
516 , m_intersectionObserversNotifyTimer(*this, &Document::notifyIntersectionObserversTimerFired)
517#endif
518 , m_loadEventDelayTimer(*this, &Document::loadEventDelayTimerFired)
519#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
520 , m_deviceMotionClient(std::make_unique<DeviceMotionClientIOS>())
521 , m_deviceMotionController(std::make_unique<DeviceMotionController>(*m_deviceMotionClient))
522 , m_deviceOrientationClient(std::make_unique<DeviceOrientationClientIOS>())
523 , m_deviceOrientationController(std::make_unique<DeviceOrientationController>(*m_deviceOrientationClient))
524#endif
525 , m_pendingTasksTimer(*this, &Document::pendingTasksTimerFired)
526 , m_visualUpdatesSuppressionTimer(*this, &Document::visualUpdatesSuppressionTimerFired)
527 , m_sharedObjectPoolClearTimer(*this, &Document::clearSharedObjectPool)
528 , m_fontSelector(CSSFontSelector::create(*this))
529 , m_didAssociateFormControlsTimer(*this, &Document::didAssociateFormControlsTimerFired)
530 , m_cookieCacheExpiryTimer(*this, &Document::invalidateDOMCookieCache)
531 , m_socketProvider(page() ? &page()->socketProvider() : nullptr)
532 , m_isSynthesized(constructionFlags & Synthesized)
533 , m_isNonRenderedPlaceholder(constructionFlags & NonRenderedPlaceholder)
534 , m_orientationNotifier(currentOrientation(frame))
535 , m_identifier(DocumentIdentifier::generate())
536 , m_undoManager(UndoManager::create(*this))
537{
538 auto addResult = allDocumentsMap().add(m_identifier, this);
539 ASSERT_UNUSED(addResult, addResult.isNewEntry);
540
541 // We depend on the url getting immediately set in subframes, but we
542 // also depend on the url NOT getting immediately set in opened windows.
543 // See fast/dom/early-frame-url.html
544 // and fast/dom/location-new-window-no-crash.html, respectively.
545 // FIXME: Can/should we unify this behavior?
546 if ((frame && frame->ownerElement()) || !url.isEmpty())
547 setURL(url);
548
549 m_cachedResourceLoader->setDocument(this);
550
551 resetLinkColor();
552 resetVisitedLinkColor();
553 resetActiveLinkColor();
554
555 initSecurityContext();
556 initDNSPrefetch();
557
558 m_fontSelector->registerForInvalidationCallbacks(*this);
559
560 for (auto& nodeListAndCollectionCount : m_nodeListAndCollectionCounts)
561 nodeListAndCollectionCount = 0;
562
563 InspectorInstrumentation::addEventListenersToNode(*this);
564}
565
566Ref<Document> Document::create(Document& contextDocument)
567{
568 auto document = adoptRef(*new Document(nullptr, URL()));
569 document->setContextDocument(contextDocument);
570 document->setSecurityOriginPolicy(contextDocument.securityOriginPolicy());
571 return document;
572}
573
574Document::~Document()
575{
576 if (m_logger)
577 m_logger->removeObserver(*this);
578
579 ASSERT(allDocumentsMap().contains(m_identifier));
580 allDocumentsMap().remove(m_identifier);
581 // We need to remove from the contexts map very early in the destructor so that calling postTask() on this Document from another thread is safe.
582 removeFromContextsMap();
583
584 ASSERT(!renderView());
585 ASSERT(m_pageCacheState != InPageCache);
586 ASSERT(m_ranges.isEmpty());
587 ASSERT(!m_parentTreeScope);
588 ASSERT(!m_disabledFieldsetElementsCount);
589 ASSERT(m_inDocumentShadowRoots.isEmpty());
590
591#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
592 m_deviceMotionClient->deviceMotionControllerDestroyed();
593 m_deviceOrientationClient->deviceOrientationControllerDestroyed();
594#endif
595
596 if (m_templateDocument)
597 m_templateDocument->setTemplateDocumentHost(nullptr); // balanced in templateDocument().
598
599 // FIXME: Should we reset m_domWindow when we detach from the Frame?
600 if (m_domWindow)
601 m_domWindow->resetUnlessSuspendedForDocumentSuspension();
602
603 m_scriptRunner = nullptr;
604 m_moduleLoader = nullptr;
605
606 removeAllEventListeners();
607
608 // Currently we believe that Document can never outlive the parser.
609 // Although the Document may be replaced synchronously, DocumentParsers
610 // generally keep at least one reference to an Element which would in turn
611 // has a reference to the Document. If you hit this ASSERT, then that
612 // assumption is wrong. DocumentParser::detach() should ensure that even
613 // if the DocumentParser outlives the Document it won't cause badness.
614 ASSERT(!m_parser || m_parser->refCount() == 1);
615 detachParser();
616
617 if (this == &topDocument())
618 clearAXObjectCache();
619
620 m_decoder = nullptr;
621
622 if (m_styleSheetList)
623 m_styleSheetList->detach();
624
625 extensionStyleSheets().detachFromDocument();
626
627 styleScope().clearResolver(); // We need to destroy CSSFontSelector before destroying m_cachedResourceLoader.
628 m_fontSelector->clearDocument();
629 m_fontSelector->unregisterForInvalidationCallbacks(*this);
630
631 // It's possible for multiple Documents to end up referencing the same CachedResourceLoader (e.g., SVGImages
632 // load the initial empty document and the SVGDocument with the same DocumentLoader).
633 if (m_cachedResourceLoader->document() == this)
634 m_cachedResourceLoader->setDocument(nullptr);
635
636#if ENABLE(VIDEO)
637 stopAllMediaPlayback();
638#endif
639
640 // We must call clearRareData() here since a Document class inherits TreeScope
641 // as well as Node. See a comment on TreeScope.h for the reason.
642 if (hasRareData())
643 clearRareData();
644
645 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_listsInvalidatedAtDocument.isEmpty());
646 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_collectionsInvalidatedAtDocument.isEmpty());
647 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(m_svgUseElements.isEmpty());
648
649 for (unsigned count : m_nodeListAndCollectionCounts)
650 ASSERT_UNUSED(count, !count);
651}
652
653void Document::removedLastRef()
654{
655 ASSERT(!m_deletionHasBegun);
656 if (m_referencingNodeCount) {
657 // Node::removedLastRef doesn't set refCount() to zero because it's not observable.
658 // But we need to remember that our refCount reached zero in subsequent calls to decrementReferencingNodeCount().
659 m_refCountAndParentBit = 0;
660
661 // If removing a child removes the last node reference, we don't want the scope to be destroyed
662 // until after removeDetachedChildren returns, so we protect ourselves.
663 incrementReferencingNodeCount();
664
665 RELEASE_ASSERT(!hasLivingRenderTree());
666 // We must make sure not to be retaining any of our children through
667 // these extra pointers or we will create a reference cycle.
668 m_focusedElement = nullptr;
669 m_hoveredElement = nullptr;
670 m_activeElement = nullptr;
671 m_titleElement = nullptr;
672 m_documentElement = nullptr;
673 m_focusNavigationStartingNode = nullptr;
674 m_userActionElements.clear();
675#if ENABLE(FULLSCREEN_API)
676 m_fullscreenManager->clear();
677#endif
678 m_associatedFormControls.clear();
679
680 m_fontSelector->clearDocument();
681 m_fontSelector->unregisterForInvalidationCallbacks(*this);
682
683 detachParser();
684
685 // removeDetachedChildren() doesn't always unregister IDs,
686 // so tear down scope information up front to avoid having
687 // stale references in the map.
688
689 destroyTreeScopeData();
690 removeDetachedChildren();
691 m_formController = nullptr;
692
693 m_markers->detach();
694
695 m_cssCanvasElements.clear();
696
697 commonTeardown();
698
699#ifndef NDEBUG
700 // We need to do this right now since selfOnlyDeref() can delete this.
701 m_inRemovedLastRefFunction = false;
702#endif
703 decrementReferencingNodeCount();
704 } else {
705#ifndef NDEBUG
706 m_inRemovedLastRefFunction = false;
707 m_deletionHasBegun = true;
708#endif
709 delete this;
710 }
711}
712
713void Document::commonTeardown()
714{
715 if (svgExtensions())
716 accessSVGExtensions().pauseAnimations();
717
718 clearScriptedAnimationController();
719}
720
721Element* Document::elementForAccessKey(const String& key)
722{
723 if (key.isEmpty())
724 return nullptr;
725 if (!m_accessKeyCache)
726 buildAccessKeyCache();
727 return m_accessKeyCache->get(key);
728}
729
730void Document::buildAccessKeyCache()
731{
732 m_accessKeyCache = std::make_unique<HashMap<String, Element*, ASCIICaseInsensitiveHash>>([this] {
733 HashMap<String, Element*, ASCIICaseInsensitiveHash> map;
734 for (auto& node : composedTreeDescendants(*this)) {
735 if (!is<Element>(node))
736 continue;
737 auto& element = downcast<Element>(node);
738 auto& key = element.attributeWithoutSynchronization(accesskeyAttr);
739 if (key.isEmpty())
740 continue;
741 map.add(key, &element);
742 }
743 return map;
744 }());
745}
746
747void Document::invalidateAccessKeyCacheSlowCase()
748{
749 m_accessKeyCache = nullptr;
750}
751
752ExceptionOr<SelectorQuery&> Document::selectorQueryForString(const String& selectorString)
753{
754 if (selectorString.isEmpty())
755 return Exception { SyntaxError };
756 if (!m_selectorQueryCache)
757 m_selectorQueryCache = std::make_unique<SelectorQueryCache>();
758 return m_selectorQueryCache->add(selectorString, *this);
759}
760
761void Document::clearSelectorQueryCache()
762{
763 m_selectorQueryCache = nullptr;
764}
765
766void Document::setReferrerPolicy(ReferrerPolicy referrerPolicy)
767{
768 // Do not override existing referrer policy with the "empty string" one as the "empty string" means we should use
769 // the policy defined elsewhere.
770 if (m_referrerPolicy && referrerPolicy == ReferrerPolicy::EmptyString)
771 return;
772
773 m_referrerPolicy = referrerPolicy;
774}
775
776MediaQueryMatcher& Document::mediaQueryMatcher()
777{
778 if (!m_mediaQueryMatcher)
779 m_mediaQueryMatcher = MediaQueryMatcher::create(*this);
780 return *m_mediaQueryMatcher;
781}
782
783void Document::setCompatibilityMode(DocumentCompatibilityMode mode)
784{
785 if (m_compatibilityModeLocked || mode == m_compatibilityMode)
786 return;
787 bool wasInQuirksMode = inQuirksMode();
788 m_compatibilityMode = mode;
789
790 clearSelectorQueryCache();
791
792 if (inQuirksMode() != wasInQuirksMode) {
793 // All user stylesheets have to reparse using the different mode.
794 extensionStyleSheets().clearPageUserSheet();
795 extensionStyleSheets().invalidateInjectedStyleSheetCache();
796 }
797}
798
799String Document::compatMode() const
800{
801 return inQuirksMode() ? "BackCompat" : "CSS1Compat";
802}
803
804void Document::resetLinkColor()
805{
806 m_linkColor = StyleColor::colorFromKeyword(CSSValueWebkitLink, styleColorOptions(nullptr));
807}
808
809void Document::resetVisitedLinkColor()
810{
811 m_visitedLinkColor = StyleColor::colorFromKeyword(CSSValueWebkitLink, styleColorOptions(nullptr) | StyleColor::Options::ForVisitedLink);
812}
813
814void Document::resetActiveLinkColor()
815{
816 m_activeLinkColor = StyleColor::colorFromKeyword(CSSValueWebkitActivelink, styleColorOptions(nullptr));
817}
818
819DOMImplementation& Document::implementation()
820{
821 if (!m_implementation)
822 m_implementation = std::make_unique<DOMImplementation>(*this);
823 return *m_implementation;
824}
825
826bool Document::hasManifest() const
827{
828 return documentElement() && documentElement()->hasTagName(htmlTag) && documentElement()->hasAttributeWithoutSynchronization(manifestAttr);
829}
830
831DocumentType* Document::doctype() const
832{
833 for (Node* node = firstChild(); node; node = node->nextSibling()) {
834 if (is<DocumentType>(node))
835 return downcast<DocumentType>(node);
836 }
837 return nullptr;
838}
839
840void Document::childrenChanged(const ChildChange& change)
841{
842 ContainerNode::childrenChanged(change);
843
844 // FIXME: Chrome::didReceiveDocType() used to be called only when the doctype changed. We need to check the
845 // impact of calling this systematically. If the overhead is negligible, we need to rename didReceiveDocType,
846 // otherwise, we need to detect the doc type changes before updating the viewport.
847 if (Page* page = this->page())
848 page->chrome().didReceiveDocType(*frame());
849
850 Element* newDocumentElement = childrenOfType<Element>(*this).first();
851 if (newDocumentElement == m_documentElement)
852 return;
853 m_documentElement = newDocumentElement;
854 // The root style used for media query matching depends on the document element.
855 styleScope().clearResolver();
856}
857
858static ALWAYS_INLINE Ref<HTMLElement> createUpgradeCandidateElement(Document& document, const QualifiedName& name)
859{
860 if (!RuntimeEnabledFeatures::sharedFeatures().customElementsEnabled()
861 || Document::validateCustomElementName(name.localName()) != CustomElementNameValidationStatus::Valid)
862 return HTMLUnknownElement::create(name, document);
863
864 auto element = HTMLElement::create(name, document);
865 element->setIsCustomElementUpgradeCandidate();
866 return element;
867}
868
869static ALWAYS_INLINE Ref<HTMLElement> createUpgradeCandidateElement(Document& document, const AtomicString& localName)
870{
871 return createUpgradeCandidateElement(document, QualifiedName { nullAtom(), localName, xhtmlNamespaceURI });
872}
873
874static inline bool isValidHTMLElementName(const AtomicString& localName)
875{
876 return Document::isValidName(localName);
877}
878
879static inline bool isValidHTMLElementName(const QualifiedName& name)
880{
881 return Document::isValidName(name.localName());
882}
883
884template<typename NameType>
885static ExceptionOr<Ref<Element>> createHTMLElementWithNameValidation(Document& document, const NameType& name)
886{
887 auto element = HTMLElementFactory::createKnownElement(name, document);
888 if (LIKELY(element))
889 return Ref<Element> { element.releaseNonNull() };
890
891 if (auto* window = document.domWindow()) {
892 auto* registry = window->customElementRegistry();
893 if (UNLIKELY(registry)) {
894 if (auto* elementInterface = registry->findInterface(name))
895 return elementInterface->constructElementWithFallback(document, name);
896 }
897 }
898
899 if (UNLIKELY(!isValidHTMLElementName(name)))
900 return Exception { InvalidCharacterError };
901
902 return Ref<Element> { createUpgradeCandidateElement(document, name) };
903}
904
905ExceptionOr<Ref<Element>> Document::createElementForBindings(const AtomicString& name)
906{
907 if (isHTMLDocument())
908 return createHTMLElementWithNameValidation(*this, name.convertToASCIILowercase());
909
910 if (isXHTMLDocument())
911 return createHTMLElementWithNameValidation(*this, name);
912
913 if (!isValidName(name))
914 return Exception { InvalidCharacterError };
915
916 return createElement(QualifiedName(nullAtom(), name, nullAtom()), false);
917}
918
919Ref<DocumentFragment> Document::createDocumentFragment()
920{
921 return DocumentFragment::create(document());
922}
923
924Ref<Text> Document::createTextNode(const String& data)
925{
926 return Text::create(*this, data);
927}
928
929Ref<Comment> Document::createComment(const String& data)
930{
931 return Comment::create(*this, data);
932}
933
934ExceptionOr<Ref<CDATASection>> Document::createCDATASection(const String& data)
935{
936 if (isHTMLDocument())
937 return Exception { NotSupportedError };
938 return CDATASection::create(*this, data);
939}
940
941ExceptionOr<Ref<ProcessingInstruction>> Document::createProcessingInstruction(const String& target, const String& data)
942{
943 if (!isValidName(target))
944 return Exception { InvalidCharacterError };
945
946 if (data.contains("?>"))
947 return Exception { InvalidCharacterError };
948
949 return ProcessingInstruction::create(*this, target, data);
950}
951
952Ref<Text> Document::createEditingTextNode(const String& text)
953{
954 return Text::createEditingText(*this, text);
955}
956
957Ref<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
958{
959 Ref<MutableStyleProperties> propertySet(MutableStyleProperties::create());
960 return propertySet->ensureCSSStyleDeclaration();
961}
962
963ExceptionOr<Ref<Node>> Document::importNode(Node& nodeToImport, bool deep)
964{
965 switch (nodeToImport.nodeType()) {
966 case DOCUMENT_FRAGMENT_NODE:
967 if (nodeToImport.isShadowRoot())
968 break;
969 FALLTHROUGH;
970 case ELEMENT_NODE:
971 case TEXT_NODE:
972 case CDATA_SECTION_NODE:
973 case PROCESSING_INSTRUCTION_NODE:
974 case COMMENT_NODE:
975 return nodeToImport.cloneNodeInternal(document(), deep ? CloningOperation::Everything : CloningOperation::OnlySelf);
976
977 case ATTRIBUTE_NODE: {
978 auto& attribute = downcast<Attr>(nodeToImport);
979 return Ref<Node> { Attr::create(*this, attribute.qualifiedName(), attribute.value()) };
980 }
981 case DOCUMENT_NODE: // Can't import a document into another document.
982 case DOCUMENT_TYPE_NODE: // FIXME: Support cloning a DocumentType node per DOM4.
983 break;
984 }
985
986 return Exception { NotSupportedError };
987}
988
989
990ExceptionOr<Ref<Node>> Document::adoptNode(Node& source)
991{
992 EventQueueScope scope;
993
994 switch (source.nodeType()) {
995 case DOCUMENT_NODE:
996 return Exception { NotSupportedError };
997 case ATTRIBUTE_NODE: {
998 auto& attr = downcast<Attr>(source);
999 if (auto* element = attr.ownerElement()) {
1000 auto result = element->removeAttributeNode(attr);
1001 if (result.hasException())
1002 return result.releaseException();
1003 }
1004 break;
1005 }
1006 default:
1007 if (source.isShadowRoot()) {
1008 // ShadowRoot cannot disconnect itself from the host node.
1009 return Exception { HierarchyRequestError };
1010 }
1011 if (is<HTMLFrameOwnerElement>(source)) {
1012 auto& frameOwnerElement = downcast<HTMLFrameOwnerElement>(source);
1013 if (frame() && frame()->tree().isDescendantOf(frameOwnerElement.contentFrame()))
1014 return Exception { HierarchyRequestError };
1015 }
1016 auto result = source.remove();
1017 if (result.hasException())
1018 return result.releaseException();
1019 RELEASE_ASSERT(!source.isConnected());
1020 RELEASE_ASSERT(!source.parentNode());
1021 }
1022
1023 source.setTreeScopeRecursively(*this);
1024
1025 return Ref<Node> { source };
1026}
1027
1028bool Document::hasValidNamespaceForElements(const QualifiedName& qName)
1029{
1030 // These checks are from DOM Core Level 2, createElementNS
1031 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
1032 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div")
1033 return false;
1034 if (qName.prefix() == xmlAtom() && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang")
1035 return false;
1036
1037 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
1038 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1039 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar"), createElementNS(null, "xmlns")
1040 if (qName.prefix() == xmlnsAtom() || (qName.prefix().isEmpty() && qName.localName() == xmlnsAtom()))
1041 return qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI;
1042 return qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI;
1043}
1044
1045bool Document::hasValidNamespaceForAttributes(const QualifiedName& qName)
1046{
1047 return hasValidNamespaceForElements(qName);
1048}
1049
1050static Ref<HTMLElement> createFallbackHTMLElement(Document& document, const QualifiedName& name)
1051{
1052 if (auto* window = document.domWindow()) {
1053 auto* registry = window->customElementRegistry();
1054 if (UNLIKELY(registry)) {
1055 if (auto* elementInterface = registry->findInterface(name)) {
1056 auto element = HTMLElement::create(name, document);
1057 element->enqueueToUpgrade(*elementInterface);
1058 return element;
1059 }
1060 }
1061 }
1062 // FIXME: Should we also check the equality of prefix between the custom element and name?
1063 return createUpgradeCandidateElement(document, name);
1064}
1065
1066// FIXME: This should really be in a possible ElementFactory class.
1067Ref<Element> Document::createElement(const QualifiedName& name, bool createdByParser)
1068{
1069 RefPtr<Element> element;
1070
1071 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
1072 if (name.namespaceURI() == xhtmlNamespaceURI) {
1073 element = HTMLElementFactory::createKnownElement(name, *this, nullptr, createdByParser);
1074 if (UNLIKELY(!element))
1075 element = createFallbackHTMLElement(*this, name);
1076 } else if (name.namespaceURI() == SVGNames::svgNamespaceURI)
1077 element = SVGElementFactory::createElement(name, *this, createdByParser);
1078#if ENABLE(MATHML)
1079 else if (name.namespaceURI() == MathMLNames::mathmlNamespaceURI)
1080 element = MathMLElementFactory::createElement(name, *this, createdByParser);
1081#endif
1082
1083 if (element)
1084 m_sawElementsInKnownNamespaces = true;
1085 else
1086 element = Element::create(name, document());
1087
1088 // <image> uses imgTag so we need a special rule.
1089 ASSERT((name.matches(imageTag) && element->tagQName().matches(imgTag) && element->tagQName().prefix() == name.prefix()) || name == element->tagQName());
1090
1091 return element.releaseNonNull();
1092}
1093
1094// https://html.spec.whatwg.org/#valid-custom-element-name
1095
1096struct UnicodeCodePointRange {
1097 UChar32 minimum;
1098 UChar32 maximum;
1099};
1100
1101#if !ASSERT_DISABLED
1102
1103static inline bool operator<(const UnicodeCodePointRange& a, const UnicodeCodePointRange& b)
1104{
1105 ASSERT(a.minimum <= a.maximum);
1106 ASSERT(b.minimum <= b.maximum);
1107 return a.maximum < b.minimum;
1108}
1109
1110#endif
1111
1112static inline bool operator<(const UnicodeCodePointRange& a, UChar32 b)
1113{
1114 ASSERT(a.minimum <= a.maximum);
1115 return a.maximum < b;
1116}
1117
1118static inline bool operator<(UChar32 a, const UnicodeCodePointRange& b)
1119{
1120 ASSERT(b.minimum <= b.maximum);
1121 return a < b.minimum;
1122}
1123
1124static inline bool isPotentialCustomElementNameCharacter(UChar32 character)
1125{
1126 static const UnicodeCodePointRange ranges[] = {
1127 { '-', '.' },
1128 { '0', '9' },
1129 { '_', '_' },
1130 { 'a', 'z' },
1131 { 0xB7, 0xB7 },
1132 { 0xC0, 0xD6 },
1133 { 0xD8, 0xF6 },
1134 { 0xF8, 0x37D },
1135 { 0x37F, 0x1FFF },
1136 { 0x200C, 0x200D },
1137 { 0x203F, 0x2040 },
1138 { 0x2070, 0x218F },
1139 { 0x2C00, 0x2FEF },
1140 { 0x3001, 0xD7FF },
1141 { 0xF900, 0xFDCF },
1142 { 0xFDF0, 0xFFFD },
1143 { 0x10000, 0xEFFFF },
1144 };
1145
1146 ASSERT(std::is_sorted(std::begin(ranges), std::end(ranges)));
1147 return std::binary_search(std::begin(ranges), std::end(ranges), character);
1148}
1149
1150CustomElementNameValidationStatus Document::validateCustomElementName(const AtomicString& localName)
1151{
1152 if (!isASCIILower(localName[0]))
1153 return CustomElementNameValidationStatus::FirstCharacterIsNotLowercaseASCIILetter;
1154
1155 bool containsHyphen = false;
1156 for (auto character : StringView(localName).codePoints()) {
1157 if (isASCIIUpper(character))
1158 return CustomElementNameValidationStatus::ContainsUppercaseASCIILetter;
1159 if (!isPotentialCustomElementNameCharacter(character))
1160 return CustomElementNameValidationStatus::ContainsDisallowedCharacter;
1161 if (character == '-')
1162 containsHyphen = true;
1163 }
1164
1165 if (!containsHyphen)
1166 return CustomElementNameValidationStatus::ContainsNoHyphen;
1167
1168#if ENABLE(MATHML)
1169 const auto& annotationXmlLocalName = MathMLNames::annotation_xmlTag->localName();
1170#else
1171 static NeverDestroyed<const AtomicString> annotationXmlLocalName("annotation-xml", AtomicString::ConstructFromLiteral);
1172#endif
1173
1174 if (localName == SVGNames::color_profileTag->localName()
1175 || localName == SVGNames::font_faceTag->localName()
1176 || localName == SVGNames::font_face_formatTag->localName()
1177 || localName == SVGNames::font_face_nameTag->localName()
1178 || localName == SVGNames::font_face_srcTag->localName()
1179 || localName == SVGNames::font_face_uriTag->localName()
1180 || localName == SVGNames::missing_glyphTag->localName()
1181 || localName == annotationXmlLocalName)
1182 return CustomElementNameValidationStatus::ConflictsWithStandardElementName;
1183
1184 return CustomElementNameValidationStatus::Valid;
1185}
1186
1187ExceptionOr<Ref<Element>> Document::createElementNS(const AtomicString& namespaceURI, const String& qualifiedName)
1188{
1189 auto parseResult = parseQualifiedName(namespaceURI, qualifiedName);
1190 if (parseResult.hasException())
1191 return parseResult.releaseException();
1192 QualifiedName parsedName { parseResult.releaseReturnValue() };
1193 if (!hasValidNamespaceForElements(parsedName))
1194 return Exception { NamespaceError };
1195
1196 if (parsedName.namespaceURI() == xhtmlNamespaceURI)
1197 return createHTMLElementWithNameValidation(*this, parsedName);
1198
1199 return createElement(parsedName, false);
1200}
1201
1202void Document::setReadyState(ReadyState readyState)
1203{
1204 if (readyState == m_readyState)
1205 return;
1206
1207 switch (readyState) {
1208 case Loading:
1209 if (!m_documentTiming.domLoading)
1210 m_documentTiming.domLoading = MonotonicTime::now();
1211 break;
1212 case Interactive:
1213 if (!m_documentTiming.domInteractive)
1214 m_documentTiming.domInteractive = MonotonicTime::now();
1215 break;
1216 case Complete:
1217 if (!m_documentTiming.domComplete)
1218 m_documentTiming.domComplete = MonotonicTime::now();
1219 break;
1220 }
1221
1222 m_readyState = readyState;
1223 dispatchEvent(Event::create(eventNames().readystatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
1224
1225 if (settings().suppressesIncrementalRendering())
1226 setVisualUpdatesAllowed(readyState);
1227}
1228
1229void Document::setVisualUpdatesAllowed(ReadyState readyState)
1230{
1231 ASSERT(settings().suppressesIncrementalRendering());
1232 switch (readyState) {
1233 case Loading:
1234 ASSERT(!m_visualUpdatesSuppressionTimer.isActive());
1235 ASSERT(m_visualUpdatesAllowed);
1236 setVisualUpdatesAllowed(false);
1237 break;
1238 case Interactive:
1239 ASSERT(m_visualUpdatesSuppressionTimer.isActive() || m_visualUpdatesAllowed);
1240 break;
1241 case Complete:
1242 if (m_visualUpdatesSuppressionTimer.isActive()) {
1243 ASSERT(!m_visualUpdatesAllowed);
1244
1245 if (view() && !view()->visualUpdatesAllowedByClient())
1246 return;
1247
1248 setVisualUpdatesAllowed(true);
1249 } else
1250 ASSERT(m_visualUpdatesAllowed);
1251 break;
1252 }
1253}
1254
1255void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed)
1256{
1257 if (m_visualUpdatesAllowed == visualUpdatesAllowed)
1258 return;
1259
1260 m_visualUpdatesAllowed = visualUpdatesAllowed;
1261
1262 if (visualUpdatesAllowed)
1263 m_visualUpdatesSuppressionTimer.stop();
1264 else
1265 m_visualUpdatesSuppressionTimer.startOneShot(1_s * settings().incrementalRenderingSuppressionTimeoutInSeconds());
1266
1267 if (!visualUpdatesAllowed)
1268 return;
1269
1270 RefPtr<FrameView> frameView = view();
1271 bool needsLayout = frameView && renderView() && (frameView->layoutContext().isLayoutPending() || renderView()->needsLayout());
1272 if (needsLayout)
1273 updateLayout();
1274
1275 if (Page* page = this->page()) {
1276 if (frame()->isMainFrame()) {
1277 frameView->addPaintPendingMilestones(DidFirstPaintAfterSuppressedIncrementalRendering);
1278 if (page->requestedLayoutMilestones() & DidFirstLayoutAfterSuppressedIncrementalRendering)
1279 frame()->loader().didReachLayoutMilestone(DidFirstLayoutAfterSuppressedIncrementalRendering);
1280 }
1281 }
1282
1283 if (frameView)
1284 frameView->updateCompositingLayersAfterLayout();
1285
1286 if (RenderView* renderView = this->renderView())
1287 renderView->repaintViewAndCompositedLayers();
1288
1289 if (Frame* frame = this->frame())
1290 frame->loader().forcePageTransitionIfNeeded();
1291}
1292
1293void Document::visualUpdatesSuppressionTimerFired()
1294{
1295 ASSERT(!m_visualUpdatesAllowed);
1296
1297 // If the client is extending the visual update suppression period explicitly, the
1298 // watchdog should not re-enable visual updates itself, but should wait for the client.
1299 if (view() && !view()->visualUpdatesAllowedByClient())
1300 return;
1301
1302 setVisualUpdatesAllowed(true);
1303}
1304
1305void Document::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowedByClient)
1306{
1307 // We should only re-enable visual updates if ReadyState is Completed or the watchdog timer has fired,
1308 // both of which we can determine by looking at the timer.
1309
1310 if (visualUpdatesAllowedByClient && !m_visualUpdatesSuppressionTimer.isActive() && !visualUpdatesAllowed())
1311 setVisualUpdatesAllowed(true);
1312}
1313
1314String Document::characterSetWithUTF8Fallback() const
1315{
1316 AtomicString name = encoding();
1317 if (!name.isNull())
1318 return name;
1319 return UTF8Encoding().domName();
1320}
1321
1322String Document::defaultCharsetForLegacyBindings() const
1323{
1324 if (!frame())
1325 UTF8Encoding().domName();
1326 return settings().defaultTextEncodingName();
1327}
1328
1329void Document::setCharset(const String& charset)
1330{
1331 if (!decoder())
1332 return;
1333 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
1334}
1335
1336void Document::setContentLanguage(const String& language)
1337{
1338 if (m_contentLanguage == language)
1339 return;
1340 m_contentLanguage = language;
1341
1342 // Recalculate style so language is used when selecting the initial font.
1343 m_styleScope->didChangeStyleSheetEnvironment();
1344}
1345
1346ExceptionOr<void> Document::setXMLVersion(const String& version)
1347{
1348 if (!XMLDocumentParser::supportsXMLVersion(version))
1349 return Exception { NotSupportedError };
1350
1351 m_xmlVersion = version;
1352 return { };
1353}
1354
1355void Document::setXMLStandalone(bool standalone)
1356{
1357 m_xmlStandalone = standalone ? StandaloneStatus::Standalone : StandaloneStatus::NotStandalone;
1358}
1359
1360void Document::setDocumentURI(const String& uri)
1361{
1362 // This property is read-only from JavaScript, but writable from Objective-C.
1363 m_documentURI = uri;
1364 updateBaseURL();
1365}
1366
1367void Document::setContent(const String& content)
1368{
1369 open();
1370 // FIXME: This should probably use insert(), but that's (intentionally)
1371 // not implemented for the XML parser as it's normally synonymous with
1372 // document.write(). append() will end up yielding, but close() will
1373 // pump the tokenizer syncrhonously and finish the parse.
1374 m_parser->append(content.impl());
1375 close();
1376}
1377
1378String Document::suggestedMIMEType() const
1379{
1380 if (isXHTMLDocument())
1381 return "application/xhtml+xml"_s;
1382 if (isSVGDocument())
1383 return "image/svg+xml"_s;
1384 if (xmlStandalone())
1385 return "text/xml"_s;
1386 if (isHTMLDocument())
1387 return "text/html"_s;
1388 if (DocumentLoader* loader = this->loader())
1389 return loader->responseMIMEType();
1390 return String();
1391}
1392
1393void Document::overrideMIMEType(const String& mimeType)
1394{
1395 m_overriddenMIMEType = mimeType;
1396}
1397
1398String Document::contentType() const
1399{
1400 if (!m_overriddenMIMEType.isNull())
1401 return m_overriddenMIMEType;
1402
1403 if (DocumentLoader* documentLoader = loader())
1404 return documentLoader->currentContentType();
1405
1406 String mimeType = suggestedMIMEType();
1407 if (!mimeType.isNull())
1408 return mimeType;
1409
1410 return "application/xml"_s;
1411}
1412
1413RefPtr<Range> Document::caretRangeFromPoint(int x, int y)
1414{
1415 return caretRangeFromPoint(LayoutPoint(x, y));
1416}
1417
1418RefPtr<Range> Document::caretRangeFromPoint(const LayoutPoint& clientPoint)
1419{
1420 if (!hasLivingRenderTree())
1421 return nullptr;
1422
1423 LayoutPoint localPoint;
1424 Node* node = nodeFromPoint(clientPoint, &localPoint);
1425 if (!node)
1426 return nullptr;
1427
1428 RenderObject* renderer = node->renderer();
1429 if (!renderer)
1430 return nullptr;
1431 Position rangeCompliantPosition = renderer->positionForPoint(localPoint).parentAnchoredEquivalent();
1432 if (rangeCompliantPosition.isNull())
1433 return nullptr;
1434
1435 unsigned offset = rangeCompliantPosition.offsetInContainerNode();
1436 node = &retargetToScope(*rangeCompliantPosition.containerNode());
1437 if (node != rangeCompliantPosition.containerNode())
1438 offset = 0;
1439
1440 return Range::create(*this, node, offset, node, offset);
1441}
1442
1443bool Document::isBodyPotentiallyScrollable(HTMLBodyElement& body)
1444{
1445 // See https://www.w3.org/TR/cssom-view-1/#potentially-scrollable.
1446 // An element is potentially scrollable if all of the following conditions are true:
1447 // - The element has an associated CSS layout box.
1448 // - The element is not the HTML body element, or it is and the root element's used value of the
1449 // overflow-x or overflow-y properties is not visible.
1450 // - The element's used value of the overflow-x or overflow-y properties is not visible.
1451 //
1452 // FIXME: We should use RenderObject::hasOverflowClip() instead of Element::computedStyle() but
1453 // the used values are currently not correctly updated. See https://webkit.org/b/182292.
1454 return body.renderer()
1455 && documentElement()->computedStyle()
1456 && !documentElement()->computedStyle()->isOverflowVisible()
1457 && body.computedStyle()
1458 && !body.computedStyle()->isOverflowVisible();
1459}
1460
1461Element* Document::scrollingElementForAPI()
1462{
1463 if (inQuirksMode() && settings().CSSOMViewScrollingAPIEnabled())
1464 updateLayoutIgnorePendingStylesheets();
1465 return scrollingElement();
1466}
1467
1468Element* Document::scrollingElement()
1469{
1470 if (settings().CSSOMViewScrollingAPIEnabled()) {
1471 // See https://drafts.csswg.org/cssom-view/#dom-document-scrollingelement.
1472 // The scrollingElement attribute, on getting, must run these steps:
1473 // 1. If the Document is in quirks mode, follow these substeps:
1474 if (inQuirksMode()) {
1475 auto* firstBody = body();
1476 // 1. If the HTML body element exists, and it is not potentially scrollable, return the
1477 // HTML body element and abort these steps.
1478 if (firstBody && !isBodyPotentiallyScrollable(*firstBody))
1479 return firstBody;
1480
1481 // 2. Return null and abort these steps.
1482 return nullptr;
1483 }
1484
1485 // 2. If there is a root element, return the root element and abort these steps.
1486 // 3. Return null.
1487 return documentElement();
1488 }
1489
1490 return body();
1491}
1492
1493static String canonicalizedTitle(Document& document, const String& title)
1494{
1495 // Collapse runs of HTML spaces into single space characters.
1496 // Strip leading and trailing spaces.
1497 // Replace backslashes with currency symbols.
1498
1499 StringBuilder builder;
1500
1501 auto* decoder = document.decoder();
1502 auto backslashAsCurrencySymbol = decoder ? decoder->encoding().backslashAsCurrencySymbol() : '\\';
1503
1504 bool previousCharacterWasHTMLSpace = false;
1505 for (auto character : StringView { title }.codeUnits()) {
1506 if (isHTMLSpace(character))
1507 previousCharacterWasHTMLSpace = true;
1508 else {
1509 if (character == '\\')
1510 character = backslashAsCurrencySymbol;
1511 if (previousCharacterWasHTMLSpace && !builder.isEmpty())
1512 builder.append(' ');
1513 builder.append(character);
1514 previousCharacterWasHTMLSpace = false;
1515 }
1516 }
1517
1518 return builder == title ? title : builder.toString();
1519}
1520
1521void Document::updateTitle(const StringWithDirection& title)
1522{
1523 if (m_rawTitle == title)
1524 return;
1525
1526 m_rawTitle = title;
1527
1528 m_title.string = canonicalizedTitle(*this, title.string);
1529 m_title.direction = title.direction;
1530
1531 if (auto* loader = this->loader())
1532 loader->setTitle(m_title);
1533}
1534
1535void Document::updateTitleFromTitleElement()
1536{
1537 if (!m_titleElement) {
1538 updateTitle({ });
1539 return;
1540 }
1541
1542 if (is<HTMLTitleElement>(*m_titleElement))
1543 updateTitle(downcast<HTMLTitleElement>(*m_titleElement).textWithDirection());
1544 else if (is<SVGTitleElement>(*m_titleElement)) {
1545 // FIXME: Does the SVG title element have a text direction?
1546 updateTitle({ downcast<SVGTitleElement>(*m_titleElement).textContent(), TextDirection::LTR });
1547 }
1548}
1549
1550void Document::setTitle(const String& title)
1551{
1552 auto* element = documentElement();
1553 if (is<SVGSVGElement>(element)) {
1554 if (!m_titleElement) {
1555 m_titleElement = SVGTitleElement::create(SVGNames::titleTag, *this);
1556 element->insertBefore(*m_titleElement, element->firstChild());
1557 }
1558 m_titleElement->setTextContent(title);
1559 } else if (is<HTMLElement>(element)) {
1560 if (!m_titleElement) {
1561 auto* headElement = head();
1562 if (!headElement)
1563 return;
1564 m_titleElement = HTMLTitleElement::create(HTMLNames::titleTag, *this);
1565 headElement->appendChild(*m_titleElement);
1566 }
1567 m_titleElement->setTextContent(title);
1568 }
1569}
1570
1571template<typename> struct TitleTraits;
1572
1573template<> struct TitleTraits<HTMLTitleElement> {
1574 static bool isInEligibleLocation(HTMLTitleElement& element) { return element.isConnected() && !element.isInShadowTree(); }
1575 static HTMLTitleElement* findTitleElement(Document& document) { return descendantsOfType<HTMLTitleElement>(document).first(); }
1576};
1577
1578template<> struct TitleTraits<SVGTitleElement> {
1579 static bool isInEligibleLocation(SVGTitleElement& element) { return element.parentNode() == element.document().documentElement(); }
1580 static SVGTitleElement* findTitleElement(Document& document) { return childrenOfType<SVGTitleElement>(*document.documentElement()).first(); }
1581};
1582
1583template<typename TitleElement> Element* selectNewTitleElement(Document& document, Element* oldTitleElement, Element& changingTitleElement)
1584{
1585 using Traits = TitleTraits<TitleElement>;
1586
1587 if (!is<TitleElement>(changingTitleElement)) {
1588 ASSERT(oldTitleElement == Traits::findTitleElement(document));
1589 return oldTitleElement;
1590 }
1591
1592 if (oldTitleElement)
1593 return Traits::findTitleElement(document);
1594
1595 // Optimized common case: We have no title element yet.
1596 // We can figure out which title element should be used without searching.
1597 bool isEligible = Traits::isInEligibleLocation(downcast<TitleElement>(changingTitleElement));
1598 auto* newTitleElement = isEligible ? &changingTitleElement : nullptr;
1599 ASSERT(newTitleElement == Traits::findTitleElement(document));
1600 return newTitleElement;
1601}
1602
1603void Document::updateTitleElement(Element& changingTitleElement)
1604{
1605 // Most documents use HTML title rules.
1606 // Documents with SVG document elements use SVG title rules.
1607 auto selectTitleElement = is<SVGSVGElement>(documentElement())
1608 ? selectNewTitleElement<SVGTitleElement> : selectNewTitleElement<HTMLTitleElement>;
1609 auto newTitleElement = selectTitleElement(*this, m_titleElement.get(), changingTitleElement);
1610 if (m_titleElement == newTitleElement)
1611 return;
1612 m_titleElement = newTitleElement;
1613 updateTitleFromTitleElement();
1614}
1615
1616void Document::titleElementAdded(Element& titleElement)
1617{
1618 if (m_titleElement == &titleElement)
1619 return;
1620
1621 updateTitleElement(titleElement);
1622}
1623
1624void Document::titleElementRemoved(Element& titleElement)
1625{
1626 if (m_titleElement != &titleElement)
1627 return;
1628
1629 updateTitleElement(titleElement);
1630}
1631
1632void Document::titleElementTextChanged(Element& titleElement)
1633{
1634 if (m_titleElement != &titleElement)
1635 return;
1636
1637 updateTitleFromTitleElement();
1638}
1639
1640void Document::registerForVisibilityStateChangedCallbacks(VisibilityChangeClient& client)
1641{
1642 m_visibilityStateCallbackClients.add(&client);
1643}
1644
1645void Document::unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClient& client)
1646{
1647 m_visibilityStateCallbackClients.remove(&client);
1648}
1649
1650void Document::visibilityStateChanged()
1651{
1652 enqueueDocumentEvent(Event::create(eventNames().visibilitychangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
1653 for (auto* client : m_visibilityStateCallbackClients)
1654 client->visibilityStateChanged();
1655
1656 notifyMediaCaptureOfVisibilityChanged();
1657}
1658
1659VisibilityState Document::visibilityState() const
1660{
1661 // The visibility of the document is inherited from the visibility of the
1662 // page. If there is no page associated with the document, we will assume
1663 // that the page is hidden, as specified by the spec:
1664 // http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#dom-document-hidden
1665 if (!m_frame || !m_frame->page())
1666 return VisibilityState::Hidden;
1667 return m_frame->page()->visibilityState();
1668}
1669
1670bool Document::hidden() const
1671{
1672 return visibilityState() != VisibilityState::Visible;
1673}
1674
1675#if ENABLE(VIDEO)
1676
1677void Document::registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement& element)
1678{
1679 m_allowsMediaDocumentInlinePlaybackElements.add(&element);
1680}
1681
1682void Document::unregisterForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement& element)
1683{
1684 m_allowsMediaDocumentInlinePlaybackElements.remove(&element);
1685}
1686
1687void Document::allowsMediaDocumentInlinePlaybackChanged()
1688{
1689 for (auto* element : m_allowsMediaDocumentInlinePlaybackElements)
1690 element->allowsMediaDocumentInlinePlaybackChanged();
1691}
1692
1693void Document::stopAllMediaPlayback()
1694{
1695 if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
1696 platformMediaSessionManager->stopAllMediaPlaybackForDocument(this);
1697}
1698
1699void Document::suspendAllMediaPlayback()
1700{
1701 if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
1702 platformMediaSessionManager->suspendAllMediaPlaybackForDocument(*this);
1703}
1704
1705void Document::resumeAllMediaPlayback()
1706{
1707 if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
1708 platformMediaSessionManager->resumeAllMediaPlaybackForDocument(*this);
1709}
1710
1711void Document::suspendAllMediaBuffering()
1712{
1713 if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
1714 platformMediaSessionManager->suspendAllMediaBufferingForDocument(*this);
1715}
1716
1717void Document::resumeAllMediaBuffering()
1718{
1719 if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
1720 platformMediaSessionManager->resumeAllMediaBufferingForDocument(*this);
1721}
1722#endif
1723
1724String Document::nodeName() const
1725{
1726 return "#document"_s;
1727}
1728
1729Node::NodeType Document::nodeType() const
1730{
1731 return DOCUMENT_NODE;
1732}
1733
1734FormController& Document::formController()
1735{
1736 if (!m_formController)
1737 m_formController = std::make_unique<FormController>();
1738 return *m_formController;
1739}
1740
1741Vector<String> Document::formElementsState() const
1742{
1743 if (!m_formController)
1744 return Vector<String>();
1745 return m_formController->formElementsState();
1746}
1747
1748void Document::setStateForNewFormElements(const Vector<String>& stateVector)
1749{
1750 if (!stateVector.size() && !m_formController)
1751 return;
1752 formController().setStateForNewFormElements(stateVector);
1753}
1754
1755FrameView* Document::view() const
1756{
1757 return m_frame ? m_frame->view() : nullptr;
1758}
1759
1760Page* Document::page() const
1761{
1762 return m_frame ? m_frame->page() : nullptr;
1763}
1764
1765Ref<Range> Document::createRange()
1766{
1767 return Range::create(*this);
1768}
1769
1770Ref<NodeIterator> Document::createNodeIterator(Node& root, unsigned long whatToShow, RefPtr<NodeFilter>&& filter, bool)
1771{
1772 return NodeIterator::create(root, whatToShow, WTFMove(filter));
1773}
1774
1775Ref<TreeWalker> Document::createTreeWalker(Node& root, unsigned long whatToShow, RefPtr<NodeFilter>&& filter, bool)
1776{
1777 return TreeWalker::create(root, whatToShow, WTFMove(filter));
1778}
1779
1780void Document::scheduleFullStyleRebuild()
1781{
1782 m_needsFullStyleRebuild = true;
1783 scheduleStyleRecalc();
1784}
1785
1786void Document::scheduleStyleRecalc()
1787{
1788 ASSERT(!m_renderView || !m_renderView->inHitTesting());
1789
1790 if (m_styleRecalcTimer.isActive() || pageCacheState() != NotInPageCache)
1791 return;
1792
1793 ASSERT(childNeedsStyleRecalc() || m_needsFullStyleRebuild);
1794 auto shouldThrottleStyleRecalc = [&] {
1795 if (!view() || !view()->isVisuallyNonEmpty())
1796 return false;
1797 if (!page() || !page()->chrome().client().layerFlushThrottlingIsActive())
1798 return false;
1799 return true;
1800 };
1801
1802 if (shouldThrottleStyleRecalc())
1803 return;
1804
1805 m_styleRecalcTimer.startOneShot(0_s);
1806
1807 InspectorInstrumentation::didScheduleStyleRecalculation(*this);
1808}
1809
1810void Document::unscheduleStyleRecalc()
1811{
1812 ASSERT(!childNeedsStyleRecalc());
1813
1814 m_styleRecalcTimer.stop();
1815 m_needsFullStyleRebuild = false;
1816}
1817
1818bool Document::hasPendingStyleRecalc() const
1819{
1820 return needsStyleRecalc() && !m_inStyleRecalc;
1821}
1822
1823bool Document::hasPendingFullStyleRebuild() const
1824{
1825 return hasPendingStyleRecalc() && m_needsFullStyleRebuild;
1826}
1827
1828void Document::resolveStyle(ResolveStyleType type)
1829{
1830 ASSERT(!view() || !view()->isPainting());
1831
1832 // NOTE: XSL code seems to be the only client stumbling in here without a RenderView.
1833 if (!m_renderView)
1834 return;
1835
1836 FrameView& frameView = m_renderView->frameView();
1837 Ref<FrameView> protect(frameView);
1838 if (frameView.isPainting())
1839 return;
1840
1841 if (m_inStyleRecalc)
1842 return; // Guard against re-entrancy. -dwh
1843
1844 TraceScope tracingScope(StyleRecalcStart, StyleRecalcEnd);
1845
1846 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
1847 AnimationUpdateBlock animationUpdateBlock(&m_frame->animation());
1848
1849 // FIXME: Do this update per tree scope.
1850 {
1851 auto elements = copyToVectorOf<RefPtr<SVGUseElement>>(m_svgUseElements);
1852 // We can't clear m_svgUseElements here because updateShadowTree may end up executing arbitrary scripts
1853 // which may insert new SVG use elements or remove existing ones inside sync IPC via ImageLoader::updateFromElement.
1854 for (auto& element : elements)
1855 element->updateShadowTree();
1856 }
1857
1858 // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless),
1859 // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach
1860 // before setting the DOMWindow on the Frame, or the SecurityOrigin on the document. The attach, in turn
1861 // resolves style (here) and then when we resolve style on the parent chain, we may end up
1862 // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed
1863 // hits a null-dereference due to security code always assuming the document has a SecurityOrigin.
1864
1865 {
1866 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
1867 styleScope().flushPendingUpdate();
1868 frameView.willRecalcStyle();
1869 }
1870
1871 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(*this);
1872
1873 bool updatedCompositingLayers = false;
1874 {
1875 Style::PostResolutionCallbackDisabler disabler(*this);
1876 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1877 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
1878
1879 m_inStyleRecalc = true;
1880
1881 if (m_needsFullStyleRebuild)
1882 type = ResolveStyleType::Rebuild;
1883
1884 if (type == ResolveStyleType::Rebuild) {
1885 // This may get set again during style resolve.
1886 m_hasNodesWithNonFinalStyle = false;
1887 m_hasNodesWithMissingStyle = false;
1888
1889 auto documentStyle = Style::resolveForDocument(*this);
1890
1891 // Inserting the pictograph font at the end of the font fallback list is done by the
1892 // font selector, so set a font selector if needed.
1893 if (settings().fontFallbackPrefersPictographs())
1894 documentStyle.fontCascade().update(&fontSelector());
1895
1896 auto documentChange = Style::determineChange(documentStyle, m_renderView->style());
1897 if (documentChange != Style::NoChange)
1898 renderView()->setStyle(WTFMove(documentStyle));
1899
1900 if (auto* documentElement = this->documentElement())
1901 documentElement->invalidateStyleForSubtree();
1902 }
1903
1904 Style::TreeResolver resolver(*this);
1905 auto styleUpdate = resolver.resolve();
1906
1907 m_lastStyleUpdateSizeForTesting = styleUpdate ? styleUpdate->size() : 0;
1908
1909 setHasValidStyle();
1910 clearChildNeedsStyleRecalc();
1911 unscheduleStyleRecalc();
1912
1913 m_inStyleRecalc = false;
1914
1915 if (styleUpdate) {
1916 SetForScope<bool> inRenderTreeUpdate(m_inRenderTreeUpdate, true);
1917
1918 RenderTreeUpdater updater(*this);
1919 updater.commit(WTFMove(styleUpdate));
1920
1921 frameView.styleDidChange();
1922 }
1923
1924 updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange();
1925
1926 if (m_renderView->needsLayout())
1927 frameView.layoutContext().scheduleLayout();
1928
1929 // Usually this is handled by post-layout.
1930 if (!frameView.needsLayout())
1931 frameView.frame().selection().scheduleAppearanceUpdateAfterStyleChange();
1932
1933 // As a result of the style recalculation, the currently hovered element might have been
1934 // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event
1935 // to check if any other elements ended up under the mouse pointer due to re-layout.
1936 if (m_hoveredElement && !m_hoveredElement->renderer())
1937 frameView.frame().mainFrame().eventHandler().dispatchFakeMouseMoveEventSoon();
1938
1939 ++m_styleRecalcCount;
1940 // FIXME: Assert ASSERT(!needsStyleRecalc()) here. Do we still have some cases where it's not true?
1941 }
1942
1943 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
1944 if (m_closeAfterStyleRecalc) {
1945 m_closeAfterStyleRecalc = false;
1946 implicitClose();
1947 }
1948
1949 InspectorInstrumentation::didRecalculateStyle(cookie);
1950
1951 // Some animated images may now be inside the viewport due to style recalc,
1952 // resume them if necessary if there is no layout pending. Otherwise, we'll
1953 // check if they need to be resumed after layout.
1954 if (updatedCompositingLayers && !frameView.needsLayout())
1955 frameView.viewportContentsChanged();
1956
1957 if (m_gotoAnchorNeededAfterStylesheetsLoad && !styleScope().hasPendingSheets())
1958 frameView.scrollToFragment(m_url);
1959}
1960
1961void Document::updateTextRenderer(Text& text, unsigned offsetOfReplacedText, unsigned lengthOfReplacedText)
1962{
1963 ASSERT(!m_inRenderTreeUpdate);
1964 SetForScope<bool> inRenderTreeUpdate(m_inRenderTreeUpdate, true);
1965
1966 auto textUpdate = std::make_unique<Style::Update>(*this);
1967 textUpdate->addText(text, { offsetOfReplacedText, lengthOfReplacedText, WTF::nullopt });
1968
1969 RenderTreeUpdater renderTreeUpdater(*this);
1970 renderTreeUpdater.commit(WTFMove(textUpdate));
1971}
1972
1973bool Document::needsStyleRecalc() const
1974{
1975 if (pageCacheState() != NotInPageCache)
1976 return false;
1977
1978 if (m_needsFullStyleRebuild)
1979 return true;
1980
1981 if (childNeedsStyleRecalc())
1982 return true;
1983
1984 if (styleScope().hasPendingUpdate())
1985 return true;
1986
1987 // Ensure this happens eventually as it is currently in resolveStyle. This can be removed if the code moves.
1988 if (m_gotoAnchorNeededAfterStylesheetsLoad && !styleScope().hasPendingSheets())
1989 return true;
1990
1991 return false;
1992}
1993
1994static bool isSafeToUpdateStyleOrLayout(const Document& document)
1995{
1996 bool isSafeToExecuteScript = ScriptDisallowedScope::InMainThread::isScriptAllowed();
1997 auto* frameView = document.view();
1998 bool isInFrameFlattening = frameView && frameView->isInChildFrameWithFrameFlattening();
1999 return isSafeToExecuteScript || isInFrameFlattening || !isInWebProcess();
2000}
2001
2002bool Document::updateStyleIfNeeded()
2003{
2004 RefPtr<FrameView> frameView = view();
2005 {
2006 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
2007 ASSERT(isMainThread());
2008 ASSERT(!frameView || !frameView->isPainting());
2009
2010 if (!frameView || frameView->layoutContext().isInRenderTreeLayout())
2011 return false;
2012
2013 styleScope().flushPendingUpdate();
2014
2015 if (!needsStyleRecalc())
2016 return false;
2017 }
2018
2019#if PLATFORM(IOS_FAMILY)
2020 ContentChangeObserver::StyleRecalcScope observingScope(*this);
2021#endif
2022 // The early exit above for !needsStyleRecalc() is needed when updateWidgetPositions() is called in runOrScheduleAsynchronousTasks().
2023 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(isSafeToUpdateStyleOrLayout(*this));
2024 resolveStyle();
2025 return true;
2026}
2027
2028void Document::updateLayout()
2029{
2030 ASSERT(isMainThread());
2031
2032 RefPtr<FrameView> frameView = view();
2033 if (frameView && frameView->layoutContext().isInRenderTreeLayout()) {
2034 // View layout should not be re-entrant.
2035 ASSERT_NOT_REACHED();
2036 return;
2037 }
2038 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(isSafeToUpdateStyleOrLayout(*this));
2039
2040 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
2041
2042 if (HTMLFrameOwnerElement* owner = ownerElement())
2043 owner->document().updateLayout();
2044
2045 updateStyleIfNeeded();
2046
2047 StackStats::LayoutCheckPoint layoutCheckPoint;
2048
2049 // Only do a layout if changes have occurred that make it necessary.
2050 if (frameView && renderView() && (frameView->layoutContext().isLayoutPending() || renderView()->needsLayout()))
2051 frameView->layoutContext().layout();
2052}
2053
2054void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks)
2055{
2056 bool oldIgnore = m_ignorePendingStylesheets;
2057
2058 if (!haveStylesheetsLoaded()) {
2059 m_ignorePendingStylesheets = true;
2060 // FIXME: This should just invalidate elements with missing styles.
2061 if (m_hasNodesWithMissingStyle)
2062 scheduleFullStyleRebuild();
2063 }
2064
2065 updateLayout();
2066
2067 if (runPostLayoutTasks == RunPostLayoutTasks::Synchronously && view())
2068 view()->flushAnyPendingPostLayoutTasks();
2069
2070 m_ignorePendingStylesheets = oldIgnore;
2071}
2072
2073std::unique_ptr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element& element, const RenderStyle* parentStyle, PseudoId pseudoElementSpecifier)
2074{
2075 ASSERT(&element.document() == this);
2076 ASSERT(!element.isPseudoElement() || pseudoElementSpecifier == PseudoId::None);
2077 ASSERT(pseudoElementSpecifier == PseudoId::None || parentStyle);
2078
2079 // On iOS request delegates called during styleForElement may result in re-entering WebKit and killing the style resolver.
2080 Style::PostResolutionCallbackDisabler disabler(*this, Style::PostResolutionCallbackDisabler::DrainCallbacks::No);
2081
2082 SetForScope<bool> change(m_ignorePendingStylesheets, true);
2083 auto& resolver = element.styleResolver();
2084
2085 if (pseudoElementSpecifier != PseudoId::None)
2086 return resolver.pseudoStyleForElement(element, PseudoStyleRequest(pseudoElementSpecifier), *parentStyle);
2087
2088 auto elementStyle = resolver.styleForElement(element, parentStyle);
2089 if (elementStyle.relations) {
2090 Style::Update emptyUpdate(*this);
2091 Style::commitRelations(WTFMove(elementStyle.relations), emptyUpdate);
2092 }
2093
2094 return WTFMove(elementStyle.renderStyle);
2095}
2096
2097bool Document::updateLayoutIfDimensionsOutOfDate(Element& element, DimensionsCheck dimensionsCheck)
2098{
2099 ASSERT(isMainThread());
2100
2101 // If the stylesheets haven't loaded, just give up and do a full layout ignoring pending stylesheets.
2102 if (!haveStylesheetsLoaded()) {
2103 updateLayoutIgnorePendingStylesheets();
2104 return true;
2105 }
2106
2107 // Check for re-entrancy and assert (same code that is in updateLayout()).
2108 RefPtr<FrameView> frameView = view();
2109 if (frameView && frameView->layoutContext().isInRenderTreeLayout()) {
2110 // View layout should not be re-entrant.
2111 ASSERT_NOT_REACHED();
2112 return true;
2113 }
2114
2115 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
2116
2117 // Mimic the structure of updateLayout(), but at each step, see if we have been forced into doing a full
2118 // layout.
2119 bool requireFullLayout = false;
2120 if (HTMLFrameOwnerElement* owner = ownerElement()) {
2121 if (owner->document().updateLayoutIfDimensionsOutOfDate(*owner))
2122 requireFullLayout = true;
2123 }
2124
2125 updateStyleIfNeeded();
2126
2127 RenderObject* renderer = element.renderer();
2128 if (!renderer || renderer->needsLayout()) {
2129 // If we don't have a renderer or if the renderer needs layout for any reason, give up.
2130 requireFullLayout = true;
2131 }
2132
2133 // Turn off this optimization for input elements with shadow content.
2134 if (is<HTMLInputElement>(element))
2135 requireFullLayout = true;
2136
2137 bool isVertical = renderer && !renderer->isHorizontalWritingMode();
2138 bool checkingLogicalWidth = ((dimensionsCheck & WidthDimensionsCheck) && !isVertical) || ((dimensionsCheck & HeightDimensionsCheck) && isVertical);
2139 bool checkingLogicalHeight = ((dimensionsCheck & HeightDimensionsCheck) && !isVertical) || ((dimensionsCheck & WidthDimensionsCheck) && isVertical);
2140 bool hasSpecifiedLogicalHeight = renderer && renderer->style().logicalMinHeight() == Length(0, Fixed) && renderer->style().logicalHeight().isFixed() && renderer->style().logicalMaxHeight().isAuto();
2141
2142 if (!requireFullLayout) {
2143 RenderBox* previousBox = nullptr;
2144 RenderBox* currentBox = nullptr;
2145
2146 // Check our containing block chain. If anything in the chain needs a layout, then require a full layout.
2147 for (RenderObject* currRenderer = element.renderer(); currRenderer && !currRenderer->isRenderView(); currRenderer = currRenderer->container()) {
2148
2149 // Require the entire container chain to be boxes.
2150 if (!is<RenderBox>(currRenderer)) {
2151 requireFullLayout = true;
2152 break;
2153 }
2154
2155 previousBox = currentBox;
2156 currentBox = downcast<RenderBox>(currRenderer);
2157
2158 // If a box needs layout for itself or if a box has changed children and sizes its width to
2159 // its content, then require a full layout.
2160 if (currentBox->selfNeedsLayout() ||
2161 (checkingLogicalWidth && currRenderer->needsLayout() && currentBox->sizesLogicalWidthToFitContent(MainOrPreferredSize))) {
2162 requireFullLayout = true;
2163 break;
2164 }
2165
2166 // If a block contains floats and the child's height isn't specified, then
2167 // give up also, since our height could end up being influenced by the floats.
2168 if (checkingLogicalHeight && !hasSpecifiedLogicalHeight && currentBox->isRenderBlockFlow()) {
2169 RenderBlockFlow* currentBlockFlow = downcast<RenderBlockFlow>(currentBox);
2170 if (currentBlockFlow->containsFloats() && previousBox && !previousBox->isFloatingOrOutOfFlowPositioned()) {
2171 requireFullLayout = true;
2172 break;
2173 }
2174 }
2175
2176 if (!currentBox->isRenderBlockFlow() || currentBox->enclosingFragmentedFlow() || currentBox->isWritingModeRoot()) {
2177 // FIXME: For now require only block flows all the way back to the root. This limits the optimization
2178 // for now, and we'll expand it in future patches to apply to more and more scenarios.
2179 // Disallow columns from having the optimization.
2180 // Give up if the writing mode changes at all in the containing block chain.
2181 requireFullLayout = true;
2182 break;
2183 }
2184
2185 if (currRenderer == frameView->layoutContext().subtreeLayoutRoot())
2186 break;
2187 }
2188 }
2189
2190 StackStats::LayoutCheckPoint layoutCheckPoint;
2191
2192 // Only do a layout if changes have occurred that make it necessary.
2193 if (requireFullLayout && frameView && renderView() && (frameView->layoutContext().isLayoutPending() || renderView()->needsLayout()))
2194 frameView->layoutContext().layout();
2195
2196 return requireFullLayout;
2197}
2198
2199bool Document::isPageBoxVisible(int pageIndex)
2200{
2201 updateStyleIfNeeded();
2202 std::unique_ptr<RenderStyle> pageStyle(styleScope().resolver().styleForPage(pageIndex));
2203 return pageStyle->visibility() != Visibility::Hidden; // display property doesn't apply to @page.
2204}
2205
2206void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
2207{
2208 updateStyleIfNeeded();
2209 auto style = styleScope().resolver().styleForPage(pageIndex);
2210
2211 int width = pageSize.width();
2212 int height = pageSize.height();
2213 switch (style->pageSizeType()) {
2214 case PAGE_SIZE_AUTO:
2215 break;
2216 case PAGE_SIZE_AUTO_LANDSCAPE:
2217 if (width < height)
2218 std::swap(width, height);
2219 break;
2220 case PAGE_SIZE_AUTO_PORTRAIT:
2221 if (width > height)
2222 std::swap(width, height);
2223 break;
2224 case PAGE_SIZE_RESOLVED: {
2225 auto& size = style->pageSize();
2226 ASSERT(size.width.isFixed());
2227 ASSERT(size.height.isFixed());
2228 width = valueForLength(size.width, 0);
2229 height = valueForLength(size.height, 0);
2230 break;
2231 }
2232 default:
2233 ASSERT_NOT_REACHED();
2234 }
2235 pageSize = IntSize(width, height);
2236
2237 // The percentage is calculated with respect to the width even for margin top and bottom.
2238 // http://www.w3.org/TR/CSS2/box.html#margin-properties
2239 marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width);
2240 marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width);
2241 marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width);
2242 marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width);
2243}
2244
2245StyleResolver& Document::userAgentShadowTreeStyleResolver()
2246{
2247 if (!m_userAgentShadowTreeStyleResolver)
2248 m_userAgentShadowTreeStyleResolver = std::make_unique<StyleResolver>(*this);
2249 return *m_userAgentShadowTreeStyleResolver;
2250}
2251
2252void Document::fontsNeedUpdate(FontSelector&)
2253{
2254 invalidateMatchedPropertiesCacheAndForceStyleRecalc();
2255}
2256
2257void Document::invalidateMatchedPropertiesCacheAndForceStyleRecalc()
2258{
2259 if (auto* resolver = styleScope().resolverIfExists())
2260 resolver->invalidateMatchedPropertiesCache();
2261 if (pageCacheState() != NotInPageCache || !renderView())
2262 return;
2263 scheduleFullStyleRebuild();
2264}
2265
2266void Document::didClearStyleResolver()
2267{
2268 m_userAgentShadowTreeStyleResolver = nullptr;
2269}
2270
2271void Document::setIsResolvingTreeStyle(bool value)
2272{
2273 RELEASE_ASSERT(value != m_isResolvingTreeStyle);
2274 m_isResolvingTreeStyle = value;
2275}
2276
2277void Document::createRenderTree()
2278{
2279 ASSERT(!renderView());
2280 ASSERT(m_pageCacheState != InPageCache);
2281 ASSERT(!m_axObjectCache || this != &topDocument());
2282
2283 if (m_isNonRenderedPlaceholder)
2284 return;
2285
2286 // FIXME: It would be better if we could pass the resolved document style directly here.
2287 m_renderView = createRenderer<RenderView>(*this, RenderStyle::create());
2288 Node::setRenderer(m_renderView.get());
2289
2290 renderView()->setIsInWindow(true);
2291
2292 resolveStyle(ResolveStyleType::Rebuild);
2293}
2294
2295void Document::didBecomeCurrentDocumentInFrame()
2296{
2297 // FIXME: Are there cases where the document can be dislodged from the frame during the event handling below?
2298 // If so, then m_frame could become 0, and we need to do something about that.
2299
2300 m_frame->script().updateDocument();
2301
2302 if (!hasLivingRenderTree())
2303 createRenderTree();
2304
2305 dispatchDisabledAdaptationsDidChangeForMainFrame();
2306 updateViewportArguments();
2307
2308 // FIXME: Doing this only for the main frame is insufficient.
2309 // Changing a subframe can also change the wheel event handler count.
2310 // FIXME: Doing this only when a document goes into the frame is insufficient.
2311 // Removing a document can also change the wheel event handler count.
2312 // FIXME: Doing this every time is a waste. If the current document and its
2313 // subframes' documents have no wheel event handlers, then the count did not change,
2314 // unless the documents they are replacing had wheel event handlers.
2315 if (page() && m_frame->isMainFrame())
2316 wheelEventHandlersChanged();
2317
2318 // Ensure that the scheduled task state of the document matches the DOM suspension state of the frame. It can
2319 // be out of sync if the DOM suspension state changed while the document was not in the frame (possibly in the
2320 // page cache, or simply newly created).
2321 if (m_frame->activeDOMObjectsAndAnimationsSuspended()) {
2322 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
2323 if (auto* timeline = existingTimeline())
2324 timeline->suspendAnimations();
2325 } else
2326 m_frame->animation().suspendAnimationsForDocument(this);
2327 suspendScheduledTasks(ReasonForSuspension::PageWillBeSuspended);
2328 } else {
2329 resumeScheduledTasks(ReasonForSuspension::PageWillBeSuspended);
2330 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
2331 if (auto* timeline = existingTimeline())
2332 timeline->resumeAnimations();
2333 } else
2334 m_frame->animation().resumeAnimationsForDocument(this);
2335 }
2336}
2337
2338void Document::frameDestroyed()
2339{
2340 // detachFromFrame() must be called before destroying the Frame.
2341 RELEASE_ASSERT(!m_frame);
2342
2343 if (auto* window = domWindow())
2344 window->frameDestroyed();
2345
2346 FrameDestructionObserver::frameDestroyed();
2347}
2348
2349void Document::willDetachPage()
2350{
2351 FrameDestructionObserver::willDetachPage();
2352#if PLATFORM(IOS_FAMILY)
2353 contentChangeObserver().willDetachPage();
2354#endif
2355 if (domWindow() && frame())
2356 InspectorInstrumentation::frameWindowDiscarded(*frame(), domWindow());
2357}
2358
2359void Document::attachToCachedFrame(CachedFrameBase& cachedFrame)
2360{
2361 RELEASE_ASSERT(cachedFrame.document() == this);
2362 ASSERT(cachedFrame.view());
2363 ASSERT(m_pageCacheState == Document::InPageCache);
2364 observeFrame(&cachedFrame.view()->frame());
2365}
2366
2367void Document::detachFromCachedFrame(CachedFrameBase& cachedFrame)
2368{
2369 ASSERT_UNUSED(cachedFrame, cachedFrame.view());
2370 RELEASE_ASSERT(cachedFrame.document() == this);
2371 ASSERT(m_frame == &cachedFrame.view()->frame());
2372 ASSERT(m_pageCacheState == Document::InPageCache);
2373 detachFromFrame();
2374}
2375
2376void Document::destroyRenderTree()
2377{
2378 ASSERT(hasLivingRenderTree());
2379 ASSERT(frame());
2380 ASSERT(frame()->document() == this);
2381 ASSERT(page());
2382
2383 // Prevent Widget tree changes from committing until the RenderView is dead and gone.
2384 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2385
2386 SetForScope<bool> change(m_renderTreeBeingDestroyed, true);
2387
2388 if (this == &topDocument())
2389 clearAXObjectCache();
2390
2391 documentWillBecomeInactive();
2392
2393 if (view())
2394 view()->willDestroyRenderTree();
2395
2396 if (m_documentElement)
2397 RenderTreeUpdater::tearDownRenderers(*m_documentElement);
2398
2399 clearChildNeedsStyleRecalc();
2400
2401 unscheduleStyleRecalc();
2402
2403 // FIXME: RenderObject::view() uses m_renderView and we can't null it before destruction is completed
2404 {
2405 RenderTreeBuilder builder(*m_renderView);
2406 // FIXME: This is a workaround for leftover content (see webkit.org/b/182547).
2407 while (m_renderView->firstChild())
2408 builder.destroy(*m_renderView->firstChild());
2409 m_renderView->destroy();
2410 }
2411 m_renderView.release();
2412
2413 Node::setRenderer(nullptr);
2414
2415#if ENABLE(TEXT_AUTOSIZING)
2416 m_textAutoSizing = nullptr;
2417#endif
2418
2419 if (view())
2420 view()->didDestroyRenderTree();
2421}
2422
2423void Document::prepareForDestruction()
2424{
2425 if (m_hasPreparedForDestruction)
2426 return;
2427
2428 if (m_frame)
2429 m_frame->animation().detachFromDocument(this);
2430
2431#if USE(LIBWEBRTC)
2432 // FIXME: This should be moved to Modules/mediastream.
2433 if (LibWebRTCProvider::webRTCAvailable()) {
2434 if (auto* page = this->page())
2435 page->libWebRTCProvider().unregisterMDNSNames(identifier().toUInt64());
2436 }
2437#endif
2438
2439#if ENABLE(SERVICE_WORKER)
2440 setActiveServiceWorker(nullptr);
2441 setServiceWorkerConnection(nullptr);
2442#endif
2443
2444#if ENABLE(IOS_TOUCH_EVENTS)
2445 clearTouchEventHandlersAndListeners();
2446#endif
2447
2448 m_undoManager->removeAllItems();
2449
2450#if HAVE(ACCESSIBILITY)
2451 if (this != &topDocument()) {
2452 // Let the ax cache know that this subframe goes out of scope.
2453 if (auto* cache = existingAXObjectCache())
2454 cache->prepareForDocumentDestruction(*this);
2455 }
2456#endif
2457
2458 {
2459 NavigationDisabler navigationDisabler(m_frame);
2460 disconnectDescendantFrames();
2461 }
2462
2463 if (m_domWindow && m_frame)
2464 m_domWindow->willDetachDocumentFromFrame();
2465
2466 styleScope().clearResolver();
2467
2468 if (hasLivingRenderTree())
2469 destroyRenderTree();
2470
2471 if (is<PluginDocument>(*this))
2472 downcast<PluginDocument>(*this).detachFromPluginElement();
2473
2474#if ENABLE(POINTER_LOCK)
2475 if (page())
2476 page()->pointerLockController().documentDetached(*this);
2477#endif
2478
2479 if (auto* page = this->page()) {
2480 if (auto* validationMessageClient = page->validationMessageClient())
2481 validationMessageClient->documentDetached(*this);
2482 }
2483
2484 InspectorInstrumentation::documentDetached(*this);
2485
2486 stopActiveDOMObjects();
2487 m_eventQueue.close();
2488#if ENABLE(FULLSCREEN_API)
2489 m_fullscreenManager->emptyEventQueue();
2490#endif
2491
2492 commonTeardown();
2493
2494#if ENABLE(TOUCH_EVENTS)
2495 if (m_touchEventTargets && m_touchEventTargets->size() && parentDocument())
2496 parentDocument()->didRemoveEventTargetNode(*this);
2497#endif
2498
2499 if (m_wheelEventTargets && m_wheelEventTargets->size() && parentDocument())
2500 parentDocument()->didRemoveEventTargetNode(*this);
2501
2502 if (m_mediaQueryMatcher)
2503 m_mediaQueryMatcher->documentDestroyed();
2504
2505#if ENABLE(WIRELESS_PLAYBACK_TARGET)
2506 if (!m_clientToIDMap.isEmpty() && page()) {
2507 for (auto* client : copyToVector(m_clientToIDMap.keys()))
2508 removePlaybackTargetPickerClient(*client);
2509 }
2510#endif
2511
2512 m_cachedResourceLoader->stopUnusedPreloadsTimer();
2513
2514 if (page() && m_mediaState != MediaProducer::IsNotPlaying) {
2515 m_mediaState = MediaProducer::IsNotPlaying;
2516 page()->updateIsPlayingMedia(HTMLMediaElementInvalidID);
2517 }
2518
2519 detachFromFrame();
2520
2521 if (m_timeline) {
2522 m_timeline->detachFromDocument();
2523 m_timeline = nullptr;
2524 }
2525
2526#if ENABLE(CSS_PAINTING_API)
2527 for (auto& scope : m_paintWorkletGlobalScopes.values())
2528 scope->prepareForDestruction();
2529 m_paintWorkletGlobalScopes.clear();
2530#endif
2531
2532 m_hasPreparedForDestruction = true;
2533
2534 // Note that m_pageCacheState can be Document::AboutToEnterPageCache if our frame
2535 // was removed in an onpagehide event handler fired when the top-level frame is
2536 // about to enter the page cache.
2537 RELEASE_ASSERT(m_pageCacheState != Document::InPageCache);
2538}
2539
2540void Document::removeAllEventListeners()
2541{
2542 EventTarget::removeAllEventListeners();
2543
2544 if (m_domWindow)
2545 m_domWindow->removeAllEventListeners();
2546
2547#if ENABLE(IOS_TOUCH_EVENTS)
2548 clearTouchEventHandlersAndListeners();
2549#endif
2550 for (Node* node = firstChild(); node; node = NodeTraversal::next(*node))
2551 node->removeAllEventListeners();
2552
2553#if ENABLE(TOUCH_EVENTS)
2554 m_touchEventTargets = nullptr;
2555#endif
2556 m_wheelEventTargets = nullptr;
2557}
2558
2559void Document::suspendDeviceMotionAndOrientationUpdates()
2560{
2561 if (m_areDeviceMotionAndOrientationUpdatesSuspended)
2562 return;
2563 m_areDeviceMotionAndOrientationUpdatesSuspended = true;
2564#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
2565 if (m_deviceMotionController)
2566 m_deviceMotionController->suspendUpdates();
2567 if (m_deviceOrientationController)
2568 m_deviceOrientationController->suspendUpdates();
2569#endif
2570}
2571
2572void Document::resumeDeviceMotionAndOrientationUpdates()
2573{
2574 if (!m_areDeviceMotionAndOrientationUpdatesSuspended)
2575 return;
2576 m_areDeviceMotionAndOrientationUpdatesSuspended = false;
2577#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
2578 if (m_deviceMotionController)
2579 m_deviceMotionController->resumeUpdates();
2580 if (m_deviceOrientationController)
2581 m_deviceOrientationController->resumeUpdates();
2582#endif
2583}
2584
2585bool Document::shouldBypassMainWorldContentSecurityPolicy() const
2586{
2587 // Bypass this policy when the world is known, and it not the normal world.
2588 auto& callFrame = *commonVM().topCallFrame;
2589 return &callFrame != JSC::CallFrame::noCaller() && !currentWorld(callFrame).isNormal();
2590}
2591
2592void Document::platformSuspendOrStopActiveDOMObjects()
2593{
2594#if PLATFORM(IOS_FAMILY)
2595 contentChangeObserver().didSuspendActiveDOMObjects();
2596#endif
2597}
2598
2599void Document::suspendActiveDOMObjects(ReasonForSuspension why)
2600{
2601 ScriptExecutionContext::suspendActiveDOMObjects(why);
2602 suspendDeviceMotionAndOrientationUpdates();
2603 platformSuspendOrStopActiveDOMObjects();
2604}
2605
2606void Document::resumeActiveDOMObjects(ReasonForSuspension why)
2607{
2608 ScriptExecutionContext::resumeActiveDOMObjects(why);
2609 resumeDeviceMotionAndOrientationUpdates();
2610 // FIXME: For iOS, do we need to add content change observers that were removed in Document::suspendActiveDOMObjects()?
2611}
2612
2613void Document::stopActiveDOMObjects()
2614{
2615 ScriptExecutionContext::stopActiveDOMObjects();
2616 platformSuspendOrStopActiveDOMObjects();
2617}
2618
2619void Document::clearAXObjectCache()
2620{
2621 ASSERT(&topDocument() == this);
2622 // Clear the cache member variable before calling delete because attempts
2623 // are made to access it during destruction.
2624 m_axObjectCache = nullptr;
2625}
2626
2627AXObjectCache* Document::existingAXObjectCacheSlow() const
2628{
2629 ASSERT(hasEverCreatedAnAXObjectCache);
2630 return topDocument().m_axObjectCache.get();
2631}
2632
2633AXObjectCache* Document::axObjectCache() const
2634{
2635 if (!AXObjectCache::accessibilityEnabled())
2636 return nullptr;
2637
2638 // The only document that actually has a AXObjectCache is the top-level
2639 // document. This is because we need to be able to get from any WebCoreAXObject
2640 // to any other WebCoreAXObject on the same page. Using a single cache allows
2641 // lookups across nested webareas (i.e. multiple documents).
2642 Document& topDocument = this->topDocument();
2643
2644 // If the document has already been detached, do not make a new axObjectCache.
2645 if (!topDocument.hasLivingRenderTree())
2646 return nullptr;
2647
2648 ASSERT(&topDocument == this || !m_axObjectCache);
2649 if (!topDocument.m_axObjectCache) {
2650 topDocument.m_axObjectCache = std::make_unique<AXObjectCache>(topDocument);
2651 hasEverCreatedAnAXObjectCache = true;
2652 }
2653 return topDocument.m_axObjectCache.get();
2654}
2655
2656void Document::setVisuallyOrdered()
2657{
2658 m_visuallyOrdered = true;
2659 if (renderView())
2660 renderView()->mutableStyle().setRTLOrdering(Order::Visual);
2661}
2662
2663Ref<DocumentParser> Document::createParser()
2664{
2665 // FIXME: this should probably pass the frame instead
2666 return XMLDocumentParser::create(*this, view());
2667}
2668
2669ScriptableDocumentParser* Document::scriptableDocumentParser() const
2670{
2671 return parser() ? parser()->asScriptableDocumentParser() : nullptr;
2672}
2673
2674ExceptionOr<RefPtr<WindowProxy>> Document::openForBindings(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& url, const AtomicString& name, const String& features)
2675{
2676 if (!m_domWindow)
2677 return Exception { InvalidAccessError };
2678
2679 return m_domWindow->open(activeWindow, firstWindow, url, name, features);
2680}
2681
2682ExceptionOr<Document&> Document::openForBindings(Document* responsibleDocument, const String&, const String&)
2683{
2684 if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
2685 return Exception { InvalidStateError };
2686
2687 auto result = open(responsibleDocument);
2688 if (UNLIKELY(result.hasException()))
2689 return result.releaseException();
2690
2691 return *this;
2692}
2693
2694ExceptionOr<void> Document::open(Document* responsibleDocument)
2695{
2696 if (responsibleDocument && !responsibleDocument->securityOrigin().isSameOriginAs(securityOrigin()))
2697 return Exception { SecurityError };
2698
2699 if (m_ignoreOpensDuringUnloadCount)
2700 return { };
2701
2702 if (m_frame) {
2703 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) {
2704 if (parser->isParsing()) {
2705 // FIXME: HTML5 doesn't tell us to check this, it might not be correct.
2706 if (parser->isExecutingScript())
2707 return { };
2708
2709 if (!parser->wasCreatedByScript() && parser->hasInsertionPoint())
2710 return { };
2711 }
2712 }
2713
2714 if (m_frame->loader().policyChecker().delegateIsDecidingNavigationPolicy())
2715 m_frame->loader().policyChecker().stopCheck();
2716 if (m_frame && m_frame->loader().state() == FrameStateProvisional)
2717 m_frame->loader().stopAllLoaders();
2718 }
2719
2720 removeAllEventListeners();
2721
2722 if (responsibleDocument && isFullyActive()) {
2723 auto newURL = responsibleDocument->url();
2724 if (responsibleDocument != this)
2725 newURL.removeFragmentIdentifier();
2726 setURL(newURL);
2727 auto newCookieURL = responsibleDocument->cookieURL();
2728 if (responsibleDocument != this)
2729 newCookieURL.removeFragmentIdentifier();
2730 setCookieURL(newCookieURL);
2731 setSecurityOriginPolicy(responsibleDocument->securityOriginPolicy());
2732 }
2733
2734 implicitOpen();
2735 if (ScriptableDocumentParser* parser = scriptableDocumentParser())
2736 parser->setWasCreatedByScript(true);
2737
2738 if (m_frame)
2739 m_frame->loader().didExplicitOpen();
2740
2741 return { };
2742}
2743
2744// https://html.spec.whatwg.org/#fully-active
2745bool Document::isFullyActive() const
2746{
2747 auto* frame = this->frame();
2748 if (!frame || frame->document() != this)
2749 return false;
2750
2751 if (frame->isMainFrame())
2752 return true;
2753
2754 auto* parentFrame = frame->tree().parent();
2755 return parentFrame && parentFrame->document() && parentFrame->document()->isFullyActive();
2756}
2757
2758void Document::detachParser()
2759{
2760 if (!m_parser)
2761 return;
2762 m_parser->detach();
2763 m_parser = nullptr;
2764}
2765
2766void Document::cancelParsing()
2767{
2768 if (!m_parser)
2769 return;
2770
2771 // We have to clear the parser to avoid possibly triggering
2772 // the onload handler when closing as a side effect of a cancel-style
2773 // change, such as opening a new document or closing the window while
2774 // still parsing
2775 detachParser();
2776 explicitClose();
2777}
2778
2779void Document::implicitOpen()
2780{
2781 removeChildren();
2782
2783 setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
2784
2785 cancelParsing();
2786 m_parser = createParser();
2787
2788 if (hasActiveParserYieldToken())
2789 m_parser->didBeginYieldingParser();
2790
2791 setParsing(true);
2792 setReadyState(Loading);
2793}
2794
2795HTMLBodyElement* Document::body() const
2796{
2797 auto* element = documentElement();
2798 if (!is<HTMLHtmlElement>(element))
2799 return nullptr;
2800 return childrenOfType<HTMLBodyElement>(*element).first();
2801}
2802
2803HTMLElement* Document::bodyOrFrameset() const
2804{
2805 // Return the first body or frameset child of the html element.
2806 auto* element = documentElement();
2807 if (!is<HTMLHtmlElement>(element))
2808 return nullptr;
2809 for (auto& child : childrenOfType<HTMLElement>(*element)) {
2810 if (is<HTMLBodyElement>(child) || is<HTMLFrameSetElement>(child))
2811 return &child;
2812 }
2813 return nullptr;
2814}
2815
2816ExceptionOr<void> Document::setBodyOrFrameset(RefPtr<HTMLElement>&& newBody)
2817{
2818 if (!is<HTMLBodyElement>(newBody) && !is<HTMLFrameSetElement>(newBody))
2819 return Exception { HierarchyRequestError };
2820
2821 auto* currentBody = bodyOrFrameset();
2822 if (newBody == currentBody)
2823 return { };
2824
2825 if (!m_documentElement)
2826 return Exception { HierarchyRequestError };
2827
2828 if (currentBody)
2829 return m_documentElement->replaceChild(*newBody, *currentBody);
2830 return m_documentElement->appendChild(*newBody);
2831}
2832
2833Location* Document::location() const
2834{
2835 auto* window = domWindow();
2836 return window ? &window->location() : nullptr;
2837}
2838
2839HTMLHeadElement* Document::head()
2840{
2841 if (auto element = documentElement())
2842 return childrenOfType<HTMLHeadElement>(*element).first();
2843 return nullptr;
2844}
2845
2846ExceptionOr<void> Document::closeForBindings()
2847{
2848 // FIXME: We should follow the specification more closely:
2849 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close
2850
2851 if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
2852 return Exception { InvalidStateError };
2853
2854 close();
2855 return { };
2856}
2857
2858void Document::close()
2859{
2860 if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript() || !scriptableDocumentParser()->isParsing())
2861 return;
2862
2863 explicitClose();
2864}
2865
2866void Document::explicitClose()
2867{
2868 if (RefPtr<DocumentParser> parser = m_parser)
2869 parser->finish();
2870
2871 if (!m_frame) {
2872 // Because we have no frame, we don't know if all loading has completed,
2873 // so we just call implicitClose() immediately. FIXME: This might fire
2874 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
2875 implicitClose();
2876 return;
2877 }
2878
2879 checkCompleted();
2880}
2881
2882void Document::implicitClose()
2883{
2884 // 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.
2885 if (m_inStyleRecalc) {
2886 m_closeAfterStyleRecalc = true;
2887 return;
2888 }
2889
2890 bool wasLocationChangePending = frame() && frame()->navigationScheduler().locationChangePending();
2891 bool doload = !parsing() && m_parser && !m_processingLoadEvent && !wasLocationChangePending;
2892
2893 if (!doload)
2894 return;
2895
2896 // Call to dispatchWindowLoadEvent can blow us from underneath.
2897 Ref<Document> protectedThis(*this);
2898
2899 m_processingLoadEvent = true;
2900
2901 ScriptableDocumentParser* parser = scriptableDocumentParser();
2902 m_wellFormed = parser && parser->wellFormed();
2903
2904 // We have to clear the parser, in case someone document.write()s from the
2905 // onLoad event handler, as in Radar 3206524.
2906 detachParser();
2907
2908 // FIXME: We kick off the icon loader when the Document is done parsing.
2909 // There are earlier opportunities we could start it:
2910 // -When the <head> finishes parsing
2911 // -When any new HTMLLinkElement is inserted into the document
2912 // But those add a dynamic component to the favicon that has UI
2913 // ramifications, and we need to decide what is the Right Thing To Do(tm)
2914 RefPtr<Frame> f = frame();
2915 if (f) {
2916#if ENABLE(XSLT)
2917 // Apply XSL transforms before load events so that event handlers can access the transformed DOM tree.
2918 applyPendingXSLTransformsNowIfScheduled();
2919#endif
2920
2921 if (auto* documentLoader = loader())
2922 documentLoader->startIconLoading();
2923
2924 f->animation().startAnimationsIfNotSuspended(this);
2925
2926 // FIXME: We shouldn't be dispatching pending events globally on all Documents here.
2927 // For now, only do this when there is a Frame, otherwise this could cause JS reentrancy
2928 // below SVG font parsing, for example. <https://webkit.org/b/136269>
2929 ImageLoader::dispatchPendingBeforeLoadEvents();
2930 ImageLoader::dispatchPendingLoadEvents();
2931 ImageLoader::dispatchPendingErrorEvents();
2932 HTMLLinkElement::dispatchPendingLoadEvents();
2933 HTMLStyleElement::dispatchPendingLoadEvents();
2934
2935 // To align the HTML load event and the SVGLoad event for the outermost <svg> element, fire it from
2936 // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false",
2937 // which is the default, for ='true' its fired at a later time, once all external resources finished loading).
2938 if (svgExtensions())
2939 accessSVGExtensions().dispatchSVGLoadEventToOutermostSVGElements();
2940 }
2941
2942 dispatchWindowLoadEvent();
2943 dispatchPageshowEvent(PageshowEventNotPersisted);
2944 if (m_pendingStateObject)
2945 dispatchPopstateEvent(WTFMove(m_pendingStateObject));
2946
2947 if (f)
2948 f->loader().dispatchOnloadEvents();
2949
2950 // An event handler may have removed the frame
2951 if (!frame()) {
2952 m_processingLoadEvent = false;
2953 return;
2954 }
2955
2956 // Make sure both the initial layout and reflow happen after the onload
2957 // fires. This will improve onload scores, and other browsers do it.
2958 // If they wanna cheat, we can too. -dwh
2959
2960 if (frame()->navigationScheduler().locationChangePending() && timeSinceDocumentCreation() < settings().layoutInterval()) {
2961 // Just bail out. Before or during the onload we were shifted to another page.
2962 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
2963 m_processingLoadEvent = false;
2964 view()->layoutContext().unscheduleLayout();
2965 return;
2966 }
2967
2968 frame()->loader().checkCallImplicitClose();
2969
2970 // We used to force a synchronous display and flush here. This really isn't
2971 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
2972 // (if your platform is syncing flushes and limiting them to 60fps).
2973 m_overMinimumLayoutThreshold = true;
2974 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
2975 updateStyleIfNeeded();
2976
2977 // Always do a layout after loading if needed.
2978 if (view() && renderView() && (!renderView()->firstChild() || renderView()->needsLayout()))
2979 view()->layoutContext().layout();
2980 }
2981
2982 m_processingLoadEvent = false;
2983
2984#if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK)
2985 if (f && hasLivingRenderTree() && AXObjectCache::accessibilityEnabled()) {
2986 // The AX cache may have been cleared at this point, but we need to make sure it contains an
2987 // AX object to send the notification to. getOrCreate will make sure that an valid AX object
2988 // exists in the cache (we ignore the return value because we don't need it here). This is
2989 // only safe to call when a layout is not in progress, so it can not be used in postNotification.
2990 //
2991 // This notification is now called AXNewDocumentLoadComplete because there are other handlers that will
2992 // catch new AND page history loads, and that uses AXLoadComplete
2993
2994 axObjectCache()->getOrCreate(renderView());
2995 if (this == &topDocument())
2996 axObjectCache()->postNotification(renderView(), AXObjectCache::AXNewDocumentLoadComplete);
2997 else {
2998 // AXLoadComplete can only be posted on the top document, so if it's a document
2999 // in an iframe that just finished loading, post AXLayoutComplete instead.
3000 axObjectCache()->postNotification(renderView(), AXObjectCache::AXLayoutComplete);
3001 }
3002 }
3003#endif
3004
3005 if (svgExtensions())
3006 accessSVGExtensions().startAnimations();
3007}
3008
3009void Document::setParsing(bool b)
3010{
3011 m_bParsing = b;
3012
3013 if (m_bParsing && !m_sharedObjectPool)
3014 m_sharedObjectPool = std::make_unique<DocumentSharedObjectPool>();
3015
3016 if (!m_bParsing && view() && !view()->needsLayout())
3017 view()->fireLayoutRelatedMilestonesIfNeeded();
3018}
3019
3020bool Document::shouldScheduleLayout()
3021{
3022 if (!documentElement())
3023 return false;
3024 if (!is<HTMLHtmlElement>(*documentElement()))
3025 return true;
3026 if (!bodyOrFrameset())
3027 return false;
3028 if (styleScope().hasPendingSheetsBeforeBody())
3029 return false;
3030 if (page() && page()->chrome().client().layerFlushThrottlingIsActive() && view() && view()->isVisuallyNonEmpty())
3031 return false;
3032
3033 return true;
3034}
3035
3036bool Document::isLayoutTimerActive()
3037{
3038 return view() && view()->layoutContext().isLayoutPending() && !minimumLayoutDelay();
3039}
3040
3041Seconds Document::minimumLayoutDelay()
3042{
3043 if (m_overMinimumLayoutThreshold)
3044 return 0_s;
3045
3046 auto elapsed = timeSinceDocumentCreation();
3047 m_overMinimumLayoutThreshold = elapsed > settings().layoutInterval();
3048
3049 // We'll want to schedule the timer to fire at the minimum layout threshold.
3050 return std::max(0_s, settings().layoutInterval() - elapsed);
3051}
3052
3053Seconds Document::timeSinceDocumentCreation() const
3054{
3055 return MonotonicTime::now() - m_documentCreationTime;
3056}
3057
3058ExceptionOr<void> Document::write(Document* responsibleDocument, SegmentedString&& text)
3059{
3060 NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth);
3061
3062 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep;
3063 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep;
3064
3065 if (m_writeRecursionIsTooDeep)
3066 return { };
3067
3068 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint();
3069 if (!hasInsertionPoint && (m_ignoreOpensDuringUnloadCount || m_ignoreDestructiveWriteCount))
3070 return { };
3071
3072 if (!hasInsertionPoint) {
3073 auto result = open(responsibleDocument);
3074 if (UNLIKELY(result.hasException()))
3075 return result.releaseException();
3076 }
3077
3078 ASSERT(m_parser);
3079 m_parser->insert(WTFMove(text));
3080 return { };
3081}
3082
3083ExceptionOr<void> Document::write(Document* responsibleDocument, Vector<String>&& strings)
3084{
3085 if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
3086 return Exception { InvalidStateError };
3087
3088 SegmentedString text;
3089 for (auto& string : strings)
3090 text.append(WTFMove(string));
3091
3092 return write(responsibleDocument, WTFMove(text));
3093}
3094
3095ExceptionOr<void> Document::writeln(Document* responsibleDocument, Vector<String>&& strings)
3096{
3097 if (!isHTMLDocument() || m_throwOnDynamicMarkupInsertionCount)
3098 return Exception { InvalidStateError };
3099
3100 SegmentedString text;
3101 for (auto& string : strings)
3102 text.append(WTFMove(string));
3103
3104 text.append("\n"_s);
3105 return write(responsibleDocument, WTFMove(text));
3106}
3107
3108Seconds Document::minimumDOMTimerInterval() const
3109{
3110 auto* page = this->page();
3111 if (!page)
3112 return ScriptExecutionContext::minimumDOMTimerInterval();
3113 return page->settings().minimumDOMTimerInterval();
3114}
3115
3116void Document::setTimerThrottlingEnabled(bool shouldThrottle)
3117{
3118 if (m_isTimerThrottlingEnabled == shouldThrottle)
3119 return;
3120
3121 m_isTimerThrottlingEnabled = shouldThrottle;
3122 didChangeTimerAlignmentInterval();
3123}
3124
3125Seconds Document::domTimerAlignmentInterval(bool hasReachedMaxNestingLevel) const
3126{
3127 auto alignmentInterval = ScriptExecutionContext::domTimerAlignmentInterval(hasReachedMaxNestingLevel);
3128 if (!hasReachedMaxNestingLevel)
3129 return alignmentInterval;
3130
3131 // Apply Document-level DOMTimer throttling only if timers have reached their maximum nesting level as the Page may still be visible.
3132 if (m_isTimerThrottlingEnabled)
3133 alignmentInterval = std::max(alignmentInterval, DOMTimer::hiddenPageAlignmentInterval());
3134
3135 if (Page* page = this->page())
3136 alignmentInterval = std::max(alignmentInterval, page->domTimerAlignmentInterval());
3137
3138 if (!topOrigin().canAccess(securityOrigin()) && !hasHadUserInteraction())
3139 alignmentInterval = std::max(alignmentInterval, DOMTimer::nonInteractedCrossOriginFrameAlignmentInterval());
3140
3141 return alignmentInterval;
3142}
3143
3144EventTarget* Document::errorEventTarget()
3145{
3146 return m_domWindow.get();
3147}
3148
3149void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<Inspector::ScriptCallStack>&& callStack)
3150{
3151 addMessage(MessageSource::JS, MessageLevel::Error, errorMessage, sourceURL, lineNumber, columnNumber, WTFMove(callStack));
3152}
3153
3154void Document::setURL(const URL& url)
3155{
3156 const URL& newURL = url.isEmpty() ? WTF::blankURL() : url;
3157 if (newURL == m_url)
3158 return;
3159
3160 m_url = newURL;
3161 m_documentURI = m_url.string();
3162 updateBaseURL();
3163}
3164
3165void Document::updateBaseURL()
3166{
3167 URL oldBaseURL = m_baseURL;
3168 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using
3169 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute
3170 // from the Document interface otherwise.
3171 if (!m_baseElementURL.isEmpty())
3172 m_baseURL = m_baseElementURL;
3173 else if (!m_baseURLOverride.isEmpty())
3174 m_baseURL = m_baseURLOverride;
3175 else {
3176 // The documentURI attribute is read-only from JavaScript, but writable from Objective C, so we need to retain
3177 // this fallback behavior. We use a null base URL, since the documentURI attribute is an arbitrary string
3178 // and DOM 3 Core does not specify how it should be resolved.
3179 m_baseURL = URL({ }, documentURI());
3180 }
3181
3182 clearSelectorQueryCache();
3183
3184 if (!m_baseURL.isValid())
3185 m_baseURL = URL();
3186}
3187
3188void Document::setBaseURLOverride(const URL& url)
3189{
3190 m_baseURLOverride = url;
3191 updateBaseURL();
3192}
3193
3194void Document::processBaseElement()
3195{
3196 // Find the first href attribute in a base element and the first target attribute in a base element.
3197 const AtomicString* href = nullptr;
3198 const AtomicString* target = nullptr;
3199 auto baseDescendants = descendantsOfType<HTMLBaseElement>(*this);
3200 for (auto& base : baseDescendants) {
3201 if (!href) {
3202 const AtomicString& value = base.attributeWithoutSynchronization(hrefAttr);
3203 if (!value.isNull()) {
3204 href = &value;
3205 if (target)
3206 break;
3207 }
3208 }
3209 if (!target) {
3210 const AtomicString& value = base.attributeWithoutSynchronization(targetAttr);
3211 if (!value.isNull()) {
3212 target = &value;
3213 if (href)
3214 break;
3215 }
3216 }
3217 }
3218
3219 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly.
3220 URL baseElementURL;
3221 if (href) {
3222 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href);
3223 if (!strippedHref.isEmpty())
3224 baseElementURL = URL(url(), strippedHref);
3225 }
3226 if (m_baseElementURL != baseElementURL && contentSecurityPolicy()->allowBaseURI(baseElementURL)) {
3227 m_baseElementURL = baseElementURL;
3228 updateBaseURL();
3229 }
3230
3231 m_baseTarget = target ? *target : nullAtom();
3232}
3233
3234String Document::userAgent(const URL& url) const
3235{
3236 return frame() ? frame()->loader().userAgent(url) : String();
3237}
3238
3239void Document::disableEval(const String& errorMessage)
3240{
3241 if (!frame())
3242 return;
3243
3244 frame()->script().disableEval(errorMessage);
3245}
3246
3247void Document::disableWebAssembly(const String& errorMessage)
3248{
3249 if (!frame())
3250 return;
3251
3252 frame()->script().disableWebAssembly(errorMessage);
3253}
3254
3255#if ENABLE(INDEXED_DATABASE)
3256IDBClient::IDBConnectionProxy* Document::idbConnectionProxy()
3257{
3258 if (!m_idbConnectionProxy) {
3259 Page* currentPage = page();
3260 if (!currentPage)
3261 return nullptr;
3262 m_idbConnectionProxy = &currentPage->idbConnection().proxy();
3263 }
3264 return m_idbConnectionProxy.get();
3265}
3266#endif
3267
3268SocketProvider* Document::socketProvider()
3269{
3270 return m_socketProvider.get();
3271}
3272
3273bool Document::canNavigate(Frame* targetFrame, const URL& destinationURL)
3274{
3275 if (!m_frame)
3276 return false;
3277
3278 // FIXME: We shouldn't call this function without a target frame, but
3279 // fast/forms/submit-to-blank-multiple-times.html depends on this function
3280 // returning true when supplied with a 0 targetFrame.
3281 if (!targetFrame)
3282 return true;
3283
3284 if (!canNavigateInternal(*targetFrame))
3285 return false;
3286
3287 if (isNavigationBlockedByThirdPartyIFrameRedirectBlocking(*targetFrame, destinationURL)) {
3288 printNavigationErrorMessage(*targetFrame, url(), "The frame attempting navigation of the top-level window is cross-origin and the user has never interacted with the frame."_s);
3289 return false;
3290 }
3291
3292 return true;
3293}
3294
3295bool Document::canNavigateInternal(Frame& targetFrame)
3296{
3297 ASSERT(m_frame);
3298
3299 // Cases (i), (ii) and (iii) pass the tests from the specifications but might not pass the "security origin" tests.
3300
3301 // i. A frame can navigate its top ancestor when its 'allow-top-navigation' flag is set (sometimes known as 'frame-busting').
3302 if (!isSandboxed(SandboxTopNavigation) && &targetFrame == &m_frame->tree().top())
3303 return true;
3304
3305 // ii. A frame can navigate its top ancestor when its 'allow-top-navigation-by-user-activation' flag is set and navigation is triggered by user activation.
3306 if (!isSandboxed(SandboxTopNavigationByUserActivation) && UserGestureIndicator::processingUserGesture() && &targetFrame == &m_frame->tree().top())
3307 return true;
3308
3309 // iii. A sandboxed frame can always navigate its descendants.
3310 if (isSandboxed(SandboxNavigation) && targetFrame.tree().isDescendantOf(m_frame))
3311 return true;
3312
3313 // From https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate.
3314 // 1. If A is not the same browsing context as B, and A is not one of the ancestor browsing contexts of B, and B is not a top-level browsing context, and A's active document's active sandboxing
3315 // flag set has its sandboxed navigation browsing context flag set, then abort these steps negatively.
3316 if (m_frame != &targetFrame && isSandboxed(SandboxNavigation) && targetFrame.tree().parent() && !targetFrame.tree().isDescendantOf(m_frame)) {
3317 printNavigationErrorMessage(targetFrame, url(), "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors."_s);
3318 return false;
3319 }
3320
3321 // 2. Otherwise, if B is a top-level browsing context, and is one of the ancestor browsing contexts of A, then:
3322 if (m_frame != &targetFrame && &targetFrame == &m_frame->tree().top()) {
3323 bool triggeredByUserActivation = UserGestureIndicator::processingUserGesture();
3324 // 1. If this algorithm is triggered by user activation and A's active document's active sandboxing flag set has its sandboxed top-level navigation with user activation browsing context flag set, then abort these steps negatively.
3325 if (triggeredByUserActivation && isSandboxed(SandboxTopNavigationByUserActivation)) {
3326 printNavigationErrorMessage(targetFrame, url(), "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation-by-user-activation' flag is not set and navigation is not triggered by user activation."_s);
3327 return false;
3328 }
3329 // 2. Otherwise, If this algorithm is not triggered by user activation and A's active document's active sandboxing flag set has its sandboxed top-level navigation without user activation browsing context flag set, then abort these steps negatively.
3330 if (!triggeredByUserActivation && isSandboxed(SandboxTopNavigation)) {
3331 printNavigationErrorMessage(targetFrame, url(), "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set."_s);
3332 return false;
3333 }
3334 }
3335
3336 // 3. Otherwise, if B is a top-level browsing context, and is neither A nor one of the ancestor browsing contexts of A, and A's Document's active sandboxing flag set has its
3337 // sandboxed navigation browsing context flag set, and A is not the one permitted sandboxed navigator of B, then abort these steps negatively.
3338 if (!targetFrame.tree().parent() && m_frame != &targetFrame && &targetFrame != &m_frame->tree().top() && isSandboxed(SandboxNavigation) && targetFrame.loader().opener() != m_frame) {
3339 printNavigationErrorMessage(targetFrame, url(), "The frame attempting navigation is sandboxed, and is not allowed to navigate this popup."_s);
3340 return false;
3341 }
3342
3343 // 4. Otherwise, terminate positively!
3344
3345 // This is the normal case. A document can navigate its descendant frames,
3346 // or, more generally, a document can navigate a frame if the document is
3347 // in the same origin as any of that frame's ancestors (in the frame
3348 // hierarchy).
3349 //
3350 // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for
3351 // historical information about this security check.
3352 if (canAccessAncestor(securityOrigin(), &targetFrame))
3353 return true;
3354
3355 // Top-level frames are easier to navigate than other frames because they
3356 // display their URLs in the address bar (in most browsers). However, there
3357 // are still some restrictions on navigation to avoid nuisance attacks.
3358 // Specifically, a document can navigate a top-level frame if that frame
3359 // opened the document or if the document is the same-origin with any of
3360 // the top-level frame's opener's ancestors (in the frame hierarchy).
3361 //
3362 // In both of these cases, the document performing the navigation is in
3363 // some way related to the frame being navigate (e.g., by the "opener"
3364 // and/or "parent" relation). Requiring some sort of relation prevents a
3365 // document from navigating arbitrary, unrelated top-level frames.
3366 if (!targetFrame.tree().parent()) {
3367 if (&targetFrame == m_frame->loader().opener())
3368 return true;
3369
3370 if (canAccessAncestor(securityOrigin(), targetFrame.loader().opener()))
3371 return true;
3372 }
3373
3374 printNavigationErrorMessage(targetFrame, url(), "The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener.");
3375 return false;
3376}
3377
3378// Prevent cross-site top-level redirects from third-party iframes unless the user has ever interacted with the frame.
3379bool Document::isNavigationBlockedByThirdPartyIFrameRedirectBlocking(Frame& targetFrame, const URL& destinationURL)
3380{
3381 if (!settings().thirdPartyIframeRedirectBlockingEnabled())
3382 return false;
3383
3384 // Only prevent top frame navigations by subframes.
3385 if (m_frame == &targetFrame || &targetFrame != &m_frame->tree().top())
3386 return false;
3387
3388 // Only prevent navigations by subframes that the user has not interacted with.
3389 if (m_frame->hasHadUserInteraction())
3390 return false;
3391
3392 // Only prevent navigations by unsandboxed iframes. Such navigations by unsandboxed iframes would have already been blocked unless
3393 // "allow-top-navigation" / "allow-top-navigation-by-user-activation" was explicitly specified.
3394 if (sandboxFlags() != SandboxNone)
3395 return false;
3396
3397 // Only prevent navigations by third-party iframes.
3398 if (canAccessAncestor(securityOrigin(), &targetFrame))
3399 return false;
3400
3401 // Only prevent cross-site navigations.
3402 auto* targetDocument = targetFrame.document();
3403 if (targetDocument && (targetDocument->securityOrigin().canAccess(SecurityOrigin::create(destinationURL)) || areRegistrableDomainsEqual(targetDocument->url(), destinationURL)))
3404 return false;
3405
3406 return true;
3407}
3408
3409void Document::didRemoveAllPendingStylesheet()
3410{
3411 if (auto* parser = scriptableDocumentParser())
3412 parser->executeScriptsWaitingForStylesheetsSoon();
3413}
3414
3415bool Document::usesStyleBasedEditability() const
3416{
3417 if (m_hasElementUsingStyleBasedEditability)
3418 return true;
3419
3420 ASSERT(!m_renderView || !m_renderView->frameView().isPainting());
3421 ASSERT(!m_inStyleRecalc);
3422
3423 auto& styleScope = const_cast<Style::Scope&>(this->styleScope());
3424 styleScope.flushPendingUpdate();
3425 return styleScope.usesStyleBasedEditability();
3426}
3427
3428void Document::setHasElementUsingStyleBasedEditability()
3429{
3430 m_hasElementUsingStyleBasedEditability = true;
3431}
3432
3433void Document::processHttpEquiv(const String& equiv, const String& content, bool isInDocumentHead)
3434{
3435 ASSERT(!equiv.isNull());
3436 ASSERT(!content.isNull());
3437
3438 HttpEquivPolicy policy = httpEquivPolicy();
3439 if (policy != HttpEquivPolicy::Enabled) {
3440 String reason;
3441 switch (policy) {
3442 case HttpEquivPolicy::Enabled:
3443 ASSERT_NOT_REACHED();
3444 break;
3445 case HttpEquivPolicy::DisabledBySettings:
3446 reason = "by the embedder.";
3447 break;
3448 case HttpEquivPolicy::DisabledByContentDispositionAttachmentSandbox:
3449 reason = "for documents with Content-Disposition: attachment.";
3450 break;
3451 }
3452 String message = "http-equiv '" + equiv + "' is disabled " + reason;
3453 addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
3454 return;
3455 }
3456
3457 Frame* frame = this->frame();
3458 auto* documentLoader = frame ? frame->loader().documentLoader() : nullptr;
3459 auto httpStatusCode = documentLoader ? documentLoader->response().httpStatusCode() : 0;
3460
3461 HTTPHeaderName headerName;
3462 if (!findHTTPHeaderName(equiv, headerName))
3463 return;
3464
3465 switch (headerName) {
3466 case HTTPHeaderName::DefaultStyle:
3467 // The preferred style set has been overridden as per section
3468 // 14.3.2 of the HTML4.0 specification. We need to update the
3469 // sheet used variable and then update our style selector.
3470 // For more info, see the test at:
3471 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
3472 // -dwh
3473 styleScope().setPreferredStylesheetSetName(content);
3474 break;
3475
3476 case HTTPHeaderName::Refresh: {
3477 double delay;
3478 String urlString;
3479 if (frame && parseMetaHTTPEquivRefresh(content, delay, urlString)) {
3480 URL completedURL;
3481 if (urlString.isEmpty())
3482 completedURL = m_url;
3483 else
3484 completedURL = completeURL(urlString);
3485 if (!WTF::protocolIsJavaScript(completedURL))
3486 frame->navigationScheduler().scheduleRedirect(*this, delay, completedURL);
3487 else {
3488 String message = "Refused to refresh " + m_url.stringCenterEllipsizedToLength() + " to a javascript: URL";
3489 addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
3490 }
3491 }
3492
3493 break;
3494 }
3495
3496 case HTTPHeaderName::SetCookie:
3497 if (isHTMLDocument())
3498 addConsoleMessage(MessageSource::Security, MessageLevel::Error, "The Set-Cookie meta tag is obsolete and was ignored. Use the HTTP header Set-Cookie or document.cookie instead."_s);
3499 break;
3500
3501 case HTTPHeaderName::ContentLanguage:
3502 setContentLanguage(content);
3503 break;
3504
3505 case HTTPHeaderName::XDNSPrefetchControl:
3506 parseDNSPrefetchControlHeader(content);
3507 break;
3508
3509 case HTTPHeaderName::XFrameOptions:
3510 if (frame) {
3511 FrameLoader& frameLoader = frame->loader();
3512 unsigned long requestIdentifier = 0;
3513 if (frameLoader.activeDocumentLoader() && frameLoader.activeDocumentLoader()->mainResourceLoader())
3514 requestIdentifier = frameLoader.activeDocumentLoader()->mainResourceLoader()->identifier();
3515
3516 String message = "The X-Frame-Option '" + content + "' supplied in a <meta> element was ignored. X-Frame-Options may only be provided by an HTTP header sent with the document.";
3517 addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, requestIdentifier);
3518 }
3519 break;
3520
3521 case HTTPHeaderName::ContentSecurityPolicy:
3522 if (isInDocumentHead)
3523 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicyHeaderType::Enforce, ContentSecurityPolicy::PolicyFrom::HTTPEquivMeta, referrer(), httpStatusCode);
3524 break;
3525
3526 case HTTPHeaderName::XWebKitCSP:
3527 if (isInDocumentHead)
3528 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicyHeaderType::PrefixedEnforce, ContentSecurityPolicy::PolicyFrom::HTTPEquivMeta, referrer(), httpStatusCode);
3529 break;
3530
3531 default:
3532 break;
3533 }
3534}
3535
3536void Document::processDisabledAdaptations(const String& disabledAdaptationsString)
3537{
3538 auto disabledAdaptations = parseDisabledAdaptations(disabledAdaptationsString);
3539 if (m_disabledAdaptations == disabledAdaptations)
3540 return;
3541
3542 m_disabledAdaptations = disabledAdaptations;
3543 dispatchDisabledAdaptationsDidChangeForMainFrame();
3544}
3545
3546void Document::dispatchDisabledAdaptationsDidChangeForMainFrame()
3547{
3548 if (!frame()->isMainFrame())
3549 return;
3550
3551 if (!page())
3552 return;
3553
3554 page()->chrome().dispatchDisabledAdaptationsDidChange(m_disabledAdaptations);
3555}
3556
3557void Document::processViewport(const String& features, ViewportArguments::Type origin)
3558{
3559 ASSERT(!features.isNull());
3560
3561 LOG_WITH_STREAM(Viewports, stream << "Document::processViewport " << features);
3562
3563 if (origin < m_viewportArguments.type)
3564 return;
3565
3566 m_viewportArguments = ViewportArguments(origin);
3567
3568 LOG_WITH_STREAM(Viewports, stream << " resolved to " << m_viewportArguments);
3569
3570 processFeaturesString(features, FeatureMode::Viewport, [this](StringView key, StringView value) {
3571 setViewportFeature(m_viewportArguments, *this, key, value);
3572 });
3573
3574 updateViewportArguments();
3575}
3576
3577ViewportArguments Document::viewportArguments() const
3578{
3579 auto* page = this->page();
3580 if (!page)
3581 return m_viewportArguments;
3582 return page->overrideViewportArguments().valueOr(m_viewportArguments);
3583}
3584
3585void Document::updateViewportArguments()
3586{
3587 if (page() && frame()->isMainFrame()) {
3588#ifndef NDEBUG
3589 m_didDispatchViewportPropertiesChanged = true;
3590#endif
3591 page()->chrome().dispatchViewportPropertiesDidChange(viewportArguments());
3592 page()->chrome().didReceiveDocType(*frame());
3593 }
3594}
3595
3596#if ENABLE(DARK_MODE_CSS)
3597static void processColorSchemeString(StringView colorScheme, const WTF::Function<void(StringView key)>& callback)
3598{
3599 unsigned length = colorScheme.length();
3600 for (unsigned i = 0; i < length; ) {
3601 // Skip to first non-separator.
3602 while (i < length && isHTMLSpace(colorScheme[i]))
3603 ++i;
3604 unsigned keyBegin = i;
3605
3606 // Skip to first separator.
3607 while (i < length && !isHTMLSpace(colorScheme[i]))
3608 ++i;
3609 unsigned keyEnd = i;
3610
3611 if (keyBegin == keyEnd)
3612 continue;
3613
3614 callback(colorScheme.substring(keyBegin, keyEnd - keyBegin));
3615 }
3616}
3617
3618void Document::processColorScheme(const String& colorSchemeString)
3619{
3620 OptionSet<ColorScheme> colorScheme;
3621 bool allowsTransformations = true;
3622 bool autoEncountered = false;
3623
3624 processColorSchemeString(colorSchemeString, [&](StringView key) {
3625 if (equalLettersIgnoringASCIICase(key, "auto")) {
3626 colorScheme = { };
3627 allowsTransformations = true;
3628 autoEncountered = true;
3629 return;
3630 }
3631
3632 if (autoEncountered)
3633 return;
3634
3635 if (equalLettersIgnoringASCIICase(key, "light"))
3636 colorScheme.add(ColorScheme::Light);
3637 else if (equalLettersIgnoringASCIICase(key, "dark"))
3638 colorScheme.add(ColorScheme::Dark);
3639 else if (equalLettersIgnoringASCIICase(key, "only"))
3640 allowsTransformations = false;
3641 });
3642
3643 // If the value was just "only", that is synonymous for "only light".
3644 if (colorScheme.isEmpty() && !allowsTransformations)
3645 colorScheme.add(ColorScheme::Light);
3646
3647 m_colorScheme = colorScheme;
3648 m_allowsColorSchemeTransformations = allowsTransformations;
3649
3650 if (auto* frameView = view())
3651 frameView->recalculateBaseBackgroundColor();
3652
3653 if (auto* page = this->page())
3654 page->updateStyleAfterChangeInEnvironment();
3655}
3656#endif
3657
3658#if PLATFORM(IOS_FAMILY)
3659
3660void Document::processFormatDetection(const String& features)
3661{
3662 // FIXME: Find a better place for this function.
3663 processFeaturesString(features, FeatureMode::Viewport, [this](StringView key, StringView value) {
3664 if (equalLettersIgnoringASCIICase(key, "telephone") && equalLettersIgnoringASCIICase(value, "no"))
3665 m_isTelephoneNumberParsingAllowed = false;
3666 });
3667}
3668
3669void Document::processWebAppOrientations()
3670{
3671 if (Page* page = this->page())
3672 page->chrome().client().webAppOrientationsUpdated();
3673}
3674
3675#endif
3676
3677void Document::processReferrerPolicy(const String& policy, ReferrerPolicySource source)
3678{
3679 ASSERT(!policy.isNull());
3680
3681 // Documents in a Content-Disposition: attachment sandbox should never send a Referer header,
3682 // even if the document has a meta tag saying otherwise.
3683 if (shouldEnforceContentDispositionAttachmentSandbox())
3684 return;
3685
3686#if USE(QUICK_LOOK)
3687 if (shouldEnforceQuickLookSandbox())
3688 return;
3689#endif
3690
3691 auto referrerPolicy = parseReferrerPolicy(policy, source);
3692 if (!referrerPolicy) {
3693 // Unknown policy values are ignored (https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values).
3694 addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, "Failed to set referrer policy: The value '" + policy + "' is not one of 'no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'origin', 'strict-origin', 'origin-when-cross-origin', 'strict-origin-when-cross-origin' or 'unsafe-url'.");
3695 return;
3696 }
3697 setReferrerPolicy(referrerPolicy.value());
3698}
3699
3700MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event)
3701{
3702 if (!hasLivingRenderTree())
3703 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint()));
3704
3705 HitTestResult result(documentPoint);
3706 renderView()->hitTest(request, result);
3707
3708 if (!request.readOnly())
3709 updateHoverActiveState(request, result.targetElement());
3710
3711 return MouseEventWithHitTestResults(event, result);
3712}
3713
3714// DOM Section 1.1.1
3715bool Document::childTypeAllowed(NodeType type) const
3716{
3717 switch (type) {
3718 case ATTRIBUTE_NODE:
3719 case CDATA_SECTION_NODE:
3720 case DOCUMENT_FRAGMENT_NODE:
3721 case DOCUMENT_NODE:
3722 case TEXT_NODE:
3723 return false;
3724 case COMMENT_NODE:
3725 case PROCESSING_INSTRUCTION_NODE:
3726 return true;
3727 case DOCUMENT_TYPE_NODE:
3728 case ELEMENT_NODE:
3729 // Documents may contain no more than one of each of these.
3730 // (One Element and one DocumentType.)
3731 for (Node* c = firstChild(); c; c = c->nextSibling())
3732 if (c->nodeType() == type)
3733 return false;
3734 return true;
3735 }
3736 return false;
3737}
3738
3739bool Document::canAcceptChild(const Node& newChild, const Node* refChild, AcceptChildOperation operation) const
3740{
3741 if (operation == AcceptChildOperation::Replace && refChild->nodeType() == newChild.nodeType())
3742 return true;
3743
3744 switch (newChild.nodeType()) {
3745 case ATTRIBUTE_NODE:
3746 case CDATA_SECTION_NODE:
3747 case DOCUMENT_NODE:
3748 case TEXT_NODE:
3749 return false;
3750 case COMMENT_NODE:
3751 case PROCESSING_INSTRUCTION_NODE:
3752 return true;
3753 case DOCUMENT_FRAGMENT_NODE: {
3754 bool hasSeenElementChild = false;
3755 for (auto* node = downcast<DocumentFragment>(newChild).firstChild(); node; node = node->nextSibling()) {
3756 if (is<Element>(*node)) {
3757 if (hasSeenElementChild)
3758 return false;
3759 hasSeenElementChild = true;
3760 }
3761 if (!canAcceptChild(*node, refChild, operation))
3762 return false;
3763 }
3764 break;
3765 }
3766 case DOCUMENT_TYPE_NODE: {
3767 auto* existingDocType = childrenOfType<DocumentType>(*this).first();
3768 if (operation == AcceptChildOperation::Replace) {
3769 // parent has a doctype child that is not child, or an element is preceding child.
3770 if (existingDocType && existingDocType != refChild)
3771 return false;
3772 if (refChild->previousElementSibling())
3773 return false;
3774 } else {
3775 ASSERT(operation == AcceptChildOperation::InsertOrAdd);
3776 if (existingDocType)
3777 return false;
3778 if ((refChild && refChild->previousElementSibling()) || (!refChild && firstElementChild()))
3779 return false;
3780 }
3781 break;
3782 }
3783 case ELEMENT_NODE: {
3784 auto* existingElementChild = firstElementChild();
3785 if (operation == AcceptChildOperation::Replace) {
3786 if (existingElementChild && existingElementChild != refChild)
3787 return false;
3788 for (auto* child = refChild->nextSibling(); child; child = child->nextSibling()) {
3789 if (is<DocumentType>(*child))
3790 return false;
3791 }
3792 } else {
3793 ASSERT(operation == AcceptChildOperation::InsertOrAdd);
3794 if (existingElementChild)
3795 return false;
3796 for (auto* child = refChild; child; child = child->nextSibling()) {
3797 if (is<DocumentType>(*child))
3798 return false;
3799 }
3800 }
3801 break;
3802 }
3803 }
3804 return true;
3805}
3806
3807Ref<Node> Document::cloneNodeInternal(Document&, CloningOperation type)
3808{
3809 Ref<Document> clone = cloneDocumentWithoutChildren();
3810 clone->cloneDataFromDocument(*this);
3811 switch (type) {
3812 case CloningOperation::OnlySelf:
3813 case CloningOperation::SelfWithTemplateContent:
3814 break;
3815 case CloningOperation::Everything:
3816 cloneChildNodes(clone);
3817 break;
3818 }
3819 return clone;
3820}
3821
3822Ref<Document> Document::cloneDocumentWithoutChildren() const
3823{
3824 if (isXMLDocument()) {
3825 if (isXHTMLDocument())
3826 return XMLDocument::createXHTML(nullptr, url());
3827 return XMLDocument::create(nullptr, url());
3828 }
3829 return create(url());
3830}
3831
3832void Document::cloneDataFromDocument(const Document& other)
3833{
3834 ASSERT(m_url == other.url());
3835 m_baseURL = other.baseURL();
3836 m_baseURLOverride = other.baseURLOverride();
3837 m_documentURI = other.documentURI();
3838
3839 setCompatibilityMode(other.m_compatibilityMode);
3840 setContextDocument(other.contextDocument());
3841 setSecurityOriginPolicy(other.securityOriginPolicy());
3842 overrideMIMEType(other.contentType());
3843 setDecoder(other.decoder());
3844}
3845
3846StyleSheetList& Document::styleSheets()
3847{
3848 if (!m_styleSheetList)
3849 m_styleSheetList = StyleSheetList::create(*this);
3850 return *m_styleSheetList;
3851}
3852
3853void Document::evaluateMediaQueryList()
3854{
3855 if (m_mediaQueryMatcher)
3856 m_mediaQueryMatcher->styleResolverChanged();
3857
3858 checkViewportDependentPictures();
3859 checkAppearanceDependentPictures();
3860}
3861
3862void Document::checkViewportDependentPictures()
3863{
3864 Vector<HTMLPictureElement*, 16> changedPictures;
3865 HashSet<HTMLPictureElement*>::iterator end = m_viewportDependentPictures.end();
3866 for (HashSet<HTMLPictureElement*>::iterator it = m_viewportDependentPictures.begin(); it != end; ++it) {
3867 if ((*it)->viewportChangeAffectedPicture())
3868 changedPictures.append(*it);
3869 }
3870 for (auto* picture : changedPictures)
3871 picture->sourcesChanged();
3872}
3873
3874void Document::checkAppearanceDependentPictures()
3875{
3876 Vector<HTMLPictureElement*, 16> changedPictures;
3877 for (auto* picture : m_appearanceDependentPictures) {
3878 if (picture->appearanceChangeAffectedPicture())
3879 changedPictures.append(picture);
3880 }
3881
3882 for (auto* picture : changedPictures)
3883 picture->sourcesChanged();
3884}
3885
3886void Document::updateViewportUnitsOnResize()
3887{
3888 if (!hasStyleWithViewportUnits())
3889 return;
3890
3891 styleScope().resolver().clearCachedPropertiesAffectedByViewportUnits();
3892
3893 // FIXME: Ideally, we should save the list of elements that have viewport units and only iterate over those.
3894 for (Element* element = ElementTraversal::firstWithin(rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) {
3895 auto* renderer = element->renderer();
3896 if (renderer && renderer->style().hasViewportUnits())
3897 element->invalidateStyle();
3898 }
3899}
3900
3901void Document::addAudioProducer(MediaProducer& audioProducer)
3902{
3903 m_audioProducers.add(audioProducer);
3904 updateIsPlayingMedia();
3905}
3906
3907void Document::removeAudioProducer(MediaProducer& audioProducer)
3908{
3909 m_audioProducers.remove(audioProducer);
3910 updateIsPlayingMedia();
3911}
3912
3913void Document::noteUserInteractionWithMediaElement()
3914{
3915 if (m_userHasInteractedWithMediaElement)
3916 return;
3917
3918 if (!topDocument().userDidInteractWithPage())
3919 return;
3920
3921 m_userHasInteractedWithMediaElement = true;
3922 updateIsPlayingMedia();
3923}
3924
3925void Document::updateIsPlayingMedia(uint64_t sourceElementID)
3926{
3927 ASSERT(!m_audioProducers.hasNullReferences());
3928 MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
3929 for (auto& audioProducer : m_audioProducers)
3930 state |= audioProducer.mediaState();
3931
3932#if ENABLE(MEDIA_SESSION)
3933 if (HTMLMediaElement* sourceElement = HTMLMediaElement::elementWithID(sourceElementID)) {
3934 if (sourceElement->isPlaying())
3935 state |= MediaProducer::IsSourceElementPlaying;
3936
3937 if (auto* session = sourceElement->session()) {
3938 if (auto* controls = session->controls()) {
3939 if (controls->previousTrackEnabled())
3940 state |= MediaProducer::IsPreviousTrackControlEnabled;
3941 if (controls->nextTrackEnabled())
3942 state |= MediaProducer::IsNextTrackControlEnabled;
3943 }
3944 }
3945 }
3946#endif
3947
3948 if (m_userHasInteractedWithMediaElement)
3949 state |= MediaProducer::HasUserInteractedWithMediaElement;
3950
3951 if (state == m_mediaState)
3952 return;
3953
3954#if ENABLE(MEDIA_STREAM)
3955 bool captureStateChanged = MediaProducer::isCapturing(m_mediaState) != MediaProducer::isCapturing(state);
3956#endif
3957
3958 m_mediaState = state;
3959
3960 if (page())
3961 page()->updateIsPlayingMedia(sourceElementID);
3962
3963#if ENABLE(MEDIA_STREAM)
3964 if (captureStateChanged)
3965 mediaStreamCaptureStateChanged();
3966#endif
3967}
3968
3969void Document::pageMutedStateDidChange()
3970{
3971 for (auto& audioProducer : m_audioProducers)
3972 audioProducer.pageMutedStateDidChange();
3973}
3974
3975static bool isNodeInSubtree(Node& node, Node& container, Document::NodeRemoval nodeRemoval)
3976{
3977 if (nodeRemoval == Document::NodeRemoval::ChildrenOfNode)
3978 return node.isDescendantOf(container);
3979
3980 return &node == &container || node.isDescendantOf(container);
3981}
3982
3983void Document::adjustFocusedNodeOnNodeRemoval(Node& node, NodeRemoval nodeRemoval)
3984{
3985 if (!m_focusedElement || pageCacheState() != NotInPageCache) // If the document is in the page cache, then we don't need to clear out the focused node.
3986 return;
3987
3988 Element* focusedElement = node.treeScope().focusedElementInScope();
3989 if (!focusedElement)
3990 return;
3991
3992 if (isNodeInSubtree(*focusedElement, node, nodeRemoval)) {
3993 // FIXME: We should avoid synchronously updating the style inside setFocusedElement.
3994 // FIXME: Object elements should avoid loading a frame synchronously in a post style recalc callback.
3995 SubframeLoadingDisabler disabler(is<ContainerNode>(node) ? &downcast<ContainerNode>(node) : nullptr);
3996 setFocusedElement(nullptr, FocusDirectionNone, FocusRemovalEventsMode::DoNotDispatch);
3997 // Set the focus navigation starting node to the previous focused element so that
3998 // we can fallback to the siblings or parent node for the next search.
3999 // Also we need to call removeFocusNavigationNodeOfSubtree after this function because
4000 // setFocusedElement(nullptr) will reset m_focusNavigationStartingNode.
4001 setFocusNavigationStartingNode(focusedElement);
4002 }
4003}
4004
4005void Document::hoveredElementDidDetach(Element& element)
4006{
4007 if (!m_hoveredElement || &element != m_hoveredElement)
4008 return;
4009
4010 m_hoveredElement = element.parentElement();
4011 while (m_hoveredElement && !m_hoveredElement->renderer())
4012 m_hoveredElement = m_hoveredElement->parentElement();
4013 if (frame())
4014 frame()->eventHandler().scheduleHoverStateUpdate();
4015}
4016
4017void Document::elementInActiveChainDidDetach(Element& element)
4018{
4019 if (!m_activeElement || &element != m_activeElement)
4020 return;
4021
4022 m_activeElement = element.parentElement();
4023 while (m_activeElement && !m_activeElement->renderer())
4024 m_activeElement = m_activeElement->parentElement();
4025}
4026
4027#if ENABLE(DASHBOARD_SUPPORT)
4028const Vector<AnnotatedRegionValue>& Document::annotatedRegions() const
4029{
4030 return m_annotatedRegions;
4031}
4032
4033void Document::setAnnotatedRegions(const Vector<AnnotatedRegionValue>& regions)
4034{
4035 m_annotatedRegions = regions;
4036 setAnnotatedRegionsDirty(false);
4037}
4038
4039void Document::updateAnnotatedRegions()
4040{
4041 if (!hasAnnotatedRegions())
4042 return;
4043
4044 Vector<AnnotatedRegionValue> newRegions;
4045 renderBox()->collectAnnotatedRegions(newRegions); // FIXME.
4046 if (newRegions == annotatedRegions())
4047 return;
4048
4049 setAnnotatedRegions(newRegions);
4050
4051 if (Page* page = this->page())
4052 page->chrome().client().annotatedRegionsChanged();
4053}
4054#endif
4055
4056void Document::invalidateRenderingDependentRegions(AnnotationsAction annotationsAction)
4057{
4058#if ENABLE(DASHBOARD_SUPPORT)
4059 // FIXME: we don't have a good invalidation/update policy for Dashboard regions. They get eagerly updated
4060 // on forced layouts, and don't need to be.
4061 if (annotationsAction == AnnotationsAction::Update)
4062 updateAnnotatedRegions();
4063 else
4064 setAnnotatedRegionsDirty();
4065#else
4066 UNUSED_PARAM(annotationsAction);
4067#endif
4068
4069#if PLATFORM(IOS_FAMILY) && ENABLE(TOUCH_EVENTS)
4070 setTouchEventRegionsNeedUpdate();
4071#endif
4072
4073#if PLATFORM(IOS_FAMILY) && ENABLE(POINTER_EVENTS)
4074 if (auto* page = this->page()) {
4075 if (auto* frameView = view()) {
4076 if (auto* scrollingCoordinator = page->scrollingCoordinator())
4077 scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
4078 }
4079 }
4080#endif
4081}
4082
4083void Document::invalidateScrollbarDependentRegions()
4084{
4085#if ENABLE(DASHBOARD_SUPPORT)
4086 if (hasAnnotatedRegions())
4087 setAnnotatedRegionsDirty();
4088#endif
4089}
4090
4091void Document::updateZOrderDependentRegions()
4092{
4093#if ENABLE(DASHBOARD_SUPPORT)
4094 if (annotatedRegionsDirty())
4095 updateAnnotatedRegions();
4096#endif
4097}
4098
4099bool Document::setFocusedElement(Element* element, FocusDirection direction, FocusRemovalEventsMode eventsMode)
4100{
4101 RefPtr<Element> newFocusedElement = element;
4102 // Make sure newFocusedElement is actually in this document
4103 if (newFocusedElement && (&newFocusedElement->document() != this))
4104 return true;
4105
4106 if (m_focusedElement == newFocusedElement)
4107 return true;
4108
4109 if (pageCacheState() != NotInPageCache)
4110 return false;
4111
4112 bool focusChangeBlocked = false;
4113 RefPtr<Element> oldFocusedElement = WTFMove(m_focusedElement);
4114
4115 // Remove focus from the existing focus node (if any)
4116 if (oldFocusedElement) {
4117 oldFocusedElement->setFocus(false);
4118 setFocusNavigationStartingNode(nullptr);
4119
4120 if (eventsMode == FocusRemovalEventsMode::Dispatch) {
4121 // Dispatch a change event for form control elements that have been edited.
4122 if (is<HTMLFormControlElement>(*oldFocusedElement)) {
4123 HTMLFormControlElement& formControlElement = downcast<HTMLFormControlElement>(*oldFocusedElement);
4124 if (formControlElement.wasChangedSinceLastFormControlChangeEvent())
4125 formControlElement.dispatchFormControlChangeEvent();
4126 }
4127
4128 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
4129 oldFocusedElement->dispatchBlurEvent(newFocusedElement.copyRef());
4130
4131 if (m_focusedElement) {
4132 // handler shifted focus
4133 focusChangeBlocked = true;
4134 newFocusedElement = nullptr;
4135 }
4136
4137 oldFocusedElement->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedElement.copyRef()); // DOM level 3 name for the bubbling blur event.
4138 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
4139 // on it, probably when <rdar://problem/8503958> is resolved.
4140 oldFocusedElement->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedElement.copyRef()); // DOM level 2 name for compatibility.
4141
4142 if (m_focusedElement) {
4143 // handler shifted focus
4144 focusChangeBlocked = true;
4145 newFocusedElement = nullptr;
4146 }
4147 } else {
4148 // Match the order in HTMLTextFormControlElement::dispatchBlurEvent.
4149 if (is<HTMLInputElement>(*oldFocusedElement))
4150 downcast<HTMLInputElement>(*oldFocusedElement).endEditing();
4151 if (page())
4152 page()->chrome().client().elementDidBlur(*oldFocusedElement);
4153 ASSERT(!m_focusedElement);
4154 }
4155
4156 if (oldFocusedElement->isRootEditableElement())
4157 frame()->editor().didEndEditing();
4158
4159 if (view()) {
4160 if (Widget* oldWidget = widgetForElement(oldFocusedElement.get()))
4161 oldWidget->setFocus(false);
4162 else
4163 view()->setFocus(false);
4164 }
4165
4166 if (is<HTMLInputElement>(oldFocusedElement)) {
4167 // HTMLInputElement::didBlur just scrolls text fields back to the beginning.
4168 // FIXME: This could be done asynchronusly.
4169 // Updating style may dispatch events due to PostResolutionCallback
4170 if (eventsMode == FocusRemovalEventsMode::Dispatch)
4171 updateStyleIfNeeded();
4172 downcast<HTMLInputElement>(*oldFocusedElement).didBlur();
4173 }
4174 }
4175
4176 if (newFocusedElement && newFocusedElement->isFocusable()) {
4177 if (newFocusedElement->isRootEditableElement() && !acceptsEditingFocus(*newFocusedElement)) {
4178 // delegate blocks focus change
4179 focusChangeBlocked = true;
4180 goto SetFocusedNodeDone;
4181 }
4182 // Set focus on the new node
4183 m_focusedElement = newFocusedElement;
4184 setFocusNavigationStartingNode(m_focusedElement.get());
4185
4186 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
4187 m_focusedElement->dispatchFocusEvent(oldFocusedElement.copyRef(), direction);
4188
4189 if (m_focusedElement != newFocusedElement) {
4190 // handler shifted focus
4191 focusChangeBlocked = true;
4192 goto SetFocusedNodeDone;
4193 }
4194
4195 m_focusedElement->dispatchFocusInEvent(eventNames().focusinEvent, oldFocusedElement.copyRef()); // DOM level 3 bubbling focus event.
4196
4197 if (m_focusedElement != newFocusedElement) {
4198 // handler shifted focus
4199 focusChangeBlocked = true;
4200 goto SetFocusedNodeDone;
4201 }
4202
4203 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends
4204 // on it, probably when <rdar://problem/8503958> is m.
4205 m_focusedElement->dispatchFocusInEvent(eventNames().DOMFocusInEvent, oldFocusedElement.copyRef()); // DOM level 2 for compatibility.
4206
4207 if (m_focusedElement != newFocusedElement) {
4208 // handler shifted focus
4209 focusChangeBlocked = true;
4210 goto SetFocusedNodeDone;
4211 }
4212
4213 m_focusedElement->setFocus(true);
4214
4215 // The setFocus call triggers a blur and a focus event. Event handlers could cause the focused element to be cleared.
4216 if (m_focusedElement != newFocusedElement) {
4217 // handler shifted focus
4218 focusChangeBlocked = true;
4219 goto SetFocusedNodeDone;
4220 }
4221
4222 if (m_focusedElement->isRootEditableElement())
4223 frame()->editor().didBeginEditing();
4224
4225 // eww, I suck. set the qt focus correctly
4226 // ### find a better place in the code for this
4227 if (view()) {
4228 Widget* focusWidget = widgetForElement(m_focusedElement.get());
4229 if (focusWidget) {
4230 // Make sure a widget has the right size before giving it focus.
4231 // Otherwise, we are testing edge cases of the Widget code.
4232 // Specifically, in WebCore this does not work well for text fields.
4233 updateLayout();
4234 // Re-get the widget in case updating the layout changed things.
4235 focusWidget = widgetForElement(m_focusedElement.get());
4236 }
4237 if (focusWidget)
4238 focusWidget->setFocus(true);
4239 else
4240 view()->setFocus(true);
4241 }
4242 }
4243
4244 if (!focusChangeBlocked && m_focusedElement) {
4245 // Create the AXObject cache in a focus change because GTK relies on it.
4246 if (AXObjectCache* cache = axObjectCache())
4247 cache->deferFocusedUIElementChangeIfNeeded(oldFocusedElement.get(), newFocusedElement.get());
4248 }
4249
4250 if (!focusChangeBlocked && page())
4251 page()->chrome().focusedElementChanged(m_focusedElement.get());
4252
4253SetFocusedNodeDone:
4254 // Updating style may dispatch events due to PostResolutionCallback
4255 // FIXME: Why is synchronous style update needed here at all?
4256 if (eventsMode == FocusRemovalEventsMode::Dispatch)
4257 updateStyleIfNeeded();
4258 return !focusChangeBlocked;
4259}
4260
4261static bool shouldResetFocusNavigationStartingNode(Node& node)
4262{
4263 // Setting focus navigation starting node to the following nodes means that we should start
4264 // the search from the beginning of the document.
4265 return is<HTMLHtmlElement>(node) || is<HTMLDocument>(node);
4266}
4267
4268void Document::setFocusNavigationStartingNode(Node* node)
4269{
4270 if (!m_frame)
4271 return;
4272
4273 m_focusNavigationStartingNodeIsRemoved = false;
4274 if (!node || shouldResetFocusNavigationStartingNode(*node)) {
4275 m_focusNavigationStartingNode = nullptr;
4276 return;
4277 }
4278
4279 ASSERT(!node || node != this);
4280 m_focusNavigationStartingNode = node;
4281}
4282
4283Element* Document::focusNavigationStartingNode(FocusDirection direction) const
4284{
4285 if (m_focusedElement) {
4286 if (!m_focusNavigationStartingNode || !m_focusNavigationStartingNode->isDescendantOf(m_focusedElement.get()))
4287 return m_focusedElement.get();
4288 }
4289
4290 if (!m_focusNavigationStartingNode)
4291 return nullptr;
4292
4293 Node* node = m_focusNavigationStartingNode.get();
4294
4295 // When the node was removed from the document tree. This case is not specified in the spec:
4296 // https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation-starting-point
4297 // Current behaivor is to move the sequential navigation node to / after (based on the focus direction)
4298 // the previous sibling of the removed node.
4299 if (m_focusNavigationStartingNodeIsRemoved) {
4300 Node* nextNode = NodeTraversal::next(*node);
4301 if (!nextNode)
4302 nextNode = node;
4303 if (direction == FocusDirectionForward)
4304 return ElementTraversal::previous(*nextNode);
4305 if (is<Element>(*nextNode))
4306 return downcast<Element>(nextNode);
4307 return ElementTraversal::next(*nextNode);
4308 }
4309
4310 if (is<Element>(*node))
4311 return downcast<Element>(node);
4312 if (Element* elementBeforeNextFocusableElement = direction == FocusDirectionForward ? ElementTraversal::previous(*node) : ElementTraversal::next(*node))
4313 return elementBeforeNextFocusableElement;
4314 return node->parentOrShadowHostElement();
4315}
4316
4317void Document::setCSSTarget(Element* targetNode)
4318{
4319 if (m_cssTarget)
4320 m_cssTarget->invalidateStyleForSubtree();
4321 m_cssTarget = targetNode;
4322 if (targetNode)
4323 targetNode->invalidateStyleForSubtree();
4324}
4325
4326void Document::registerNodeListForInvalidation(LiveNodeList& list)
4327{
4328 m_nodeListAndCollectionCounts[list.invalidationType()]++;
4329 if (!list.isRootedAtDocument())
4330 return;
4331 ASSERT(!list.isRegisteredForInvalidationAtDocument());
4332 list.setRegisteredForInvalidationAtDocument(true);
4333 m_listsInvalidatedAtDocument.add(&list);
4334}
4335
4336void Document::unregisterNodeListForInvalidation(LiveNodeList& list)
4337{
4338 m_nodeListAndCollectionCounts[list.invalidationType()]--;
4339 if (!list.isRegisteredForInvalidationAtDocument())
4340 return;
4341
4342 list.setRegisteredForInvalidationAtDocument(false);
4343 ASSERT(m_listsInvalidatedAtDocument.contains(&list));
4344 m_listsInvalidatedAtDocument.remove(&list);
4345}
4346
4347void Document::registerCollection(HTMLCollection& collection)
4348{
4349 m_nodeListAndCollectionCounts[collection.invalidationType()]++;
4350 if (collection.isRootedAtDocument())
4351 m_collectionsInvalidatedAtDocument.add(&collection);
4352}
4353
4354void Document::unregisterCollection(HTMLCollection& collection)
4355{
4356 ASSERT(m_nodeListAndCollectionCounts[collection.invalidationType()]);
4357 m_nodeListAndCollectionCounts[collection.invalidationType()]--;
4358 if (!collection.isRootedAtDocument())
4359 return;
4360
4361 m_collectionsInvalidatedAtDocument.remove(&collection);
4362}
4363
4364void Document::collectionCachedIdNameMap(const HTMLCollection& collection)
4365{
4366 ASSERT_UNUSED(collection, collection.hasNamedElementCache());
4367 m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]++;
4368}
4369
4370void Document::collectionWillClearIdNameMap(const HTMLCollection& collection)
4371{
4372 ASSERT_UNUSED(collection, collection.hasNamedElementCache());
4373 ASSERT(m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]);
4374 m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]--;
4375}
4376
4377void Document::attachNodeIterator(NodeIterator& iterator)
4378{
4379 m_nodeIterators.add(&iterator);
4380}
4381
4382void Document::detachNodeIterator(NodeIterator& iterator)
4383{
4384 // The node iterator can be detached without having been attached if its root node didn't have a document
4385 // when the iterator was created, but has it now.
4386 m_nodeIterators.remove(&iterator);
4387}
4388
4389void Document::moveNodeIteratorsToNewDocumentSlowCase(Node& node, Document& newDocument)
4390{
4391 ASSERT(!m_nodeIterators.isEmpty());
4392 for (auto* iterator : copyToVector(m_nodeIterators)) {
4393 if (&iterator->root() == &node) {
4394 detachNodeIterator(*iterator);
4395 newDocument.attachNodeIterator(*iterator);
4396 }
4397 }
4398}
4399
4400void Document::updateRangesAfterChildrenChanged(ContainerNode& container)
4401{
4402 for (auto* range : m_ranges)
4403 range->nodeChildrenChanged(container);
4404}
4405
4406void Document::nodeChildrenWillBeRemoved(ContainerNode& container)
4407{
4408 ASSERT(ScriptDisallowedScope::InMainThread::hasDisallowedScope());
4409
4410 adjustFocusedNodeOnNodeRemoval(container, NodeRemoval::ChildrenOfNode);
4411 adjustFocusNavigationNodeOnNodeRemoval(container, NodeRemoval::ChildrenOfNode);
4412
4413#if ENABLE(FULLSCREEN_API)
4414 m_fullscreenManager->adjustFullscreenElementOnNodeRemoval(container, NodeRemoval::ChildrenOfNode);
4415#endif
4416
4417 for (auto* range : m_ranges)
4418 range->nodeChildrenWillBeRemoved(container);
4419
4420 for (auto* it : m_nodeIterators) {
4421 for (Node* n = container.firstChild(); n; n = n->nextSibling())
4422 it->nodeWillBeRemoved(*n);
4423 }
4424
4425 if (RefPtr<Frame> frame = this->frame()) {
4426 for (Node* n = container.firstChild(); n; n = n->nextSibling()) {
4427 frame->eventHandler().nodeWillBeRemoved(*n);
4428 frame->selection().nodeWillBeRemoved(*n);
4429 frame->page()->dragCaretController().nodeWillBeRemoved(*n);
4430 }
4431 }
4432
4433 if (m_markers->hasMarkers()) {
4434 for (Text* textNode = TextNodeTraversal::firstChild(container); textNode; textNode = TextNodeTraversal::nextSibling(*textNode))
4435 m_markers->removeMarkers(*textNode);
4436 }
4437}
4438
4439void Document::nodeWillBeRemoved(Node& node)
4440{
4441 ASSERT(ScriptDisallowedScope::InMainThread::hasDisallowedScope());
4442
4443 adjustFocusedNodeOnNodeRemoval(node);
4444 adjustFocusNavigationNodeOnNodeRemoval(node);
4445
4446#if ENABLE(FULLSCREEN_API)
4447 m_fullscreenManager->adjustFullscreenElementOnNodeRemoval(node, NodeRemoval::Node);
4448#endif
4449
4450 for (auto* it : m_nodeIterators)
4451 it->nodeWillBeRemoved(node);
4452
4453 for (auto* range : m_ranges)
4454 range->nodeWillBeRemoved(node);
4455
4456 if (RefPtr<Frame> frame = this->frame()) {
4457 frame->eventHandler().nodeWillBeRemoved(node);
4458 frame->selection().nodeWillBeRemoved(node);
4459 frame->page()->dragCaretController().nodeWillBeRemoved(node);
4460 }
4461
4462 if (is<Text>(node))
4463 m_markers->removeMarkers(node);
4464
4465#if PLATFORM(IOS_FAMILY) && ENABLE(POINTER_EVENTS)
4466 if (m_touchActionElements && is<Element>(node))
4467 m_touchActionElements->remove(&downcast<Element>(node));
4468#endif
4469}
4470
4471static Node* fallbackFocusNavigationStartingNodeAfterRemoval(Node& node)
4472{
4473 return node.previousSibling() ? node.previousSibling() : node.parentNode();
4474}
4475
4476void Document::adjustFocusNavigationNodeOnNodeRemoval(Node& node, NodeRemoval nodeRemoval)
4477{
4478 if (!m_focusNavigationStartingNode)
4479 return;
4480
4481 if (isNodeInSubtree(*m_focusNavigationStartingNode, node, nodeRemoval)) {
4482 auto* newNode = (nodeRemoval == NodeRemoval::ChildrenOfNode) ? &node : fallbackFocusNavigationStartingNodeAfterRemoval(node);
4483 m_focusNavigationStartingNode = (newNode != this) ? newNode : nullptr;
4484 m_focusNavigationStartingNodeIsRemoved = true;
4485 }
4486}
4487
4488void Document::textInserted(Node& text, unsigned offset, unsigned length)
4489{
4490 if (!m_ranges.isEmpty()) {
4491 for (auto* range : m_ranges)
4492 range->textInserted(text, offset, length);
4493 }
4494
4495 // Update the markers for spelling and grammar checking.
4496 m_markers->shiftMarkers(text, offset, length);
4497
4498#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)
4499 // Freshly inserted text is expected to not inherit PlatformTextChecking markers.
4500 m_markers->removeMarkers(text, offset, length, DocumentMarker::PlatformTextChecking);
4501#endif
4502}
4503
4504void Document::textRemoved(Node& text, unsigned offset, unsigned length)
4505{
4506 if (!m_ranges.isEmpty()) {
4507 for (auto* range : m_ranges)
4508 range->textRemoved(text, offset, length);
4509 }
4510
4511 // Update the markers for spelling and grammar checking.
4512 m_markers->removeMarkers(text, offset, length);
4513 m_markers->shiftMarkers(text, offset + length, 0 - length);
4514}
4515
4516void Document::textNodesMerged(Text& oldNode, unsigned offset)
4517{
4518 if (!m_ranges.isEmpty()) {
4519 NodeWithIndex oldNodeWithIndex(&oldNode);
4520 for (auto* range : m_ranges)
4521 range->textNodesMerged(oldNodeWithIndex, offset);
4522 }
4523
4524 // FIXME: This should update markers for spelling and grammar checking.
4525}
4526
4527void Document::textNodeSplit(Text& oldNode)
4528{
4529 for (auto* range : m_ranges)
4530 range->textNodeSplit(oldNode);
4531
4532 // FIXME: This should update markers for spelling and grammar checking.
4533}
4534
4535void Document::createDOMWindow()
4536{
4537 ASSERT(m_frame);
4538 ASSERT(!m_domWindow);
4539
4540 m_domWindow = DOMWindow::create(*this);
4541
4542 ASSERT(m_domWindow->document() == this);
4543 ASSERT(m_domWindow->frame() == m_frame);
4544
4545 m_frame->loader().client().didCreateWindow(*m_domWindow);
4546}
4547
4548void Document::takeDOMWindowFrom(Document& document)
4549{
4550 ASSERT(m_frame);
4551 ASSERT(!m_domWindow);
4552 ASSERT(document.m_domWindow);
4553 // A valid DOMWindow is needed by CachedFrame for its documents.
4554 ASSERT(pageCacheState() == NotInPageCache);
4555
4556 m_domWindow = WTFMove(document.m_domWindow);
4557 m_domWindow->didSecureTransitionTo(*this);
4558
4559 ASSERT(m_domWindow->document() == this);
4560 ASSERT(m_domWindow->frame() == m_frame);
4561}
4562
4563WindowProxy* Document::windowProxy() const
4564{
4565 if (!m_frame)
4566 return nullptr;
4567 return &m_frame->windowProxy();
4568}
4569
4570Document& Document::contextDocument() const
4571{
4572 if (m_contextDocument)
4573 return *m_contextDocument.get();
4574 return const_cast<Document&>(*this);
4575}
4576
4577void Document::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue, DOMWrapperWorld& isolatedWorld)
4578{
4579 setAttributeEventListener(eventType, JSLazyEventListener::create(*this, attributeName, attributeValue), isolatedWorld);
4580}
4581
4582void Document::setWindowAttributeEventListener(const AtomicString& eventType, RefPtr<EventListener>&& listener, DOMWrapperWorld& isolatedWorld)
4583{
4584 if (!m_domWindow)
4585 return;
4586 m_domWindow->setAttributeEventListener(eventType, WTFMove(listener), isolatedWorld);
4587}
4588
4589void Document::setWindowAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue, DOMWrapperWorld& isolatedWorld)
4590{
4591 if (!m_domWindow)
4592 return;
4593 setWindowAttributeEventListener(eventType, JSLazyEventListener::create(*m_domWindow, attributeName, attributeValue), isolatedWorld);
4594}
4595
4596EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld& isolatedWorld)
4597{
4598 if (!m_domWindow)
4599 return nullptr;
4600 return m_domWindow->attributeEventListener(eventType, isolatedWorld);
4601}
4602
4603void Document::dispatchWindowEvent(Event& event, EventTarget* target)
4604{
4605 ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
4606 if (!m_domWindow)
4607 return;
4608 m_domWindow->dispatchEvent(event, target);
4609}
4610
4611void Document::dispatchWindowLoadEvent()
4612{
4613 ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
4614 if (!m_domWindow)
4615 return;
4616 m_domWindow->dispatchLoadEvent();
4617 m_loadEventFinished = true;
4618 m_cachedResourceLoader->documentDidFinishLoadEvent();
4619}
4620
4621void Document::enqueueWindowEvent(Ref<Event>&& event)
4622{
4623 event->setTarget(m_domWindow.get());
4624 m_eventQueue.enqueueEvent(WTFMove(event));
4625}
4626
4627void Document::enqueueDocumentEvent(Ref<Event>&& event)
4628{
4629 event->setTarget(this);
4630 m_eventQueue.enqueueEvent(WTFMove(event));
4631}
4632
4633void Document::enqueueOverflowEvent(Ref<Event>&& event)
4634{
4635 m_eventQueue.enqueueEvent(WTFMove(event));
4636}
4637
4638ExceptionOr<Ref<Event>> Document::createEvent(const String& type)
4639{
4640 // Please do *not* add new event classes to this function unless they are required
4641 // for compatibility with the DOM specification or some actual legacy web content.
4642
4643 // This mechanism is superceded by use of event constructors.
4644 // That is what we should use for any new event classes.
4645
4646 // The following strings are the ones from the DOM specification
4647 // <https://dom.spec.whatwg.org/#dom-document-createevent>.
4648
4649 if (equalLettersIgnoringASCIICase(type, "beforeunloadevent"))
4650 return Ref<Event> { BeforeUnloadEvent::createForBindings() };
4651 if (equalLettersIgnoringASCIICase(type, "compositionevent"))
4652 return Ref<Event> { CompositionEvent::createForBindings() };
4653 if (equalLettersIgnoringASCIICase(type, "customevent"))
4654 return Ref<Event> { CustomEvent::create() };
4655 if (equalLettersIgnoringASCIICase(type, "event") || equalLettersIgnoringASCIICase(type, "events") || equalLettersIgnoringASCIICase(type, "htmlevents") || equalLettersIgnoringASCIICase(type, "svgevents"))
4656 return Event::createForBindings();
4657 if (equalLettersIgnoringASCIICase(type, "focusevent"))
4658 return Ref<Event> { FocusEvent::createForBindings() };
4659 if (equalLettersIgnoringASCIICase(type, "hashchangeevent"))
4660 return Ref<Event> { HashChangeEvent::createForBindings() };
4661 if (equalLettersIgnoringASCIICase(type, "keyboardevent"))
4662 return Ref<Event> { KeyboardEvent::createForBindings() };
4663 if (equalLettersIgnoringASCIICase(type, "messageevent"))
4664 return Ref<Event> { MessageEvent::createForBindings() };
4665 if (equalLettersIgnoringASCIICase(type, "storageevent"))
4666 return Ref<Event> { StorageEvent::createForBindings() };
4667 if (equalLettersIgnoringASCIICase(type, "mouseevent") || equalLettersIgnoringASCIICase(type, "mouseevents"))
4668 return Ref<Event> { MouseEvent::createForBindings() };
4669 if (equalLettersIgnoringASCIICase(type, "textevent"))
4670 return Ref<Event> { TextEvent::createForBindings() }; // FIXME: HTML specification says this should create a CompositionEvent, not a TextEvent.
4671 if (equalLettersIgnoringASCIICase(type, "uievent") || equalLettersIgnoringASCIICase(type, "uievents"))
4672 return Ref<Event> { UIEvent::createForBindings() };
4673
4674 // FIXME: Consider including support for these event classes even when device orientation
4675 // support is not enabled.
4676#if ENABLE(DEVICE_ORIENTATION)
4677 if (equalLettersIgnoringASCIICase(type, "devicemotionevent"))
4678 return Ref<Event> { DeviceMotionEvent::createForBindings() };
4679 if (equalLettersIgnoringASCIICase(type, "deviceorientationevent"))
4680 return Ref<Event> { DeviceOrientationEvent::createForBindings() };
4681#endif
4682
4683#if ENABLE(TOUCH_EVENTS)
4684 if (equalLettersIgnoringASCIICase(type, "touchevent"))
4685 return Ref<Event> { TouchEvent::createForBindings() };
4686#endif
4687
4688 // FIXME: Add support for "dragevent", which the DOM specification calls for.
4689
4690 // The following string comes from the SVG specification
4691 // <http://www.w3.org/TR/SVG/script.html#InterfaceSVGZoomEvent>
4692 // However, since there is no provision for initializing the event once it is created,
4693 // there is no practical value in this feature.
4694 // FIXME: Confirm there is no content depending on this and remove it.
4695
4696 if (equalLettersIgnoringASCIICase(type, "svgzoomevents"))
4697 return Ref<Event> { SVGZoomEvent::createForBindings() };
4698
4699 // The following strings are not part of the DOM specification and we would like to eliminate them.
4700 // However, we currently include them until we resolve any issues with backward compatibility.
4701 // FIXME: For each of the strings below, confirm that there is no content depending on it and remove
4702 // the string, remove the createForBindings function, and also consider removing the corresponding
4703 // init function for that class.
4704
4705 if (equalLettersIgnoringASCIICase(type, "keyboardevents"))
4706 return Ref<Event> { KeyboardEvent::createForBindings() };
4707 if (equalLettersIgnoringASCIICase(type, "mutationevent") || equalLettersIgnoringASCIICase(type, "mutationevents"))
4708 return Ref<Event> { MutationEvent::createForBindings() };
4709 if (equalLettersIgnoringASCIICase(type, "overflowevent"))
4710 return Ref<Event> { OverflowEvent::createForBindings() };
4711 if (equalLettersIgnoringASCIICase(type, "popstateevent"))
4712 return Ref<Event> { PopStateEvent::createForBindings() };
4713 if (equalLettersIgnoringASCIICase(type, "wheelevent"))
4714 return Ref<Event> { WheelEvent::createForBindings() };
4715
4716 return Exception { NotSupportedError };
4717}
4718
4719bool Document::hasListenerTypeForEventType(PlatformEvent::Type eventType) const
4720{
4721 switch (eventType) {
4722 case PlatformEvent::MouseForceChanged:
4723 return m_listenerTypes & Document::FORCECHANGED_LISTENER;
4724 case PlatformEvent::MouseForceDown:
4725 return m_listenerTypes & Document::FORCEDOWN_LISTENER;
4726 case PlatformEvent::MouseForceUp:
4727 return m_listenerTypes & Document::FORCEUP_LISTENER;
4728 case PlatformEvent::MouseScroll:
4729 return m_listenerTypes & Document::SCROLL_LISTENER;
4730 default:
4731 return false;
4732 }
4733}
4734
4735void Document::addListenerTypeIfNeeded(const AtomicString& eventType)
4736{
4737 if (eventType == eventNames().DOMSubtreeModifiedEvent)
4738 addListenerType(DOMSUBTREEMODIFIED_LISTENER);
4739 else if (eventType == eventNames().DOMNodeInsertedEvent)
4740 addListenerType(DOMNODEINSERTED_LISTENER);
4741 else if (eventType == eventNames().DOMNodeRemovedEvent)
4742 addListenerType(DOMNODEREMOVED_LISTENER);
4743 else if (eventType == eventNames().DOMNodeRemovedFromDocumentEvent)
4744 addListenerType(DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
4745 else if (eventType == eventNames().DOMNodeInsertedIntoDocumentEvent)
4746 addListenerType(DOMNODEINSERTEDINTODOCUMENT_LISTENER);
4747 else if (eventType == eventNames().DOMCharacterDataModifiedEvent)
4748 addListenerType(DOMCHARACTERDATAMODIFIED_LISTENER);
4749 else if (eventType == eventNames().overflowchangedEvent)
4750 addListenerType(OVERFLOWCHANGED_LISTENER);
4751 else if (eventType == eventNames().webkitAnimationStartEvent || eventType == eventNames().animationstartEvent)
4752 addListenerType(ANIMATIONSTART_LISTENER);
4753 else if (eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent)
4754 addListenerType(ANIMATIONEND_LISTENER);
4755 else if (eventType == eventNames().webkitAnimationIterationEvent || eventType == eventNames().animationiterationEvent)
4756 addListenerType(ANIMATIONITERATION_LISTENER);
4757 else if (eventType == eventNames().webkitTransitionEndEvent || eventType == eventNames().transitionendEvent)
4758 addListenerType(TRANSITIONEND_LISTENER);
4759 else if (eventType == eventNames().beforeloadEvent)
4760 addListenerType(BEFORELOAD_LISTENER);
4761 else if (eventType == eventNames().scrollEvent)
4762 addListenerType(SCROLL_LISTENER);
4763 else if (eventType == eventNames().webkitmouseforcewillbeginEvent)
4764 addListenerType(FORCEWILLBEGIN_LISTENER);
4765 else if (eventType == eventNames().webkitmouseforcechangedEvent)
4766 addListenerType(FORCECHANGED_LISTENER);
4767 else if (eventType == eventNames().webkitmouseforcedownEvent)
4768 addListenerType(FORCEDOWN_LISTENER);
4769 else if (eventType == eventNames().webkitmouseforceupEvent)
4770 addListenerType(FORCEUP_LISTENER);
4771 else if (eventType == eventNames().resizeEvent)
4772 addListenerType(RESIZE_LISTENER);
4773}
4774
4775HTMLFrameOwnerElement* Document::ownerElement() const
4776{
4777 if (!frame())
4778 return nullptr;
4779 return frame()->ownerElement();
4780}
4781
4782// https://html.spec.whatwg.org/#cookie-averse-document-object
4783bool Document::isCookieAverse() const
4784{
4785 // A Document that has no browsing context is cookie-averse.
4786 if (!frame())
4787 return true;
4788
4789 URL cookieURL = this->cookieURL();
4790
4791 // This is not part of the specification but we have historically allowed cookies over file protocol
4792 // and some developers rely on this for testing.
4793 if (cookieURL.isLocalFile())
4794 return false;
4795
4796 // A Document whose URL's scheme is not a network scheme is cookie-averse (https://fetch.spec.whatwg.org/#network-scheme).
4797 return !cookieURL.protocolIsInHTTPFamily() && !cookieURL.protocolIs("ftp");
4798}
4799
4800ExceptionOr<String> Document::cookie()
4801{
4802 if (page() && !page()->settings().cookieEnabled())
4803 return String();
4804
4805 if (isCookieAverse())
4806 return String();
4807
4808 if (!securityOrigin().canAccessCookies())
4809 return Exception { SecurityError };
4810
4811 URL cookieURL = this->cookieURL();
4812 if (cookieURL.isEmpty())
4813 return String();
4814
4815 if (!isDOMCookieCacheValid() && page())
4816 setCachedDOMCookies(page()->cookieJar().cookies(*this, cookieURL));
4817
4818 return String { cachedDOMCookies() };
4819}
4820
4821ExceptionOr<void> Document::setCookie(const String& value)
4822{
4823 if (page() && !page()->settings().cookieEnabled())
4824 return { };
4825
4826 if (isCookieAverse())
4827 return { };
4828
4829 if (!securityOrigin().canAccessCookies())
4830 return Exception { SecurityError };
4831
4832 URL cookieURL = this->cookieURL();
4833 if (cookieURL.isEmpty())
4834 return { };
4835
4836 invalidateDOMCookieCache();
4837 if (page())
4838 page()->cookieJar().setCookies(*this, cookieURL, value);
4839 return { };
4840}
4841
4842String Document::referrer() const
4843{
4844 if (frame())
4845 return frame()->loader().referrer();
4846 return String();
4847}
4848
4849String Document::origin() const
4850{
4851 return securityOrigin().toString();
4852}
4853
4854String Document::domain() const
4855{
4856 return securityOrigin().domain();
4857}
4858
4859ExceptionOr<void> Document::setDomain(const String& newDomain)
4860{
4861 if (!frame())
4862 return Exception { SecurityError, "A browsing context is required to set a domain." };
4863
4864 if (isSandboxed(SandboxDocumentDomain))
4865 return Exception { SecurityError, "Assignment is forbidden for sandboxed iframes." };
4866
4867 if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin().protocol()))
4868 return Exception { SecurityError };
4869
4870 // FIXME: We should add logging indicating why a domain was not allowed.
4871
4872 const String& effectiveDomain = domain();
4873 if (effectiveDomain.isEmpty())
4874 return Exception { SecurityError, "The document has a null effectiveDomain." };
4875
4876 if (!securityOrigin().isMatchingRegistrableDomainSuffix(newDomain, settings().treatIPAddressAsDomain()))
4877 return Exception { SecurityError, "Attempted to use a non-registrable domain." };
4878
4879 securityOrigin().setDomainFromDOM(newDomain);
4880 return { };
4881}
4882
4883void Document::overrideLastModified(const Optional<WallTime>& lastModified)
4884{
4885 m_overrideLastModified = lastModified;
4886}
4887
4888// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified
4889String Document::lastModified() const
4890{
4891 Optional<WallTime> dateTime;
4892 if (m_overrideLastModified)
4893 dateTime = m_overrideLastModified;
4894 else if (loader())
4895 dateTime = loader()->response().lastModified();
4896
4897 // FIXME: If this document came from the file system, the HTML specification tells
4898 // us to read the last modification date from the file system.
4899 if (!dateTime)
4900 dateTime = WallTime::now();
4901
4902 auto ctime = dateTime.value().secondsSinceEpoch().secondsAs<time_t>();
4903 auto localDateTime = std::localtime(&ctime);
4904 return makeString(pad('0', 2, localDateTime->tm_mon + 1), '/',
4905 pad('0', 2, localDateTime->tm_mday), '/',
4906 pad('0', 4, 1900 + localDateTime->tm_year), ' ',
4907 pad('0', 2, localDateTime->tm_hour), ':',
4908 pad('0', 2, localDateTime->tm_min), ':',
4909 pad('0', 2, localDateTime->tm_sec));
4910}
4911
4912void Document::setCookieURL(const URL& url)
4913{
4914 if (m_cookieURL == url)
4915 return;
4916 m_cookieURL = url;
4917 invalidateDOMCookieCache();
4918}
4919
4920static bool isValidNameNonASCII(const LChar* characters, unsigned length)
4921{
4922 if (!isValidNameStart(characters[0]))
4923 return false;
4924
4925 for (unsigned i = 1; i < length; ++i) {
4926 if (!isValidNamePart(characters[i]))
4927 return false;
4928 }
4929
4930 return true;
4931}
4932
4933static bool isValidNameNonASCII(const UChar* characters, unsigned length)
4934{
4935 unsigned i = 0;
4936
4937 UChar32 c;
4938 U16_NEXT(characters, i, length, c)
4939 if (!isValidNameStart(c))
4940 return false;
4941
4942 while (i < length) {
4943 U16_NEXT(characters, i, length, c)
4944 if (!isValidNamePart(c))
4945 return false;
4946 }
4947
4948 return true;
4949}
4950
4951template<typename CharType>
4952static inline bool isValidNameASCII(const CharType* characters, unsigned length)
4953{
4954 CharType c = characters[0];
4955 if (!(isASCIIAlpha(c) || c == ':' || c == '_'))
4956 return false;
4957
4958 for (unsigned i = 1; i < length; ++i) {
4959 c = characters[i];
4960 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.'))
4961 return false;
4962 }
4963
4964 return true;
4965}
4966
4967bool Document::isValidName(const String& name)
4968{
4969 unsigned length = name.length();
4970 if (!length)
4971 return false;
4972
4973 if (name.is8Bit()) {
4974 const LChar* characters = name.characters8();
4975
4976 if (isValidNameASCII(characters, length))
4977 return true;
4978
4979 return isValidNameNonASCII(characters, length);
4980 }
4981
4982 const UChar* characters = name.characters16();
4983
4984 if (isValidNameASCII(characters, length))
4985 return true;
4986
4987 return isValidNameNonASCII(characters, length);
4988}
4989
4990ExceptionOr<std::pair<AtomicString, AtomicString>> Document::parseQualifiedName(const String& qualifiedName)
4991{
4992 unsigned length = qualifiedName.length();
4993
4994 if (!length)
4995 return Exception { InvalidCharacterError };
4996
4997 bool nameStart = true;
4998 bool sawColon = false;
4999 unsigned colonPosition = 0;
5000
5001 for (unsigned i = 0; i < length; ) {
5002 UChar32 c;
5003 U16_NEXT(qualifiedName, i, length, c)
5004 if (c == ':') {
5005 if (sawColon)
5006 return Exception { InvalidCharacterError };
5007 nameStart = true;
5008 sawColon = true;
5009 colonPosition = i - 1;
5010 } else if (nameStart) {
5011 if (!isValidNameStart(c))
5012 return Exception { InvalidCharacterError };
5013 nameStart = false;
5014 } else {
5015 if (!isValidNamePart(c))
5016 return Exception { InvalidCharacterError };
5017 }
5018 }
5019
5020 if (!sawColon)
5021 return std::pair<AtomicString, AtomicString> { { }, { qualifiedName } };
5022
5023 if (!colonPosition || length - colonPosition <= 1)
5024 return Exception { InvalidCharacterError };
5025
5026 return std::pair<AtomicString, AtomicString> { StringView { qualifiedName }.substring(0, colonPosition).toAtomicString(), StringView { qualifiedName }.substring(colonPosition + 1).toAtomicString() };
5027}
5028
5029ExceptionOr<QualifiedName> Document::parseQualifiedName(const AtomicString& namespaceURI, const String& qualifiedName)
5030{
5031 auto parseResult = parseQualifiedName(qualifiedName);
5032 if (parseResult.hasException())
5033 return parseResult.releaseException();
5034 auto parsedPieces = parseResult.releaseReturnValue();
5035 return QualifiedName { parsedPieces.first, parsedPieces.second, namespaceURI };
5036}
5037
5038void Document::setDecoder(RefPtr<TextResourceDecoder>&& decoder)
5039{
5040 m_decoder = WTFMove(decoder);
5041}
5042
5043URL Document::completeURL(const String& url, const URL& baseURLOverride) const
5044{
5045 // Always return a null URL when passed a null string.
5046 // FIXME: Should we change the URL constructor to have this behavior?
5047 // See also [CSS]StyleSheet::completeURL(const String&)
5048 if (url.isNull())
5049 return URL();
5050 const URL& baseURL = ((baseURLOverride.isEmpty() || baseURLOverride == WTF::blankURL()) && parentDocument()) ? parentDocument()->baseURL() : baseURLOverride;
5051 if (!m_decoder)
5052 return URL(baseURL, url);
5053 return URL(baseURL, url, m_decoder->encodingForURLParsing());
5054}
5055
5056URL Document::completeURL(const String& url) const
5057{
5058 return completeURL(url, m_baseURL);
5059}
5060
5061PAL::SessionID Document::sessionID() const
5062{
5063 if (m_sessionID.isValid())
5064 return m_sessionID;
5065
5066 if (auto* page = this->page())
5067 m_sessionID = page->sessionID();
5068
5069 return m_sessionID;
5070}
5071
5072void Document::setPageCacheState(PageCacheState state)
5073{
5074 if (m_pageCacheState == state)
5075 return;
5076
5077 m_pageCacheState = state;
5078
5079 FrameView* v = view();
5080 Page* page = this->page();
5081
5082 switch (state) {
5083 case InPageCache:
5084 if (v) {
5085 // FIXME: There is some scrolling related work that needs to happen whenever a page goes into the
5086 // page cache and similar work that needs to occur when it comes out. This is where we do the work
5087 // that needs to happen when we enter, and the work that needs to happen when we exit is in
5088 // HistoryController::restoreScrollPositionAndViewState(). It can't be here because this function is
5089 // called too early on in the process of a page exiting the cache for that work to be possible in this
5090 // function. It would be nice if there was more symmetry here.
5091 // https://bugs.webkit.org/show_bug.cgi?id=98698
5092 v->cacheCurrentScrollPosition();
5093 if (page && m_frame->isMainFrame()) {
5094 v->resetScrollbarsAndClearContentsSize();
5095 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
5096 scrollingCoordinator->clearAllNodes();
5097 }
5098 }
5099
5100#if ENABLE(POINTER_LOCK)
5101 exitPointerLock();
5102#endif
5103
5104 styleScope().clearResolver();
5105 clearSelectorQueryCache();
5106 m_styleRecalcTimer.stop();
5107
5108 clearSharedObjectPool();
5109 break;
5110 case NotInPageCache:
5111 if (childNeedsStyleRecalc())
5112 scheduleStyleRecalc();
5113 break;
5114 case AboutToEnterPageCache:
5115 break;
5116 }
5117}
5118
5119void Document::documentWillBecomeInactive()
5120{
5121 if (renderView())
5122 renderView()->setIsInWindow(false);
5123}
5124
5125void Document::suspend(ReasonForSuspension reason)
5126{
5127 if (m_isSuspended)
5128 return;
5129
5130 documentWillBecomeInactive();
5131
5132 for (auto* element : m_documentSuspensionCallbackElements)
5133 element->prepareForDocumentSuspension();
5134
5135#ifndef NDEBUG
5136 // Clear the update flag to be able to check if the viewport arguments update
5137 // is dispatched, after the document is restored from the page cache.
5138 m_didDispatchViewportPropertiesChanged = false;
5139#endif
5140
5141 ASSERT(page());
5142 page()->lockAllOverlayScrollbarsToHidden(true);
5143
5144 if (RenderView* view = renderView()) {
5145 if (view->usesCompositing())
5146 view->compositor().cancelCompositingLayerUpdate();
5147 }
5148
5149#if USE(LIBWEBRTC)
5150 // FIXME: This should be moved to Modules/mediastream.
5151 if (LibWebRTCProvider::webRTCAvailable()) {
5152 if (auto* page = this->page())
5153 page->libWebRTCProvider().unregisterMDNSNames(identifier().toUInt64());
5154 }
5155#endif
5156
5157#if ENABLE(SERVICE_WORKER)
5158 if (RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled() && reason == ReasonForSuspension::PageCache) {
5159 ASSERT_WITH_MESSAGE(!activeServiceWorker(), "Documents with an active service worker should not go into PageCache in the first place");
5160 setServiceWorkerConnection(nullptr);
5161 }
5162#endif
5163
5164 suspendScheduledTasks(reason);
5165
5166 ASSERT(m_frame);
5167 m_frame->clearTimers();
5168
5169 m_visualUpdatesAllowed = false;
5170 m_visualUpdatesSuppressionTimer.stop();
5171
5172 m_isSuspended = true;
5173}
5174
5175void Document::resume(ReasonForSuspension reason)
5176{
5177 if (!m_isSuspended)
5178 return;
5179
5180 for (auto* element : copyToVector(m_documentSuspensionCallbackElements))
5181 element->resumeFromDocumentSuspension();
5182
5183 if (renderView())
5184 renderView()->setIsInWindow(true);
5185
5186 ASSERT(page());
5187 page()->lockAllOverlayScrollbarsToHidden(false);
5188
5189 ASSERT(m_frame);
5190 m_frame->loader().client().dispatchDidBecomeFrameset(isFrameSet());
5191
5192 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
5193 if (auto* timeline = existingTimeline())
5194 timeline->resumeAnimations();
5195 } else
5196 m_frame->animation().resumeAnimationsForDocument(this);
5197
5198 resumeScheduledTasks(reason);
5199
5200 m_visualUpdatesAllowed = true;
5201
5202 m_isSuspended = false;
5203
5204#if ENABLE(SERVICE_WORKER)
5205 if (RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled() && reason == ReasonForSuspension::PageCache) {
5206 ASSERT_WITH_MESSAGE(!activeServiceWorker(), "Documents with an active service worker should not go into PageCache in the first place");
5207 setServiceWorkerConnection(ServiceWorkerProvider::singleton().existingServiceWorkerConnectionForSession(sessionID()));
5208 }
5209#endif
5210}
5211
5212void Document::registerForDocumentSuspensionCallbacks(Element& element)
5213{
5214 m_documentSuspensionCallbackElements.add(&element);
5215}
5216
5217void Document::unregisterForDocumentSuspensionCallbacks(Element& element)
5218{
5219 m_documentSuspensionCallbackElements.remove(&element);
5220}
5221
5222void Document::mediaVolumeDidChange()
5223{
5224 for (auto* element : m_mediaVolumeCallbackElements)
5225 element->mediaVolumeDidChange();
5226}
5227
5228void Document::registerForMediaVolumeCallbacks(Element& element)
5229{
5230 m_mediaVolumeCallbackElements.add(&element);
5231}
5232
5233void Document::unregisterForMediaVolumeCallbacks(Element& element)
5234{
5235 m_mediaVolumeCallbackElements.remove(&element);
5236}
5237
5238bool Document::audioPlaybackRequiresUserGesture() const
5239{
5240 if (DocumentLoader* loader = this->loader()) {
5241 // If an audio playback policy was set during navigation, use it. If not, use the global settings.
5242 AutoplayPolicy policy = loader->autoplayPolicy();
5243 if (policy != AutoplayPolicy::Default)
5244 return policy == AutoplayPolicy::AllowWithoutSound || policy == AutoplayPolicy::Deny;
5245 }
5246
5247 return settings().audioPlaybackRequiresUserGesture();
5248}
5249
5250bool Document::videoPlaybackRequiresUserGesture() const
5251{
5252 if (DocumentLoader* loader = this->loader()) {
5253 // If a video playback policy was set during navigation, use it. If not, use the global settings.
5254 AutoplayPolicy policy = loader->autoplayPolicy();
5255 if (policy != AutoplayPolicy::Default)
5256 return policy == AutoplayPolicy::Deny;
5257 }
5258
5259 return settings().videoPlaybackRequiresUserGesture();
5260}
5261
5262void Document::storageBlockingStateDidChange()
5263{
5264 securityOrigin().setStorageBlockingPolicy(settings().storageBlockingPolicy());
5265}
5266
5267void Document::privateBrowsingStateDidChange()
5268{
5269 m_sessionID = SessionID::emptySessionID();
5270 if (m_logger)
5271 m_logger->setEnabled(this, sessionID().isAlwaysOnLoggingAllowed());
5272
5273 for (auto* element : m_privateBrowsingStateChangedElements)
5274 element->privateBrowsingStateDidChange();
5275
5276#if ENABLE(SERVICE_WORKER)
5277 ASSERT(sessionID().isValid());
5278 if (RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled() && m_serviceWorkerConnection && sessionID().isValid())
5279 setServiceWorkerConnection(&ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(sessionID()));
5280#endif
5281}
5282
5283void Document::registerForPrivateBrowsingStateChangedCallbacks(Element& element)
5284{
5285 m_privateBrowsingStateChangedElements.add(&element);
5286}
5287
5288void Document::unregisterForPrivateBrowsingStateChangedCallbacks(Element& element)
5289{
5290 m_privateBrowsingStateChangedElements.remove(&element);
5291}
5292
5293#if ENABLE(VIDEO_TRACK)
5294
5295void Document::registerForCaptionPreferencesChangedCallbacks(Element& element)
5296{
5297 if (page())
5298 page()->group().captionPreferences().setInterestedInCaptionPreferenceChanges();
5299
5300 m_captionPreferencesChangedElements.add(&element);
5301}
5302
5303void Document::unregisterForCaptionPreferencesChangedCallbacks(Element& element)
5304{
5305 m_captionPreferencesChangedElements.remove(&element);
5306}
5307
5308void Document::captionPreferencesChanged()
5309{
5310 for (auto* element : m_captionPreferencesChangedElements)
5311 element->captionPreferencesChanged();
5312}
5313
5314#endif
5315
5316#if ENABLE(MEDIA_CONTROLS_SCRIPT)
5317
5318void Document::registerForPageScaleFactorChangedCallbacks(HTMLMediaElement& element)
5319{
5320 m_pageScaleFactorChangedElements.add(&element);
5321}
5322
5323void Document::unregisterForPageScaleFactorChangedCallbacks(HTMLMediaElement& element)
5324{
5325 m_pageScaleFactorChangedElements.remove(&element);
5326}
5327
5328void Document::pageScaleFactorChangedAndStable()
5329{
5330 for (HTMLMediaElement* mediaElement : m_pageScaleFactorChangedElements)
5331 mediaElement->pageScaleFactorChanged();
5332}
5333
5334void Document::registerForUserInterfaceLayoutDirectionChangedCallbacks(HTMLMediaElement& element)
5335{
5336 m_userInterfaceLayoutDirectionChangedElements.add(&element);
5337}
5338
5339void Document::unregisterForUserInterfaceLayoutDirectionChangedCallbacks(HTMLMediaElement& element)
5340{
5341 m_userInterfaceLayoutDirectionChangedElements.remove(&element);
5342}
5343
5344void Document::userInterfaceLayoutDirectionChanged()
5345{
5346 for (auto* mediaElement : m_userInterfaceLayoutDirectionChangedElements)
5347 mediaElement->userInterfaceLayoutDirectionChanged();
5348}
5349
5350#endif
5351
5352void Document::setShouldCreateRenderers(bool f)
5353{
5354 m_createRenderers = f;
5355}
5356
5357bool Document::shouldCreateRenderers()
5358{
5359 return m_createRenderers;
5360}
5361
5362// Support for Javascript execCommand, and related methods
5363
5364static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
5365{
5366 RefPtr<Frame> frame = document->frame();
5367 if (!frame || frame->document() != document)
5368 return Editor::Command();
5369
5370 document->updateStyleIfNeeded();
5371
5372 return frame->editor().command(commandName,
5373 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
5374}
5375
5376bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
5377{
5378 EventQueueScope eventQueueScope;
5379 return command(this, commandName, userInterface).execute(value);
5380}
5381
5382bool Document::queryCommandEnabled(const String& commandName)
5383{
5384 return command(this, commandName).isEnabled();
5385}
5386
5387bool Document::queryCommandIndeterm(const String& commandName)
5388{
5389 return command(this, commandName).state() == MixedTriState;
5390}
5391
5392bool Document::queryCommandState(const String& commandName)
5393{
5394 return command(this, commandName).state() == TrueTriState;
5395}
5396
5397bool Document::queryCommandSupported(const String& commandName)
5398{
5399 return command(this, commandName).isSupported();
5400}
5401
5402String Document::queryCommandValue(const String& commandName)
5403{
5404 return command(this, commandName).value();
5405}
5406
5407void Document::pushCurrentScript(HTMLScriptElement* newCurrentScript)
5408{
5409 m_currentScriptStack.append(newCurrentScript);
5410}
5411
5412void Document::popCurrentScript()
5413{
5414 ASSERT(!m_currentScriptStack.isEmpty());
5415 m_currentScriptStack.removeLast();
5416}
5417
5418bool Document::shouldDeferAsynchronousScriptsUntilParsingFinishes() const
5419{
5420 return parsing() && settings().shouldDeferAsynchronousScriptsUntilAfterDocumentLoad();
5421}
5422
5423#if ENABLE(XSLT)
5424
5425void Document::scheduleToApplyXSLTransforms()
5426{
5427 m_hasPendingXSLTransforms = true;
5428 if (!m_applyPendingXSLTransformsTimer.isActive())
5429 m_applyPendingXSLTransformsTimer.startOneShot(0_s);
5430}
5431
5432void Document::applyPendingXSLTransformsNowIfScheduled()
5433{
5434 if (!m_hasPendingXSLTransforms)
5435 return;
5436 m_applyPendingXSLTransformsTimer.stop();
5437 applyPendingXSLTransformsTimerFired();
5438}
5439
5440void Document::applyPendingXSLTransformsTimerFired()
5441{
5442 if (parsing())
5443 return;
5444
5445 m_hasPendingXSLTransforms = false;
5446 ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
5447 for (auto& processingInstruction : styleScope().collectXSLTransforms()) {
5448 ASSERT(processingInstruction->isXSL());
5449
5450 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
5451 if (transformSourceDocument() || !processingInstruction->sheet())
5452 return;
5453
5454 auto processor = XSLTProcessor::create();
5455 processor->setXSLStyleSheet(downcast<XSLStyleSheet>(processingInstruction->sheet()));
5456 String resultMIMEType;
5457 String newSource;
5458 String resultEncoding;
5459 if (!processor->transformToString(*this, resultMIMEType, newSource, resultEncoding))
5460 continue;
5461 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
5462 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
5463 }
5464}
5465
5466void Document::setTransformSource(std::unique_ptr<TransformSource> source)
5467{
5468 m_transformSource = WTFMove(source);
5469}
5470
5471#endif
5472
5473void Document::setDesignMode(InheritedBool value)
5474{
5475 m_designMode = value;
5476 for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree().traverseNext(m_frame))
5477 frame->document()->scheduleFullStyleRebuild();
5478}
5479
5480String Document::designMode() const
5481{
5482 return inDesignMode() ? "on"_s : "off"_s;
5483}
5484
5485void Document::setDesignMode(const String& value)
5486{
5487 InheritedBool mode;
5488 if (equalLettersIgnoringASCIICase(value, "on"))
5489 mode = on;
5490 else if (equalLettersIgnoringASCIICase(value, "off"))
5491 mode = off;
5492 else
5493 mode = inherit;
5494 setDesignMode(mode);
5495}
5496
5497auto Document::getDesignMode() const -> InheritedBool
5498{
5499 return m_designMode;
5500}
5501
5502bool Document::inDesignMode() const
5503{
5504 for (const Document* d = this; d; d = d->parentDocument()) {
5505 if (d->m_designMode != inherit)
5506 return d->m_designMode;
5507 }
5508 return false;
5509}
5510
5511Document* Document::parentDocument() const
5512{
5513 if (!m_frame)
5514 return nullptr;
5515 Frame* parent = m_frame->tree().parent();
5516 if (!parent)
5517 return nullptr;
5518 return parent->document();
5519}
5520
5521Document& Document::topDocument() const
5522{
5523 // FIXME: This special-casing avoids incorrectly determined top documents during the process
5524 // of AXObjectCache teardown or notification posting for cached or being-destroyed documents.
5525 if (pageCacheState() == NotInPageCache && !m_renderTreeBeingDestroyed) {
5526 if (!m_frame)
5527 return const_cast<Document&>(*this);
5528 // This should always be non-null.
5529 Document* mainFrameDocument = m_frame->mainFrame().document();
5530 return mainFrameDocument ? *mainFrameDocument : const_cast<Document&>(*this);
5531 }
5532
5533 Document* document = const_cast<Document*>(this);
5534 while (HTMLFrameOwnerElement* element = document->ownerElement())
5535 document = &element->document();
5536 return *document;
5537}
5538
5539ExceptionOr<Ref<Attr>> Document::createAttribute(const String& name)
5540{
5541 return createAttributeNS({ }, isHTMLDocument() ? name.convertToASCIILowercase() : name, true);
5542}
5543
5544ExceptionOr<Ref<Attr>> Document::createAttributeNS(const AtomicString& namespaceURI, const String& qualifiedName, bool shouldIgnoreNamespaceChecks)
5545{
5546 auto parseResult = parseQualifiedName(namespaceURI, qualifiedName);
5547 if (parseResult.hasException())
5548 return parseResult.releaseException();
5549 QualifiedName parsedName { parseResult.releaseReturnValue() };
5550 if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(parsedName))
5551 return Exception { NamespaceError };
5552 return Attr::create(*this, parsedName, emptyString());
5553}
5554
5555const SVGDocumentExtensions* Document::svgExtensions()
5556{
5557 return m_svgExtensions.get();
5558}
5559
5560SVGDocumentExtensions& Document::accessSVGExtensions()
5561{
5562 if (!m_svgExtensions)
5563 m_svgExtensions = std::make_unique<SVGDocumentExtensions>(*this);
5564 return *m_svgExtensions;
5565}
5566
5567void Document::addSVGUseElement(SVGUseElement& element)
5568{
5569 auto result = m_svgUseElements.add(&element);
5570 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(result.isNewEntry);
5571}
5572
5573void Document::removeSVGUseElement(SVGUseElement& element)
5574{
5575 m_svgUseElements.remove(&element);
5576 // FIXME: Assert that element was in m_svgUseElements once re-entrancy to update style and layout have been removed.
5577}
5578
5579bool Document::hasSVGRootNode() const
5580{
5581 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag);
5582}
5583
5584template <CollectionType collectionType>
5585Ref<HTMLCollection> Document::ensureCachedCollection()
5586{
5587 return ensureRareData().ensureNodeLists().addCachedCollection<GenericCachedHTMLCollection<CollectionTypeTraits<collectionType>::traversalType>>(*this, collectionType);
5588}
5589
5590Ref<HTMLCollection> Document::images()
5591{
5592 return ensureCachedCollection<DocImages>();
5593}
5594
5595Ref<HTMLCollection> Document::applets()
5596{
5597 return ensureCachedCollection<DocApplets>();
5598}
5599
5600Ref<HTMLCollection> Document::embeds()
5601{
5602 return ensureCachedCollection<DocEmbeds>();
5603}
5604
5605Ref<HTMLCollection> Document::plugins()
5606{
5607 // This is an alias for embeds() required for the JS DOM bindings.
5608 return ensureCachedCollection<DocEmbeds>();
5609}
5610
5611Ref<HTMLCollection> Document::scripts()
5612{
5613 return ensureCachedCollection<DocScripts>();
5614}
5615
5616Ref<HTMLCollection> Document::links()
5617{
5618 return ensureCachedCollection<DocLinks>();
5619}
5620
5621Ref<HTMLCollection> Document::forms()
5622{
5623 return ensureCachedCollection<DocForms>();
5624}
5625
5626Ref<HTMLCollection> Document::anchors()
5627{
5628 return ensureCachedCollection<DocAnchors>();
5629}
5630
5631Ref<HTMLCollection> Document::all()
5632{
5633 return ensureRareData().ensureNodeLists().addCachedCollection<HTMLAllCollection>(*this, DocAll);
5634}
5635
5636Ref<HTMLCollection> Document::allFilteredByName(const AtomicString& name)
5637{
5638 return ensureRareData().ensureNodeLists().addCachedCollection<HTMLAllNamedSubCollection>(*this, DocumentAllNamedItems, name);
5639}
5640
5641Ref<HTMLCollection> Document::windowNamedItems(const AtomicString& name)
5642{
5643 return ensureRareData().ensureNodeLists().addCachedCollection<WindowNameCollection>(*this, WindowNamedItems, name);
5644}
5645
5646Ref<HTMLCollection> Document::documentNamedItems(const AtomicString& name)
5647{
5648 return ensureRareData().ensureNodeLists().addCachedCollection<DocumentNameCollection>(*this, DocumentNamedItems, name);
5649}
5650
5651void Document::finishedParsing()
5652{
5653 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
5654 ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
5655 setParsing(false);
5656
5657 Ref<Document> protectedThis(*this);
5658
5659 scriptRunner().documentFinishedParsing();
5660
5661 if (!m_documentTiming.domContentLoadedEventStart)
5662 m_documentTiming.domContentLoadedEventStart = MonotonicTime::now();
5663
5664 // FIXME: Schdule a task to fire DOMContentLoaded event instead. See webkit.org/b/82931
5665 MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint();
5666
5667 dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
5668
5669 if (!m_documentTiming.domContentLoadedEventEnd)
5670 m_documentTiming.domContentLoadedEventEnd = MonotonicTime::now();
5671
5672 if (RefPtr<Frame> frame = this->frame()) {
5673#if ENABLE(XSLT)
5674 applyPendingXSLTransformsNowIfScheduled();
5675#endif
5676
5677 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
5678 // resource loads are complete. HTMLObjectElements can start loading their resources from
5679 // post attach callbacks triggered by resolveStyle(). This means if we parse out an <object>
5680 // tag and then reach the end of the document without updating styles, we might not have yet
5681 // started the resource load and might fire the window load event too early. To avoid this
5682 // we force the styles to be up to date before calling FrameLoader::finishedParsing().
5683 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
5684 updateStyleIfNeeded();
5685
5686 frame->loader().finishedParsing();
5687 InspectorInstrumentation::domContentLoadedEventFired(*frame);
5688 }
5689
5690 // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes
5691 // so that dynamically inserted content can also benefit from sharing optimizations.
5692 // Note that we don't refresh the timer on pool access since that could lead to huge caches being kept
5693 // alive indefinitely by something innocuous like JS setting .innerHTML repeatedly on a timer.
5694 static const Seconds timeToKeepSharedObjectPoolAliveAfterParsingFinished { 10_s };
5695 m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinished);
5696
5697 // Parser should have picked up all speculative preloads by now
5698 m_cachedResourceLoader->clearPreloads(CachedResourceLoader::ClearPreloadsMode::ClearSpeculativePreloads);
5699}
5700
5701void Document::clearSharedObjectPool()
5702{
5703 m_sharedObjectPool = nullptr;
5704 m_sharedObjectPoolClearTimer.stop();
5705}
5706
5707#if ENABLE(TELEPHONE_NUMBER_DETECTION)
5708
5709// FIXME: Find a better place for this code.
5710
5711bool Document::isTelephoneNumberParsingEnabled() const
5712{
5713 return settings().telephoneNumberParsingEnabled() && m_isTelephoneNumberParsingAllowed;
5714}
5715
5716bool Document::isTelephoneNumberParsingAllowed() const
5717{
5718 return m_isTelephoneNumberParsingAllowed;
5719}
5720
5721#endif
5722
5723String Document::originIdentifierForPasteboard()
5724{
5725 auto origin = securityOrigin().toString();
5726 if (origin != "null")
5727 return origin;
5728 if (!m_uniqueIdentifier)
5729 m_uniqueIdentifier = "null:" + createCanonicalUUIDString();
5730 return m_uniqueIdentifier;
5731}
5732
5733ExceptionOr<Ref<XPathExpression>> Document::createExpression(const String& expression, RefPtr<XPathNSResolver>&& resolver)
5734{
5735 if (!m_xpathEvaluator)
5736 m_xpathEvaluator = XPathEvaluator::create();
5737 return m_xpathEvaluator->createExpression(expression, WTFMove(resolver));
5738}
5739
5740Ref<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
5741{
5742 if (!m_xpathEvaluator)
5743 m_xpathEvaluator = XPathEvaluator::create();
5744 return m_xpathEvaluator->createNSResolver(nodeResolver);
5745}
5746
5747ExceptionOr<Ref<XPathResult>> Document::evaluate(const String& expression, Node* contextNode, RefPtr<XPathNSResolver>&& resolver, unsigned short type, XPathResult* result)
5748{
5749 if (!m_xpathEvaluator)
5750 m_xpathEvaluator = XPathEvaluator::create();
5751 return m_xpathEvaluator->evaluate(expression, contextNode, WTFMove(resolver), type, result);
5752}
5753
5754void Document::initSecurityContext()
5755{
5756 if (haveInitializedSecurityOrigin()) {
5757 ASSERT(SecurityContext::securityOrigin());
5758 return;
5759 }
5760
5761 if (!m_frame) {
5762 // No source for a security context.
5763 // This can occur via document.implementation.createDocument().
5764 setCookieURL(URL({ }, emptyString()));
5765 setSecurityOriginPolicy(SecurityOriginPolicy::create(SecurityOrigin::createUnique()));
5766 setContentSecurityPolicy(std::make_unique<ContentSecurityPolicy>(URL { { }, emptyString() }, *this));
5767 return;
5768 }
5769
5770 // In the common case, create the security context from the currently
5771 // loading URL with a fresh content security policy.
5772 setCookieURL(m_url);
5773 enforceSandboxFlags(m_frame->loader().effectiveSandboxFlags());
5774 setReferrerPolicy(m_frame->loader().effectiveReferrerPolicy());
5775
5776 if (shouldEnforceContentDispositionAttachmentSandbox())
5777 applyContentDispositionAttachmentSandbox();
5778
5779 auto* documentLoader = m_frame->loader().documentLoader();
5780 bool isSecurityOriginUnique = isSandboxed(SandboxOrigin);
5781 if (!isSecurityOriginUnique)
5782 isSecurityOriginUnique = documentLoader && documentLoader->response().tainting() == ResourceResponse::Tainting::Opaque;
5783
5784 setSecurityOriginPolicy(SecurityOriginPolicy::create(isSecurityOriginUnique ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url)));
5785 setContentSecurityPolicy(std::make_unique<ContentSecurityPolicy>(URL { m_url }, *this));
5786
5787 String overrideContentSecurityPolicy = m_frame->loader().client().overrideContentSecurityPolicy();
5788 if (!overrideContentSecurityPolicy.isNull())
5789 contentSecurityPolicy()->didReceiveHeader(overrideContentSecurityPolicy, ContentSecurityPolicyHeaderType::Enforce, ContentSecurityPolicy::PolicyFrom::API, referrer(), documentLoader ? documentLoader->response().httpStatusCode() : 0);
5790
5791#if USE(QUICK_LOOK)
5792 if (shouldEnforceQuickLookSandbox())
5793 applyQuickLookSandbox();
5794#endif
5795
5796 if (shouldEnforceHTTP09Sandbox()) {
5797 String message = makeString("Sandboxing '", m_url.stringCenterEllipsizedToLength(), "' because it is using HTTP/0.9.");
5798 addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
5799 enforceSandboxFlags(SandboxScripts | SandboxPlugins);
5800 }
5801
5802 if (settings().needsStorageAccessFromFileURLsQuirk())
5803 securityOrigin().grantStorageAccessFromFileURLsQuirk();
5804 if (!settings().webSecurityEnabled()) {
5805 // Web security is turned off. We should let this document access every other document. This is used primary by testing
5806 // harnesses for web sites.
5807 securityOrigin().grantUniversalAccess();
5808 } else if (securityOrigin().isLocal()) {
5809 if (settings().allowUniversalAccessFromFileURLs() || m_frame->loader().client().shouldForceUniversalAccessFromLocalURL(m_url)) {
5810 // Some clients want local URLs to have universal access, but that setting is dangerous for other clients.
5811 securityOrigin().grantUniversalAccess();
5812 } else if (!settings().allowFileAccessFromFileURLs()) {
5813 // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files.
5814 // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files
5815 // still can have other privileges that can be remembered, thereby not making them unique origins.
5816 securityOrigin().setEnforcesFilePathSeparation();
5817 }
5818 }
5819 securityOrigin().setStorageBlockingPolicy(settings().storageBlockingPolicy());
5820
5821 Document* parentDocument = ownerElement() ? &ownerElement()->document() : nullptr;
5822 if (parentDocument && m_frame->loader().shouldTreatURLAsSrcdocDocument(url())) {
5823 m_isSrcdocDocument = true;
5824 setBaseURLOverride(parentDocument->baseURL());
5825 }
5826 if (parentDocument)
5827 setStrictMixedContentMode(parentDocument->isStrictMixedContentMode());
5828
5829 if (!SecurityPolicy::shouldInheritSecurityOriginFromOwner(m_url))
5830 return;
5831
5832 // If we do not obtain a meaningful origin from the URL, then we try to
5833 // find one via the frame hierarchy.
5834 Frame* parentFrame = m_frame->tree().parent();
5835 Frame* openerFrame = m_frame->loader().opener();
5836
5837 Frame* ownerFrame = parentFrame;
5838 if (!ownerFrame)
5839 ownerFrame = openerFrame;
5840
5841 if (!ownerFrame) {
5842 didFailToInitializeSecurityOrigin();
5843 return;
5844 }
5845
5846 Document* openerDocument = openerFrame ? openerFrame->document() : nullptr;
5847
5848 // Per <http://www.w3.org/TR/upgrade-insecure-requests/>, new browsing contexts must inherit from an
5849 // ongoing set of upgraded requests. When opening a new browsing context, we need to capture its
5850 // existing upgrade request. Nested browsing contexts are handled during DocumentWriter::begin.
5851 if (openerDocument)
5852 contentSecurityPolicy()->inheritInsecureNavigationRequestsToUpgradeFromOpener(*openerDocument->contentSecurityPolicy());
5853
5854 if (isSandboxed(SandboxOrigin)) {
5855 // If we're supposed to inherit our security origin from our owner,
5856 // but we're also sandboxed, the only thing we inherit is the ability
5857 // to load local resources. This lets about:blank iframes in file://
5858 // URL documents load images and other resources from the file system.
5859 if (ownerFrame->document()->securityOrigin().canLoadLocalResources())
5860 securityOrigin().grantLoadLocalResources();
5861 return;
5862 }
5863
5864 setCookieURL(ownerFrame->document()->cookieURL());
5865 // We alias the SecurityOrigins to match Firefox, see Bug 15313
5866 // https://bugs.webkit.org/show_bug.cgi?id=15313
5867 setSecurityOriginPolicy(ownerFrame->document()->securityOriginPolicy());
5868}
5869
5870bool Document::shouldInheritContentSecurityPolicyFromOwner() const
5871{
5872 ASSERT(m_frame);
5873 if (SecurityPolicy::shouldInheritSecurityOriginFromOwner(m_url))
5874 return true;
5875 if (!isPluginDocument())
5876 return false;
5877 if (m_frame->tree().parent())
5878 return true;
5879 Frame* openerFrame = m_frame->loader().opener();
5880 if (!openerFrame)
5881 return false;
5882 return openerFrame->document()->securityOrigin().canAccess(securityOrigin());
5883}
5884
5885void Document::initContentSecurityPolicy()
5886{
5887 // 1. Inherit Upgrade Insecure Requests
5888 Frame* parentFrame = m_frame->tree().parent();
5889 if (parentFrame)
5890 contentSecurityPolicy()->copyUpgradeInsecureRequestStateFrom(*parentFrame->document()->contentSecurityPolicy());
5891
5892 // 2. Inherit Content Security Policy (without copying Upgrade Insecure Requests state).
5893 if (!shouldInheritContentSecurityPolicyFromOwner())
5894 return;
5895 Frame* ownerFrame = parentFrame;
5896 if (!ownerFrame)
5897 ownerFrame = m_frame->loader().opener();
5898 if (!ownerFrame)
5899 return;
5900 // FIXME: The CSP 3 spec. implies that only plugin documents delivered with a local scheme (e.g. blob, file, data)
5901 // should inherit a policy.
5902 if (isPluginDocument() && m_frame->loader().opener())
5903 contentSecurityPolicy()->createPolicyForPluginDocumentFrom(*ownerFrame->document()->contentSecurityPolicy());
5904 else
5905 contentSecurityPolicy()->copyStateFrom(ownerFrame->document()->contentSecurityPolicy());
5906}
5907
5908bool Document::isContextThread() const
5909{
5910 return isMainThread();
5911}
5912
5913bool Document::isSecureContext() const
5914{
5915 if (!m_frame)
5916 return true;
5917 if (!securityOrigin().isPotentiallyTrustworthy())
5918 return false;
5919 for (Frame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
5920 if (!frame->document()->securityOrigin().isPotentiallyTrustworthy())
5921 return false;
5922 }
5923 return true;
5924}
5925
5926void Document::updateURLForPushOrReplaceState(const URL& url)
5927{
5928 Frame* f = frame();
5929 if (!f)
5930 return;
5931
5932 setURL(url);
5933 f->loader().setOutgoingReferrer(url);
5934
5935 if (DocumentLoader* documentLoader = loader())
5936 documentLoader->replaceRequestURLForSameDocumentNavigation(url);
5937}
5938
5939void Document::statePopped(Ref<SerializedScriptValue>&& stateObject)
5940{
5941 if (!frame())
5942 return;
5943
5944 // Per step 11 of section 6.5.9 (history traversal) of the HTML5 spec, we
5945 // defer firing of popstate until we're in the complete state.
5946 if (m_readyState == Complete)
5947 dispatchPopstateEvent(WTFMove(stateObject));
5948 else
5949 m_pendingStateObject = WTFMove(stateObject);
5950}
5951
5952void Document::attachRange(Range& range)
5953{
5954 ASSERT(!m_ranges.contains(&range));
5955 m_ranges.add(&range);
5956}
5957
5958void Document::detachRange(Range& range)
5959{
5960 // We don't ASSERT m_ranges.contains(&range) to allow us to call this
5961 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044
5962 m_ranges.remove(&range);
5963}
5964
5965Optional<RenderingContext> Document::getCSSCanvasContext(const String& type, const String& name, int width, int height)
5966{
5967 HTMLCanvasElement* element = getCSSCanvasElement(name);
5968 if (!element)
5969 return WTF::nullopt;
5970 element->setSize({ width, height });
5971 auto context = element->getContext(type);
5972 if (!context)
5973 return WTF::nullopt;
5974
5975#if ENABLE(WEBGL)
5976 if (is<WebGLRenderingContext>(*context))
5977 return RenderingContext { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*context) } };
5978#endif
5979#if ENABLE(WEBGL2)
5980 if (is<WebGL2RenderingContext>(*context))
5981 return RenderingContext { RefPtr<WebGL2RenderingContext> { &downcast<WebGL2RenderingContext>(*context) } };
5982#endif
5983#if ENABLE(WEBGPU)
5984 if (is<GPUCanvasContext>(*context))
5985 return RenderingContext { RefPtr<GPUCanvasContext> { &downcast<GPUCanvasContext>(*context) } };
5986#endif
5987
5988 return RenderingContext { RefPtr<CanvasRenderingContext2D> { &downcast<CanvasRenderingContext2D>(*context) } };
5989}
5990
5991HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
5992{
5993 RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, nullptr).iterator->value;
5994 if (!element)
5995 element = HTMLCanvasElement::create(*this);
5996 return element.get();
5997}
5998
5999String Document::nameForCSSCanvasElement(const HTMLCanvasElement& canvasElement) const
6000{
6001 for (const auto& entry : m_cssCanvasElements) {
6002 if (entry.value.get() == &canvasElement)
6003 return entry.key;
6004 }
6005 return String();
6006}
6007
6008#if ENABLE(TEXT_AUTOSIZING)
6009TextAutoSizing& Document::textAutoSizing()
6010{
6011 if (!m_textAutoSizing)
6012 m_textAutoSizing = std::make_unique<TextAutoSizing>();
6013 return *m_textAutoSizing;
6014}
6015#endif // ENABLE(TEXT_AUTOSIZING)
6016
6017void Document::initDNSPrefetch()
6018{
6019 m_haveExplicitlyDisabledDNSPrefetch = false;
6020 m_isDNSPrefetchEnabled = settings().dnsPrefetchingEnabled() && securityOrigin().protocol() == "http";
6021
6022 // Inherit DNS prefetch opt-out from parent frame
6023 if (Document* parent = parentDocument()) {
6024 if (!parent->isDNSPrefetchEnabled())
6025 m_isDNSPrefetchEnabled = false;
6026 }
6027}
6028
6029void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl)
6030{
6031 if (!settings().dnsPrefetchingEnabled())
6032 return;
6033
6034 if (equalLettersIgnoringASCIICase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) {
6035 m_isDNSPrefetchEnabled = true;
6036 return;
6037 }
6038
6039 m_isDNSPrefetchEnabled = false;
6040 m_haveExplicitlyDisabledDNSPrefetch = true;
6041}
6042
6043void Document::getParserLocation(String& completedURL, unsigned& line, unsigned& column) const
6044{
6045 // We definitely cannot associate the message with a location being parsed if we are not even parsing.
6046 if (!parsing())
6047 return;
6048
6049 ScriptableDocumentParser* parser = scriptableDocumentParser();
6050 if (!parser)
6051 return;
6052
6053 // When the parser waits for scripts, any messages must be coming from some other source, and are not related to the location of the script element that made the parser wait.
6054 if (!parser->shouldAssociateConsoleMessagesWithTextPosition())
6055 return;
6056
6057 completedURL = url().string();
6058 TextPosition position = parser->textPosition();
6059 line = position.m_line.oneBasedInt();
6060 column = position.m_column.oneBasedInt();
6061}
6062
6063void Document::addConsoleMessage(std::unique_ptr<Inspector::ConsoleMessage>&& consoleMessage)
6064{
6065 if (!isContextThread()) {
6066 postTask(AddConsoleMessageTask(WTFMove(consoleMessage)));
6067 return;
6068 }
6069
6070 if (Page* page = this->page())
6071 page->console().addMessage(WTFMove(consoleMessage));
6072}
6073
6074void Document::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
6075{
6076 if (!isContextThread()) {
6077 postTask(AddConsoleMessageTask(source, level, message));
6078 return;
6079 }
6080
6081 if (Page* page = this->page())
6082 page->console().addMessage(source, level, message, requestIdentifier, this);
6083
6084 if (m_consoleMessageListener)
6085 m_consoleMessageListener->scheduleCallback(*this, message);
6086}
6087
6088void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<Inspector::ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
6089{
6090 if (!isContextThread()) {
6091 postTask(AddConsoleMessageTask(source, level, message));
6092 return;
6093 }
6094
6095 if (Page* page = this->page())
6096 page->console().addMessage(source, level, message, sourceURL, lineNumber, columnNumber, WTFMove(callStack), state, requestIdentifier);
6097}
6098
6099void Document::postTask(Task&& task)
6100{
6101 callOnMainThread([documentReference = makeWeakPtr(*this), task = WTFMove(task)]() mutable {
6102 ASSERT(isMainThread());
6103
6104 Document* document = documentReference.get();
6105 if (!document)
6106 return;
6107
6108 Page* page = document->page();
6109 if ((page && page->defersLoading() && document->activeDOMObjectsAreSuspended()) || !document->m_pendingTasks.isEmpty())
6110 document->m_pendingTasks.append(WTFMove(task));
6111 else
6112 task.performTask(*document);
6113 });
6114}
6115
6116void Document::pendingTasksTimerFired()
6117{
6118 Vector<Task> pendingTasks = WTFMove(m_pendingTasks);
6119 for (auto& task : pendingTasks)
6120 task.performTask(*this);
6121}
6122
6123void Document::suspendScheduledTasks(ReasonForSuspension reason)
6124{
6125 if (m_scheduledTasksAreSuspended) {
6126 // A page may subsequently suspend DOM objects, say as part of handling a scroll or zoom gesture, after the
6127 // embedding client requested the page be suspended. We ignore such requests so long as the embedding client
6128 // requested the suspension first. See <rdar://problem/13754896> for more details.
6129 ASSERT(reasonForSuspendingActiveDOMObjects() == ReasonForSuspension::PageWillBeSuspended);
6130 return;
6131 }
6132
6133 suspendScriptedAnimationControllerCallbacks();
6134 suspendActiveDOMObjects(reason);
6135 scriptRunner().suspend();
6136 m_pendingTasksTimer.stop();
6137
6138#if ENABLE(XSLT)
6139 m_applyPendingXSLTransformsTimer.stop();
6140#endif
6141
6142 // Deferring loading and suspending parser is necessary when we need to prevent re-entrant JavaScript execution
6143 // (e.g. while displaying an alert).
6144 // It is not currently possible to suspend parser unless loading is deferred, because new data arriving from network
6145 // will trigger parsing, and leave the scheduler in an inconsistent state where it doesn't know whether it's suspended or not.
6146 if (reason == ReasonForSuspension::WillDeferLoading && m_parser)
6147 m_parser->suspendScheduledTasks();
6148
6149 m_scheduledTasksAreSuspended = true;
6150}
6151
6152void Document::resumeScheduledTasks(ReasonForSuspension reason)
6153{
6154 if (reasonForSuspendingActiveDOMObjects() != reason)
6155 return;
6156
6157 ASSERT(m_scheduledTasksAreSuspended);
6158
6159 if (reason == ReasonForSuspension::WillDeferLoading && m_parser)
6160 m_parser->resumeScheduledTasks();
6161
6162#if ENABLE(XSLT)
6163 if (m_hasPendingXSLTransforms)
6164 m_applyPendingXSLTransformsTimer.startOneShot(0_s);
6165#endif
6166
6167 if (!m_pendingTasks.isEmpty())
6168 m_pendingTasksTimer.startOneShot(0_s);
6169 scriptRunner().resume();
6170 resumeActiveDOMObjects(reason);
6171 resumeScriptedAnimationControllerCallbacks();
6172
6173 m_scheduledTasksAreSuspended = false;
6174}
6175
6176void Document::suspendScriptedAnimationControllerCallbacks()
6177{
6178 if (m_scriptedAnimationController)
6179 m_scriptedAnimationController->suspend();
6180}
6181
6182void Document::resumeScriptedAnimationControllerCallbacks()
6183{
6184 if (m_scriptedAnimationController)
6185 m_scriptedAnimationController->resume();
6186}
6187
6188void Document::updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp)
6189{
6190 if (m_timeline)
6191 m_timeline->updateAnimationsAndSendEvents(timestamp);
6192}
6193
6194void Document::serviceRequestAnimationFrameCallbacks(DOMHighResTimeStamp timestamp)
6195{
6196 if (m_scriptedAnimationController)
6197 m_scriptedAnimationController->serviceRequestAnimationFrameCallbacks(timestamp);
6198}
6199
6200void Document::windowScreenDidChange(PlatformDisplayID displayID)
6201{
6202 if (RenderView* view = renderView()) {
6203 if (view->usesCompositing())
6204 view->compositor().windowScreenDidChange(displayID);
6205 }
6206}
6207
6208String Document::displayStringModifiedByEncoding(const String& string) const
6209{
6210 if (!m_decoder)
6211 return string;
6212 return String { string }.replace('\\', m_decoder->encoding().backslashAsCurrencySymbol());
6213}
6214
6215void Document::dispatchPageshowEvent(PageshowEventPersistence persisted)
6216{
6217 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously.
6218 dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, persisted), this);
6219}
6220
6221void Document::enqueueSecurityPolicyViolationEvent(SecurityPolicyViolationEvent::Init&& eventInit)
6222{
6223 enqueueDocumentEvent(SecurityPolicyViolationEvent::create(eventNames().securitypolicyviolationEvent, WTFMove(eventInit), Event::IsTrusted::Yes));
6224}
6225
6226void Document::enqueueHashchangeEvent(const String& oldURL, const String& newURL)
6227{
6228 enqueueWindowEvent(HashChangeEvent::create(oldURL, newURL));
6229}
6230
6231void Document::dispatchPopstateEvent(RefPtr<SerializedScriptValue>&& stateObject)
6232{
6233 dispatchWindowEvent(PopStateEvent::create(WTFMove(stateObject), m_domWindow ? &m_domWindow->history() : nullptr));
6234}
6235
6236void Document::addMediaCanStartListener(MediaCanStartListener& listener)
6237{
6238 ASSERT(!m_mediaCanStartListeners.contains(&listener));
6239 m_mediaCanStartListeners.add(&listener);
6240}
6241
6242void Document::removeMediaCanStartListener(MediaCanStartListener& listener)
6243{
6244 ASSERT(m_mediaCanStartListeners.contains(&listener));
6245 m_mediaCanStartListeners.remove(&listener);
6246}
6247
6248MediaCanStartListener* Document::takeAnyMediaCanStartListener()
6249{
6250 return m_mediaCanStartListeners.takeAny();
6251}
6252
6253#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
6254
6255DeviceMotionController& Document::deviceMotionController() const
6256{
6257 return *m_deviceMotionController;
6258}
6259
6260DeviceOrientationController& Document::deviceOrientationController() const
6261{
6262 return *m_deviceOrientationController;
6263}
6264
6265void Document::simulateDeviceOrientationChange(double alpha, double beta, double gamma)
6266{
6267 auto orientation = DeviceOrientationData::create(alpha, beta, gamma, WTF::nullopt, WTF::nullopt);
6268 deviceOrientationController().didChangeDeviceOrientation(orientation.ptr());
6269}
6270
6271#endif
6272
6273#if ENABLE(POINTER_LOCK)
6274
6275void Document::exitPointerLock()
6276{
6277 Page* page = this->page();
6278 if (!page)
6279 return;
6280 if (auto* target = page->pointerLockController().element()) {
6281 if (&target->document() != this)
6282 return;
6283 }
6284 page->pointerLockController().requestPointerUnlock();
6285}
6286
6287#endif
6288
6289void Document::decrementLoadEventDelayCount()
6290{
6291 ASSERT(m_loadEventDelayCount);
6292 --m_loadEventDelayCount;
6293
6294 if (frame() && !m_loadEventDelayCount && !m_loadEventDelayTimer.isActive())
6295 m_loadEventDelayTimer.startOneShot(0_s);
6296}
6297
6298void Document::loadEventDelayTimerFired()
6299{
6300 // FIXME: Should the call to FrameLoader::checkLoadComplete be moved inside Document::checkCompleted?
6301 // FIXME: Should this also call DocumentLoader::checkLoadComplete?
6302 // FIXME: Not obvious why checkCompleted needs to go first. The order these are called is
6303 // visible to WebKit clients, but it's more like a race than a well-defined relationship.
6304 Ref<Document> protectedThis(*this);
6305 checkCompleted();
6306 if (auto* frame = this->frame())
6307 frame->loader().checkLoadComplete();
6308}
6309
6310void Document::checkCompleted()
6311{
6312 if (auto* frame = this->frame())
6313 frame->loader().checkCompleted();
6314}
6315
6316double Document::monotonicTimestamp() const
6317{
6318 auto* loader = this->loader();
6319 if (!loader)
6320 return 0;
6321
6322 return loader->timing().secondsSinceStartTime(MonotonicTime::now()).seconds();
6323}
6324
6325int Document::requestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback)
6326{
6327 if (!m_scriptedAnimationController) {
6328 m_scriptedAnimationController = ScriptedAnimationController::create(*this);
6329
6330 // It's possible that the Page may have suspended scripted animations before
6331 // we were created. We need to make sure that we don't start up the animation
6332 // controller on a background tab, for example.
6333 if (!page() || page()->scriptedAnimationsSuspended())
6334 m_scriptedAnimationController->suspend();
6335
6336 if (page() && page()->isLowPowerModeEnabled())
6337 m_scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::LowPowerMode);
6338
6339 if (!topOrigin().canAccess(securityOrigin()) && !hasHadUserInteraction())
6340 m_scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::NonInteractedCrossOriginFrame);
6341 }
6342
6343 return m_scriptedAnimationController->registerCallback(WTFMove(callback));
6344}
6345
6346void Document::cancelAnimationFrame(int id)
6347{
6348 if (!m_scriptedAnimationController)
6349 return;
6350 m_scriptedAnimationController->cancelCallback(id);
6351}
6352
6353void Document::clearScriptedAnimationController()
6354{
6355 // FIXME: consider using ActiveDOMObject.
6356 if (m_scriptedAnimationController)
6357 m_scriptedAnimationController->clearDocumentPointer();
6358 m_scriptedAnimationController = nullptr;
6359}
6360
6361void Document::wheelEventHandlersChanged()
6362{
6363 Page* page = this->page();
6364 if (!page)
6365 return;
6366
6367 if (FrameView* frameView = view()) {
6368 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
6369 scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
6370 }
6371
6372 bool haveHandlers = m_wheelEventTargets && !m_wheelEventTargets->isEmpty();
6373 page->chrome().client().wheelEventHandlersChanged(haveHandlers);
6374}
6375
6376void Document::didAddWheelEventHandler(Node& node)
6377{
6378 if (!m_wheelEventTargets)
6379 m_wheelEventTargets = std::make_unique<EventTargetSet>();
6380
6381 m_wheelEventTargets->add(&node);
6382
6383 wheelEventHandlersChanged();
6384
6385 if (Frame* frame = this->frame())
6386 DebugPageOverlays::didChangeEventHandlers(*frame);
6387}
6388
6389HttpEquivPolicy Document::httpEquivPolicy() const
6390{
6391 if (shouldEnforceContentDispositionAttachmentSandbox())
6392 return HttpEquivPolicy::DisabledByContentDispositionAttachmentSandbox;
6393 if (page() && !page()->settings().httpEquivEnabled())
6394 return HttpEquivPolicy::DisabledBySettings;
6395 return HttpEquivPolicy::Enabled;
6396}
6397
6398static bool removeHandlerFromSet(EventTargetSet& handlerSet, Node& node, EventHandlerRemoval removal)
6399{
6400 switch (removal) {
6401 case EventHandlerRemoval::One:
6402 return handlerSet.remove(&node);
6403 case EventHandlerRemoval::All:
6404 return handlerSet.removeAll(&node);
6405 }
6406 return false;
6407}
6408
6409void Document::didRemoveWheelEventHandler(Node& node, EventHandlerRemoval removal)
6410{
6411 if (!m_wheelEventTargets)
6412 return;
6413
6414 if (!removeHandlerFromSet(*m_wheelEventTargets, node, removal))
6415 return;
6416
6417 wheelEventHandlersChanged();
6418
6419 if (Frame* frame = this->frame())
6420 DebugPageOverlays::didChangeEventHandlers(*frame);
6421}
6422
6423unsigned Document::wheelEventHandlerCount() const
6424{
6425 if (!m_wheelEventTargets)
6426 return 0;
6427
6428 unsigned count = 0;
6429 for (auto& handler : *m_wheelEventTargets)
6430 count += handler.value;
6431
6432 return count;
6433}
6434
6435void Document::didAddTouchEventHandler(Node& handler)
6436{
6437#if ENABLE(TOUCH_EVENTS)
6438 if (!m_touchEventTargets)
6439 m_touchEventTargets = std::make_unique<EventTargetSet>();
6440
6441 m_touchEventTargets->add(&handler);
6442
6443 if (Document* parent = parentDocument()) {
6444 parent->didAddTouchEventHandler(*this);
6445 return;
6446 }
6447#else
6448 UNUSED_PARAM(handler);
6449#endif
6450}
6451
6452void Document::didRemoveTouchEventHandler(Node& handler, EventHandlerRemoval removal)
6453{
6454#if ENABLE(TOUCH_EVENTS)
6455 if (!m_touchEventTargets)
6456 return;
6457
6458 removeHandlerFromSet(*m_touchEventTargets, handler, removal);
6459
6460 if (Document* parent = parentDocument())
6461 parent->didRemoveTouchEventHandler(*this);
6462#else
6463 UNUSED_PARAM(handler);
6464 UNUSED_PARAM(removal);
6465#endif
6466}
6467
6468void Document::didRemoveEventTargetNode(Node& handler)
6469{
6470#if ENABLE(TOUCH_EVENTS)
6471 if (m_touchEventTargets) {
6472 m_touchEventTargets->removeAll(&handler);
6473 if ((&handler == this || m_touchEventTargets->isEmpty()) && parentDocument())
6474 parentDocument()->didRemoveEventTargetNode(*this);
6475 }
6476#endif
6477
6478 if (m_wheelEventTargets) {
6479 m_wheelEventTargets->removeAll(&handler);
6480 if ((&handler == this || m_wheelEventTargets->isEmpty()) && parentDocument())
6481 parentDocument()->didRemoveEventTargetNode(*this);
6482 }
6483}
6484
6485unsigned Document::touchEventHandlerCount() const
6486{
6487#if ENABLE(TOUCH_EVENTS)
6488 if (!m_touchEventTargets)
6489 return 0;
6490
6491 unsigned count = 0;
6492 for (auto& handler : *m_touchEventTargets)
6493 count += handler.value;
6494
6495 return count;
6496#else
6497 return 0;
6498#endif
6499}
6500
6501LayoutRect Document::absoluteEventHandlerBounds(bool& includesFixedPositionElements)
6502{
6503 includesFixedPositionElements = false;
6504 if (RenderView* renderView = this->renderView())
6505 return renderView->documentRect();
6506
6507 return LayoutRect();
6508}
6509
6510Document::RegionFixedPair Document::absoluteEventRegionForNode(Node& node)
6511{
6512 Region region;
6513 LayoutRect rootRelativeBounds;
6514 bool insideFixedPosition = false;
6515
6516 if (is<Document>(node)) {
6517 auto& document = downcast<Document>(node);
6518 if (&document == this)
6519 rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
6520 else if (Element* element = document.ownerElement())
6521 rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
6522 } else if (is<Element>(node)) {
6523 auto& element = downcast<Element>(node);
6524 if (is<HTMLBodyElement>(element)) {
6525 // For the body, just use the document bounds.
6526 // The body may not cover this whole area, but it's OK for this region to be an overestimate.
6527 rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
6528 } else
6529 rootRelativeBounds = element.absoluteEventHandlerBounds(insideFixedPosition);
6530 }
6531
6532 if (!rootRelativeBounds.isEmpty())
6533 region.unite(Region(enclosingIntRect(rootRelativeBounds)));
6534
6535 return RegionFixedPair(region, insideFixedPosition);
6536}
6537
6538Document::RegionFixedPair Document::absoluteRegionForEventTargets(const EventTargetSet* targets)
6539{
6540 LayoutDisallowedScope layoutDisallowedScope(LayoutDisallowedScope::Reason::ReentrancyAvoidance);
6541
6542 if (!targets)
6543 return RegionFixedPair(Region(), false);
6544
6545 Region targetRegion;
6546 bool insideFixedPosition = false;
6547
6548 for (auto& keyValuePair : *targets) {
6549 if (auto* node = keyValuePair.key) {
6550 auto targetRegionFixedPair = absoluteEventRegionForNode(*node);
6551 targetRegion.unite(targetRegionFixedPair.first);
6552 insideFixedPosition |= targetRegionFixedPair.second;
6553 }
6554 }
6555
6556 return RegionFixedPair(targetRegion, insideFixedPosition);
6557}
6558
6559void Document::updateLastHandledUserGestureTimestamp(MonotonicTime time)
6560{
6561 m_lastHandledUserGestureTimestamp = time;
6562
6563 if (static_cast<bool>(time) && m_scriptedAnimationController) {
6564 // It's OK to always remove NonInteractedCrossOriginFrame even if this frame isn't cross-origin.
6565 m_scriptedAnimationController->removeThrottlingReason(ScriptedAnimationController::ThrottlingReason::NonInteractedCrossOriginFrame);
6566 }
6567
6568 // DOM Timer alignment may depend on the user having interacted with the document.
6569 didChangeTimerAlignmentInterval();
6570
6571 if (HTMLFrameOwnerElement* element = ownerElement())
6572 element->document().updateLastHandledUserGestureTimestamp(time);
6573}
6574
6575bool Document::processingUserGestureForMedia() const
6576{
6577 if (UserGestureIndicator::processingUserGestureForMedia())
6578 return true;
6579
6580 if (m_userActivatedMediaFinishedPlayingTimestamp + maxIntervalForUserGestureForwardingAfterMediaFinishesPlaying >= MonotonicTime::now())
6581 return true;
6582
6583 if (settings().mediaUserGestureInheritsFromDocument())
6584 return topDocument().hasHadUserInteraction();
6585
6586 auto* loader = this->loader();
6587 if (loader && loader->allowedAutoplayQuirks().contains(AutoplayQuirk::InheritedUserGestures))
6588 return topDocument().hasHadUserInteraction();
6589
6590 return false;
6591}
6592
6593void Document::startTrackingStyleRecalcs()
6594{
6595 m_styleRecalcCount = 0;
6596}
6597
6598unsigned Document::styleRecalcCount() const
6599{
6600 return m_styleRecalcCount;
6601}
6602
6603DocumentLoader* Document::loader() const
6604{
6605 if (!m_frame)
6606 return nullptr;
6607
6608 DocumentLoader* loader = m_frame->loader().documentLoader();
6609 if (!loader)
6610 return nullptr;
6611
6612 if (m_frame->document() != this)
6613 return nullptr;
6614
6615 return loader;
6616}
6617
6618#if ENABLE(CSS_DEVICE_ADAPTATION)
6619
6620IntSize Document::initialViewportSize() const
6621{
6622 if (!view())
6623 return IntSize();
6624 return view()->initialViewportSize();
6625}
6626
6627#endif
6628
6629Element* eventTargetElementForDocument(Document* document)
6630{
6631 if (!document)
6632 return nullptr;
6633 Element* element = document->focusedElement();
6634 if (!element && is<PluginDocument>(*document))
6635 element = downcast<PluginDocument>(*document).pluginElement();
6636 if (!element && document->isHTMLDocument())
6637 element = document->bodyOrFrameset();
6638 if (!element)
6639 element = document->documentElement();
6640 return element;
6641}
6642
6643void Document::convertAbsoluteToClientQuads(Vector<FloatQuad>& quads, const RenderStyle& style)
6644{
6645 if (!view())
6646 return;
6647
6648 const auto& frameView = *view();
6649 float inverseFrameScale = frameView.absoluteToDocumentScaleFactor(style.effectiveZoom());
6650 auto documentToClientOffset = frameView.documentToClientOffset();
6651
6652 for (auto& quad : quads) {
6653 if (inverseFrameScale != 1)
6654 quad.scale(inverseFrameScale);
6655
6656 quad.move(documentToClientOffset);
6657 }
6658}
6659
6660void Document::convertAbsoluteToClientRects(Vector<FloatRect>& rects, const RenderStyle& style)
6661{
6662 if (!view())
6663 return;
6664
6665 auto& frameView = *view();
6666 float inverseFrameScale = frameView.absoluteToDocumentScaleFactor(style.effectiveZoom());
6667 auto documentToClientOffset = frameView.documentToClientOffset();
6668
6669 for (auto& rect : rects) {
6670 if (inverseFrameScale != 1)
6671 rect.scale(inverseFrameScale);
6672
6673 rect.move(documentToClientOffset);
6674 }
6675}
6676
6677void Document::convertAbsoluteToClientRect(FloatRect& rect, const RenderStyle& style)
6678{
6679 if (!view())
6680 return;
6681
6682 const auto& frameView = *view();
6683 rect = frameView.absoluteToDocumentRect(rect, style.effectiveZoom());
6684 rect = frameView.documentToClientRect(rect);
6685}
6686
6687bool Document::hasActiveParser()
6688{
6689 return m_activeParserCount || (m_parser && m_parser->processingData());
6690}
6691
6692void Document::decrementActiveParserCount()
6693{
6694 --m_activeParserCount;
6695 if (!frame())
6696 return;
6697
6698 // FIXME: We should call DocumentLoader::checkLoadComplete as well here,
6699 // but it seems to cause http/tests/security/feed-urls-from-remote.html
6700 // to timeout on Mac WK1; see http://webkit.org/b/110554 and http://webkit.org/b/110401.
6701 frame()->loader().checkLoadComplete();
6702}
6703
6704DocumentParserYieldToken::DocumentParserYieldToken(Document& document)
6705 : m_document(makeWeakPtr(document))
6706{
6707 if (++document.m_parserYieldTokenCount != 1)
6708 return;
6709
6710 document.scriptRunner().didBeginYieldingParser();
6711 if (auto* parser = document.parser())
6712 parser->didBeginYieldingParser();
6713}
6714
6715DocumentParserYieldToken::~DocumentParserYieldToken()
6716{
6717 if (!m_document)
6718 return;
6719
6720 ASSERT(m_document->m_parserYieldTokenCount);
6721 if (--m_document->m_parserYieldTokenCount)
6722 return;
6723
6724 m_document->scriptRunner().didEndYieldingParser();
6725 if (auto* parser = m_document->parser())
6726 parser->didEndYieldingParser();
6727}
6728
6729static Element* findNearestCommonComposedAncestor(Element* elementA, Element* elementB)
6730{
6731 if (!elementA || !elementB)
6732 return nullptr;
6733
6734 if (elementA == elementB)
6735 return elementA;
6736
6737 HashSet<Element*> ancestorChain;
6738 for (auto* element = elementA; element; element = element->parentElementInComposedTree())
6739 ancestorChain.add(element);
6740
6741 for (auto* element = elementB; element; element = element->parentElementInComposedTree()) {
6742 if (ancestorChain.contains(element))
6743 return element;
6744 }
6745 return nullptr;
6746}
6747
6748void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement)
6749{
6750 ASSERT(!request.readOnly());
6751
6752 Element* innerElementInDocument = innerElement;
6753 while (innerElementInDocument && &innerElementInDocument->document() != this) {
6754 innerElementInDocument->document().updateHoverActiveState(request, innerElementInDocument);
6755 innerElementInDocument = innerElementInDocument->document().ownerElement();
6756 }
6757
6758 Element* oldActiveElement = m_activeElement.get();
6759 if (oldActiveElement && !request.active()) {
6760 // We are clearing the :active chain because the mouse has been released.
6761 for (Element* currentElement = oldActiveElement; currentElement; currentElement = currentElement->parentElementInComposedTree()) {
6762 currentElement->setActive(false);
6763 m_userActionElements.setInActiveChain(*currentElement, false);
6764 }
6765 m_activeElement = nullptr;
6766 } else {
6767 Element* newActiveElement = innerElementInDocument;
6768 if (!oldActiveElement && newActiveElement && request.active() && !request.touchMove()) {
6769 // We are setting the :active chain and freezing it. If future moves happen, they
6770 // will need to reference this chain.
6771 for (RenderElement* curr = newActiveElement->renderer(); curr; curr = curr->parent()) {
6772 Element* element = curr->element();
6773 if (!element || curr->isTextOrLineBreak())
6774 continue;
6775 m_userActionElements.setInActiveChain(*element, true);
6776 }
6777
6778 m_activeElement = newActiveElement;
6779 }
6780 }
6781 // If the mouse has just been pressed, set :active on the chain. Those (and only those)
6782 // nodes should remain :active until the mouse is released.
6783 bool allowActiveChanges = !oldActiveElement && m_activeElement;
6784
6785 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
6786 // :hover/:active to only apply to elements that are in the :active chain that we froze
6787 // at the time the mouse went down.
6788 bool mustBeInActiveChain = request.active() && request.move();
6789
6790 RefPtr<Element> oldHoveredElement = WTFMove(m_hoveredElement);
6791
6792 // A touch release does not set a new hover target; clearing the element we're working with
6793 // will clear the chain of hovered elements all the way to the top of the tree.
6794 if (request.touchRelease())
6795 innerElementInDocument = nullptr;
6796
6797 // Check to see if the hovered Element has changed.
6798 // If it hasn't, we do not need to do anything.
6799 Element* newHoveredElement = innerElementInDocument;
6800 while (newHoveredElement && !newHoveredElement->renderer())
6801 newHoveredElement = newHoveredElement->parentElementInComposedTree();
6802
6803 m_hoveredElement = newHoveredElement;
6804
6805 auto* commonAncestor = findNearestCommonComposedAncestor(oldHoveredElement.get(), newHoveredElement);
6806
6807 Vector<RefPtr<Element>, 32> elementsToRemoveFromChain;
6808 Vector<RefPtr<Element>, 32> elementsToAddToChain;
6809
6810 if (oldHoveredElement != newHoveredElement) {
6811 for (auto* element = oldHoveredElement.get(); element; element = element->parentElementInComposedTree()) {
6812 if (element == commonAncestor)
6813 break;
6814 if (!mustBeInActiveChain || element->isInActiveChain())
6815 elementsToRemoveFromChain.append(element);
6816 }
6817 // Unset hovered nodes in sub frame documents if the old hovered node was a frame owner.
6818 if (is<HTMLFrameOwnerElement>(oldHoveredElement)) {
6819 if (auto* contentDocument = downcast<HTMLFrameOwnerElement>(*oldHoveredElement).contentDocument())
6820 contentDocument->updateHoverActiveState(request, nullptr);
6821 }
6822 }
6823
6824 for (auto* element = newHoveredElement; element; element = element->parentElementInComposedTree()) {
6825 if (!mustBeInActiveChain || element->isInActiveChain())
6826 elementsToAddToChain.append(element);
6827 }
6828
6829 for (auto& element : elementsToRemoveFromChain)
6830 element->setHovered(false);
6831
6832 bool sawCommonAncestor = false;
6833 for (auto& element : elementsToAddToChain) {
6834 if (allowActiveChanges)
6835 element->setActive(true);
6836 if (element == commonAncestor)
6837 sawCommonAncestor = true;
6838 if (!sawCommonAncestor) {
6839 // Elements after the common hover ancestor does not change hover state, but are iterated over because they may change active state.
6840 element->setHovered(true);
6841 }
6842 }
6843}
6844
6845bool Document::haveStylesheetsLoaded() const
6846{
6847 return !styleScope().hasPendingSheets() || m_ignorePendingStylesheets;
6848}
6849
6850Locale& Document::getCachedLocale(const AtomicString& locale)
6851{
6852 AtomicString localeKey = locale;
6853 if (locale.isEmpty() || !settings().langAttributeAwareFormControlUIEnabled())
6854 localeKey = defaultLanguage();
6855 LocaleIdentifierToLocaleMap::AddResult result = m_localeCache.add(localeKey, nullptr);
6856 if (result.isNewEntry)
6857 result.iterator->value = Locale::create(localeKey);
6858 return *(result.iterator->value);
6859}
6860
6861Document& Document::ensureTemplateDocument()
6862{
6863 if (const Document* document = templateDocument())
6864 return const_cast<Document&>(*document);
6865
6866 if (isHTMLDocument())
6867 m_templateDocument = HTMLDocument::create(nullptr, WTF::blankURL());
6868 else
6869 m_templateDocument = create(WTF::blankURL());
6870
6871 m_templateDocument->setContextDocument(contextDocument());
6872 m_templateDocument->setTemplateDocumentHost(this); // balanced in dtor.
6873
6874 return *m_templateDocument;
6875}
6876
6877Ref<FontFaceSet> Document::fonts()
6878{
6879 updateStyleIfNeeded();
6880 return fontSelector().fontFaceSet();
6881}
6882
6883EditingBehavior Document::editingBehavior() const
6884{
6885 return EditingBehavior { settings().editingBehaviorType() };
6886}
6887
6888float Document::deviceScaleFactor() const
6889{
6890 float deviceScaleFactor = 1.0;
6891 if (Page* documentPage = page())
6892 deviceScaleFactor = documentPage->deviceScaleFactor();
6893 return deviceScaleFactor;
6894}
6895
6896bool Document::useSystemAppearance() const
6897{
6898 if (auto* documentPage = page())
6899 return documentPage->useSystemAppearance();
6900 return false;
6901}
6902
6903bool Document::useDarkAppearance(const RenderStyle* style) const
6904{
6905#if HAVE(OS_DARK_MODE_SUPPORT)
6906#if ENABLE(DARK_MODE_CSS)
6907 OptionSet<ColorScheme> colorScheme;
6908
6909 // Use the style's supported color schemes, if supplied.
6910 if (style)
6911 colorScheme = style->colorScheme().colorScheme();
6912
6913 // Fallback to the document's supported color schemes if style was empty (auto).
6914 if (colorScheme.isEmpty())
6915 colorScheme = m_colorScheme;
6916
6917 if (colorScheme.contains(ColorScheme::Dark) && !colorScheme.contains(ColorScheme::Light))
6918 return true;
6919#else
6920 UNUSED_PARAM(style);
6921#endif
6922
6923 bool pageUsesDarkAppearance = false;
6924 if (Page* documentPage = page())
6925 pageUsesDarkAppearance = documentPage->useDarkAppearance();
6926
6927 if (useSystemAppearance())
6928 return pageUsesDarkAppearance;
6929
6930#if ENABLE(DARK_MODE_CSS)
6931 if (colorScheme.contains(ColorScheme::Dark))
6932 return pageUsesDarkAppearance;
6933#endif
6934#else
6935 UNUSED_PARAM(style);
6936#endif
6937
6938 return false;
6939}
6940
6941bool Document::useInactiveAppearance() const
6942{
6943 if (auto* documentPage = page())
6944 return documentPage->useInactiveAppearance();
6945 return false;
6946}
6947
6948OptionSet<StyleColor::Options> Document::styleColorOptions(const RenderStyle* style) const
6949{
6950 OptionSet<StyleColor::Options> options;
6951 if (useSystemAppearance())
6952 options.add(StyleColor::Options::UseSystemAppearance);
6953 if (useDarkAppearance(style))
6954 options.add(StyleColor::Options::UseDarkAppearance);
6955 if (useInactiveAppearance())
6956 options.add(StyleColor::Options::UseInactiveAppearance);
6957 return options;
6958}
6959
6960void Document::didAssociateFormControl(Element& element)
6961{
6962 auto* page = this->page();
6963 if (!page || !page->chrome().client().shouldNotifyOnFormChanges())
6964 return;
6965 m_associatedFormControls.add(&element);
6966 if (!m_didAssociateFormControlsTimer.isActive())
6967 m_didAssociateFormControlsTimer.startOneShot(0_s);
6968}
6969
6970void Document::didAssociateFormControlsTimerFired()
6971{
6972 auto vector = copyToVector(m_associatedFormControls);
6973 m_associatedFormControls.clear();
6974 if (auto* page = this->page()) {
6975 ASSERT(m_frame);
6976 page->chrome().client().didAssociateFormControls(vector, *m_frame);
6977 }
6978}
6979
6980void Document::setCachedDOMCookies(const String& cookies)
6981{
6982 ASSERT(!isDOMCookieCacheValid());
6983 m_cachedDOMCookies = cookies;
6984 // The cookie cache is valid at most until we go back to the event loop.
6985 m_cookieCacheExpiryTimer.startOneShot(0_s);
6986}
6987
6988void Document::invalidateDOMCookieCache()
6989{
6990 m_cookieCacheExpiryTimer.stop();
6991 m_cachedDOMCookies = String();
6992}
6993
6994void Document::didLoadResourceSynchronously()
6995{
6996 // Synchronous resources loading can set cookies so we invalidate the cookies cache
6997 // in this case, to be safe.
6998 invalidateDOMCookieCache();
6999}
7000
7001void Document::ensurePlugInsInjectedScript(DOMWrapperWorld& world)
7002{
7003 if (m_hasInjectedPlugInsScript)
7004 return;
7005
7006 auto& scriptController = frame()->script();
7007
7008 // Use the JS file provided by the Chrome client, or fallback to the default one.
7009 String jsString = page()->chrome().client().plugInExtraScript();
7010 if (!jsString || !scriptController.shouldAllowUserAgentScripts(*this))
7011 jsString = String(plugInsJavaScript, sizeof(plugInsJavaScript));
7012
7013 setHasEvaluatedUserAgentScripts();
7014 scriptController.evaluateInWorld(ScriptSourceCode(jsString), world);
7015
7016 m_hasInjectedPlugInsScript = true;
7017}
7018
7019#if ENABLE(WEB_CRYPTO)
7020
7021bool Document::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey)
7022{
7023 Page* page = this->page();
7024 if (!page)
7025 return false;
7026 return page->chrome().client().wrapCryptoKey(key, wrappedKey);
7027}
7028
7029bool Document::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key)
7030{
7031 Page* page = this->page();
7032 if (!page)
7033 return false;
7034 return page->chrome().client().unwrapCryptoKey(wrappedKey, key);
7035}
7036
7037#endif // ENABLE(WEB_CRYPTO)
7038
7039Element* Document::activeElement()
7040{
7041 if (Element* element = treeScope().focusedElementInScope())
7042 return element;
7043 return bodyOrFrameset();
7044}
7045
7046bool Document::hasFocus() const
7047{
7048 Page* page = this->page();
7049 if (!page || !page->focusController().isActive())
7050 return false;
7051 if (Frame* focusedFrame = page->focusController().focusedFrame()) {
7052 if (focusedFrame->tree().isDescendantOf(frame()))
7053 return true;
7054 }
7055 return false;
7056}
7057
7058#if ENABLE(WIRELESS_PLAYBACK_TARGET)
7059
7060static uint64_t nextPlaybackTargetClientContextId()
7061{
7062 static uint64_t contextId = 0;
7063 return ++contextId;
7064}
7065
7066void Document::addPlaybackTargetPickerClient(MediaPlaybackTargetClient& client)
7067{
7068 Page* page = this->page();
7069 if (!page)
7070 return;
7071
7072 // FIXME: change this back to an ASSERT once https://webkit.org/b/144970 is fixed.
7073 if (m_clientToIDMap.contains(&client))
7074 return;
7075
7076 uint64_t contextId = nextPlaybackTargetClientContextId();
7077 m_clientToIDMap.add(&client, contextId);
7078 m_idToClientMap.add(contextId, &client);
7079 page->addPlaybackTargetPickerClient(contextId);
7080}
7081
7082void Document::removePlaybackTargetPickerClient(MediaPlaybackTargetClient& client)
7083{
7084 auto it = m_clientToIDMap.find(&client);
7085 if (it == m_clientToIDMap.end())
7086 return;
7087
7088 uint64_t clientId = it->value;
7089 m_idToClientMap.remove(clientId);
7090 m_clientToIDMap.remove(it);
7091
7092 Page* page = this->page();
7093 if (!page)
7094 return;
7095 page->removePlaybackTargetPickerClient(clientId);
7096}
7097
7098void Document::showPlaybackTargetPicker(MediaPlaybackTargetClient& client, bool isVideo, RouteSharingPolicy routeSharingPolicy, const String& routingContextUID)
7099{
7100 Page* page = this->page();
7101 if (!page)
7102 return;
7103
7104 auto it = m_clientToIDMap.find(&client);
7105 if (it == m_clientToIDMap.end())
7106 return;
7107
7108 page->showPlaybackTargetPicker(it->value, view()->lastKnownMousePosition(), isVideo, routeSharingPolicy, routingContextUID);
7109}
7110
7111void Document::playbackTargetPickerClientStateDidChange(MediaPlaybackTargetClient& client, MediaProducer::MediaStateFlags state)
7112{
7113 Page* page = this->page();
7114 if (!page)
7115 return;
7116
7117 auto it = m_clientToIDMap.find(&client);
7118 if (it == m_clientToIDMap.end())
7119 return;
7120
7121 page->playbackTargetPickerClientStateDidChange(it->value, state);
7122}
7123
7124void Document::playbackTargetAvailabilityDidChange(uint64_t clientId, bool available)
7125{
7126 auto it = m_idToClientMap.find(clientId);
7127 if (it == m_idToClientMap.end())
7128 return;
7129
7130 it->value->externalOutputDeviceAvailableDidChange(available);
7131}
7132
7133void Document::setPlaybackTarget(uint64_t clientId, Ref<MediaPlaybackTarget>&& target)
7134{
7135 auto it = m_idToClientMap.find(clientId);
7136 if (it == m_idToClientMap.end())
7137 return;
7138
7139 it->value->setPlaybackTarget(target.copyRef());
7140}
7141
7142void Document::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
7143{
7144 auto it = m_idToClientMap.find(clientId);
7145 if (it == m_idToClientMap.end())
7146 return;
7147
7148 it->value->setShouldPlayToPlaybackTarget(shouldPlay);
7149}
7150
7151#endif // ENABLE(WIRELESS_PLAYBACK_TARGET)
7152
7153#if ENABLE(MEDIA_SESSION)
7154
7155MediaSession& Document::defaultMediaSession()
7156{
7157 if (!m_defaultMediaSession)
7158 m_defaultMediaSession = MediaSession::create(*scriptExecutionContext());
7159 return *m_defaultMediaSession;
7160}
7161
7162#endif
7163
7164ShouldOpenExternalURLsPolicy Document::shouldOpenExternalURLsPolicyToPropagate() const
7165{
7166 if (DocumentLoader* documentLoader = loader())
7167 return documentLoader->shouldOpenExternalURLsPolicyToPropagate();
7168
7169 return ShouldOpenExternalURLsPolicy::ShouldNotAllow;
7170}
7171
7172bool Document::shouldEnforceHTTP09Sandbox() const
7173{
7174 if (m_isSynthesized || !m_frame)
7175 return false;
7176 DocumentLoader* documentLoader = m_frame->loader().activeDocumentLoader();
7177 return documentLoader && documentLoader->response().isHTTP09();
7178}
7179
7180#if USE(QUICK_LOOK)
7181bool Document::shouldEnforceQuickLookSandbox() const
7182{
7183 if (m_isSynthesized || !m_frame)
7184 return false;
7185 DocumentLoader* documentLoader = m_frame->loader().activeDocumentLoader();
7186 return documentLoader && documentLoader->response().isQuickLook();
7187}
7188
7189void Document::applyQuickLookSandbox()
7190{
7191 auto& documentLoader = *m_frame->loader().activeDocumentLoader();
7192 auto documentURL = documentLoader.documentURL();
7193 auto& responseURL = documentLoader.responseURL();
7194 ASSERT(!documentURL.protocolIs(QLPreviewProtocol));
7195 ASSERT(responseURL.protocolIs(QLPreviewProtocol));
7196
7197 auto securityOrigin = SecurityOrigin::createNonLocalWithAllowedFilePath(responseURL, documentURL.fileSystemPath());
7198 securityOrigin->setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage);
7199 setSecurityOriginPolicy(SecurityOriginPolicy::create(WTFMove(securityOrigin)));
7200
7201 static NeverDestroyed<String> quickLookCSP = makeString("default-src ", QLPreviewProtocol, ": 'unsafe-inline'; base-uri 'none'; sandbox allow-same-origin allow-scripts");
7202 RELEASE_ASSERT(contentSecurityPolicy());
7203 // The sandbox directive is only allowed if the policy is from an HTTP header.
7204 contentSecurityPolicy()->didReceiveHeader(quickLookCSP, ContentSecurityPolicyHeaderType::Enforce, ContentSecurityPolicy::PolicyFrom::HTTPHeader, referrer());
7205
7206 disableSandboxFlags(SandboxNavigation);
7207
7208 setReferrerPolicy(ReferrerPolicy::NoReferrer);
7209}
7210#endif
7211
7212bool Document::shouldEnforceContentDispositionAttachmentSandbox() const
7213{
7214 if (!settings().contentDispositionAttachmentSandboxEnabled())
7215 return false;
7216
7217 if (m_isSynthesized)
7218 return false;
7219
7220 if (auto* documentLoader = m_frame ? m_frame->loader().activeDocumentLoader() : nullptr)
7221 return documentLoader->response().isAttachment();
7222 return false;
7223}
7224
7225void Document::applyContentDispositionAttachmentSandbox()
7226{
7227 ASSERT(shouldEnforceContentDispositionAttachmentSandbox());
7228
7229 setReferrerPolicy(ReferrerPolicy::NoReferrer);
7230 if (!isMediaDocument())
7231 enforceSandboxFlags(SandboxAll);
7232 else
7233 enforceSandboxFlags(SandboxOrigin);
7234}
7235
7236void Document::addViewportDependentPicture(HTMLPictureElement& picture)
7237{
7238 m_viewportDependentPictures.add(&picture);
7239}
7240
7241void Document::removeViewportDependentPicture(HTMLPictureElement& picture)
7242{
7243 m_viewportDependentPictures.remove(&picture);
7244}
7245
7246void Document::addAppearanceDependentPicture(HTMLPictureElement& picture)
7247{
7248 m_appearanceDependentPictures.add(&picture);
7249}
7250
7251void Document::removeAppearanceDependentPicture(HTMLPictureElement& picture)
7252{
7253 m_appearanceDependentPictures.remove(&picture);
7254}
7255
7256void Document::scheduleRenderingUpdate()
7257{
7258 if (auto page = this->page())
7259 page->renderingUpdateScheduler().scheduleRenderingUpdate();
7260}
7261
7262#if ENABLE(INTERSECTION_OBSERVER)
7263void Document::addIntersectionObserver(IntersectionObserver& observer)
7264{
7265 ASSERT(m_intersectionObservers.find(&observer) == notFound);
7266 m_intersectionObservers.append(makeWeakPtr(&observer));
7267}
7268
7269void Document::removeIntersectionObserver(IntersectionObserver& observer)
7270{
7271 m_intersectionObservers.removeFirst(&observer);
7272}
7273
7274static void expandRootBoundsWithRootMargin(FloatRect& localRootBounds, const LengthBox& rootMargin)
7275{
7276 FloatBoxExtent rootMarginFloatBox(
7277 floatValueForLength(rootMargin.top(), localRootBounds.height()),
7278 floatValueForLength(rootMargin.right(), localRootBounds.width()),
7279 floatValueForLength(rootMargin.bottom(), localRootBounds.height()),
7280 floatValueForLength(rootMargin.left(), localRootBounds.width())
7281 );
7282
7283 localRootBounds.expand(rootMarginFloatBox);
7284}
7285
7286static Optional<LayoutRect> computeClippedRectInRootContentsSpace(const LayoutRect& rect, const RenderElement* renderer)
7287{
7288 OptionSet<RenderObject::VisibleRectContextOption> visibleRectOptions = { RenderObject::VisibleRectContextOption::UseEdgeInclusiveIntersection, RenderObject::VisibleRectContextOption::ApplyCompositedClips, RenderObject::VisibleRectContextOption::ApplyCompositedContainerScrolls };
7289 Optional<LayoutRect> rectInFrameAbsoluteSpace = renderer->computeVisibleRectInContainer(rect, &renderer->view(), {false /* hasPositionFixedDescendant */, false /* dirtyRectIsFlipped */, visibleRectOptions });
7290 if (!rectInFrameAbsoluteSpace || renderer->frame().isMainFrame())
7291 return rectInFrameAbsoluteSpace;
7292
7293 bool intersects = rectInFrameAbsoluteSpace->edgeInclusiveIntersect(renderer->view().frameView().layoutViewportRect());
7294 if (!intersects)
7295 return WTF::nullopt;
7296
7297 LayoutRect rectInFrameViewSpace(renderer->view().frameView().contentsToView(snappedIntRect(*rectInFrameAbsoluteSpace)));
7298 auto* ownerRenderer = renderer->frame().ownerRenderer();
7299 if (!ownerRenderer)
7300 return WTF::nullopt;
7301
7302 rectInFrameViewSpace.moveBy(ownerRenderer->contentBoxLocation());
7303 return computeClippedRectInRootContentsSpace(rectInFrameViewSpace, ownerRenderer);
7304}
7305
7306struct IntersectionObservationState {
7307 FloatRect absoluteTargetRect;
7308 FloatRect absoluteRootBounds;
7309 FloatRect absoluteIntersectionRect;
7310 bool isIntersecting { false };
7311};
7312
7313static Optional<IntersectionObservationState> computeIntersectionState(FrameView& frameView, const IntersectionObserver& observer, Element& target, bool applyRootMargin)
7314{
7315 auto* targetRenderer = target.renderer();
7316 if (!targetRenderer)
7317 return WTF::nullopt;
7318
7319 FloatRect localRootBounds;
7320 RenderBlock* rootRenderer;
7321 if (observer.root()) {
7322 if (observer.trackingDocument() != &target.document())
7323 return WTF::nullopt;
7324
7325 if (!observer.root()->renderer() || !is<RenderBlock>(observer.root()->renderer()))
7326 return WTF::nullopt;
7327
7328 rootRenderer = downcast<RenderBlock>(observer.root()->renderer());
7329 if (!rootRenderer->isContainingBlockAncestorFor(*targetRenderer))
7330 return WTF::nullopt;
7331
7332 if (rootRenderer->hasOverflowClip())
7333 localRootBounds = rootRenderer->contentBoxRect();
7334 else
7335 localRootBounds = { FloatPoint(), rootRenderer->size() };
7336 } else {
7337 ASSERT(frameView.frame().isMainFrame());
7338 // FIXME: Handle the case of an implicit-root observer that has a target in a different frame tree.
7339 if (&targetRenderer->frame().mainFrame() != &frameView.frame())
7340 return WTF::nullopt;
7341 rootRenderer = frameView.renderView();
7342 localRootBounds = frameView.layoutViewportRect();
7343 }
7344
7345 if (applyRootMargin)
7346 expandRootBoundsWithRootMargin(localRootBounds, observer.rootMarginBox());
7347
7348 LayoutRect localTargetBounds;
7349 if (is<RenderBox>(*targetRenderer))
7350 localTargetBounds = downcast<RenderBox>(targetRenderer)->borderBoundingBox();
7351 else if (is<RenderInline>(targetRenderer))
7352 localTargetBounds = downcast<RenderInline>(targetRenderer)->linesBoundingBox();
7353 else if (is<RenderLineBreak>(targetRenderer))
7354 localTargetBounds = downcast<RenderLineBreak>(targetRenderer)->linesBoundingBox();
7355
7356 Optional<LayoutRect> rootLocalTargetRect;
7357 if (observer.root()) {
7358 OptionSet<RenderObject::VisibleRectContextOption> visibleRectOptions = { RenderObject::VisibleRectContextOption::UseEdgeInclusiveIntersection, RenderObject::VisibleRectContextOption::ApplyCompositedClips, RenderObject::VisibleRectContextOption::ApplyCompositedContainerScrolls };
7359 rootLocalTargetRect = targetRenderer->computeVisibleRectInContainer(localTargetBounds, rootRenderer, { false /* hasPositionFixedDescendant */, false /* dirtyRectIsFlipped */, visibleRectOptions });
7360 } else
7361 rootLocalTargetRect = computeClippedRectInRootContentsSpace(localTargetBounds, targetRenderer);
7362
7363 FloatRect rootLocalIntersectionRect = localRootBounds;
7364
7365 IntersectionObservationState intersectionState;
7366 intersectionState.isIntersecting = rootLocalTargetRect && rootLocalIntersectionRect.edgeInclusiveIntersect(*rootLocalTargetRect);
7367
7368 if (intersectionState.isIntersecting) {
7369 FloatRect rootAbsoluteIntersectionRect = rootRenderer->localToAbsoluteQuad(rootLocalIntersectionRect).boundingBox();
7370 if (&targetRenderer->frame() == &rootRenderer->frame())
7371 intersectionState.absoluteIntersectionRect = rootAbsoluteIntersectionRect;
7372 else {
7373 FloatRect rootViewIntersectionRect = frameView.contentsToView(rootAbsoluteIntersectionRect);
7374 intersectionState.absoluteIntersectionRect = targetRenderer->view().frameView().rootViewToContents(rootViewIntersectionRect);
7375 }
7376 }
7377
7378 intersectionState.absoluteTargetRect = targetRenderer->localToAbsoluteQuad(FloatRect(localTargetBounds)).boundingBox();
7379 intersectionState.absoluteRootBounds = rootRenderer->localToAbsoluteQuad(localRootBounds).boundingBox();
7380 return intersectionState;
7381}
7382
7383void Document::updateIntersectionObservations()
7384{
7385 auto* frameView = view();
7386 if (!frameView)
7387 return;
7388
7389 bool needsLayout = frameView->layoutContext().isLayoutPending() || (renderView() && renderView()->needsLayout());
7390 if (needsLayout || hasPendingStyleRecalc())
7391 return;
7392
7393 for (const auto& observer : m_intersectionObservers) {
7394 bool needNotify = false;
7395 DOMHighResTimeStamp timestamp;
7396 if (!observer->createTimestamp(timestamp))
7397 continue;
7398 for (Element* target : observer->observationTargets()) {
7399 auto& targetRegistrations = target->intersectionObserverData()->registrations;
7400 auto index = targetRegistrations.findMatching([observer](auto& registration) {
7401 return registration.observer.get() == observer;
7402 });
7403 ASSERT(index != notFound);
7404 auto& registration = targetRegistrations[index];
7405
7406 bool isSameOriginObservation = &target->document() == this || target->document().securityOrigin().canAccess(securityOrigin());
7407 auto intersectionState = computeIntersectionState(*frameView, *observer, *target, isSameOriginObservation);
7408
7409 float intersectionRatio = 0;
7410 size_t thresholdIndex = 0;
7411 if (intersectionState) {
7412 if (intersectionState->isIntersecting) {
7413 float absTargetArea = intersectionState->absoluteTargetRect.area();
7414 if (absTargetArea)
7415 intersectionRatio = intersectionState->absoluteIntersectionRect.area() / absTargetArea;
7416 else
7417 intersectionRatio = 1;
7418
7419 auto& thresholds = observer->thresholds();
7420 while (thresholdIndex < thresholds.size() && thresholds[thresholdIndex] <= intersectionRatio)
7421 ++thresholdIndex;
7422 }
7423 }
7424
7425 if (!registration.previousThresholdIndex || thresholdIndex != registration.previousThresholdIndex) {
7426 FloatRect targetBoundingClientRect;
7427 FloatRect clientIntersectionRect;
7428 FloatRect clientRootBounds;
7429 if (intersectionState) {
7430 auto* targetFrameView = target->document().view();
7431 targetBoundingClientRect = targetFrameView->absoluteToClientRect(intersectionState->absoluteTargetRect, target->renderer()->style().effectiveZoom());
7432 auto* rootRenderer = observer->root() ? observer->root()->renderer() : frameView->renderView();
7433 clientRootBounds = frameView->absoluteToClientRect(intersectionState->absoluteRootBounds, rootRenderer->style().effectiveZoom());
7434 if (intersectionState->isIntersecting)
7435 clientIntersectionRect = targetFrameView->absoluteToClientRect(intersectionState->absoluteIntersectionRect, target->renderer()->style().effectiveZoom());
7436 }
7437
7438 Optional<DOMRectInit> reportedRootBounds;
7439 if (isSameOriginObservation) {
7440 reportedRootBounds = DOMRectInit({
7441 clientRootBounds.x(),
7442 clientRootBounds.y(),
7443 clientRootBounds.width(),
7444 clientRootBounds.height()
7445 });
7446 }
7447
7448 observer->appendQueuedEntry(IntersectionObserverEntry::create({
7449 timestamp,
7450 reportedRootBounds,
7451 { targetBoundingClientRect.x(), targetBoundingClientRect.y(), targetBoundingClientRect.width(), targetBoundingClientRect.height() },
7452 { clientIntersectionRect.x(), clientIntersectionRect.y(), clientIntersectionRect.width(), clientIntersectionRect.height() },
7453 intersectionRatio,
7454 target,
7455 thresholdIndex > 0,
7456 }));
7457 needNotify = true;
7458 registration.previousThresholdIndex = thresholdIndex;
7459 }
7460 }
7461 if (needNotify)
7462 m_intersectionObserversWithPendingNotifications.append(makeWeakPtr(observer.get()));
7463 }
7464
7465 if (m_intersectionObserversWithPendingNotifications.size())
7466 m_intersectionObserversNotifyTimer.startOneShot(0_s);
7467}
7468
7469void Document::notifyIntersectionObserversTimerFired()
7470{
7471 for (const auto& observer : m_intersectionObserversWithPendingNotifications) {
7472 if (observer)
7473 observer->notify();
7474 }
7475 m_intersectionObserversWithPendingNotifications.clear();
7476}
7477#endif
7478
7479#if ENABLE(RESIZE_OBSERVER)
7480void Document::addResizeObserver(ResizeObserver& observer)
7481{
7482 if (!m_resizeObservers.contains(&observer))
7483 m_resizeObservers.append(makeWeakPtr(&observer));
7484}
7485
7486void Document::removeResizeObserver(ResizeObserver& observer)
7487{
7488 m_resizeObservers.removeFirst(&observer);
7489}
7490
7491bool Document::hasResizeObservers()
7492{
7493 return !m_resizeObservers.isEmpty();
7494}
7495
7496size_t Document::gatherResizeObservations(size_t deeperThan)
7497{
7498 size_t minDepth = ResizeObserver::maxElementDepth();
7499 for (const auto& observer : m_resizeObservers) {
7500 if (!observer->hasObservations())
7501 continue;
7502 auto depth = observer->gatherObservations(deeperThan);
7503 minDepth = std::min(minDepth, depth);
7504 }
7505 return minDepth;
7506}
7507
7508void Document::deliverResizeObservations()
7509{
7510 for (const auto& observer : m_resizeObservers) {
7511 if (!observer->hasActiveObservations())
7512 continue;
7513 observer->deliverObservations();
7514 }
7515}
7516
7517bool Document::hasSkippedResizeObservations() const
7518{
7519 for (const auto& observer : m_resizeObservers) {
7520 if (observer->hasSkippedObservations())
7521 return true;
7522 }
7523 return false;
7524}
7525
7526void Document::setHasSkippedResizeObservations(bool skipped)
7527{
7528 for (const auto& observer : m_resizeObservers)
7529 observer->setHasSkippedObservations(skipped);
7530}
7531
7532void Document::updateResizeObservations(Page& page)
7533{
7534 if (!hasResizeObservers())
7535 return;
7536
7537 // We need layout the whole frame tree here. Because ResizeObserver could observe element in other frame,
7538 // and it could change other frame in deliverResizeObservations().
7539 page.layoutIfNeeded();
7540
7541 // Start check resize obervers;
7542 for (size_t depth = gatherResizeObservations(0); depth != ResizeObserver::maxElementDepth(); depth = gatherResizeObservations(depth)) {
7543 deliverResizeObservations();
7544 page.layoutIfNeeded();
7545 }
7546
7547 if (hasSkippedResizeObservations()) {
7548 setHasSkippedResizeObservations(false);
7549 String url;
7550 unsigned line = 0;
7551 unsigned column = 0;
7552 getParserLocation(url, line, column);
7553 reportException("ResizeObserver loop completed with undelivered notifications.", line, column, url, nullptr, nullptr);
7554 // Starting a new schedule the next round of notify.
7555 scheduleRenderingUpdate();
7556 }
7557}
7558#endif
7559
7560const AtomicString& Document::dir() const
7561{
7562 auto* documentElement = this->documentElement();
7563 if (!is<HTMLHtmlElement>(documentElement))
7564 return nullAtom();
7565 return downcast<HTMLHtmlElement>(*documentElement).dir();
7566}
7567
7568void Document::setDir(const AtomicString& value)
7569{
7570 auto* documentElement = this->documentElement();
7571 if (is<HTMLHtmlElement>(documentElement))
7572 downcast<HTMLHtmlElement>(*documentElement).setDir(value);
7573}
7574
7575DOMSelection* Document::getSelection()
7576{
7577 return m_domWindow ? m_domWindow->getSelection() : nullptr;
7578}
7579
7580void Document::didInsertInDocumentShadowRoot(ShadowRoot& shadowRoot)
7581{
7582 ASSERT(shadowRoot.isConnected());
7583 ASSERT(!m_inDocumentShadowRoots.contains(&shadowRoot));
7584 m_inDocumentShadowRoots.add(&shadowRoot);
7585}
7586
7587void Document::didRemoveInDocumentShadowRoot(ShadowRoot& shadowRoot)
7588{
7589 ASSERT(m_inDocumentShadowRoots.contains(&shadowRoot));
7590 m_inDocumentShadowRoots.remove(&shadowRoot);
7591}
7592
7593void Document::orientationChanged(int orientation)
7594{
7595 LOG(Events, "Document %p orientationChanged - orientation %d", this, orientation);
7596 dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
7597 m_orientationNotifier.orientationChanged(orientation);
7598}
7599
7600void Document::notifyMediaCaptureOfVisibilityChanged()
7601{
7602#if ENABLE(MEDIA_STREAM)
7603 if (!page())
7604 return;
7605
7606 RealtimeMediaSourceCenter::singleton().setVideoCapturePageState(hidden(), page()->isMediaCaptureMuted());
7607#endif
7608}
7609
7610#if ENABLE(MEDIA_STREAM)
7611void Document::stopMediaCapture()
7612{
7613 MediaStreamRegistry::shared().forEach([this](MediaStream& stream) {
7614 if (stream.document() == this)
7615 stream.endCaptureTracks();
7616 });
7617}
7618
7619void Document::registerForMediaStreamStateChangeCallbacks(HTMLMediaElement& element)
7620{
7621 m_mediaStreamStateChangeElements.add(&element);
7622}
7623
7624void Document::unregisterForMediaStreamStateChangeCallbacks(HTMLMediaElement& element)
7625{
7626 m_mediaStreamStateChangeElements.remove(&element);
7627}
7628
7629void Document::mediaStreamCaptureStateChanged()
7630{
7631 if (!MediaProducer::isCapturing(m_mediaState))
7632 return;
7633
7634 for (auto* mediaElement : m_mediaStreamStateChangeElements)
7635 mediaElement->mediaStreamCaptureStarted();
7636}
7637
7638void Document::setDeviceIDHashSalt(const String& salt)
7639{
7640 ASSERT(m_idHashSalt.isEmpty() || m_idHashSalt == salt);
7641 m_idHashSalt = salt;
7642}
7643
7644#endif
7645
7646void Document::addApplicationStateChangeListener(ApplicationStateChangeListener& listener)
7647{
7648 m_applicationStateChangeListeners.add(&listener);
7649}
7650
7651void Document::removeApplicationStateChangeListener(ApplicationStateChangeListener& listener)
7652{
7653 m_applicationStateChangeListeners.remove(&listener);
7654}
7655
7656void Document::forEachApplicationStateChangeListener(const Function<void(ApplicationStateChangeListener&)>& functor)
7657{
7658 for (auto* listener : m_applicationStateChangeListeners)
7659 functor(*listener);
7660}
7661
7662const AtomicString& Document::bgColor() const
7663{
7664 auto* bodyElement = body();
7665 if (!bodyElement)
7666 return emptyAtom();
7667 return bodyElement->attributeWithoutSynchronization(bgcolorAttr);
7668}
7669
7670void Document::setBgColor(const String& value)
7671{
7672 if (auto* bodyElement = body())
7673 bodyElement->setAttributeWithoutSynchronization(bgcolorAttr, value);
7674}
7675
7676const AtomicString& Document::fgColor() const
7677{
7678 auto* bodyElement = body();
7679 if (!bodyElement)
7680 return emptyAtom();
7681 return bodyElement->attributeWithoutSynchronization(textAttr);
7682}
7683
7684void Document::setFgColor(const String& value)
7685{
7686 if (auto* bodyElement = body())
7687 bodyElement->setAttributeWithoutSynchronization(textAttr, value);
7688}
7689
7690const AtomicString& Document::alinkColor() const
7691{
7692 auto* bodyElement = body();
7693 if (!bodyElement)
7694 return emptyAtom();
7695 return bodyElement->attributeWithoutSynchronization(alinkAttr);
7696}
7697
7698void Document::setAlinkColor(const String& value)
7699{
7700 if (auto* bodyElement = body())
7701 bodyElement->setAttributeWithoutSynchronization(alinkAttr, value);
7702}
7703
7704const AtomicString& Document::linkColorForBindings() const
7705{
7706 auto* bodyElement = body();
7707 if (!bodyElement)
7708 return emptyAtom();
7709 return bodyElement->attributeWithoutSynchronization(linkAttr);
7710}
7711
7712void Document::setLinkColorForBindings(const String& value)
7713{
7714 if (auto* bodyElement = body())
7715 bodyElement->setAttributeWithoutSynchronization(linkAttr, value);
7716}
7717
7718const AtomicString& Document::vlinkColor() const
7719{
7720 auto* bodyElement = body();
7721 if (!bodyElement)
7722 return emptyAtom();
7723 return bodyElement->attributeWithoutSynchronization(vlinkAttr);
7724}
7725
7726void Document::setVlinkColor(const String& value)
7727{
7728 if (auto* bodyElement = body())
7729 bodyElement->setAttributeWithoutSynchronization(vlinkAttr, value);
7730}
7731
7732Logger& Document::logger()
7733{
7734 if (!m_logger) {
7735 m_logger = Logger::create(this);
7736 m_logger->setEnabled(this, sessionID().isAlwaysOnLoggingAllowed());
7737 m_logger->addObserver(*this);
7738 }
7739
7740 return *m_logger;
7741}
7742
7743Optional<uint64_t> Document::pageID() const
7744{
7745 return m_frame->loader().client().pageID();
7746}
7747
7748void Document::registerArticleElement(Element& article)
7749{
7750 m_articleElements.add(&article);
7751}
7752
7753void Document::unregisterArticleElement(Element& article)
7754{
7755 m_articleElements.remove(&article);
7756 if (m_mainArticleElement == &article)
7757 m_mainArticleElement = nullptr;
7758}
7759
7760void Document::updateMainArticleElementAfterLayout()
7761{
7762 ASSERT(page() && page()->requestedLayoutMilestones().contains(DidRenderSignificantAmountOfText));
7763
7764 // If there are too many article elements on the page, don't consider any one of them to be "main content".
7765 const unsigned maxNumberOfArticlesBeforeIgnoringMainContentArticle = 10;
7766
7767 // We consider an article to be main content if it is either:
7768 // 1. The only article element in the document.
7769 // 2. Much taller than the next tallest article, and also much larger than the viewport.
7770 const float minimumSecondTallestArticleHeightFactor = 4;
7771 const float minimumViewportAreaFactor = 5;
7772
7773 m_mainArticleElement = nullptr;
7774
7775 auto numberOfArticles = m_articleElements.size();
7776 if (!numberOfArticles || numberOfArticles > maxNumberOfArticlesBeforeIgnoringMainContentArticle)
7777 return;
7778
7779 Element* tallestArticle = nullptr;
7780 float tallestArticleHeight = 0;
7781 float tallestArticleWidth = 0;
7782 float secondTallestArticleHeight = 0;
7783
7784 for (auto* article : m_articleElements) {
7785 auto* box = article->renderBox();
7786 float height = box ? box->height().toFloat() : 0;
7787 if (height >= tallestArticleHeight) {
7788 secondTallestArticleHeight = tallestArticleHeight;
7789 tallestArticleHeight = height;
7790 tallestArticleWidth = box ? box->width().toFloat() : 0;
7791 tallestArticle = article;
7792 } else if (height >= secondTallestArticleHeight)
7793 secondTallestArticleHeight = height;
7794 }
7795
7796 if (numberOfArticles == 1) {
7797 m_mainArticleElement = tallestArticle;
7798 return;
7799 }
7800
7801 if (tallestArticleHeight < minimumSecondTallestArticleHeightFactor * secondTallestArticleHeight)
7802 return;
7803
7804 if (!view())
7805 return;
7806
7807 auto viewportSize = view()->layoutViewportRect().size();
7808 if (tallestArticleWidth * tallestArticleHeight < minimumViewportAreaFactor * (viewportSize.width() * viewportSize.height()).toFloat())
7809 return;
7810
7811 m_mainArticleElement = tallestArticle;
7812}
7813
7814#if ENABLE(RESOURCE_LOAD_STATISTICS)
7815bool Document::hasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain& domain)
7816{
7817 return m_registrableDomainRequestedPageSpecificStorageAccessWithUserInteraction == domain;
7818}
7819
7820void Document::setHasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain& domain)
7821{
7822 m_registrableDomainRequestedPageSpecificStorageAccessWithUserInteraction = domain;
7823}
7824#endif
7825
7826void Document::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
7827{
7828 m_consoleMessageListener = listener;
7829}
7830
7831DocumentTimeline& Document::timeline()
7832{
7833 if (!m_timeline)
7834 m_timeline = DocumentTimeline::create(*this);
7835
7836 return *m_timeline;
7837}
7838
7839Vector<RefPtr<WebAnimation>> Document::getAnimations()
7840{
7841 // For the list of animations to be current, we need to account for any pending CSS changes,
7842 // such as updates to CSS Animations and CSS Transitions.
7843 updateStyleIfNeeded();
7844
7845 if (m_timeline)
7846 return m_timeline->getAnimations();
7847 return { };
7848}
7849
7850#if ENABLE(ATTACHMENT_ELEMENT)
7851
7852void Document::registerAttachmentIdentifier(const String& identifier)
7853{
7854 if (auto* frame = this->frame())
7855 frame->editor().registerAttachmentIdentifier(identifier);
7856}
7857
7858void Document::didInsertAttachmentElement(HTMLAttachmentElement& attachment)
7859{
7860 auto identifier = attachment.uniqueIdentifier();
7861 auto previousIdentifier = identifier;
7862 bool previousIdentifierIsNotUnique = !previousIdentifier.isEmpty() && m_attachmentIdentifierToElementMap.contains(previousIdentifier);
7863 if (identifier.isEmpty() || previousIdentifierIsNotUnique) {
7864 previousIdentifier = identifier;
7865 identifier = createCanonicalUUIDString();
7866 attachment.setUniqueIdentifier(identifier);
7867 }
7868
7869 m_attachmentIdentifierToElementMap.set(identifier, attachment);
7870
7871 if (auto* frame = this->frame()) {
7872 if (previousIdentifierIsNotUnique)
7873 frame->editor().cloneAttachmentData(previousIdentifier, identifier);
7874 frame->editor().didInsertAttachmentElement(attachment);
7875 }
7876}
7877
7878void Document::didRemoveAttachmentElement(HTMLAttachmentElement& attachment)
7879{
7880 auto identifier = attachment.uniqueIdentifier();
7881 if (!identifier)
7882 return;
7883
7884 m_attachmentIdentifierToElementMap.remove(identifier);
7885
7886 if (frame())
7887 frame()->editor().didRemoveAttachmentElement(attachment);
7888}
7889
7890RefPtr<HTMLAttachmentElement> Document::attachmentForIdentifier(const String& identifier) const
7891{
7892 return m_attachmentIdentifierToElementMap.get(identifier);
7893}
7894
7895#endif // ENABLE(ATTACHMENT_ELEMENT)
7896
7897static MessageSource messageSourceForWTFLogChannel(const WTFLogChannel& channel)
7898{
7899 static const NeverDestroyed<String> mediaChannel = MAKE_STATIC_STRING_IMPL("media");
7900 static const NeverDestroyed<String> webrtcChannel = MAKE_STATIC_STRING_IMPL("webrtc");
7901 static const NeverDestroyed<String> mediaSourceChannel = MAKE_STATIC_STRING_IMPL("mediasource");
7902
7903 if (equalIgnoringASCIICase(mediaChannel, channel.name))
7904 return MessageSource::Media;
7905
7906 if (equalIgnoringASCIICase(webrtcChannel, channel.name))
7907 return MessageSource::WebRTC;
7908
7909 if (equalIgnoringASCIICase(mediaSourceChannel, channel.name))
7910 return MessageSource::MediaSource;
7911
7912 return MessageSource::Other;
7913}
7914
7915static MessageLevel messageLevelFromWTFLogLevel(WTFLogLevel level)
7916{
7917 switch (level) {
7918 case WTFLogLevel::Always:
7919 return MessageLevel::Log;
7920 case WTFLogLevel::Error:
7921 return MessageLevel::Error;
7922 break;
7923 case WTFLogLevel::Warning:
7924 return MessageLevel::Warning;
7925 break;
7926 case WTFLogLevel::Info:
7927 return MessageLevel::Info;
7928 break;
7929 case WTFLogLevel::Debug:
7930 return MessageLevel::Debug;
7931 break;
7932 }
7933
7934 ASSERT_NOT_REACHED();
7935 return MessageLevel::Log;
7936}
7937
7938void Document::didLogMessage(const WTFLogChannel& channel, WTFLogLevel level, Vector<JSONLogValue>&& logMessages)
7939{
7940 if (!page())
7941 return;
7942
7943 ASSERT(sessionID().isAlwaysOnLoggingAllowed());
7944
7945 auto messageSource = messageSourceForWTFLogChannel(channel);
7946 if (messageSource == MessageSource::Other)
7947 return;
7948
7949 m_logMessageTaskQueue.enqueueTask([this, level, messageSource, logMessages = WTFMove(logMessages)]() mutable {
7950 if (!page())
7951 return;
7952
7953 auto messageLevel = messageLevelFromWTFLogLevel(level);
7954 auto message = std::make_unique<Inspector::ConsoleMessage>(messageSource, MessageType::Log, messageLevel, WTFMove(logMessages), mainWorldExecState(frame()));
7955
7956 addConsoleMessage(WTFMove(message));
7957 });
7958}
7959
7960#if ENABLE(SERVICE_WORKER)
7961void Document::setServiceWorkerConnection(SWClientConnection* serviceWorkerConnection)
7962{
7963 if (m_serviceWorkerConnection == serviceWorkerConnection || m_hasPreparedForDestruction || m_isSuspended)
7964 return;
7965
7966 if (m_serviceWorkerConnection)
7967 m_serviceWorkerConnection->unregisterServiceWorkerClient(identifier());
7968
7969 m_serviceWorkerConnection = serviceWorkerConnection;
7970
7971 if (!m_serviceWorkerConnection)
7972 return;
7973
7974 auto controllingServiceWorkerRegistrationIdentifier = activeServiceWorker() ? makeOptional<ServiceWorkerRegistrationIdentifier>(activeServiceWorker()->registrationIdentifier()) : WTF::nullopt;
7975 m_serviceWorkerConnection->registerServiceWorkerClient(topOrigin(), ServiceWorkerClientData::from(*this, *serviceWorkerConnection), controllingServiceWorkerRegistrationIdentifier, userAgent(url()));
7976}
7977#endif
7978
7979String Document::signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const URL& url)
7980{
7981 Page* page = this->page();
7982 if (!page)
7983 return emptyString();
7984 return page->chrome().client().signedPublicKeyAndChallengeString(keySizeIndex, challengeString, url);
7985}
7986
7987bool Document::registerCSSProperty(CSSRegisteredCustomProperty&& prop)
7988{
7989 return m_CSSRegisteredPropertySet.add(prop.name, std::make_unique<CSSRegisteredCustomProperty>(WTFMove(prop))).isNewEntry;
7990}
7991
7992void Document::detachFromFrame()
7993{
7994 // Assertion to help pinpint rdar://problem/49877867. If this hits, the crash trace should tell us
7995 // which piece of code is detaching the document from its frame while constructing the CachedFrames.
7996 RELEASE_ASSERT(m_mayBeDetachedFromFrame);
7997
7998 observeFrame(nullptr);
7999}
8000
8001void Document::frameWasDisconnectedFromOwner()
8002{
8003 if (!frame())
8004 return;
8005
8006 if (auto* window = domWindow())
8007 window->willDetachDocumentFromFrame();
8008
8009 detachFromFrame();
8010}
8011
8012ElementIdentifier Document::identifierForElement(Element& element)
8013{
8014 ASSERT(&element.document() == this);
8015 auto result = m_identifiedElementsMap.ensure(&element, [&] {
8016 return element.createElementIdentifier();
8017 });
8018 return result.iterator->value;
8019}
8020
8021Element* Document::searchForElementByIdentifier(const ElementIdentifier& identifier)
8022{
8023 for (auto it = m_identifiedElementsMap.begin(); it != m_identifiedElementsMap.end(); ++it) {
8024 if (it->value == identifier)
8025 return it->key;
8026 }
8027
8028 return nullptr;
8029}
8030
8031void Document::identifiedElementWasRemovedFromDocument(Element& element)
8032{
8033 m_identifiedElementsMap.remove(&element);
8034}
8035
8036#if ENABLE(DEVICE_ORIENTATION)
8037
8038DeviceOrientationAndMotionAccessController& Document::deviceOrientationAndMotionAccessController()
8039{
8040 if (&topDocument() != this)
8041 return topDocument().deviceOrientationAndMotionAccessController();
8042
8043 if (!m_deviceOrientationAndMotionAccessController)
8044 m_deviceOrientationAndMotionAccessController = std::make_unique<DeviceOrientationAndMotionAccessController>(*this);
8045 return *m_deviceOrientationAndMotionAccessController;
8046}
8047
8048#endif
8049
8050#if ENABLE(CSS_PAINTING_API)
8051Worklet& Document::ensurePaintWorklet()
8052{
8053 if (!m_paintWorklet)
8054 m_paintWorklet = Worklet::create();
8055 return *m_paintWorklet;
8056}
8057
8058PaintWorkletGlobalScope* Document::paintWorkletGlobalScopeForName(const String& name)
8059{
8060 return m_paintWorkletGlobalScopes.get(name);
8061}
8062
8063void Document::setPaintWorkletGlobalScopeForName(const String& name, Ref<PaintWorkletGlobalScope>&& scope)
8064{
8065 auto addResult = m_paintWorkletGlobalScopes.add(name, WTFMove(scope));
8066 ASSERT_UNUSED(addResult, addResult);
8067}
8068#endif
8069
8070#if PLATFORM(IOS_FAMILY) && ENABLE(POINTER_EVENTS)
8071void Document::updateTouchActionElements(Element& element, const RenderStyle& style)
8072{
8073 bool changed = false;
8074
8075 if (style.touchActions() != TouchAction::Auto) {
8076 if (!m_touchActionElements)
8077 m_touchActionElements = std::make_unique<HashSet<RefPtr<Element>>>();
8078 changed |= m_touchActionElements->add(&element).isNewEntry;
8079 } else if (m_touchActionElements)
8080 changed |= m_touchActionElements->remove(&element);
8081
8082 if (!changed)
8083 return;
8084
8085 Page* page = this->page();
8086 if (!page)
8087 return;
8088
8089 if (FrameView* frameView = view()) {
8090 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
8091 scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
8092 }
8093}
8094#endif
8095
8096#if PLATFORM(IOS_FAMILY)
8097ContentChangeObserver& Document::contentChangeObserver()
8098{
8099 if (!m_contentChangeObserver)
8100 m_contentChangeObserver = std::make_unique<ContentChangeObserver>(*this);
8101 return *m_contentChangeObserver;
8102}
8103#endif
8104
8105bool Document::hasEvaluatedUserAgentScripts() const
8106{
8107 auto& top = topDocument();
8108 return this == &top ? m_hasEvaluatedUserAgentScripts : top.hasEvaluatedUserAgentScripts();
8109}
8110
8111bool Document::isRunningUserScripts() const
8112{
8113 auto& top = topDocument();
8114 return this == &top ? m_isRunningUserScripts : top.isRunningUserScripts();
8115}
8116
8117void Document::setAsRunningUserScripts()
8118{
8119 auto& top = topDocument();
8120 if (this == &top)
8121 m_isRunningUserScripts = true;
8122 else
8123 top.setAsRunningUserScripts();
8124}
8125
8126void Document::setHasEvaluatedUserAgentScripts()
8127{
8128 auto& top = topDocument();
8129 if (this == &top)
8130 m_hasEvaluatedUserAgentScripts = true;
8131 else
8132 top.setHasEvaluatedUserAgentScripts();
8133}
8134
8135#if ENABLE(APPLE_PAY)
8136
8137bool Document::hasStartedApplePaySession() const
8138{
8139 auto& top = topDocument();
8140 return this == &top ? m_hasStartedApplePaySession : top.hasStartedApplePaySession();
8141}
8142
8143void Document::setHasStartedApplePaySession()
8144{
8145 auto& top = topDocument();
8146 if (this == &top)
8147 m_hasStartedApplePaySession = true;
8148 else
8149 top.setHasStartedApplePaySession();
8150}
8151
8152#endif
8153
8154} // namespace WebCore
8155