2 * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include "ActivityStateChangeObserver.h"
24 #include "AlternativeTextClient.h"
25 #include "ApplicationCacheStorage.h"
26 #include "ApplicationStateChangeListener.h"
27 #include "AuthenticatorCoordinator.h"
28 #include "BackForwardCache.h"
29 #include "BackForwardClient.h"
30 #include "BackForwardController.h"
31 #include "CSSAnimationController.h"
32 #include "CacheStorageProvider.h"
34 #include "ChromeClient.h"
35 #include "ConstantPropertyMap.h"
36 #include "ContextMenuClient.h"
37 #include "ContextMenuController.h"
38 #include "CookieJar.h"
39 #include "CustomHeaderFields.h"
41 #include "DOMRectList.h"
42 #include "DatabaseProvider.h"
43 #include "DiagnosticLoggingClient.h"
44 #include "DiagnosticLoggingKeys.h"
45 #include "DocumentLoader.h"
46 #include "DocumentMarkerController.h"
47 #include "DocumentTimeline.h"
48 #include "DragController.h"
51 #include "EditorClient.h"
52 #include "EmptyClients.h"
54 #include "EventNames.h"
55 #include "ExtensionStyleSheets.h"
56 #include "FocusController.h"
57 #include "FrameLoader.h"
58 #include "FrameLoaderClient.h"
59 #include "FrameSelection.h"
60 #include "FrameTree.h"
61 #include "FrameView.h"
62 #include "FullscreenManager.h"
63 #include "HTMLElement.h"
64 #include "HTMLMediaElement.h"
65 #include "HTMLTextAreaElement.h"
66 #include "HTMLTextFormControlElement.h"
67 #include "HistoryController.h"
68 #include "HistoryItem.h"
69 #include "InspectorClient.h"
70 #include "InspectorController.h"
71 #include "InspectorInstrumentation.h"
72 #include "LegacySchemeRegistry.h"
73 #include "LibWebRTCProvider.h"
74 #include "LoaderStrategy.h"
76 #include "LowPowerModeNotifier.h"
77 #include "MediaCanStartListener.h"
78 #include "Navigator.h"
79 #include "PageConfiguration.h"
80 #include "PageConsoleClient.h"
81 #include "PageDebuggable.h"
82 #include "PageGroup.h"
83 #include "PageOverlayController.h"
84 #include "PaymentCoordinator.h"
85 #include "PerformanceLogging.h"
86 #include "PerformanceLoggingClient.h"
87 #include "PerformanceMonitor.h"
88 #include "PlatformMediaSessionManager.h"
89 #include "PlatformStrategies.h"
90 #include "PlugInClient.h"
91 #include "PluginData.h"
92 #include "PluginInfoProvider.h"
93 #include "PluginViewBase.h"
94 #include "PointerCaptureController.h"
95 #include "PointerLockController.h"
96 #include "ProgressTracker.h"
97 #include "RenderDescendantIterator.h"
98 #include "RenderLayerCompositor.h"
99 #include "RenderTheme.h"
100 #include "RenderView.h"
101 #include "RenderWidget.h"
102 #include "ResizeObserver.h"
103 #include "ResourceUsageOverlay.h"
104 #include "RuntimeEnabledFeatures.h"
105 #include "SVGDocumentExtensions.h"
106 #include "ScriptController.h"
107 #include "ScriptedAnimationController.h"
108 #include "ScrollLatchingState.h"
109 #include "ScrollingCoordinator.h"
110 #include "Settings.h"
111 #include "SharedBuffer.h"
112 #include "SocketProvider.h"
113 #include "StorageArea.h"
114 #include "StorageNamespace.h"
115 #include "StorageNamespaceProvider.h"
116 #include "StyleResolver.h"
117 #include "StyleScope.h"
118 #include "SubframeLoader.h"
119 #include "TextIterator.h"
120 #include "TextResourceDecoder.h"
121 #include "UserContentProvider.h"
122 #include "UserInputBridge.h"
123 #include "ValidationMessageClient.h"
124 #include "VisitedLinkState.h"
125 #include "VisitedLinkStore.h"
126 #include "VoidCallback.h"
127 #include "WheelEventDeltaFilter.h"
129 #include <wtf/Deque.h>
130 #include <wtf/FileSystem.h>
131 #include <wtf/RefCountedLeakCounter.h>
132 #include <wtf/StdLibExtras.h>
133 #include <wtf/SystemTracing.h>
134 #include <wtf/text/Base64.h>
135 #include <wtf/text/StringHash.h>
137 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
138 #include "HTMLVideoElement.h"
139 #include "MediaPlaybackTarget.h"
143 #include "ServicesOverlayController.h"
146 #if ENABLE(MEDIA_SESSION)
147 #include "MediaSessionManager.h"
150 #if ENABLE(INDEXED_DATABASE)
151 #include "IDBConnectionToServer.h"
152 #include "InProcessIDBServer.h"
155 #if ENABLE(DATA_INTERACTION)
156 #include "SelectionRect.h"
160 #include "WebGLStateTracker.h"
165 static HashSet<Page*>& allPages()
167 static NeverDestroyed<HashSet<Page*>> set;
171 static unsigned nonUtilityPageCount { 0 };
173 static inline bool isUtilityPageChromeClient(ChromeClient& chromeClient)
175 return chromeClient.isEmptyChromeClient() || chromeClient.isSVGImageChromeClient();
178 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
180 void Page::forEachPage(const WTF::Function<void(Page&)>& function)
182 for (auto* page : allPages())
186 void Page::updateValidationBubbleStateIfNeeded()
188 if (auto* client = validationMessageClient())
189 client->updateValidationBubbleStateIfNeeded();
192 static void networkStateChanged(bool isOnLine)
194 Vector<Ref<Frame>> frames;
196 // Get all the frames of all the pages in all the page groups
197 for (auto* page : allPages()) {
198 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
199 frames.append(*frame);
200 InspectorInstrumentation::networkStateChanged(*page);
203 auto& eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
204 for (auto& frame : frames) {
205 if (!frame->document())
207 frame->document()->dispatchWindowEvent(Event::create(eventName, Event::CanBubble::No, Event::IsCancelable::No));
211 static constexpr OptionSet<ActivityState::Flag> pageInitialActivityState()
213 return { ActivityState::IsVisible, ActivityState::IsInWindow };
216 Page::Page(PageConfiguration&& pageConfiguration)
217 : m_chrome(makeUnique<Chrome>(*this, *pageConfiguration.chromeClient))
218 , m_dragCaretController(makeUnique<DragCaretController>())
219 #if ENABLE(DRAG_SUPPORT)
220 , m_dragController(makeUnique<DragController>(*this, *pageConfiguration.dragClient))
222 , m_focusController(makeUnique<FocusController>(*this, pageInitialActivityState()))
223 #if ENABLE(CONTEXT_MENUS)
224 , m_contextMenuController(makeUnique<ContextMenuController>(*this, *pageConfiguration.contextMenuClient))
226 , m_userInputBridge(makeUnique<UserInputBridge>(*this))
227 , m_inspectorController(makeUnique<InspectorController>(*this, pageConfiguration.inspectorClient))
228 #if ENABLE(POINTER_EVENTS)
229 , m_pointerCaptureController(makeUnique<PointerCaptureController>(*this))
231 #if ENABLE(POINTER_LOCK)
232 , m_pointerLockController(makeUnique<PointerLockController>(*this))
234 , m_settings(Settings::create(this))
235 , m_progress(makeUnique<ProgressTracker>(*pageConfiguration.progressTrackerClient))
236 , m_backForwardController(makeUnique<BackForwardController>(*this, WTFMove(pageConfiguration.backForwardClient)))
237 , m_mainFrame(Frame::create(this, nullptr, pageConfiguration.loaderClientForMainFrame))
238 , m_editorClient(WTFMove(pageConfiguration.editorClient))
239 , m_plugInClient(pageConfiguration.plugInClient)
240 , m_validationMessageClient(WTFMove(pageConfiguration.validationMessageClient))
241 , m_diagnosticLoggingClient(WTFMove(pageConfiguration.diagnosticLoggingClient))
242 , m_performanceLoggingClient(WTFMove(pageConfiguration.performanceLoggingClient))
244 , m_webGLStateTracker(WTFMove(pageConfiguration.webGLStateTracker))
246 #if ENABLE(SPEECH_SYNTHESIS)
247 , m_speechSynthesisClient(WTFMove(pageConfiguration.speechSynthesisClient))
249 , m_libWebRTCProvider(WTFMove(pageConfiguration.libWebRTCProvider))
250 , m_verticalScrollElasticity(ScrollElasticityAllowed)
251 , m_horizontalScrollElasticity(ScrollElasticityAllowed)
252 , m_domTimerAlignmentInterval(DOMTimer::defaultAlignmentInterval())
253 , m_domTimerAlignmentIntervalIncreaseTimer(*this, &Page::domTimerAlignmentIntervalIncreaseTimerFired)
254 , m_activityState(pageInitialActivityState())
255 , m_alternativeTextClient(pageConfiguration.alternativeTextClient)
256 , m_consoleClient(makeUnique<PageConsoleClient>(*this))
257 #if ENABLE(REMOTE_INSPECTOR)
258 , m_inspectorDebuggable(makeUnique<PageDebuggable>(*this))
260 , m_socketProvider(WTFMove(pageConfiguration.socketProvider))
261 , m_cookieJar(WTFMove(pageConfiguration.cookieJar))
262 , m_applicationCacheStorage(*WTFMove(pageConfiguration.applicationCacheStorage))
263 , m_cacheStorageProvider(WTFMove(pageConfiguration.cacheStorageProvider))
264 , m_databaseProvider(*WTFMove(pageConfiguration.databaseProvider))
265 , m_pluginInfoProvider(*WTFMove(pageConfiguration.pluginInfoProvider))
266 , m_storageNamespaceProvider(*WTFMove(pageConfiguration.storageNamespaceProvider))
267 , m_userContentProvider(*WTFMove(pageConfiguration.userContentProvider))
268 , m_visitedLinkStore(*WTFMove(pageConfiguration.visitedLinkStore))
269 , m_sessionID(pageConfiguration.sessionID)
271 , m_playbackControlsManagerUpdateTimer(*this, &Page::playbackControlsManagerUpdateTimerFired)
273 , m_isUtilityPage(isUtilityPageChromeClient(chrome().client()))
274 , m_performanceMonitor(isUtilityPage() ? nullptr : makeUnique<PerformanceMonitor>(*this))
275 , m_lowPowerModeNotifier(makeUnique<LowPowerModeNotifier>([this](bool isLowPowerModeEnabled) { handleLowModePowerChange(isLowPowerModeEnabled); }))
276 , m_performanceLogging(makeUnique<PerformanceLogging>(*this))
277 #if PLATFORM(MAC) && (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION))
278 , m_servicesOverlayController(makeUnique<ServicesOverlayController>(*this))
280 , m_recentWheelEventDeltaFilter(WheelEventDeltaFilter::create())
281 , m_pageOverlayController(makeUnique<PageOverlayController>(*this))
282 #if ENABLE(APPLE_PAY)
283 , m_paymentCoordinator(makeUnique<PaymentCoordinator>(*pageConfiguration.paymentCoordinatorClient))
285 #if ENABLE(WEB_AUTHN)
286 , m_authenticatorCoordinator(makeUniqueRef<AuthenticatorCoordinator>(WTFMove(pageConfiguration.authenticatorCoordinatorClient)))
288 #if ENABLE(APPLICATION_MANIFEST)
289 , m_applicationManifest(pageConfiguration.applicationManifest)
292 updateTimerThrottlingState();
294 m_pluginInfoProvider->addPage(*this);
295 m_userContentProvider->addPage(*this);
296 m_visitedLinkStore->addPage(*this);
298 static bool addedListener;
299 if (!addedListener) {
300 platformStrategies()->loaderStrategy()->addOnlineStateChangeListener(&networkStateChanged);
301 addedListener = true;
304 ASSERT(!allPages().contains(this));
305 allPages().add(this);
307 if (!isUtilityPage()) {
308 ++nonUtilityPageCount;
309 MemoryPressureHandler::setPageCount(nonUtilityPageCount);
313 pageCounter.increment();
316 #if ENABLE(REMOTE_INSPECTOR)
317 if (m_inspectorController->inspectorClient() && m_inspectorController->inspectorClient()->allowRemoteInspectionToPageDirectly())
318 m_inspectorDebuggable->init();
322 platformInitialize();
326 m_libWebRTCProvider->supportsVP8(RuntimeEnabledFeatures::sharedFeatures().webRTCVP8CodecEnabled());
332 ASSERT(!m_nestedRunLoopCount);
333 ASSERT(!m_unnestCallback);
335 m_validationMessageClient = nullptr;
336 m_diagnosticLoggingClient = nullptr;
337 m_performanceLoggingClient = nullptr;
338 m_mainFrame->setView(nullptr);
339 setGroupName(String());
340 allPages().remove(this);
341 if (!isUtilityPage()) {
342 --nonUtilityPageCount;
343 MemoryPressureHandler::setPageCount(nonUtilityPageCount);
346 m_settings->pageDestroyed();
348 m_inspectorController->inspectedPageDestroyed();
350 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
351 frame->willDetachPage();
352 frame->detachFromPage();
356 m_plugInClient->pageDestroyed();
357 if (m_alternativeTextClient)
358 m_alternativeTextClient->pageDestroyed();
360 if (m_scrollingCoordinator)
361 m_scrollingCoordinator->pageDestroyed();
363 backForward().close();
364 if (!isUtilityPage())
365 BackForwardCache::singleton().removeAllItemsForPage(*this);
368 pageCounter.decrement();
371 m_pluginInfoProvider->removePage(*this);
372 m_userContentProvider->removePage(*this);
373 m_visitedLinkStore->removePage(*this);
376 void Page::clearPreviousItemFromAllPages(HistoryItem* item)
378 for (auto* page : allPages()) {
379 auto& controller = page->mainFrame().loader().history();
380 if (item == controller.previousItem()) {
381 controller.clearPreviousItem();
387 uint64_t Page::renderTreeSize() const
390 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
391 if (!frame->document() || !frame->document()->renderView())
393 total += frame->document()->renderView()->rendererCount();
398 OptionSet<DisabledAdaptations> Page::disabledAdaptations() const
400 if (mainFrame().document())
401 return mainFrame().document()->disabledAdaptations();
406 ViewportArguments Page::viewportArguments() const
408 return mainFrame().document() ? mainFrame().document()->viewportArguments() : ViewportArguments();
411 void Page::setOverrideViewportArguments(const Optional<ViewportArguments>& viewportArguments)
413 if (viewportArguments == m_overrideViewportArguments)
416 m_overrideViewportArguments = viewportArguments;
417 if (auto* document = mainFrame().document())
418 document->updateViewportArguments();
421 ScrollingCoordinator* Page::scrollingCoordinator()
423 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) {
424 m_scrollingCoordinator = chrome().client().createScrollingCoordinator(*this);
425 if (!m_scrollingCoordinator)
426 m_scrollingCoordinator = ScrollingCoordinator::create(this);
429 return m_scrollingCoordinator.get();
432 String Page::scrollingStateTreeAsText()
434 if (Document* document = m_mainFrame->document())
435 document->updateLayout();
437 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
438 return scrollingCoordinator->scrollingStateTreeAsText();
443 String Page::synchronousScrollingReasonsAsText()
445 if (Document* document = m_mainFrame->document())
446 document->updateLayout();
448 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
449 return scrollingCoordinator->synchronousScrollingReasonsAsText();
454 Ref<DOMRectList> Page::nonFastScrollableRects()
456 if (Document* document = m_mainFrame->document())
457 document->updateLayout();
459 Vector<IntRect> rects;
460 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
461 const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions();
462 for (const auto& synchronousEventRegion : eventTrackingRegions.eventSpecificSynchronousDispatchRegions)
463 rects.appendVector(synchronousEventRegion.value.rects());
466 Vector<FloatQuad> quads(rects.size());
467 for (size_t i = 0; i < rects.size(); ++i)
468 quads[i] = FloatRect(rects[i]);
470 return DOMRectList::create(quads);
473 Ref<DOMRectList> Page::touchEventRectsForEvent(const String& eventName)
475 if (Document* document = m_mainFrame->document()) {
476 document->updateLayout();
477 #if ENABLE(IOS_TOUCH_EVENTS)
478 document->updateTouchEventRegions();
482 Vector<IntRect> rects;
483 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
484 const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions();
485 const auto& region = eventTrackingRegions.eventSpecificSynchronousDispatchRegions.get(eventName);
486 rects.appendVector(region.rects());
489 Vector<FloatQuad> quads(rects.size());
490 for (size_t i = 0; i < rects.size(); ++i)
491 quads[i] = FloatRect(rects[i]);
493 return DOMRectList::create(quads);
496 Ref<DOMRectList> Page::passiveTouchEventListenerRects()
498 if (Document* document = m_mainFrame->document()) {
499 document->updateLayout();
500 #if ENABLE(IOS_TOUCH_EVENTS)
501 document->updateTouchEventRegions();
505 Vector<IntRect> rects;
506 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
507 rects.appendVector(scrollingCoordinator->absoluteEventTrackingRegions().asynchronousDispatchRegion.rects());
509 Vector<FloatQuad> quads(rects.size());
510 for (size_t i = 0; i < rects.size(); ++i)
511 quads[i] = FloatRect(rects[i]);
513 return DOMRectList::create(quads);
516 bool Page::openedByDOM() const
518 return m_openedByDOM;
521 void Page::setOpenedByDOM()
523 m_openedByDOM = true;
526 void Page::goToItem(HistoryItem& item, FrameLoadType type, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad)
528 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
529 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
530 Ref<HistoryItem> protector(item);
532 auto& frameLoader = m_mainFrame->loader();
533 if (frameLoader.history().shouldStopLoadingForHistoryItem(item))
534 m_mainFrame->loader().stopAllLoadersAndCheckCompleteness();
536 m_mainFrame->loader().history().goToItem(item, type, shouldTreatAsContinuingLoad);
539 void Page::setGroupName(const String& name)
541 if (m_group && !m_group->name().isEmpty()) {
542 ASSERT(m_group != m_singlePageGroup.get());
543 ASSERT(!m_singlePageGroup);
544 m_group->removePage(*this);
548 m_group = m_singlePageGroup.get();
550 m_singlePageGroup = nullptr;
551 m_group = PageGroup::pageGroup(name);
552 m_group->addPage(*this);
556 const String& Page::groupName() const
558 return m_group ? m_group->name() : nullAtom().string();
561 void Page::initGroup()
563 ASSERT(!m_singlePageGroup);
565 m_singlePageGroup = makeUnique<PageGroup>(*this);
566 m_group = m_singlePageGroup.get();
569 void Page::updateStyleAfterChangeInEnvironment()
571 forEachDocument([](Document& document) {
572 if (StyleResolver* styleResolver = document.styleScope().resolverIfExists())
573 styleResolver->invalidateMatchedDeclarationsCache();
574 document.scheduleFullStyleRebuild();
575 document.styleScope().didChangeStyleSheetEnvironment();
576 document.scheduleTimedRenderingUpdate();
580 void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
582 for (auto* page : allPages())
583 page->updateStyleAfterChangeInEnvironment();
586 void Page::setNeedsRecalcStyleInAllFrames()
588 // FIXME: Figure out what this function is actually trying to add in different call sites.
589 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
590 if (Document* document = frame->document())
591 document->styleScope().didChangeStyleSheetEnvironment();
595 void Page::refreshPlugins(bool reload)
597 HashSet<PluginInfoProvider*> pluginInfoProviders;
599 for (auto* page : allPages())
600 pluginInfoProviders.add(&page->pluginInfoProvider());
602 for (auto& pluginInfoProvider : pluginInfoProviders)
603 pluginInfoProvider->refresh(reload);
606 PluginData& Page::pluginData()
609 m_pluginData = PluginData::create(*this);
610 return *m_pluginData;
613 void Page::clearPluginData()
615 m_pluginData = nullptr;
618 bool Page::showAllPlugins() const
620 if (m_showAllPlugins)
623 if (Document* document = mainFrame().document())
624 return document->securityOrigin().isLocal();
629 inline Optional<std::pair<MediaCanStartListener&, Document&>> Page::takeAnyMediaCanStartListener()
631 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
632 if (!frame->document())
634 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
635 return { { *listener, *frame->document() } };
640 void Page::setCanStartMedia(bool canStartMedia)
642 if (m_canStartMedia == canStartMedia)
645 m_canStartMedia = canStartMedia;
647 while (m_canStartMedia) {
648 auto listener = takeAnyMediaCanStartListener();
651 listener->first.mediaCanStart(listener->second);
655 static Frame* incrementFrame(Frame* curr, bool forward, CanWrap canWrap, DidWrap* didWrap = nullptr)
658 ? curr->tree().traverseNext(canWrap, didWrap)
659 : curr->tree().traversePrevious(canWrap, didWrap);
662 bool Page::findString(const String& target, FindOptions options, DidWrap* didWrap)
664 if (target.isEmpty())
667 CanWrap canWrap = options.contains(WrapAround) ? CanWrap::Yes : CanWrap::No;
668 Frame* frame = &focusController().focusedOrMainFrame();
669 Frame* startFrame = frame;
671 if (frame->editor().findString(target, (options - WrapAround) | StartInSelection)) {
672 if (frame != startFrame)
673 startFrame->selection().clear();
674 focusController().setFocusedFrame(frame);
677 frame = incrementFrame(frame, !options.contains(Backwards), canWrap, didWrap);
678 } while (frame && frame != startFrame);
680 // Search contents of startFrame, on the other side of the selection that we did earlier.
681 // We cheat a bit and just research with wrap on
682 if (canWrap == CanWrap::Yes && !startFrame->selection().isNone()) {
684 *didWrap = DidWrap::Yes;
685 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
686 focusController().setFocusedFrame(frame);
693 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection)
695 indexForSelection = 0;
697 Frame* frame = &mainFrame();
698 Frame* frameWithSelection = nullptr;
700 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges);
701 if (frame->selection().isRange())
702 frameWithSelection = frame;
703 frame = incrementFrame(frame, true, CanWrap::No);
706 if (matchRanges.isEmpty())
709 if (frameWithSelection) {
710 indexForSelection = NoMatchAfterUserSelection;
711 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
712 if (options.contains(Backwards)) {
713 for (size_t i = matchRanges.size(); i > 0; --i) {
714 auto result = selectedRange->compareBoundaryPoints(Range::END_TO_START, *matchRanges[i - 1]);
715 if (!result.hasException() && result.releaseReturnValue() > 0) {
716 indexForSelection = i - 1;
721 for (size_t i = 0, size = matchRanges.size(); i < size; ++i) {
722 auto result = selectedRange->compareBoundaryPoints(Range::START_TO_END, *matchRanges[i]);
723 if (!result.hasException() && result.releaseReturnValue() < 0) {
724 indexForSelection = i;
730 if (options.contains(Backwards))
731 indexForSelection = matchRanges.size() - 1;
733 indexForSelection = 0;
737 RefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
739 if (target.isEmpty())
742 if (referenceRange && referenceRange->ownerDocument().page() != this)
745 CanWrap canWrap = options.contains(WrapAround) ? CanWrap::Yes : CanWrap::No;
746 Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame();
747 Frame* startFrame = frame;
749 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options - WrapAround))
752 frame = incrementFrame(frame, !options.contains(Backwards), canWrap);
753 } while (frame && frame != startFrame);
755 // Search contents of startFrame, on the other side of the reference range that we did earlier.
756 // We cheat a bit and just search again with wrap on.
757 if (canWrap == CanWrap::Yes && referenceRange) {
758 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
765 unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
767 if (target.isEmpty())
770 unsigned matchCount = 0;
772 Frame* frame = &mainFrame();
774 if (shouldMarkMatches == MarkMatches)
775 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
776 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
777 frame = incrementFrame(frame, true, CanWrap::No);
783 unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
785 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
788 unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
790 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
793 struct FindReplacementRange {
794 RefPtr<ContainerNode> root;
795 size_t location { notFound };
799 static void replaceRanges(Page& page, const Vector<FindReplacementRange>& ranges, const String& replacementText)
801 HashMap<RefPtr<ContainerNode>, Vector<FindReplacementRange>> rangesByContainerNode;
802 for (auto& range : ranges) {
803 auto& rangeList = rangesByContainerNode.ensure(range.root, [] {
804 return Vector<FindReplacementRange> { };
807 // Ensure that ranges are sorted by their end offsets, per editing container.
808 auto endOffsetForRange = range.location + range.length;
809 auto insertionIndex = rangeList.size();
810 for (auto iterator = rangeList.rbegin(); iterator != rangeList.rend(); ++iterator) {
811 auto endOffsetBeforeInsertionIndex = iterator->location + iterator->length;
812 if (endOffsetForRange >= endOffsetBeforeInsertionIndex)
816 rangeList.insert(insertionIndex, range);
819 HashMap<RefPtr<Frame>, unsigned> frameToTraversalIndexMap;
820 unsigned currentFrameTraversalIndex = 0;
821 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext())
822 frameToTraversalIndexMap.set(frame, currentFrameTraversalIndex++);
824 // Likewise, iterate backwards (in document and frame order) through editing containers that contain text matches,
825 // so that we're consistent with our backwards iteration behavior per editing container when replacing text.
826 auto containerNodesInOrderOfReplacement = copyToVector(rangesByContainerNode.keys());
827 std::sort(containerNodesInOrderOfReplacement.begin(), containerNodesInOrderOfReplacement.end(), [frameToTraversalIndexMap] (auto& firstNode, auto& secondNode) {
828 if (firstNode == secondNode)
831 auto firstFrame = makeRefPtr(firstNode->document().frame());
835 auto secondFrame = makeRefPtr(secondNode->document().frame());
839 if (firstFrame == secondFrame) {
840 // comparePositions is used here instead of Node::compareDocumentPosition because some editing roots may exist inside shadow roots.
841 return comparePositions({ firstNode.get(), Position::PositionIsBeforeChildren }, { secondNode.get(), Position::PositionIsBeforeChildren }) > 0;
843 return frameToTraversalIndexMap.get(firstFrame) > frameToTraversalIndexMap.get(secondFrame);
846 for (auto& container : containerNodesInOrderOfReplacement) {
847 auto frame = makeRefPtr(container->document().frame());
851 // Iterate backwards through ranges when replacing text, such that earlier text replacements don't clobber replacement ranges later on.
852 auto& ranges = rangesByContainerNode.find(container)->value;
853 for (auto iterator = ranges.rbegin(); iterator != ranges.rend(); ++iterator) {
854 auto range = TextIterator::rangeFromLocationAndLength(container.get(), iterator->location, iterator->length);
855 if (!range || range->collapsed())
858 frame->selection().setSelectedRange(range.get(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);
859 frame->editor().replaceSelectionWithText(replacementText, Editor::SelectReplacement::Yes, Editor::SmartReplace::No, EditAction::InsertReplacement);
864 uint32_t Page::replaceRangesWithText(const Vector<Ref<Range>>& rangesToReplace, const String& replacementText, bool selectionOnly)
866 // FIXME: In the future, we should respect the `selectionOnly` flag by checking whether each range being replaced is
867 // contained within its frame's selection.
868 UNUSED_PARAM(selectionOnly);
870 Vector<FindReplacementRange> replacementRanges;
871 replacementRanges.reserveInitialCapacity(rangesToReplace.size());
873 for (auto& range : rangesToReplace) {
874 auto highestRoot = makeRefPtr(highestEditableRoot(range->startPosition()));
875 if (!highestRoot || highestRoot != highestEditableRoot(range->endPosition()))
878 auto frame = makeRefPtr(highestRoot->document().frame());
882 size_t replacementLocation = notFound;
883 size_t replacementLength = 0;
884 if (!TextIterator::getLocationAndLengthFromRange(highestRoot.get(), range.ptr(), replacementLocation, replacementLength))
887 if (replacementLocation == notFound || !replacementLength)
890 replacementRanges.append({ WTFMove(highestRoot), replacementLocation, replacementLength });
893 replaceRanges(*this, replacementRanges, replacementText);
894 return rangesToReplace.size();
897 uint32_t Page::replaceSelectionWithText(const String& replacementText)
899 auto frame = makeRef(focusController().focusedOrMainFrame());
900 auto selection = frame->selection().selection();
901 if (!selection.isContentEditable())
904 auto editAction = selection.isRange() ? EditAction::InsertReplacement : EditAction::Insert;
905 frame->editor().replaceSelectionWithText(replacementText, Editor::SelectReplacement::Yes, Editor::SmartReplace::No, editAction);
909 void Page::unmarkAllTextMatches()
911 Frame* frame = &mainFrame();
913 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
914 frame = incrementFrame(frame, true, CanWrap::No);
918 static bool isEditableTextInputElement(const Element& element)
920 if (is<HTMLTextFormControlElement>(element)) {
921 if (!element.isTextField() && !is<HTMLTextAreaElement>(element))
923 return downcast<HTMLTextFormControlElement>(element).isInnerTextElementEditable();
925 return element.isRootEditableElement();
928 Vector<Ref<Element>> Page::editableElementsInRect(const FloatRect& searchRectInRootViewCoordinates) const
930 Vector<Ref<Element>> result;
931 for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
932 auto* document = frame->document();
936 Deque<Node*> nodesToSearch;
937 nodesToSearch.append(document);
938 while (!nodesToSearch.isEmpty()) {
939 auto* node = nodesToSearch.takeFirst();
941 // It is possible to have nested text input contexts (e.g. <input type='text'> inside contenteditable) but
942 // in this case we just take the outermost context and skip the rest.
943 if (!is<Element>(node) || !isEditableTextInputElement(downcast<Element>(*node))) {
944 for (auto* child = node->firstChild(); child; child = child->nextSibling())
945 nodesToSearch.append(child);
949 auto& element = downcast<Element>(*node);
950 if (searchRectInRootViewCoordinates.intersects(element.clientRect()))
951 result.append(element);
957 const VisibleSelection& Page::selection() const
959 return focusController().focusedOrMainFrame().selection().selection();
962 void Page::setDefersLoading(bool defers)
964 if (!m_settings->loadDeferringEnabled())
967 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
968 ASSERT(defers || m_defersLoadingCallCount);
969 if (defers && ++m_defersLoadingCallCount > 1)
971 if (!defers && --m_defersLoadingCallCount)
974 ASSERT(!m_defersLoadingCallCount);
975 if (defers == m_defersLoading)
979 m_defersLoading = defers;
980 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
981 frame->loader().setDefersLoading(defers);
984 void Page::clearUndoRedoOperations()
986 m_editorClient->clearUndoRedoOperations();
989 bool Page::inLowQualityImageInterpolationMode() const
991 return m_inLowQualityInterpolationMode;
994 void Page::setInLowQualityImageInterpolationMode(bool mode)
996 m_inLowQualityInterpolationMode = mode;
999 DiagnosticLoggingClient& Page::diagnosticLoggingClient() const
1001 if (!settings().diagnosticLoggingEnabled() || !m_diagnosticLoggingClient)
1002 return emptyDiagnosticLoggingClient();
1003 return *m_diagnosticLoggingClient;
1006 void Page::setMediaVolume(float volume)
1008 if (volume < 0 || volume > 1)
1011 if (m_mediaVolume == volume)
1014 m_mediaVolume = volume;
1015 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1016 if (!frame->document())
1018 frame->document()->mediaVolumeDidChange();
1022 void Page::setZoomedOutPageScaleFactor(float scale)
1024 if (m_zoomedOutPageScaleFactor == scale)
1026 m_zoomedOutPageScaleFactor = scale;
1028 mainFrame().deviceOrPageScaleFactorChanged();
1031 void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState)
1033 LOG(Viewports, "Page::setPageScaleFactor %.2f - inStableState %d", scale, inStableState);
1035 Document* document = mainFrame().document();
1036 FrameView* view = document->view();
1038 if (scale == m_pageScaleFactor) {
1039 if (view && view->scrollPosition() != origin) {
1040 if (!m_settings->delegatesPageScaling())
1041 document->updateLayoutIgnorePendingStylesheets();
1043 if (!view->delegatesScrolling())
1044 view->setScrollPosition(origin);
1045 #if USE(COORDINATED_GRAPHICS)
1047 view->requestScrollPositionUpdate(origin);
1050 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1051 if (inStableState) {
1052 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1053 if (!frame->document())
1055 frame->document()->pageScaleFactorChangedAndStable();
1062 m_pageScaleFactor = scale;
1064 if (!m_settings->delegatesPageScaling()) {
1065 view->setNeedsLayoutAfterViewConfigurationChange();
1066 view->setNeedsCompositingGeometryUpdate();
1068 document->resolveStyle(Document::ResolveStyleType::Rebuild);
1070 // Transform change on RenderView doesn't trigger repaint on non-composited contents.
1071 mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
1074 mainFrame().deviceOrPageScaleFactorChanged();
1076 if (view && view->fixedElementsLayoutRelativeToFrame())
1077 view->setViewportConstrainedObjectsNeedLayout();
1079 if (view && view->scrollPosition() != origin) {
1080 if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
1081 view->layoutContext().layout();
1083 if (!view->delegatesScrolling())
1084 view->setScrollPosition(origin);
1085 #if USE(COORDINATED_GRAPHICS)
1087 view->requestScrollPositionUpdate(origin);
1091 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1092 if (inStableState) {
1093 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1094 if (!frame->document())
1096 frame->document()->pageScaleFactorChangedAndStable();
1100 UNUSED_PARAM(inStableState);
1104 void Page::setViewScaleFactor(float scale)
1106 if (m_viewScaleFactor == scale)
1109 m_viewScaleFactor = scale;
1110 BackForwardCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
1113 void Page::setDeviceScaleFactor(float scaleFactor)
1115 ASSERT(scaleFactor > 0);
1116 if (scaleFactor <= 0)
1119 if (m_deviceScaleFactor == scaleFactor)
1122 m_deviceScaleFactor = scaleFactor;
1123 setNeedsRecalcStyleInAllFrames();
1125 mainFrame().deviceOrPageScaleFactorChanged();
1126 BackForwardCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
1128 pageOverlayController().didChangeDeviceScaleFactor();
1131 void Page::setInitialScale(float initialScale)
1133 m_initialScale = initialScale;
1136 void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
1138 if (m_userInterfaceLayoutDirection == userInterfaceLayoutDirection)
1141 m_userInterfaceLayoutDirection = userInterfaceLayoutDirection;
1142 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
1143 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1144 if (!frame->document())
1146 frame->document()->userInterfaceLayoutDirectionChanged();
1152 void Page::updateMediaElementRateChangeRestrictions()
1154 for (auto* mediaElement : HTMLMediaElement::allMediaElements())
1155 mediaElement->updateRateChangeRestrictions();
1159 void Page::didStartProvisionalLoad()
1161 if (m_performanceMonitor)
1162 m_performanceMonitor->didStartProvisionalLoad();
1165 void Page::didFinishLoad()
1167 resetRelevantPaintedObjectCounter();
1169 if (m_performanceMonitor)
1170 m_performanceMonitor->didFinishLoad();
1173 bool Page::isOnlyNonUtilityPage() const
1175 return !isUtilityPage() && nonUtilityPageCount == 1;
1178 bool Page::isLowPowerModeEnabled() const
1180 if (m_lowPowerModeEnabledOverrideForTesting)
1181 return m_lowPowerModeEnabledOverrideForTesting.value();
1183 return m_lowPowerModeNotifier->isLowPowerModeEnabled();
1186 void Page::setLowPowerModeEnabledOverrideForTesting(Optional<bool> isEnabled)
1188 m_lowPowerModeEnabledOverrideForTesting = isEnabled;
1189 handleLowModePowerChange(m_lowPowerModeEnabledOverrideForTesting.valueOr(false));
1192 void Page::setTopContentInset(float contentInset)
1194 if (m_topContentInset == contentInset)
1197 m_topContentInset = contentInset;
1199 if (FrameView* view = mainFrame().view())
1200 view->topContentInsetDidChange(m_topContentInset);
1203 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
1205 if (suppressAnimations == m_suppressScrollbarAnimations)
1208 lockAllOverlayScrollbarsToHidden(suppressAnimations);
1209 m_suppressScrollbarAnimations = suppressAnimations;
1212 void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
1214 FrameView* view = mainFrame().view();
1218 view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
1220 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1221 FrameView* frameView = frame->view();
1225 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
1226 if (!scrollableAreas)
1229 for (auto& scrollableArea : *scrollableAreas)
1230 scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
1234 void Page::setVerticalScrollElasticity(ScrollElasticity elasticity)
1236 if (m_verticalScrollElasticity == elasticity)
1239 m_verticalScrollElasticity = elasticity;
1241 if (FrameView* view = mainFrame().view())
1242 view->setVerticalScrollElasticity(elasticity);
1245 void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity)
1247 if (m_horizontalScrollElasticity == elasticity)
1250 m_horizontalScrollElasticity = elasticity;
1252 if (FrameView* view = mainFrame().view())
1253 view->setHorizontalScrollElasticity(elasticity);
1256 void Page::setPagination(const Pagination& pagination)
1258 if (m_pagination == pagination)
1261 m_pagination = pagination;
1263 setNeedsRecalcStyleInAllFrames();
1266 void Page::setPaginationLineGridEnabled(bool enabled)
1268 if (m_paginationLineGridEnabled == enabled)
1271 m_paginationLineGridEnabled = enabled;
1273 setNeedsRecalcStyleInAllFrames();
1276 unsigned Page::pageCount() const
1278 if (m_pagination.mode == Pagination::Unpaginated)
1281 if (Document* document = mainFrame().document())
1282 document->updateLayoutIgnorePendingStylesheets();
1284 RenderView* contentRenderer = mainFrame().contentRenderer();
1285 return contentRenderer ? contentRenderer->pageCount() : 0;
1288 void Page::setIsInWindow(bool isInWindow)
1290 setActivityState(isInWindow ? m_activityState | ActivityState::IsInWindow : m_activityState - ActivityState::IsInWindow);
1293 void Page::setIsInWindowInternal(bool isInWindow)
1295 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1296 if (FrameView* frameView = frame->view())
1297 frameView->setIsInWindow(isInWindow);
1301 resumeAnimatingImages();
1304 void Page::addActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1306 m_activityStateChangeObservers.add(&observer);
1309 void Page::removeActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1311 m_activityStateChangeObservers.remove(&observer);
1314 void Page::layoutIfNeeded()
1316 if (FrameView* view = m_mainFrame->view())
1317 view->updateLayoutAndStyleIfNeededRecursive();
1320 // https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering
1321 void Page::updateRendering()
1323 // This function is not reentrant, e.g. a rAF callback may force repaint.
1324 if (m_inUpdateRendering) {
1329 TraceScope traceScope(RenderingUpdateStart, RenderingUpdateEnd);
1331 SetForScope<bool> change(m_inUpdateRendering, true);
1335 // Flush autofocus candidates
1337 forEachDocument([&](Document& document) {
1338 document.runResizeSteps();
1341 forEachDocument([&](Document& document) {
1342 document.runScrollSteps();
1345 forEachDocument([&](Document& document) {
1346 document.evaluateMediaQueriesAndReportChanges();
1349 Vector<Ref<Document>> documents = collectDocuments(); // The requestAnimationFrame callbacks may change the frame hierarchy of the page
1350 for (auto& document : documents) {
1351 DOMHighResTimeStamp timestamp = document->domWindow()->nowTimestamp();
1352 document->updateAnimationsAndSendEvents(timestamp);
1353 // FIXME: Run the fullscreen steps.
1354 document->serviceRequestAnimationFrameCallbacks(timestamp);
1359 #if ENABLE(INTERSECTION_OBSERVER)
1360 for (auto& document : documents)
1361 document->updateIntersectionObservations();
1363 #if ENABLE(RESIZE_OBSERVER)
1364 for (auto& document : documents)
1365 document->updateResizeObservations(*this);
1371 void Page::suspendScriptedAnimations()
1373 m_scriptedAnimationsSuspended = true;
1374 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1375 if (frame->document())
1376 frame->document()->suspendScriptedAnimationControllerCallbacks();
1380 void Page::resumeScriptedAnimations()
1382 m_scriptedAnimationsSuspended = false;
1383 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1384 if (frame->document())
1385 frame->document()->resumeScriptedAnimationControllerCallbacks();
1389 enum class ThrottlingReasonOperation { Add, Remove };
1390 static void updateScriptedAnimationsThrottlingReason(Page& page, ThrottlingReasonOperation operation, ScriptedAnimationController::ThrottlingReason reason)
1392 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
1393 auto* document = frame->document();
1396 auto* scriptedAnimationController = document->scriptedAnimationController();
1397 if (!scriptedAnimationController)
1400 if (operation == ThrottlingReasonOperation::Add)
1401 scriptedAnimationController->addThrottlingReason(reason);
1403 scriptedAnimationController->removeThrottlingReason(reason);
1407 void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
1409 updateScriptedAnimationsThrottlingReason(*this, isVisuallyIdle ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::VisuallyIdle);
1412 void Page::handleLowModePowerChange(bool isLowPowerModeEnabled)
1414 updateScriptedAnimationsThrottlingReason(*this, isLowPowerModeEnabled ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::LowPowerMode);
1415 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1416 forEachDocument([&] (Document& document) {
1417 if (auto timeline = document.existingTimeline())
1418 timeline->updateThrottlingState();
1421 mainFrame().animation().updateThrottlingState();
1422 updateDOMTimerAlignmentInterval();
1425 void Page::userStyleSheetLocationChanged()
1427 // FIXME: Eventually we will move to a model of just being handed the sheet
1428 // text instead of loading the URL ourselves.
1429 URL url = m_settings->userStyleSheetLocation();
1431 // Allow any local file URL scheme to be loaded.
1432 if (LegacySchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toStringWithoutCopying()))
1433 m_userStyleSheetPath = url.fileSystemPath();
1435 m_userStyleSheetPath = String();
1437 m_didLoadUserStyleSheet = false;
1438 m_userStyleSheet = String();
1439 m_userStyleSheetModificationTime = WTF::nullopt;
1441 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
1442 // synchronously and avoid using a loader.
1443 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
1444 m_didLoadUserStyleSheet = true;
1446 Vector<char> styleSheetAsUTF8;
1447 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreSpacesAndNewLines))
1448 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
1451 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1452 if (frame->document())
1453 frame->document()->extensionStyleSheets().updatePageUserSheet();
1457 const String& Page::userStyleSheet() const
1459 if (m_userStyleSheetPath.isEmpty())
1460 return m_userStyleSheet;
1462 auto modificationTime = FileSystem::getFileModificationTime(m_userStyleSheetPath);
1463 if (!modificationTime) {
1464 // The stylesheet either doesn't exist, was just deleted, or is
1465 // otherwise unreadable. If we've read the stylesheet before, we should
1466 // throw away that data now as it no longer represents what's on disk.
1467 m_userStyleSheet = String();
1468 return m_userStyleSheet;
1471 // If the stylesheet hasn't changed since the last time we read it, we can
1472 // just return the old data.
1473 if (m_didLoadUserStyleSheet && (m_userStyleSheetModificationTime && modificationTime.value() <= m_userStyleSheetModificationTime.value()))
1474 return m_userStyleSheet;
1476 m_didLoadUserStyleSheet = true;
1477 m_userStyleSheet = String();
1478 m_userStyleSheetModificationTime = modificationTime;
1480 // FIXME: It would be better to load this asynchronously to avoid blocking
1481 // the process, but we will first need to create an asynchronous loading
1482 // mechanism that is not tied to a particular Frame. We will also have to
1483 // determine what our behavior should be before the stylesheet is loaded
1484 // and what should happen when it finishes loading, especially with respect
1485 // to when the load event fires, when Document::close is called, and when
1486 // layout/paint are allowed to happen.
1487 auto data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1489 return m_userStyleSheet;
1491 m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size());
1493 return m_userStyleSheet;
1496 void Page::userAgentChanged()
1498 for (auto* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1499 auto* window = frame->window();
1502 if (auto* navigator = window->optionalNavigator())
1503 navigator->userAgentChanged();
1507 void Page::invalidateStylesForAllLinks()
1509 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1510 if (!frame->document())
1512 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1516 void Page::invalidateStylesForLink(SharedStringHash linkHash)
1518 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1519 if (!frame->document())
1521 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1525 void Page::invalidateInjectedStyleSheetCacheInAllFrames()
1527 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1528 Document* document = frame->document();
1531 document->extensionStyleSheets().invalidateInjectedStyleSheetCache();
1535 void Page::setDebugger(JSC::Debugger* debugger)
1537 if (m_debugger == debugger)
1540 m_debugger = debugger;
1542 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1543 frame->windowProxy().attachDebugger(m_debugger);
1546 StorageNamespace* Page::sessionStorage(bool optionalCreate)
1548 if (!m_sessionStorage && optionalCreate)
1549 m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota());
1551 return m_sessionStorage.get();
1554 void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage)
1556 m_sessionStorage = WTFMove(newStorage);
1559 bool Page::hasCustomHTMLTokenizerTimeDelay() const
1561 return m_settings->maxParseDuration() != -1;
1564 double Page::customHTMLTokenizerTimeDelay() const
1566 ASSERT(m_settings->maxParseDuration() != -1);
1567 return m_settings->maxParseDuration();
1570 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1572 if (m_areMemoryCacheClientCallsEnabled == enabled)
1575 m_areMemoryCacheClientCallsEnabled = enabled;
1579 for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1580 frame->loader().tellClientAboutPastMemoryCacheLoads();
1583 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1585 // Disable & reengage to ensure state is updated.
1586 setTimerThrottlingState(TimerThrottlingState::Disabled);
1587 updateTimerThrottlingState();
1590 void Page::updateTimerThrottlingState()
1592 // Timer throttling disabled if page is visually active, or disabled by setting.
1593 if (!m_settings->hiddenPageDOMTimerThrottlingEnabled() || !(m_activityState & ActivityState::IsVisuallyIdle)) {
1594 setTimerThrottlingState(TimerThrottlingState::Disabled);
1598 // If the page is visible (but idle), there is any activity (loading, media playing, etc), or per setting,
1599 // we allow timer throttling, but not increasing timer throttling.
1600 if (!m_settings->hiddenPageDOMTimerThrottlingAutoIncreases()
1601 || m_activityState.containsAny({ActivityState::IsVisible, ActivityState::IsAudible, ActivityState::IsLoading, ActivityState::IsCapturingMedia })) {
1602 setTimerThrottlingState(TimerThrottlingState::Enabled);
1606 // If we get here increasing timer throttling is enabled.
1607 setTimerThrottlingState(TimerThrottlingState::EnabledIncreasing);
1610 void Page::setTimerThrottlingState(TimerThrottlingState state)
1612 if (state == m_timerThrottlingState)
1615 m_timerThrottlingState = state;
1616 m_timerThrottlingStateLastChangedTime = MonotonicTime::now();
1618 updateDOMTimerAlignmentInterval();
1620 // When throttling is disabled, release all throttled timers.
1621 if (state == TimerThrottlingState::Disabled) {
1622 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1623 if (auto* document = frame->document())
1624 document->didChangeTimerAlignmentInterval();
1629 void Page::setDOMTimerAlignmentIntervalIncreaseLimit(Seconds limit)
1631 m_domTimerAlignmentIntervalIncreaseLimit = limit;
1633 // If (m_domTimerAlignmentIntervalIncreaseLimit < m_domTimerAlignmentInterval) then we need
1634 // to update m_domTimerAlignmentInterval, if greater then need to restart the increase timer.
1635 if (m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing)
1636 updateDOMTimerAlignmentInterval();
1639 void Page::updateDOMTimerAlignmentInterval()
1641 bool needsIncreaseTimer = false;
1643 switch (m_timerThrottlingState) {
1644 case TimerThrottlingState::Disabled:
1645 m_domTimerAlignmentInterval = isLowPowerModeEnabled() ? DOMTimer::defaultAlignmentIntervalInLowPowerMode() : DOMTimer::defaultAlignmentInterval();
1648 case TimerThrottlingState::Enabled:
1649 m_domTimerAlignmentInterval = DOMTimer::hiddenPageAlignmentInterval();
1652 case TimerThrottlingState::EnabledIncreasing:
1653 // For pages in prerender state maximum throttling kicks in immediately.
1655 m_domTimerAlignmentInterval = m_domTimerAlignmentIntervalIncreaseLimit;
1657 ASSERT(!!m_timerThrottlingStateLastChangedTime);
1658 m_domTimerAlignmentInterval = MonotonicTime::now() - m_timerThrottlingStateLastChangedTime;
1659 // If we're below the limit, set the timer. If above, clamp to limit.
1660 if (m_domTimerAlignmentInterval < m_domTimerAlignmentIntervalIncreaseLimit)
1661 needsIncreaseTimer = true;
1663 m_domTimerAlignmentInterval = m_domTimerAlignmentIntervalIncreaseLimit;
1665 // Alignment interval should not be less than DOMTimer::hiddenPageAlignmentInterval().
1666 m_domTimerAlignmentInterval = std::max(m_domTimerAlignmentInterval, DOMTimer::hiddenPageAlignmentInterval());
1669 // If throttling is enabled, auto-increasing of throttling is enabled, and the auto-increase
1670 // limit has not yet been reached, and then arm the timer to consider an increase. Time to wait
1671 // between increases is equal to the current throttle time. Since alinment interval increases
1672 // exponentially, time between steps is exponential too.
1673 if (!needsIncreaseTimer)
1674 m_domTimerAlignmentIntervalIncreaseTimer.stop();
1675 else if (!m_domTimerAlignmentIntervalIncreaseTimer.isActive())
1676 m_domTimerAlignmentIntervalIncreaseTimer.startOneShot(m_domTimerAlignmentInterval);
1679 void Page::domTimerAlignmentIntervalIncreaseTimerFired()
1681 ASSERT(m_settings->hiddenPageDOMTimerThrottlingAutoIncreases());
1682 ASSERT(m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing);
1683 ASSERT(m_domTimerAlignmentInterval < m_domTimerAlignmentIntervalIncreaseLimit);
1685 // Alignment interval is increased to equal the time the page has been throttled, to a limit.
1686 updateDOMTimerAlignmentInterval();
1689 void Page::dnsPrefetchingStateChanged()
1691 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1692 if (!frame->document())
1694 frame->document()->initDNSPrefetch();
1698 Vector<Ref<PluginViewBase>> Page::pluginViews()
1700 Vector<Ref<PluginViewBase>> views;
1701 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1702 auto* view = frame->view();
1705 for (auto& widget : view->children()) {
1706 if (is<PluginViewBase>(widget))
1707 views.append(downcast<PluginViewBase>(widget.get()));
1713 void Page::storageBlockingStateChanged()
1715 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1716 if (!frame->document())
1718 frame->document()->storageBlockingStateDidChange();
1721 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1722 // from below storageBlockingStateChanged does not affect their lifetime.
1723 for (auto& view : pluginViews())
1724 view->storageBlockingStateChanged();
1727 void Page::updateIsPlayingMedia(uint64_t sourceElementID)
1729 MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
1730 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1731 if (Document* document = frame->document())
1732 state |= document->mediaState();
1735 if (state == m_mediaState)
1738 m_mediaState = state;
1740 chrome().client().isPlayingMediaDidChange(state, sourceElementID);
1743 void Page::schedulePlaybackControlsManagerUpdate()
1746 if (!m_playbackControlsManagerUpdateTimer.isActive())
1747 m_playbackControlsManagerUpdateTimer.startOneShot(0_s);
1752 void Page::playbackControlsManagerUpdateTimerFired()
1754 if (auto bestMediaElement = HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager(MediaElementSession::PlaybackControlsPurpose::ControlsManager))
1755 chrome().client().setUpPlaybackControlsManager(*bestMediaElement);
1757 chrome().client().clearPlaybackControlsManager();
1761 void Page::setMuted(MediaProducer::MutedStateFlags muted)
1763 if (m_mutedState == muted)
1766 m_mutedState = muted;
1768 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1769 if (!frame->document())
1771 frame->document()->pageMutedStateDidChange();
1775 void Page::stopMediaCapture()
1777 #if ENABLE(MEDIA_STREAM)
1778 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1779 if (!frame->document())
1782 frame->document()->stopMediaCapture();
1787 void Page::stopAllMediaPlayback()
1790 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1791 if (auto* document = frame->document())
1792 document->stopAllMediaPlayback();
1797 void Page::suspendAllMediaPlayback()
1800 ASSERT(!m_mediaPlaybackIsSuspended);
1801 if (m_mediaPlaybackIsSuspended)
1804 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1805 if (auto* document = frame->document())
1806 document->suspendAllMediaPlayback();
1809 m_mediaPlaybackIsSuspended = true;
1813 void Page::resumeAllMediaPlayback()
1816 ASSERT(m_mediaPlaybackIsSuspended);
1817 if (!m_mediaPlaybackIsSuspended)
1819 m_mediaPlaybackIsSuspended = false;
1821 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1822 if (auto* document = frame->document())
1823 document->resumeAllMediaPlayback();
1828 void Page::suspendAllMediaBuffering()
1831 ASSERT(!m_mediaBufferingIsSuspended);
1832 if (m_mediaBufferingIsSuspended)
1834 m_mediaBufferingIsSuspended = true;
1836 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1837 if (auto* document = frame->document())
1838 document->suspendAllMediaBuffering();
1843 void Page::resumeAllMediaBuffering()
1846 if (!m_mediaBufferingIsSuspended)
1848 m_mediaBufferingIsSuspended = false;
1850 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1851 if (auto* document = frame->document())
1852 document->resumeAllMediaBuffering();
1857 #if ENABLE(MEDIA_SESSION)
1858 void Page::handleMediaEvent(MediaEventType eventType)
1860 switch (eventType) {
1861 case MediaEventType::PlayPause:
1862 MediaSessionManager::singleton().togglePlayback();
1864 case MediaEventType::TrackNext:
1865 MediaSessionManager::singleton().skipToNextTrack();
1867 case MediaEventType::TrackPrevious:
1868 MediaSessionManager::singleton().skipToPreviousTrack();
1873 void Page::setVolumeOfMediaElement(double volume, uint64_t elementID)
1875 if (HTMLMediaElement* element = HTMLMediaElement::elementWithID(elementID))
1876 element->setVolume(volume, ASSERT_NO_EXCEPTION);
1880 #if !ASSERT_DISABLED
1881 void Page::checkSubframeCountConsistency() const
1883 ASSERT(m_subframeCount >= 0);
1885 int subframeCount = 0;
1886 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1889 ASSERT(m_subframeCount + 1 == subframeCount);
1893 void Page::resumeAnimatingImages()
1895 // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1896 // require that we repaint animated images to kickstart the animation loop.
1897 if (FrameView* view = mainFrame().view())
1898 view->resumeVisibleImageAnimationsIncludingSubframes();
1901 void Page::setActivityState(OptionSet<ActivityState::Flag> activityState)
1903 auto changed = m_activityState ^ activityState;
1907 auto oldActivityState = m_activityState;
1909 bool wasVisibleAndActive = isVisibleAndActive();
1910 m_activityState = activityState;
1912 m_focusController->setActivityState(activityState);
1914 if (changed & ActivityState::IsVisible)
1915 setIsVisibleInternal(activityState.contains(ActivityState::IsVisible));
1916 if (changed & ActivityState::IsInWindow)
1917 setIsInWindowInternal(activityState.contains(ActivityState::IsInWindow));
1918 if (changed & ActivityState::IsVisuallyIdle)
1919 setIsVisuallyIdleInternal(activityState.contains(ActivityState::IsVisuallyIdle));
1920 if (changed & ActivityState::WindowIsActive) {
1921 if (auto* view = m_mainFrame->view())
1922 view->updateTiledBackingAdaptiveSizing();
1925 if (changed.containsAny({ActivityState::IsVisible, ActivityState::IsVisuallyIdle, ActivityState::IsAudible, ActivityState::IsLoading, ActivityState::IsCapturingMedia }))
1926 updateTimerThrottlingState();
1928 for (auto* observer : m_activityStateChangeObservers)
1929 observer->activityStateDidChange(oldActivityState, m_activityState);
1931 if (wasVisibleAndActive != isVisibleAndActive())
1932 PlatformMediaSessionManager::updateNowPlayingInfoIfNecessary();
1934 if (m_performanceMonitor)
1935 m_performanceMonitor->activityStateChanged(oldActivityState, activityState);
1938 bool Page::isVisibleAndActive() const
1940 return m_activityState.contains(ActivityState::IsVisible) && m_activityState.contains(ActivityState::WindowIsActive);
1943 bool Page::isWindowActive() const
1945 return m_activityState.contains(ActivityState::WindowIsActive);
1948 void Page::setIsVisible(bool isVisible)
1950 auto state = m_activityState;
1953 state.remove(ActivityState::IsVisuallyIdle);
1954 state.add({ ActivityState::IsVisible, ActivityState::IsVisibleOrOccluded });
1956 state.add(ActivityState::IsVisuallyIdle);
1957 state.remove({ ActivityState::IsVisible, ActivityState::IsVisibleOrOccluded });
1959 setActivityState(state);
1962 enum class SVGAnimationsState { Paused, Resumed };
1963 static inline void setSVGAnimationsState(Page& page, SVGAnimationsState state)
1965 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
1966 auto* document = frame->document();
1970 if (!document->svgExtensions())
1973 if (state == SVGAnimationsState::Paused)
1974 document->accessSVGExtensions().pauseAnimations();
1976 document->accessSVGExtensions().unpauseAnimations();
1980 void Page::setIsVisibleInternal(bool isVisible)
1982 // FIXME: The visibility state should be stored on the top-level document.
1983 // https://bugs.webkit.org/show_bug.cgi?id=116769
1986 m_isPrerender = false;
1988 resumeScriptedAnimations();
1989 #if PLATFORM(IOS_FAMILY)
1990 resumeDeviceMotionAndOrientationUpdates();
1993 if (FrameView* view = mainFrame().view())
1996 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
1997 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1998 forEachDocument([&] (Document& document) {
1999 if (auto* timeline = document.existingTimeline())
2000 timeline->resumeAnimations();
2003 mainFrame().animation().resumeAnimations();
2006 setSVGAnimationsState(*this, SVGAnimationsState::Resumed);
2008 resumeAnimatingImages();
2010 if (m_navigationToLogWhenVisible) {
2011 logNavigation(m_navigationToLogWhenVisible.value());
2012 m_navigationToLogWhenVisible = WTF::nullopt;
2017 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
2018 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
2019 forEachDocument([&] (Document& document) {
2020 if (auto* timeline = document.existingTimeline())
2021 timeline->suspendAnimations();
2024 mainFrame().animation().suspendAnimations();
2027 setSVGAnimationsState(*this, SVGAnimationsState::Paused);
2029 #if PLATFORM(IOS_FAMILY)
2030 suspendDeviceMotionAndOrientationUpdates();
2033 suspendScriptedAnimations();
2035 if (FrameView* view = mainFrame().view())
2039 Vector<Ref<Document>> documents;
2040 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
2041 documents.append(*frame->document());
2043 for (auto& document : documents)
2044 document->visibilityStateChanged();
2047 void Page::setIsPrerender()
2049 m_isPrerender = true;
2050 updateDOMTimerAlignmentInterval();
2053 VisibilityState Page::visibilityState() const
2056 return VisibilityState::Visible;
2058 return VisibilityState::Prerender;
2059 return VisibilityState::Hidden;
2062 void Page::setHeaderHeight(int headerHeight)
2064 if (headerHeight == m_headerHeight)
2067 m_headerHeight = headerHeight;
2069 FrameView* frameView = mainFrame().view();
2073 RenderView* renderView = frameView->renderView();
2077 frameView->setNeedsLayoutAfterViewConfigurationChange();
2078 frameView->setNeedsCompositingGeometryUpdate();
2081 void Page::setFooterHeight(int footerHeight)
2083 if (footerHeight == m_footerHeight)
2086 m_footerHeight = footerHeight;
2088 FrameView* frameView = mainFrame().view();
2092 RenderView* renderView = frameView->renderView();
2096 frameView->setNeedsLayoutAfterViewConfigurationChange();
2097 frameView->setNeedsCompositingGeometryUpdate();
2100 void Page::incrementNestedRunLoopCount()
2102 m_nestedRunLoopCount++;
2105 void Page::decrementNestedRunLoopCount()
2107 ASSERT(m_nestedRunLoopCount);
2108 if (m_nestedRunLoopCount <= 0)
2111 m_nestedRunLoopCount--;
2113 if (!m_nestedRunLoopCount && m_unnestCallback) {
2114 callOnMainThread([this] {
2115 if (insideNestedRunLoop())
2118 // This callback may destruct the Page.
2119 if (m_unnestCallback) {
2120 auto callback = WTFMove(m_unnestCallback);
2127 void Page::whenUnnested(WTF::Function<void()>&& callback)
2129 ASSERT(!m_unnestCallback);
2131 m_unnestCallback = WTFMove(callback);
2134 #if ENABLE(REMOTE_INSPECTOR)
2135 bool Page::remoteInspectionAllowed() const
2137 return m_inspectorDebuggable->remoteDebuggingAllowed();
2140 void Page::setRemoteInspectionAllowed(bool allowed)
2142 m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
2145 String Page::remoteInspectionNameOverride() const
2147 return m_inspectorDebuggable->nameOverride();
2150 void Page::setRemoteInspectionNameOverride(const String& name)
2152 m_inspectorDebuggable->setNameOverride(name);
2155 void Page::remoteInspectorInformationDidChange() const
2157 m_inspectorDebuggable->update();
2161 void Page::addLayoutMilestones(OptionSet<LayoutMilestone> milestones)
2163 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
2164 m_requestedLayoutMilestones.add(milestones);
2167 void Page::removeLayoutMilestones(OptionSet<LayoutMilestone> milestones)
2169 m_requestedLayoutMilestones.remove(milestones);
2172 Color Page::pageExtendedBackgroundColor() const
2174 FrameView* frameView = mainFrame().view();
2178 RenderView* renderView = frameView->renderView();
2182 return renderView->compositor().rootExtendedBackgroundColor();
2185 // These are magical constants that might be tweaked over time.
2186 static const double gMinimumPaintedAreaRatio = 0.1;
2187 static const double gMaximumUnpaintedAreaRatio = 0.04;
2189 bool Page::isCountingRelevantRepaintedObjects() const
2191 return m_isCountingRelevantRepaintedObjects && m_requestedLayoutMilestones.contains(DidHitRelevantRepaintedObjectsAreaThreshold);
2194 void Page::startCountingRelevantRepaintedObjects()
2196 // Reset everything in case we didn't hit the threshold last time.
2197 resetRelevantPaintedObjectCounter();
2199 m_isCountingRelevantRepaintedObjects = true;
2202 void Page::resetRelevantPaintedObjectCounter()
2204 m_isCountingRelevantRepaintedObjects = false;
2205 m_relevantUnpaintedRenderObjects.clear();
2206 m_topRelevantPaintedRegion = Region();
2207 m_bottomRelevantPaintedRegion = Region();
2208 m_relevantUnpaintedRegion = Region();
2211 static LayoutRect relevantViewRect(RenderView* view)
2213 LayoutRect viewRect = view->viewRect();
2215 float relevantViewRectWidth = 980;
2216 #if PLATFORM(WATCHOS)
2217 // FIXME(186051): Consider limiting the relevant rect width to the view width everywhere.
2218 relevantViewRectWidth = std::min<float>(viewRect.width().toFloat(), relevantViewRectWidth);
2221 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
2222 // a certain relevant amount of content has been drawn to the screen. This is the rect that
2223 // has been determined to be relevant in the context of this goal. We may choose to tweak
2224 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
2225 // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
2226 LayoutRect relevantViewRect { 0, 0, LayoutUnit(relevantViewRectWidth), 1300 };
2227 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
2228 if (viewRect.width() > relevantViewRect.width())
2229 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
2231 return relevantViewRect;
2234 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
2236 if (!isCountingRelevantRepaintedObjects())
2239 // Objects inside sub-frames are not considered to be relevant.
2240 if (&object->frame() != &mainFrame())
2243 LayoutRect relevantRect = relevantViewRect(&object->view());
2245 // The objects are only relevant if they are being painted within the viewRect().
2246 if (!objectPaintRect.intersects(snappedIntRect(relevantRect)))
2249 IntRect snappedPaintRect = snappedIntRect(objectPaintRect);
2251 // If this object was previously counted as an unpainted object, remove it from that HashSet
2252 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
2253 if (m_relevantUnpaintedRenderObjects.remove(object))
2254 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
2256 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
2257 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
2258 // no content beneath that.
2259 LayoutRect topRelevantRect = relevantRect;
2260 topRelevantRect.contract(LayoutSize(0_lu, relevantRect.height() / 2));
2261 LayoutRect bottomRelevantRect = topRelevantRect;
2262 bottomRelevantRect.setY(relevantRect.height() / 2);
2264 // If the rect straddles both Regions, split it appropriately.
2265 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
2266 IntRect topIntersection = snappedPaintRect;
2267 topIntersection.intersect(snappedIntRect(topRelevantRect));
2268 m_topRelevantPaintedRegion.unite(topIntersection);
2270 IntRect bottomIntersection = snappedPaintRect;
2271 bottomIntersection.intersect(snappedIntRect(bottomRelevantRect));
2272 m_bottomRelevantPaintedRegion.unite(bottomIntersection);
2273 } else if (topRelevantRect.intersects(snappedPaintRect))
2274 m_topRelevantPaintedRegion.unite(snappedPaintRect);
2276 m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
2278 float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
2279 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
2280 float viewArea = relevantRect.width() * relevantRect.height();
2282 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
2283 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
2284 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
2286 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
2287 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
2288 m_isCountingRelevantRepaintedObjects = false;
2289 resetRelevantPaintedObjectCounter();
2290 if (Frame* frame = &mainFrame())
2291 frame->loader().didReachLayoutMilestone(DidHitRelevantRepaintedObjectsAreaThreshold);
2295 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
2297 if (!isCountingRelevantRepaintedObjects())
2300 // The objects are only relevant if they are being painted within the relevantViewRect().
2301 if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view()))))
2304 m_relevantUnpaintedRenderObjects.add(object);
2305 m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
2308 void Page::suspendDeviceMotionAndOrientationUpdates()
2310 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2311 if (Document* document = frame->document())
2312 document->suspendDeviceMotionAndOrientationUpdates();
2316 void Page::resumeDeviceMotionAndOrientationUpdates()
2318 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2319 if (Document* document = frame->document())
2320 document->resumeDeviceMotionAndOrientationUpdates();
2324 void Page::suspendActiveDOMObjectsAndAnimations()
2326 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
2327 frame->suspendActiveDOMObjectsAndAnimations();
2330 void Page::resumeActiveDOMObjectsAndAnimations()
2332 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
2333 frame->resumeActiveDOMObjectsAndAnimations();
2335 resumeAnimatingImages();
2338 bool Page::hasSeenAnyPlugin() const
2340 return !m_seenPlugins.isEmpty();
2343 bool Page::hasSeenPlugin(const String& serviceType) const
2345 return m_seenPlugins.contains(serviceType);
2348 void Page::sawPlugin(const String& serviceType)
2350 m_seenPlugins.add(serviceType);
2353 void Page::resetSeenPlugins()
2355 m_seenPlugins.clear();
2358 bool Page::hasSeenAnyMediaEngine() const
2360 return !m_seenMediaEngines.isEmpty();
2363 bool Page::hasSeenMediaEngine(const String& engineDescription) const
2365 return m_seenMediaEngines.contains(engineDescription);
2368 void Page::sawMediaEngine(const String& engineDescription)
2370 m_seenMediaEngines.add(engineDescription);
2373 void Page::resetSeenMediaEngines()
2375 m_seenMediaEngines.clear();
2378 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
2381 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
2382 forEachDocument([&] (Document& document) {
2383 if (auto* timeline = document.existingTimeline()) {
2384 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
2385 timeline->suspendAnimations();
2387 timeline->resumeAnimations();
2391 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
2392 mainFrame().animation().suspendAnimations();
2394 mainFrame().animation().resumeAnimations();
2399 #if ENABLE(VIDEO_TRACK)
2400 void Page::captionPreferencesChanged()
2402 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2403 if (!frame->document())
2405 frame->document()->captionPreferencesChanged();
2410 void Page::forbidPrompts()
2412 ++m_forbidPromptsDepth;
2415 void Page::allowPrompts()
2417 ASSERT(m_forbidPromptsDepth);
2418 --m_forbidPromptsDepth;
2421 bool Page::arePromptsAllowed()
2423 return !m_forbidPromptsDepth;
2426 void Page::logNavigation(const Navigation& navigation)
2428 String navigationDescription;
2429 switch (navigation.type) {
2430 case FrameLoadType::Standard:
2431 navigationDescription = "standard"_s;
2433 case FrameLoadType::Back:
2434 navigationDescription = "back"_s;
2436 case FrameLoadType::Forward:
2437 navigationDescription = "forward"_s;
2439 case FrameLoadType::IndexedBackForward:
2440 navigationDescription = "indexedBackForward"_s;
2442 case FrameLoadType::Reload:
2443 navigationDescription = "reload"_s;
2445 case FrameLoadType::Same:
2446 navigationDescription = "same"_s;
2448 case FrameLoadType::ReloadFromOrigin:
2449 navigationDescription = "reloadFromOrigin"_s;
2451 case FrameLoadType::ReloadExpiredOnly:
2452 navigationDescription = "reloadRevalidatingExpired"_s;
2454 case FrameLoadType::Replace:
2455 case FrameLoadType::RedirectWithLockedBackForwardList:
2456 // Not logging those for now.
2459 diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription, ShouldSample::No);
2461 if (!navigation.domain.isEmpty())
2462 diagnosticLoggingClient().logDiagnosticMessageWithEnhancedPrivacy(DiagnosticLoggingKeys::domainVisitedKey(), navigation.domain.string(), ShouldSample::Yes);
2465 void Page::mainFrameLoadStarted(const URL& destinationURL, FrameLoadType type)
2467 Navigation navigation = { RegistrableDomain { destinationURL }, type };
2469 // To avoid being too verbose, we only log navigations if the page is or becomes visible. This avoids logging non-user observable loads.
2471 m_navigationToLogWhenVisible = navigation;
2475 m_navigationToLogWhenVisible = WTF::nullopt;
2476 logNavigation(navigation);
2479 PluginInfoProvider& Page::pluginInfoProvider()
2481 return m_pluginInfoProvider;
2484 UserContentProvider& Page::userContentProvider()
2486 return m_userContentProvider;
2489 void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider)
2491 m_userContentProvider->removePage(*this);
2492 m_userContentProvider = WTFMove(userContentProvider);
2493 m_userContentProvider->addPage(*this);
2495 invalidateInjectedStyleSheetCacheInAllFrames();
2498 VisitedLinkStore& Page::visitedLinkStore()
2500 return m_visitedLinkStore;
2503 void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore)
2505 m_visitedLinkStore->removePage(*this);
2506 m_visitedLinkStore = WTFMove(visitedLinkStore);
2507 m_visitedLinkStore->addPage(*this);
2509 invalidateStylesForAllLinks();
2512 PAL::SessionID Page::sessionID() const
2517 // This is only called by WebKitLegacy.
2518 void Page::setSessionID(PAL::SessionID sessionID)
2520 ASSERT(sessionID.isValid());
2521 ASSERT(m_sessionID == PAL::SessionID::legacyPrivateSessionID() || m_sessionID == PAL::SessionID::defaultSessionID());
2522 ASSERT(sessionID == PAL::SessionID::legacyPrivateSessionID() || sessionID == PAL::SessionID::defaultSessionID());
2524 #if ENABLE(INDEXED_DATABASE)
2525 if (sessionID != m_sessionID)
2526 m_idbConnectionToServer = nullptr;
2529 if (sessionID != m_sessionID && m_sessionStorage)
2530 m_sessionStorage->setSessionIDForTesting(sessionID);
2532 bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral());
2534 m_sessionID = sessionID;
2536 if (!privateBrowsingStateChanged)
2539 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2540 if (!frame->document())
2542 frame->document()->privateBrowsingStateDidChange(m_sessionID);
2545 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
2546 // from below privateBrowsingStateChanged does not affect their lifetime.
2548 for (auto& view : pluginViews())
2549 view->privateBrowsingStateChanged(sessionID.isEphemeral());
2552 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2553 void Page::addPlaybackTargetPickerClient(uint64_t contextId)
2555 chrome().client().addPlaybackTargetPickerClient(contextId);
2558 void Page::removePlaybackTargetPickerClient(uint64_t contextId)
2560 chrome().client().removePlaybackTargetPickerClient(contextId);
2563 void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo, RouteSharingPolicy routeSharingPolicy, const String& routingContextUID)
2565 #if PLATFORM(IOS_FAMILY)
2566 // FIXME: refactor iOS implementation.
2567 UNUSED_PARAM(contextId);
2568 UNUSED_PARAM(location);
2569 chrome().client().showPlaybackTargetPicker(isVideo, routeSharingPolicy, routingContextUID);
2571 UNUSED_PARAM(routeSharingPolicy);
2572 UNUSED_PARAM(routingContextUID);
2573 chrome().client().showPlaybackTargetPicker(contextId, location, isVideo);
2577 void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
2579 chrome().client().playbackTargetPickerClientStateDidChange(contextId, state);
2582 void Page::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
2584 chrome().client().setMockMediaPlaybackTargetPickerEnabled(enabled);
2587 void Page::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetContext::State state)
2589 chrome().client().setMockMediaPlaybackTargetPickerState(name, state);
2592 void Page::mockMediaPlaybackTargetPickerDismissPopup()
2594 chrome().client().mockMediaPlaybackTargetPickerDismissPopup();
2597 void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
2599 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2600 if (!frame->document())
2602 frame->document()->setPlaybackTarget(contextId, target.copyRef());
2606 void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available)
2608 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2609 if (!frame->document())
2611 frame->document()->playbackTargetAvailabilityDidChange(contextId, available);
2615 void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
2617 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2618 if (!frame->document())
2620 frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay);
2624 void Page::playbackTargetPickerWasDismissed(uint64_t clientId)
2626 for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2627 if (!frame->document())
2629 frame->document()->playbackTargetPickerWasDismissed(clientId);
2634 WheelEventTestMonitor& Page::ensureWheelEventTestMonitor()
2636 if (!m_wheelEventTestMonitor) {
2637 m_wheelEventTestMonitor = adoptRef(new WheelEventTestMonitor());
2638 // We need to update the scrolling coordinator so that the mainframe scrolling node can expect wheel event test triggers.
2639 if (auto* frameView = mainFrame().view()) {
2640 if (m_scrollingCoordinator)
2641 m_scrollingCoordinator->updateIsMonitoringWheelEventsForFrameView(*frameView);
2645 return *m_wheelEventTestMonitor;
2649 void Page::setAllowsMediaDocumentInlinePlayback(bool flag)
2651 if (m_allowsMediaDocumentInlinePlayback == flag)
2653 m_allowsMediaDocumentInlinePlayback = flag;
2655 Vector<Ref<Document>> documents;
2656 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
2657 documents.append(*frame->document());
2659 for (auto& document : documents)
2660 document->allowsMediaDocumentInlinePlaybackChanged();
2664 #if ENABLE(INDEXED_DATABASE)
2665 IDBClient::IDBConnectionToServer& Page::idbConnection()
2667 if (!m_idbConnectionToServer)
2668 m_idbConnectionToServer = &databaseProvider().idbConnectionToServerForSession(m_sessionID);
2670 return *m_idbConnectionToServer;
2673 IDBClient::IDBConnectionToServer* Page::optionalIDBConnection()
2675 return m_idbConnectionToServer.get();
2678 void Page::clearIDBConnection()
2680 m_idbConnectionToServer = nullptr;
2684 #if ENABLE(RESOURCE_USAGE)
2685 void Page::setResourceUsageOverlayVisible(bool visible)
2688 m_resourceUsageOverlay = nullptr;
2692 if (!m_resourceUsageOverlay && m_settings->acceleratedCompositingEnabled())
2693 m_resourceUsageOverlay = makeUnique<ResourceUsageOverlay>(*this);
2697 bool Page::isAlwaysOnLoggingAllowed() const
2699 return m_sessionID.isAlwaysOnLoggingAllowed();
2702 String Page::captionUserPreferencesStyleSheet()
2704 return m_captionUserPreferencesStyleSheet;
2707 void Page::setCaptionUserPreferencesStyleSheet(const String& styleSheet)
2709 if (m_captionUserPreferencesStyleSheet == styleSheet)
2712 m_captionUserPreferencesStyleSheet = styleSheet;
2715 void Page::accessibilitySettingsDidChange()
2717 forEachDocument([](auto& document) {
2718 document.styleScope().evaluateMediaQueriesForAccessibilitySettingsChange();
2719 document.updateElementsAffectedByMediaQueries();
2720 document.scheduleTimedRenderingUpdate();
2724 void Page::appearanceDidChange()
2726 forEachDocument([](auto& document) {
2727 document.styleScope().didChangeStyleSheetEnvironment();
2728 document.styleScope().evaluateMediaQueriesForAppearanceChange();
2729 document.updateElementsAffectedByMediaQueries();
2730 document.scheduleTimedRenderingUpdate();
2734 void Page::setUnobscuredSafeAreaInsets(const FloatBoxExtent& insets)
2736 if (m_unobscuredSafeAreaInsets == insets)
2739 m_unobscuredSafeAreaInsets = insets;
2741 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2742 if (!frame->document())
2744 frame->document()->constantProperties().didChangeSafeAreaInsets();
2748 void Page::setUseSystemAppearance(bool value)
2750 if (m_useSystemAppearance == value)
2753 m_useSystemAppearance = value;
2755 appearanceDidChange();
2757 for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2758 auto* document = frame->document();
2762 // System apperance change may affect stylesheet parsing. We need to reparse.
2763 document->extensionStyleSheets().clearPageUserSheet();
2764 document->extensionStyleSheets().invalidateInjectedStyleSheetCache();
2768 void Page::effectiveAppearanceDidChange(bool useDarkAppearance, bool useElevatedUserInterfaceLevel)
2770 #if HAVE(OS_DARK_MODE_SUPPORT)
2771 if (m_useDarkAppearance == useDarkAppearance && m_useElevatedUserInterfaceLevel == useElevatedUserInterfaceLevel)
2774 m_useDarkAppearance = useDarkAppearance;
2775 m_useElevatedUserInterfaceLevel = useElevatedUserInterfaceLevel;
2777 InspectorInstrumentation::defaultAppearanceDidChange(*this, useDarkAppearance);
2779 appearanceDidChange();
2781 UNUSED_PARAM(useDarkAppearance);
2783 if (m_useElevatedUserInterfaceLevel == useElevatedUserInterfaceLevel)
2786 m_useElevatedUserInterfaceLevel = useElevatedUserInterfaceLevel;
2788 appearanceDidChange();
2792 bool Page::useDarkAppearance() const
2794 #if HAVE(OS_DARK_MODE_SUPPORT)
2795 FrameView* view = mainFrame().view();
2796 if (!view || !equalLettersIgnoringASCIICase(view->mediaType(), "screen"))
2798 if (m_useDarkAppearanceOverride)
2799 return m_useDarkAppearanceOverride.value();
2800 return m_useDarkAppearance;
2806 void Page::setUseDarkAppearanceOverride(Optional<bool> valueOverride)
2808 #if HAVE(OS_DARK_MODE_SUPPORT)
2809 if (valueOverride == m_useDarkAppearanceOverride)
2812 m_useDarkAppearanceOverride = valueOverride;
2814 appearanceDidChange();
2816 UNUSED_PARAM(valueOverride);
2820 void Page::setFullscreenInsets(const FloatBoxExtent& insets)
2822 if (insets == m_fullscreenInsets)
2824 m_fullscreenInsets = insets;
2826 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2827 if (!frame->document())
2829 frame->document()->constantProperties().didChangeFullscreenInsets();
2833 void Page::setFullscreenAutoHideDuration(Seconds duration)
2835 if (duration == m_fullscreenAutoHideDuration)
2837 m_fullscreenAutoHideDuration = duration;
2838 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2839 if (!frame->document())
2841 frame->document()->constantProperties().setFullscreenAutoHideDuration(duration);
2845 void Page::setFullscreenControlsHidden(bool hidden)
2847 #if ENABLE(FULLSCREEN_API)
2848 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2849 if (!frame->document())
2851 frame->document()->fullscreenManager().setFullscreenControlsHidden(hidden);
2854 UNUSED_PARAM(hidden);
2858 #if ENABLE(DATA_INTERACTION)
2860 bool Page::hasSelectionAtPosition(const FloatPoint& position) const
2862 auto currentSelection = m_mainFrame->selection().selection();
2863 if (!currentSelection.isRange())
2866 if (auto selectedRange = currentSelection.toNormalizedRange()) {
2867 Vector<SelectionRect> selectionRects;
2868 selectedRange->collectSelectionRects(selectionRects);
2869 for (auto selectionRect : selectionRects) {
2870 if (FloatRect(selectionRect.rect()).contains(position))
2880 void Page::disableICECandidateFiltering()
2882 m_shouldEnableICECandidateFilteringByDefault = false;
2884 m_rtcController.disableICECandidateFilteringForAllOrigins();
2888 void Page::enableICECandidateFiltering()
2890 m_shouldEnableICECandidateFilteringByDefault = true;
2892 m_rtcController.enableICECandidateFiltering();
2896 void Page::didChangeMainDocument()
2899 m_rtcController.reset(m_shouldEnableICECandidateFilteringByDefault);
2901 #if ENABLE(POINTER_EVENTS)
2902 m_pointerCaptureController->reset();
2906 RenderingUpdateScheduler& Page::renderingUpdateScheduler()
2908 if (!m_renderingUpdateScheduler)
2909 m_renderingUpdateScheduler = RenderingUpdateScheduler::create(*this);
2910 return *m_renderingUpdateScheduler;
2913 void Page::forEachDocument(const Function<void(Document&)>& functor)
2915 for (auto& document : collectDocuments())
2919 Vector<Ref<Document>> Page::collectDocuments()
2921 Vector<Ref<Document>> documents;
2922 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2923 auto* document = frame->document();
2926 documents.append(*document);
2931 void Page::applicationWillResignActive()
2933 forEachDocument([&] (Document& document) {
2934 document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
2935 listener.applicationWillResignActive();
2940 void Page::applicationDidEnterBackground()
2942 m_libWebRTCProvider->setActive(false);
2945 void Page::applicationWillEnterForeground()
2947 m_libWebRTCProvider->setActive(true);
2950 void Page::applicationDidBecomeActive()
2952 forEachDocument([&] (Document& document) {
2953 document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
2954 listener.applicationDidBecomeActive();
2960 ScrollLatchingState* Page::latchingState()
2962 if (m_latchingState.isEmpty())
2965 return &m_latchingState.last();
2968 void Page::pushNewLatchingState()
2970 m_latchingState.append(ScrollLatchingState());
2973 void Page::resetLatchingState()
2975 m_latchingState.clear();
2978 void Page::popLatchingState()
2980 m_latchingState.removeLast();
2983 void Page::removeLatchingStateForTarget(Element& targetNode)
2985 if (m_latchingState.isEmpty())
2988 m_latchingState.removeAllMatching([&targetNode] (ScrollLatchingState& state) {
2989 auto* wheelElement = state.wheelEventElement();
2993 return targetNode.isEqualNode(wheelElement);
2996 #endif // PLATFORM(MAC)
2998 static void dispatchPrintEvent(Frame& mainFrame, const AtomString& eventType)
3000 Vector<Ref<Frame>> frames;
3001 for (auto* frame = &mainFrame; frame; frame = frame->tree().traverseNext())
3002 frames.append(*frame);
3004 for (auto& frame : frames) {
3005 if (auto* window = frame->window())
3006 window->dispatchEvent(Event::create(eventType, Event::CanBubble::No, Event::IsCancelable::No), window->document());
3010 void Page::dispatchBeforePrintEvent()
3012 dispatchPrintEvent(m_mainFrame, eventNames().beforeprintEvent);
3015 void Page::dispatchAfterPrintEvent()
3017 dispatchPrintEvent(m_mainFrame, eventNames().afterprintEvent);
3020 #if ENABLE(APPLE_PAY)
3021 void Page::setPaymentCoordinator(std::unique_ptr<PaymentCoordinator>&& paymentCoordinator)
3023 m_paymentCoordinator = WTFMove(paymentCoordinator);
3027 void Page::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
3029 #if !RELEASE_LOG_DISABLED
3030 if (auto* channel = getLogChannel(channelName)) {
3031 channel->state = state;
3032 channel->level = level;
3035 if (channel == &LogWebRTC && m_mainFrame->document())
3036 libWebRTCProvider().setEnableLogging(!sessionID().isEphemeral());
3040 chrome().client().configureLoggingChannel(channelName, state, level);
3042 UNUSED_PARAM(channelName);
3043 UNUSED_PARAM(state);
3044 UNUSED_PARAM(level);
3048 void Page::didFinishLoadingImageForElement(HTMLImageElement& element)
3050 auto protectedElement = makeRef(element);
3051 if (auto frame = makeRefPtr(element.document().frame()))
3052 frame->editor().revealSelectionIfNeededAfterLoadingImageForElement(element);
3053 chrome().client().didFinishLoadingImageForElement(element);
3056 #if ENABLE(TEXT_AUTOSIZING)
3057 void Page::recomputeTextAutoSizingInAllFrames()
3059 ASSERT(settings().textAutosizingEnabled() && settings().textAutosizingUsesIdempotentMode());
3060 for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
3061 if (!frame->document())
3063 auto& document = *frame->document();
3064 if (!document.renderView() || !document.styleScope().resolverIfExists())
3067 auto& styleResolver = document.styleScope().resolver();
3068 for (auto& renderer : descendantsOfType<RenderElement>(*document.renderView())) {
3069 if (auto* element = renderer.element()) {
3070 auto needsLayout = styleResolver.adjustRenderStyleForTextAutosizing(renderer.mutableStyle(), *element);
3072 renderer.setNeedsLayout();
3079 } // namespace WebCore