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