1/*
2 * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4 *
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.
13 *
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.
18 */
19
20#include "config.h"
21#include "Page.h"
22
23#include "ActivityStateChangeObserver.h"
24#include "AlternativeTextClient.h"
25#include "ApplicationCacheStorage.h"
26#include "ApplicationStateChangeListener.h"
27#include "AuthenticatorCoordinator.h"
28#include "BackForwardClient.h"
29#include "BackForwardController.h"
30#include "CSSAnimationController.h"
31#include "CacheStorageProvider.h"
32#include "Chrome.h"
33#include "ChromeClient.h"
34#include "ConstantPropertyMap.h"
35#include "ContextMenuClient.h"
36#include "ContextMenuController.h"
37#include "CookieJar.h"
38#include "DOMRect.h"
39#include "DOMRectList.h"
40#include "DatabaseProvider.h"
41#include "DiagnosticLoggingClient.h"
42#include "DiagnosticLoggingKeys.h"
43#include "DocumentLoader.h"
44#include "DocumentMarkerController.h"
45#include "DocumentTimeline.h"
46#include "DragController.h"
47#include "Editing.h"
48#include "Editor.h"
49#include "EditorClient.h"
50#include "EmptyClients.h"
51#include "Event.h"
52#include "EventNames.h"
53#include "ExtensionStyleSheets.h"
54#include "FocusController.h"
55#include "FrameLoader.h"
56#include "FrameLoaderClient.h"
57#include "FrameSelection.h"
58#include "FrameTree.h"
59#include "FrameView.h"
60#include "FullscreenManager.h"
61#include "HTMLElement.h"
62#include "HTMLMediaElement.h"
63#include "HistoryController.h"
64#include "HistoryItem.h"
65#include "InspectorClient.h"
66#include "InspectorController.h"
67#include "InspectorInstrumentation.h"
68#include "LibWebRTCProvider.h"
69#include "LoaderStrategy.h"
70#include "Logging.h"
71#include "LowPowerModeNotifier.h"
72#include "MediaCanStartListener.h"
73#include "Navigator.h"
74#include "PageCache.h"
75#include "PageConfiguration.h"
76#include "PageConsoleClient.h"
77#include "PageDebuggable.h"
78#include "PageGroup.h"
79#include "PageOverlayController.h"
80#include "PaymentCoordinator.h"
81#include "PerformanceLogging.h"
82#include "PerformanceLoggingClient.h"
83#include "PerformanceMonitor.h"
84#include "PlatformMediaSessionManager.h"
85#include "PlatformStrategies.h"
86#include "PlugInClient.h"
87#include "PluginData.h"
88#include "PluginInfoProvider.h"
89#include "PluginViewBase.h"
90#include "PointerCaptureController.h"
91#include "PointerLockController.h"
92#include "ProgressTracker.h"
93#include "RenderLayerCompositor.h"
94#include "RenderTheme.h"
95#include "RenderView.h"
96#include "RenderWidget.h"
97#include "ResizeObserver.h"
98#include "ResourceUsageOverlay.h"
99#include "RuntimeEnabledFeatures.h"
100#include "SVGDocumentExtensions.h"
101#include "SchemeRegistry.h"
102#include "ScriptController.h"
103#include "ScriptedAnimationController.h"
104#include "ScrollLatchingState.h"
105#include "ScrollingCoordinator.h"
106#include "Settings.h"
107#include "SharedBuffer.h"
108#include "SocketProvider.h"
109#include "StorageArea.h"
110#include "StorageNamespace.h"
111#include "StorageNamespaceProvider.h"
112#include "StyleResolver.h"
113#include "StyleScope.h"
114#include "SubframeLoader.h"
115#include "TextIterator.h"
116#include "TextResourceDecoder.h"
117#include "UserContentProvider.h"
118#include "UserInputBridge.h"
119#include "ValidationMessageClient.h"
120#include "VisitedLinkState.h"
121#include "VisitedLinkStore.h"
122#include "VoidCallback.h"
123#include "WebGLStateTracker.h"
124#include "WheelEventDeltaFilter.h"
125#include "Widget.h"
126#include <wtf/FileSystem.h>
127#include <wtf/RefCountedLeakCounter.h>
128#include <wtf/StdLibExtras.h>
129#include <wtf/SystemTracing.h>
130#include <wtf/text/Base64.h>
131#include <wtf/text/StringHash.h>
132
133#if ENABLE(WIRELESS_PLAYBACK_TARGET)
134#include "HTMLVideoElement.h"
135#include "MediaPlaybackTarget.h"
136#endif
137
138#if PLATFORM(MAC)
139#include "ServicesOverlayController.h"
140#endif
141
142#if ENABLE(MEDIA_SESSION)
143#include "MediaSessionManager.h"
144#endif
145
146#if ENABLE(INDEXED_DATABASE)
147#include "IDBConnectionToServer.h"
148#include "InProcessIDBServer.h"
149#endif
150
151#if ENABLE(DATA_INTERACTION)
152#include "SelectionRect.h"
153#endif
154
155namespace WebCore {
156
157static HashSet<Page*>& allPages()
158{
159 static NeverDestroyed<HashSet<Page*>> set;
160 return set;
161}
162
163static unsigned nonUtilityPageCount { 0 };
164
165static inline bool isUtilityPageChromeClient(ChromeClient& chromeClient)
166{
167 return chromeClient.isEmptyChromeClient() || chromeClient.isSVGImageChromeClient();
168}
169
170DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
171
172void Page::forEachPage(const WTF::Function<void(Page&)>& function)
173{
174 for (auto* page : allPages())
175 function(*page);
176}
177
178void Page::updateValidationBubbleStateIfNeeded()
179{
180 if (auto* client = validationMessageClient())
181 client->updateValidationBubbleStateIfNeeded();
182}
183
184static void networkStateChanged(bool isOnLine)
185{
186 Vector<Ref<Frame>> frames;
187
188 // Get all the frames of all the pages in all the page groups
189 for (auto* page : allPages()) {
190 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
191 frames.append(*frame);
192 InspectorInstrumentation::networkStateChanged(*page);
193 }
194
195 auto& eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
196 for (auto& frame : frames) {
197 if (!frame->document())
198 continue;
199 frame->document()->dispatchWindowEvent(Event::create(eventName, Event::CanBubble::No, Event::IsCancelable::No));
200 }
201}
202
203static constexpr OptionSet<ActivityState::Flag> pageInitialActivityState()
204{
205 return { ActivityState::IsVisible, ActivityState::IsInWindow };
206}
207
208Page::Page(PageConfiguration&& pageConfiguration)
209 : m_chrome(std::make_unique<Chrome>(*this, *pageConfiguration.chromeClient))
210 , m_dragCaretController(std::make_unique<DragCaretController>())
211#if ENABLE(DRAG_SUPPORT)
212 , m_dragController(std::make_unique<DragController>(*this, *pageConfiguration.dragClient))
213#endif
214 , m_focusController(std::make_unique<FocusController>(*this, pageInitialActivityState()))
215#if ENABLE(CONTEXT_MENUS)
216 , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageConfiguration.contextMenuClient))
217#endif
218 , m_userInputBridge(std::make_unique<UserInputBridge>(*this))
219 , m_inspectorController(std::make_unique<InspectorController>(*this, pageConfiguration.inspectorClient))
220#if ENABLE(POINTER_EVENTS)
221 , m_pointerCaptureController(std::make_unique<PointerCaptureController>(*this))
222#endif
223#if ENABLE(POINTER_LOCK)
224 , m_pointerLockController(std::make_unique<PointerLockController>(*this))
225#endif
226 , m_settings(Settings::create(this))
227 , m_progress(std::make_unique<ProgressTracker>(*pageConfiguration.progressTrackerClient))
228 , m_backForwardController(std::make_unique<BackForwardController>(*this, WTFMove(pageConfiguration.backForwardClient)))
229 , m_mainFrame(Frame::create(this, nullptr, pageConfiguration.loaderClientForMainFrame))
230 , m_editorClient(WTFMove(pageConfiguration.editorClient))
231 , m_plugInClient(pageConfiguration.plugInClient)
232 , m_validationMessageClient(WTFMove(pageConfiguration.validationMessageClient))
233 , m_diagnosticLoggingClient(WTFMove(pageConfiguration.diagnosticLoggingClient))
234 , m_performanceLoggingClient(WTFMove(pageConfiguration.performanceLoggingClient))
235 , m_webGLStateTracker(WTFMove(pageConfiguration.webGLStateTracker))
236#if ENABLE(SPEECH_SYNTHESIS)
237 , m_speechSynthesisClient(WTFMove(pageConfiguration.speechSynthesisClient))
238#endif
239 , m_libWebRTCProvider(WTFMove(pageConfiguration.libWebRTCProvider))
240 , m_verticalScrollElasticity(ScrollElasticityAllowed)
241 , m_horizontalScrollElasticity(ScrollElasticityAllowed)
242 , m_domTimerAlignmentInterval(DOMTimer::defaultAlignmentInterval())
243 , m_domTimerAlignmentIntervalIncreaseTimer(*this, &Page::domTimerAlignmentIntervalIncreaseTimerFired)
244 , m_activityState(pageInitialActivityState())
245 , m_alternativeTextClient(pageConfiguration.alternativeTextClient)
246 , m_consoleClient(std::make_unique<PageConsoleClient>(*this))
247#if ENABLE(REMOTE_INSPECTOR)
248 , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this))
249#endif
250 , m_socketProvider(WTFMove(pageConfiguration.socketProvider))
251 , m_cookieJar(WTFMove(pageConfiguration.cookieJar))
252 , m_applicationCacheStorage(*WTFMove(pageConfiguration.applicationCacheStorage))
253 , m_cacheStorageProvider(WTFMove(pageConfiguration.cacheStorageProvider))
254 , m_databaseProvider(*WTFMove(pageConfiguration.databaseProvider))
255 , m_pluginInfoProvider(*WTFMove(pageConfiguration.pluginInfoProvider))
256 , m_storageNamespaceProvider(*WTFMove(pageConfiguration.storageNamespaceProvider))
257 , m_userContentProvider(*WTFMove(pageConfiguration.userContentProvider))
258 , m_visitedLinkStore(*WTFMove(pageConfiguration.visitedLinkStore))
259 , m_sessionID(PAL::SessionID::defaultSessionID())
260#if ENABLE(VIDEO)
261 , m_playbackControlsManagerUpdateTimer(*this, &Page::playbackControlsManagerUpdateTimerFired)
262#endif
263 , m_isUtilityPage(isUtilityPageChromeClient(chrome().client()))
264 , m_performanceMonitor(isUtilityPage() ? nullptr : std::make_unique<PerformanceMonitor>(*this))
265 , m_lowPowerModeNotifier(std::make_unique<LowPowerModeNotifier>([this](bool isLowPowerModeEnabled) { handleLowModePowerChange(isLowPowerModeEnabled); }))
266 , m_performanceLogging(std::make_unique<PerformanceLogging>(*this))
267#if PLATFORM(MAC) && (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION))
268 , m_servicesOverlayController(std::make_unique<ServicesOverlayController>(*this))
269#endif
270 , m_recentWheelEventDeltaFilter(WheelEventDeltaFilter::create())
271 , m_pageOverlayController(std::make_unique<PageOverlayController>(*this))
272#if ENABLE(APPLE_PAY)
273 , m_paymentCoordinator(std::make_unique<PaymentCoordinator>(*pageConfiguration.paymentCoordinatorClient))
274#endif
275#if ENABLE(WEB_AUTHN)
276 , m_authenticatorCoordinator(makeUniqueRef<AuthenticatorCoordinator>(WTFMove(pageConfiguration.authenticatorCoordinatorClient)))
277#endif
278#if ENABLE(APPLICATION_MANIFEST)
279 , m_applicationManifest(pageConfiguration.applicationManifest)
280#endif
281{
282 updateTimerThrottlingState();
283
284 m_pluginInfoProvider->addPage(*this);
285 m_storageNamespaceProvider->addPage(*this);
286 m_userContentProvider->addPage(*this);
287 m_visitedLinkStore->addPage(*this);
288
289 static bool addedListener;
290 if (!addedListener) {
291 platformStrategies()->loaderStrategy()->addOnlineStateChangeListener(&networkStateChanged);
292 addedListener = true;
293 }
294
295 ASSERT(!allPages().contains(this));
296 allPages().add(this);
297
298 if (!isUtilityPage()) {
299 ++nonUtilityPageCount;
300 MemoryPressureHandler::setPageCount(nonUtilityPageCount);
301 }
302
303#ifndef NDEBUG
304 pageCounter.increment();
305#endif
306
307#if ENABLE(REMOTE_INSPECTOR)
308 if (m_inspectorController->inspectorClient() && m_inspectorController->inspectorClient()->allowRemoteInspectionToPageDirectly())
309 m_inspectorDebuggable->init();
310#endif
311
312#if PLATFORM(COCOA)
313 platformInitialize();
314#endif
315
316#if USE(LIBWEBRTC)
317 m_libWebRTCProvider->supportsVP8(RuntimeEnabledFeatures::sharedFeatures().webRTCVP8CodecEnabled());
318#endif
319}
320
321Page::~Page()
322{
323 ASSERT(!m_nestedRunLoopCount);
324 ASSERT(!m_unnestCallback);
325
326 m_validationMessageClient = nullptr;
327 m_diagnosticLoggingClient = nullptr;
328 m_performanceLoggingClient = nullptr;
329 m_mainFrame->setView(nullptr);
330 setGroupName(String());
331 allPages().remove(this);
332 if (!isUtilityPage()) {
333 --nonUtilityPageCount;
334 MemoryPressureHandler::setPageCount(nonUtilityPageCount);
335 }
336
337 m_settings->pageDestroyed();
338
339 m_inspectorController->inspectedPageDestroyed();
340
341 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
342 frame->willDetachPage();
343 frame->detachFromPage();
344 }
345
346 if (m_plugInClient)
347 m_plugInClient->pageDestroyed();
348 if (m_alternativeTextClient)
349 m_alternativeTextClient->pageDestroyed();
350
351 if (m_scrollingCoordinator)
352 m_scrollingCoordinator->pageDestroyed();
353
354 backForward().close();
355 if (!isUtilityPage())
356 PageCache::singleton().removeAllItemsForPage(*this);
357
358#ifndef NDEBUG
359 pageCounter.decrement();
360#endif
361
362 m_pluginInfoProvider->removePage(*this);
363 m_storageNamespaceProvider->removePage(*this);
364 m_userContentProvider->removePage(*this);
365 m_visitedLinkStore->removePage(*this);
366}
367
368void Page::clearPreviousItemFromAllPages(HistoryItem* item)
369{
370 for (auto* page : allPages()) {
371 auto& controller = page->mainFrame().loader().history();
372 if (item == controller.previousItem()) {
373 controller.clearPreviousItem();
374 return;
375 }
376 }
377}
378
379uint64_t Page::renderTreeSize() const
380{
381 uint64_t total = 0;
382 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
383 if (!frame->document() || !frame->document()->renderView())
384 continue;
385 total += frame->document()->renderView()->rendererCount();
386 }
387 return total;
388}
389
390OptionSet<DisabledAdaptations> Page::disabledAdaptations() const
391{
392 if (mainFrame().document())
393 return mainFrame().document()->disabledAdaptations();
394
395 return { };
396}
397
398ViewportArguments Page::viewportArguments() const
399{
400 return mainFrame().document() ? mainFrame().document()->viewportArguments() : ViewportArguments();
401}
402
403void Page::setOverrideViewportArguments(const Optional<ViewportArguments>& viewportArguments)
404{
405 if (viewportArguments == m_overrideViewportArguments)
406 return;
407
408 m_overrideViewportArguments = viewportArguments;
409 if (auto* document = mainFrame().document())
410 document->updateViewportArguments();
411}
412
413ScrollingCoordinator* Page::scrollingCoordinator()
414{
415 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) {
416 m_scrollingCoordinator = chrome().client().createScrollingCoordinator(*this);
417 if (!m_scrollingCoordinator)
418 m_scrollingCoordinator = ScrollingCoordinator::create(this);
419 }
420
421 return m_scrollingCoordinator.get();
422}
423
424String Page::scrollingStateTreeAsText()
425{
426 if (Document* document = m_mainFrame->document())
427 document->updateLayout();
428
429 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
430 return scrollingCoordinator->scrollingStateTreeAsText();
431
432 return String();
433}
434
435String Page::synchronousScrollingReasonsAsText()
436{
437 if (Document* document = m_mainFrame->document())
438 document->updateLayout();
439
440 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
441 return scrollingCoordinator->synchronousScrollingReasonsAsText();
442
443 return String();
444}
445
446Ref<DOMRectList> Page::nonFastScrollableRects()
447{
448 if (Document* document = m_mainFrame->document())
449 document->updateLayout();
450
451 Vector<IntRect> rects;
452 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
453 const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions();
454 for (const auto& synchronousEventRegion : eventTrackingRegions.eventSpecificSynchronousDispatchRegions)
455 rects.appendVector(synchronousEventRegion.value.rects());
456 }
457
458 Vector<FloatQuad> quads(rects.size());
459 for (size_t i = 0; i < rects.size(); ++i)
460 quads[i] = FloatRect(rects[i]);
461
462 return DOMRectList::create(quads);
463}
464
465Ref<DOMRectList> Page::touchEventRectsForEvent(const String& eventName)
466{
467 if (Document* document = m_mainFrame->document()) {
468 document->updateLayout();
469#if ENABLE(IOS_TOUCH_EVENTS)
470 document->updateTouchEventRegions();
471#endif
472 }
473
474 Vector<IntRect> rects;
475 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
476 const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions();
477 const auto& region = eventTrackingRegions.eventSpecificSynchronousDispatchRegions.get(eventName);
478 rects.appendVector(region.rects());
479 }
480
481 Vector<FloatQuad> quads(rects.size());
482 for (size_t i = 0; i < rects.size(); ++i)
483 quads[i] = FloatRect(rects[i]);
484
485 return DOMRectList::create(quads);
486}
487
488Ref<DOMRectList> Page::passiveTouchEventListenerRects()
489{
490 if (Document* document = m_mainFrame->document()) {
491 document->updateLayout();
492#if ENABLE(IOS_TOUCH_EVENTS)
493 document->updateTouchEventRegions();
494#endif
495 }
496
497 Vector<IntRect> rects;
498 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
499 rects.appendVector(scrollingCoordinator->absoluteEventTrackingRegions().asynchronousDispatchRegion.rects());
500
501 Vector<FloatQuad> quads(rects.size());
502 for (size_t i = 0; i < rects.size(); ++i)
503 quads[i] = FloatRect(rects[i]);
504
505 return DOMRectList::create(quads);
506}
507
508bool Page::openedByDOM() const
509{
510 return m_openedByDOM;
511}
512
513void Page::setOpenedByDOM()
514{
515 m_openedByDOM = true;
516}
517
518void Page::goToItem(HistoryItem& item, FrameLoadType type, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad)
519{
520 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
521 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
522 Ref<HistoryItem> protector(item);
523
524 auto& frameLoader = m_mainFrame->loader();
525 if (frameLoader.history().shouldStopLoadingForHistoryItem(item))
526 m_mainFrame->loader().stopAllLoadersAndCheckCompleteness();
527
528 m_mainFrame->loader().history().goToItem(item, type, shouldTreatAsContinuingLoad);
529}
530
531void Page::setGroupName(const String& name)
532{
533 if (m_group && !m_group->name().isEmpty()) {
534 ASSERT(m_group != m_singlePageGroup.get());
535 ASSERT(!m_singlePageGroup);
536 m_group->removePage(*this);
537 }
538
539 if (name.isEmpty())
540 m_group = m_singlePageGroup.get();
541 else {
542 m_singlePageGroup = nullptr;
543 m_group = PageGroup::pageGroup(name);
544 m_group->addPage(*this);
545 }
546}
547
548const String& Page::groupName() const
549{
550 return m_group ? m_group->name() : nullAtom().string();
551}
552
553void Page::initGroup()
554{
555 ASSERT(!m_singlePageGroup);
556 ASSERT(!m_group);
557 m_singlePageGroup = std::make_unique<PageGroup>(*this);
558 m_group = m_singlePageGroup.get();
559}
560
561void Page::updateStyleAfterChangeInEnvironment()
562{
563 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
564 // If a change in the global environment has occurred, we need to
565 // make sure all the properties a recomputed, therefore we invalidate
566 // the properties cache.
567 auto* document = frame->document();
568 if (!document)
569 continue;
570
571 if (StyleResolver* styleResolver = document->styleScope().resolverIfExists())
572 styleResolver->invalidateMatchedPropertiesCache();
573 document->scheduleFullStyleRebuild();
574 document->styleScope().didChangeStyleSheetEnvironment();
575 }
576}
577
578void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
579{
580 for (auto* page : allPages())
581 page->updateStyleAfterChangeInEnvironment();
582}
583
584void Page::setNeedsRecalcStyleInAllFrames()
585{
586 // FIXME: Figure out what this function is actually trying to add in different call sites.
587 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
588 if (Document* document = frame->document())
589 document->styleScope().didChangeStyleSheetEnvironment();
590 }
591}
592
593void Page::refreshPlugins(bool reload)
594{
595 HashSet<PluginInfoProvider*> pluginInfoProviders;
596
597 for (auto* page : allPages())
598 pluginInfoProviders.add(&page->pluginInfoProvider());
599
600 for (auto& pluginInfoProvider : pluginInfoProviders)
601 pluginInfoProvider->refresh(reload);
602}
603
604PluginData& Page::pluginData()
605{
606 if (!m_pluginData)
607 m_pluginData = PluginData::create(*this);
608 return *m_pluginData;
609}
610
611void Page::clearPluginData()
612{
613 m_pluginData = nullptr;
614}
615
616bool Page::showAllPlugins() const
617{
618 if (m_showAllPlugins)
619 return true;
620
621 if (Document* document = mainFrame().document())
622 return document->securityOrigin().isLocal();
623
624 return false;
625}
626
627inline Optional<std::pair<MediaCanStartListener&, Document&>> Page::takeAnyMediaCanStartListener()
628{
629 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
630 if (!frame->document())
631 continue;
632 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
633 return { { *listener, *frame->document() } };
634 }
635 return WTF::nullopt;
636}
637
638void Page::setCanStartMedia(bool canStartMedia)
639{
640 if (m_canStartMedia == canStartMedia)
641 return;
642
643 m_canStartMedia = canStartMedia;
644
645 while (m_canStartMedia) {
646 auto listener = takeAnyMediaCanStartListener();
647 if (!listener)
648 break;
649 listener->first.mediaCanStart(listener->second);
650 }
651}
652
653static Frame* incrementFrame(Frame* curr, bool forward, CanWrap canWrap, DidWrap* didWrap = nullptr)
654{
655 return forward
656 ? curr->tree().traverseNext(canWrap, didWrap)
657 : curr->tree().traversePrevious(canWrap, didWrap);
658}
659
660bool Page::findString(const String& target, FindOptions options, DidWrap* didWrap)
661{
662 if (target.isEmpty())
663 return false;
664
665 CanWrap canWrap = options.contains(WrapAround) ? CanWrap::Yes : CanWrap::No;
666 Frame* frame = &focusController().focusedOrMainFrame();
667 Frame* startFrame = frame;
668 do {
669 if (frame->editor().findString(target, (options - WrapAround) | StartInSelection)) {
670 if (frame != startFrame)
671 startFrame->selection().clear();
672 focusController().setFocusedFrame(frame);
673 return true;
674 }
675 frame = incrementFrame(frame, !options.contains(Backwards), canWrap, didWrap);
676 } while (frame && frame != startFrame);
677
678 // Search contents of startFrame, on the other side of the selection that we did earlier.
679 // We cheat a bit and just research with wrap on
680 if (canWrap == CanWrap::Yes && !startFrame->selection().isNone()) {
681 if (didWrap)
682 *didWrap = DidWrap::Yes;
683 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
684 focusController().setFocusedFrame(frame);
685 return found;
686 }
687
688 return false;
689}
690
691void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection)
692{
693 indexForSelection = 0;
694
695 Frame* frame = &mainFrame();
696 Frame* frameWithSelection = nullptr;
697 do {
698 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges);
699 if (frame->selection().isRange())
700 frameWithSelection = frame;
701 frame = incrementFrame(frame, true, CanWrap::No);
702 } while (frame);
703
704 if (matchRanges.isEmpty())
705 return;
706
707 if (frameWithSelection) {
708 indexForSelection = NoMatchAfterUserSelection;
709 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
710 if (options.contains(Backwards)) {
711 for (size_t i = matchRanges.size(); i > 0; --i) {
712 auto result = selectedRange->compareBoundaryPoints(Range::END_TO_START, *matchRanges[i - 1]);
713 if (!result.hasException() && result.releaseReturnValue() > 0) {
714 indexForSelection = i - 1;
715 break;
716 }
717 }
718 } else {
719 for (size_t i = 0, size = matchRanges.size(); i < size; ++i) {
720 auto result = selectedRange->compareBoundaryPoints(Range::START_TO_END, *matchRanges[i]);
721 if (!result.hasException() && result.releaseReturnValue() < 0) {
722 indexForSelection = i;
723 break;
724 }
725 }
726 }
727 } else {
728 if (options.contains(Backwards))
729 indexForSelection = matchRanges.size() - 1;
730 else
731 indexForSelection = 0;
732 }
733}
734
735RefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
736{
737 if (target.isEmpty())
738 return nullptr;
739
740 if (referenceRange && referenceRange->ownerDocument().page() != this)
741 return nullptr;
742
743 CanWrap canWrap = options.contains(WrapAround) ? CanWrap::Yes : CanWrap::No;
744 Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame();
745 Frame* startFrame = frame;
746 do {
747 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options - WrapAround))
748 return resultRange;
749
750 frame = incrementFrame(frame, !options.contains(Backwards), canWrap);
751 } while (frame && frame != startFrame);
752
753 // Search contents of startFrame, on the other side of the reference range that we did earlier.
754 // We cheat a bit and just search again with wrap on.
755 if (canWrap == CanWrap::Yes && referenceRange) {
756 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
757 return resultRange;
758 }
759
760 return nullptr;
761}
762
763unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
764{
765 if (target.isEmpty())
766 return 0;
767
768 unsigned matchCount = 0;
769
770 Frame* frame = &mainFrame();
771 do {
772 if (shouldMarkMatches == MarkMatches)
773 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
774 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
775 frame = incrementFrame(frame, true, CanWrap::No);
776 } while (frame);
777
778 return matchCount;
779}
780
781unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
782{
783 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
784}
785
786unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
787{
788 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
789}
790
791struct FindReplacementRange {
792 RefPtr<ContainerNode> root;
793 size_t location { notFound };
794 size_t length { 0 };
795};
796
797static void replaceRanges(Page& page, const Vector<FindReplacementRange>& ranges, const String& replacementText)
798{
799 HashMap<RefPtr<ContainerNode>, Vector<FindReplacementRange>> rangesByContainerNode;
800 for (auto& range : ranges) {
801 auto& rangeList = rangesByContainerNode.ensure(range.root, [] {
802 return Vector<FindReplacementRange> { };
803 }).iterator->value;
804
805 // Ensure that ranges are sorted by their end offsets, per editing container.
806 auto endOffsetForRange = range.location + range.length;
807 auto insertionIndex = rangeList.size();
808 for (auto iterator = rangeList.rbegin(); iterator != rangeList.rend(); ++iterator) {
809 auto endOffsetBeforeInsertionIndex = iterator->location + iterator->length;
810 if (endOffsetForRange >= endOffsetBeforeInsertionIndex)
811 break;
812 insertionIndex--;
813 }
814 rangeList.insert(insertionIndex, range);
815 }
816
817 HashMap<RefPtr<Frame>, unsigned> frameToTraversalIndexMap;
818 unsigned currentFrameTraversalIndex = 0;
819 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext())
820 frameToTraversalIndexMap.set(frame, currentFrameTraversalIndex++);
821
822 // Likewise, iterate backwards (in document and frame order) through editing containers that contain text matches,
823 // so that we're consistent with our backwards iteration behavior per editing container when replacing text.
824 auto containerNodesInOrderOfReplacement = copyToVector(rangesByContainerNode.keys());
825 std::sort(containerNodesInOrderOfReplacement.begin(), containerNodesInOrderOfReplacement.end(), [frameToTraversalIndexMap] (auto& firstNode, auto& secondNode) {
826 if (firstNode == secondNode)
827 return false;
828
829 auto firstFrame = makeRefPtr(firstNode->document().frame());
830 if (!firstFrame)
831 return true;
832
833 auto secondFrame = makeRefPtr(secondNode->document().frame());
834 if (!secondFrame)
835 return false;
836
837 if (firstFrame == secondFrame) {
838 // comparePositions is used here instead of Node::compareDocumentPosition because some editing roots may exist inside shadow roots.
839 return comparePositions({ firstNode.get(), Position::PositionIsBeforeChildren }, { secondNode.get(), Position::PositionIsBeforeChildren }) > 0;
840 }
841 return frameToTraversalIndexMap.get(firstFrame) > frameToTraversalIndexMap.get(secondFrame);
842 });
843
844 for (auto& container : containerNodesInOrderOfReplacement) {
845 auto frame = makeRefPtr(container->document().frame());
846 if (!frame)
847 continue;
848
849 // Iterate backwards through ranges when replacing text, such that earlier text replacements don't clobber replacement ranges later on.
850 auto& ranges = rangesByContainerNode.find(container)->value;
851 for (auto iterator = ranges.rbegin(); iterator != ranges.rend(); ++iterator) {
852 auto range = TextIterator::rangeFromLocationAndLength(container.get(), iterator->location, iterator->length);
853 if (!range || range->collapsed())
854 continue;
855
856 frame->selection().setSelectedRange(range.get(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);
857 frame->editor().replaceSelectionWithText(replacementText, Editor::SelectReplacement::Yes, Editor::SmartReplace::No, EditAction::InsertReplacement);
858 }
859 }
860}
861
862uint32_t Page::replaceRangesWithText(const Vector<Ref<Range>>& rangesToReplace, const String& replacementText, bool selectionOnly)
863{
864 // FIXME: In the future, we should respect the `selectionOnly` flag by checking whether each range being replaced is
865 // contained within its frame's selection.
866 UNUSED_PARAM(selectionOnly);
867
868 Vector<FindReplacementRange> replacementRanges;
869 replacementRanges.reserveInitialCapacity(rangesToReplace.size());
870
871 for (auto& range : rangesToReplace) {
872 auto highestRoot = makeRefPtr(highestEditableRoot(range->startPosition()));
873 if (!highestRoot || highestRoot != highestEditableRoot(range->endPosition()))
874 continue;
875
876 auto frame = makeRefPtr(highestRoot->document().frame());
877 if (!frame)
878 continue;
879
880 size_t replacementLocation = notFound;
881 size_t replacementLength = 0;
882 if (!TextIterator::getLocationAndLengthFromRange(highestRoot.get(), range.ptr(), replacementLocation, replacementLength))
883 continue;
884
885 if (replacementLocation == notFound || !replacementLength)
886 continue;
887
888 replacementRanges.append({ WTFMove(highestRoot), replacementLocation, replacementLength });
889 }
890
891 replaceRanges(*this, replacementRanges, replacementText);
892 return rangesToReplace.size();
893}
894
895uint32_t Page::replaceSelectionWithText(const String& replacementText)
896{
897 auto frame = makeRef(focusController().focusedOrMainFrame());
898 auto selection = frame->selection().selection();
899 if (!selection.isContentEditable())
900 return 0;
901
902 auto editAction = selection.isRange() ? EditAction::InsertReplacement : EditAction::Insert;
903 frame->editor().replaceSelectionWithText(replacementText, Editor::SelectReplacement::Yes, Editor::SmartReplace::No, editAction);
904 return 1;
905}
906
907void Page::unmarkAllTextMatches()
908{
909 Frame* frame = &mainFrame();
910 do {
911 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
912 frame = incrementFrame(frame, true, CanWrap::No);
913 } while (frame);
914}
915
916const VisibleSelection& Page::selection() const
917{
918 return focusController().focusedOrMainFrame().selection().selection();
919}
920
921void Page::setDefersLoading(bool defers)
922{
923 if (!m_settings->loadDeferringEnabled())
924 return;
925
926 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
927 ASSERT(defers || m_defersLoadingCallCount);
928 if (defers && ++m_defersLoadingCallCount > 1)
929 return;
930 if (!defers && --m_defersLoadingCallCount)
931 return;
932 } else {
933 ASSERT(!m_defersLoadingCallCount);
934 if (defers == m_defersLoading)
935 return;
936 }
937
938 m_defersLoading = defers;
939 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
940 frame->loader().setDefersLoading(defers);
941}
942
943void Page::clearUndoRedoOperations()
944{
945 m_editorClient->clearUndoRedoOperations();
946}
947
948bool Page::inLowQualityImageInterpolationMode() const
949{
950 return m_inLowQualityInterpolationMode;
951}
952
953void Page::setInLowQualityImageInterpolationMode(bool mode)
954{
955 m_inLowQualityInterpolationMode = mode;
956}
957
958DiagnosticLoggingClient& Page::diagnosticLoggingClient() const
959{
960 if (!settings().diagnosticLoggingEnabled() || !m_diagnosticLoggingClient)
961 return emptyDiagnosticLoggingClient();
962 return *m_diagnosticLoggingClient;
963}
964
965void Page::setMediaVolume(float volume)
966{
967 if (volume < 0 || volume > 1)
968 return;
969
970 if (m_mediaVolume == volume)
971 return;
972
973 m_mediaVolume = volume;
974 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
975 if (!frame->document())
976 continue;
977 frame->document()->mediaVolumeDidChange();
978 }
979}
980
981void Page::setZoomedOutPageScaleFactor(float scale)
982{
983 if (m_zoomedOutPageScaleFactor == scale)
984 return;
985 m_zoomedOutPageScaleFactor = scale;
986
987 mainFrame().deviceOrPageScaleFactorChanged();
988}
989
990void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState)
991{
992 LOG(Viewports, "Page::setPageScaleFactor %.2f - inStableState %d", scale, inStableState);
993
994 Document* document = mainFrame().document();
995 FrameView* view = document->view();
996
997 if (scale == m_pageScaleFactor) {
998 if (view && view->scrollPosition() != origin) {
999 if (!m_settings->delegatesPageScaling())
1000 document->updateLayoutIgnorePendingStylesheets();
1001
1002 if (!view->delegatesScrolling())
1003 view->setScrollPosition(origin);
1004#if USE(COORDINATED_GRAPHICS)
1005 else
1006 view->requestScrollPositionUpdate(origin);
1007#endif
1008 }
1009#if ENABLE(MEDIA_CONTROLS_SCRIPT)
1010 if (inStableState) {
1011 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1012 if (!frame->document())
1013 continue;
1014 frame->document()->pageScaleFactorChangedAndStable();
1015 }
1016 }
1017#endif
1018 return;
1019 }
1020
1021 m_pageScaleFactor = scale;
1022
1023 if (!m_settings->delegatesPageScaling()) {
1024 view->setNeedsLayoutAfterViewConfigurationChange();
1025 view->setNeedsCompositingGeometryUpdate();
1026
1027 document->resolveStyle(Document::ResolveStyleType::Rebuild);
1028
1029 // Transform change on RenderView doesn't trigger repaint on non-composited contents.
1030 mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
1031 }
1032
1033 mainFrame().deviceOrPageScaleFactorChanged();
1034
1035 if (view && view->fixedElementsLayoutRelativeToFrame())
1036 view->setViewportConstrainedObjectsNeedLayout();
1037
1038 if (view && view->scrollPosition() != origin) {
1039 if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
1040 view->layoutContext().layout();
1041
1042 if (!view->delegatesScrolling())
1043 view->setScrollPosition(origin);
1044#if USE(COORDINATED_GRAPHICS)
1045 else
1046 view->requestScrollPositionUpdate(origin);
1047#endif
1048 }
1049
1050#if ENABLE(MEDIA_CONTROLS_SCRIPT)
1051 if (inStableState) {
1052 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1053 if (!frame->document())
1054 continue;
1055 frame->document()->pageScaleFactorChangedAndStable();
1056 }
1057 }
1058#else
1059 UNUSED_PARAM(inStableState);
1060#endif
1061}
1062
1063void Page::setViewScaleFactor(float scale)
1064{
1065 if (m_viewScaleFactor == scale)
1066 return;
1067
1068 m_viewScaleFactor = scale;
1069 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
1070}
1071
1072void Page::setDeviceScaleFactor(float scaleFactor)
1073{
1074 ASSERT(scaleFactor > 0);
1075 if (scaleFactor <= 0)
1076 return;
1077
1078 if (m_deviceScaleFactor == scaleFactor)
1079 return;
1080
1081 m_deviceScaleFactor = scaleFactor;
1082 setNeedsRecalcStyleInAllFrames();
1083
1084 mainFrame().deviceOrPageScaleFactorChanged();
1085 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
1086
1087 pageOverlayController().didChangeDeviceScaleFactor();
1088}
1089
1090void Page::setInitialScale(float initialScale)
1091{
1092 m_initialScale = initialScale;
1093}
1094
1095void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
1096{
1097 if (m_userInterfaceLayoutDirection == userInterfaceLayoutDirection)
1098 return;
1099
1100 m_userInterfaceLayoutDirection = userInterfaceLayoutDirection;
1101#if ENABLE(MEDIA_CONTROLS_SCRIPT)
1102 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1103 if (!frame->document())
1104 continue;
1105 frame->document()->userInterfaceLayoutDirectionChanged();
1106 }
1107#endif
1108}
1109
1110#if ENABLE(VIDEO)
1111void Page::updateMediaElementRateChangeRestrictions()
1112{
1113 for (auto* mediaElement : HTMLMediaElement::allMediaElements())
1114 mediaElement->updateRateChangeRestrictions();
1115}
1116#endif
1117
1118void Page::didStartProvisionalLoad()
1119{
1120 if (m_performanceMonitor)
1121 m_performanceMonitor->didStartProvisionalLoad();
1122}
1123
1124void Page::didFinishLoad()
1125{
1126 resetRelevantPaintedObjectCounter();
1127
1128 if (m_performanceMonitor)
1129 m_performanceMonitor->didFinishLoad();
1130}
1131
1132bool Page::isOnlyNonUtilityPage() const
1133{
1134 return !isUtilityPage() && nonUtilityPageCount == 1;
1135}
1136
1137bool Page::isLowPowerModeEnabled() const
1138{
1139 if (m_lowPowerModeEnabledOverrideForTesting)
1140 return m_lowPowerModeEnabledOverrideForTesting.value();
1141
1142 return m_lowPowerModeNotifier->isLowPowerModeEnabled();
1143}
1144
1145void Page::setLowPowerModeEnabledOverrideForTesting(Optional<bool> isEnabled)
1146{
1147 m_lowPowerModeEnabledOverrideForTesting = isEnabled;
1148 handleLowModePowerChange(m_lowPowerModeEnabledOverrideForTesting.valueOr(false));
1149}
1150
1151void Page::setTopContentInset(float contentInset)
1152{
1153 if (m_topContentInset == contentInset)
1154 return;
1155
1156 m_topContentInset = contentInset;
1157
1158 if (FrameView* view = mainFrame().view())
1159 view->topContentInsetDidChange(m_topContentInset);
1160}
1161
1162void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
1163{
1164 if (suppressAnimations == m_suppressScrollbarAnimations)
1165 return;
1166
1167 lockAllOverlayScrollbarsToHidden(suppressAnimations);
1168 m_suppressScrollbarAnimations = suppressAnimations;
1169}
1170
1171void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
1172{
1173 FrameView* view = mainFrame().view();
1174 if (!view)
1175 return;
1176
1177 view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
1178
1179 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1180 FrameView* frameView = frame->view();
1181 if (!frameView)
1182 continue;
1183
1184 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
1185 if (!scrollableAreas)
1186 continue;
1187
1188 for (auto& scrollableArea : *scrollableAreas)
1189 scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
1190 }
1191}
1192
1193void Page::setVerticalScrollElasticity(ScrollElasticity elasticity)
1194{
1195 if (m_verticalScrollElasticity == elasticity)
1196 return;
1197
1198 m_verticalScrollElasticity = elasticity;
1199
1200 if (FrameView* view = mainFrame().view())
1201 view->setVerticalScrollElasticity(elasticity);
1202}
1203
1204void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity)
1205{
1206 if (m_horizontalScrollElasticity == elasticity)
1207 return;
1208
1209 m_horizontalScrollElasticity = elasticity;
1210
1211 if (FrameView* view = mainFrame().view())
1212 view->setHorizontalScrollElasticity(elasticity);
1213}
1214
1215void Page::setPagination(const Pagination& pagination)
1216{
1217 if (m_pagination == pagination)
1218 return;
1219
1220 m_pagination = pagination;
1221
1222 setNeedsRecalcStyleInAllFrames();
1223}
1224
1225void Page::setPaginationLineGridEnabled(bool enabled)
1226{
1227 if (m_paginationLineGridEnabled == enabled)
1228 return;
1229
1230 m_paginationLineGridEnabled = enabled;
1231
1232 setNeedsRecalcStyleInAllFrames();
1233}
1234
1235unsigned Page::pageCount() const
1236{
1237 if (m_pagination.mode == Pagination::Unpaginated)
1238 return 0;
1239
1240 if (Document* document = mainFrame().document())
1241 document->updateLayoutIgnorePendingStylesheets();
1242
1243 RenderView* contentRenderer = mainFrame().contentRenderer();
1244 return contentRenderer ? contentRenderer->pageCount() : 0;
1245}
1246
1247void Page::setIsInWindow(bool isInWindow)
1248{
1249 setActivityState(isInWindow ? m_activityState | ActivityState::IsInWindow : m_activityState - ActivityState::IsInWindow);
1250}
1251
1252void Page::setIsInWindowInternal(bool isInWindow)
1253{
1254 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1255 if (FrameView* frameView = frame->view())
1256 frameView->setIsInWindow(isInWindow);
1257 }
1258
1259 if (isInWindow)
1260 resumeAnimatingImages();
1261}
1262
1263void Page::addActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1264{
1265 m_activityStateChangeObservers.add(&observer);
1266}
1267
1268void Page::removeActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1269{
1270 m_activityStateChangeObservers.remove(&observer);
1271}
1272
1273void Page::layoutIfNeeded()
1274{
1275 if (FrameView* view = m_mainFrame->view())
1276 view->updateLayoutAndStyleIfNeededRecursive();
1277}
1278
1279void Page::updateRendering()
1280{
1281 // This function is not reentrant, e.g. a rAF callback may force repaint.
1282 if (m_inUpdateRendering) {
1283 layoutIfNeeded();
1284 return;
1285 }
1286
1287 TraceScope traceScope(RenderingUpdateStart, RenderingUpdateEnd);
1288
1289 SetForScope<bool> change(m_inUpdateRendering, true);
1290
1291 Vector<RefPtr<Document>> documents;
1292
1293 // The requestAnimationFrame callbacks may change the frame hierarchy of the page
1294 forEachDocument([&documents] (Document& document) {
1295 documents.append(&document);
1296 });
1297
1298 for (auto& document : documents) {
1299 DOMHighResTimeStamp timestamp = document->domWindow()->nowTimestamp();
1300 document->updateAnimationsAndSendEvents(timestamp);
1301 document->serviceRequestAnimationFrameCallbacks(timestamp);
1302 }
1303
1304 layoutIfNeeded();
1305
1306#if ENABLE(INTERSECTION_OBSERVER)
1307 for (auto& document : documents)
1308 document->updateIntersectionObservations();
1309#endif
1310#if ENABLE(RESIZE_OBSERVER)
1311 for (auto& document : documents)
1312 document->updateResizeObservations(*this);
1313#endif
1314
1315 layoutIfNeeded();
1316}
1317
1318void Page::suspendScriptedAnimations()
1319{
1320 m_scriptedAnimationsSuspended = true;
1321 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1322 if (frame->document())
1323 frame->document()->suspendScriptedAnimationControllerCallbacks();
1324 }
1325}
1326
1327void Page::resumeScriptedAnimations()
1328{
1329 m_scriptedAnimationsSuspended = false;
1330 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1331 if (frame->document())
1332 frame->document()->resumeScriptedAnimationControllerCallbacks();
1333 }
1334}
1335
1336enum class ThrottlingReasonOperation { Add, Remove };
1337static void updateScriptedAnimationsThrottlingReason(Page& page, ThrottlingReasonOperation operation, ScriptedAnimationController::ThrottlingReason reason)
1338{
1339 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
1340 auto* document = frame->document();
1341 if (!document)
1342 continue;
1343 auto* scriptedAnimationController = document->scriptedAnimationController();
1344 if (!scriptedAnimationController)
1345 continue;
1346
1347 if (operation == ThrottlingReasonOperation::Add)
1348 scriptedAnimationController->addThrottlingReason(reason);
1349 else
1350 scriptedAnimationController->removeThrottlingReason(reason);
1351 }
1352}
1353
1354void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
1355{
1356 updateScriptedAnimationsThrottlingReason(*this, isVisuallyIdle ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::VisuallyIdle);
1357}
1358
1359void Page::handleLowModePowerChange(bool isLowPowerModeEnabled)
1360{
1361 updateScriptedAnimationsThrottlingReason(*this, isLowPowerModeEnabled ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::LowPowerMode);
1362 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1363 forEachDocument([&] (Document& document) {
1364 if (auto timeline = document.existingTimeline())
1365 timeline->updateThrottlingState();
1366 });
1367 } else
1368 mainFrame().animation().updateThrottlingState();
1369 updateDOMTimerAlignmentInterval();
1370}
1371
1372void Page::userStyleSheetLocationChanged()
1373{
1374 // FIXME: Eventually we will move to a model of just being handed the sheet
1375 // text instead of loading the URL ourselves.
1376 URL url = m_settings->userStyleSheetLocation();
1377
1378 // Allow any local file URL scheme to be loaded.
1379 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toStringWithoutCopying()))
1380 m_userStyleSheetPath = url.fileSystemPath();
1381 else
1382 m_userStyleSheetPath = String();
1383
1384 m_didLoadUserStyleSheet = false;
1385 m_userStyleSheet = String();
1386 m_userStyleSheetModificationTime = WTF::nullopt;
1387
1388 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
1389 // synchronously and avoid using a loader.
1390 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
1391 m_didLoadUserStyleSheet = true;
1392
1393 Vector<char> styleSheetAsUTF8;
1394 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreSpacesAndNewLines))
1395 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
1396 }
1397
1398 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1399 if (frame->document())
1400 frame->document()->extensionStyleSheets().updatePageUserSheet();
1401 }
1402}
1403
1404const String& Page::userStyleSheet() const
1405{
1406 if (m_userStyleSheetPath.isEmpty())
1407 return m_userStyleSheet;
1408
1409 auto modificationTime = FileSystem::getFileModificationTime(m_userStyleSheetPath);
1410 if (!modificationTime) {
1411 // The stylesheet either doesn't exist, was just deleted, or is
1412 // otherwise unreadable. If we've read the stylesheet before, we should
1413 // throw away that data now as it no longer represents what's on disk.
1414 m_userStyleSheet = String();
1415 return m_userStyleSheet;
1416 }
1417
1418 // If the stylesheet hasn't changed since the last time we read it, we can
1419 // just return the old data.
1420 if (m_didLoadUserStyleSheet && (m_userStyleSheetModificationTime && modificationTime.value() <= m_userStyleSheetModificationTime.value()))
1421 return m_userStyleSheet;
1422
1423 m_didLoadUserStyleSheet = true;
1424 m_userStyleSheet = String();
1425 m_userStyleSheetModificationTime = modificationTime;
1426
1427 // FIXME: It would be better to load this asynchronously to avoid blocking
1428 // the process, but we will first need to create an asynchronous loading
1429 // mechanism that is not tied to a particular Frame. We will also have to
1430 // determine what our behavior should be before the stylesheet is loaded
1431 // and what should happen when it finishes loading, especially with respect
1432 // to when the load event fires, when Document::close is called, and when
1433 // layout/paint are allowed to happen.
1434 auto data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1435 if (!data)
1436 return m_userStyleSheet;
1437
1438 m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size());
1439
1440 return m_userStyleSheet;
1441}
1442
1443void Page::userAgentChanged()
1444{
1445 for (auto* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1446 auto* window = frame->window();
1447 if (!window)
1448 continue;
1449 if (auto* navigator = window->optionalNavigator())
1450 navigator->userAgentChanged();
1451 }
1452}
1453
1454void Page::invalidateStylesForAllLinks()
1455{
1456 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1457 if (!frame->document())
1458 continue;
1459 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1460 }
1461}
1462
1463void Page::invalidateStylesForLink(SharedStringHash linkHash)
1464{
1465 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1466 if (!frame->document())
1467 continue;
1468 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1469 }
1470}
1471
1472void Page::invalidateInjectedStyleSheetCacheInAllFrames()
1473{
1474 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1475 Document* document = frame->document();
1476 if (!document)
1477 continue;
1478 document->extensionStyleSheets().invalidateInjectedStyleSheetCache();
1479 }
1480}
1481
1482void Page::setDebugger(JSC::Debugger* debugger)
1483{
1484 if (m_debugger == debugger)
1485 return;
1486
1487 m_debugger = debugger;
1488
1489 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1490 frame->windowProxy().attachDebugger(m_debugger);
1491}
1492
1493StorageNamespace* Page::sessionStorage(bool optionalCreate)
1494{
1495 if (!m_sessionStorage && optionalCreate)
1496 m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota());
1497
1498 return m_sessionStorage.get();
1499}
1500
1501void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage)
1502{
1503 m_sessionStorage = WTFMove(newStorage);
1504}
1505
1506StorageNamespace* Page::ephemeralLocalStorage(bool optionalCreate)
1507{
1508 if (!m_ephemeralLocalStorage && optionalCreate)
1509 m_ephemeralLocalStorage = m_storageNamespaceProvider->createEphemeralLocalStorageNamespace(*this, m_settings->sessionStorageQuota());
1510
1511 return m_ephemeralLocalStorage.get();
1512}
1513
1514void Page::setEphemeralLocalStorage(RefPtr<StorageNamespace>&& newStorage)
1515{
1516 m_ephemeralLocalStorage = WTFMove(newStorage);
1517}
1518
1519bool Page::hasCustomHTMLTokenizerTimeDelay() const
1520{
1521 return m_settings->maxParseDuration() != -1;
1522}
1523
1524double Page::customHTMLTokenizerTimeDelay() const
1525{
1526 ASSERT(m_settings->maxParseDuration() != -1);
1527 return m_settings->maxParseDuration();
1528}
1529
1530void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1531{
1532 if (m_areMemoryCacheClientCallsEnabled == enabled)
1533 return;
1534
1535 m_areMemoryCacheClientCallsEnabled = enabled;
1536 if (!enabled)
1537 return;
1538
1539 for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1540 frame->loader().tellClientAboutPastMemoryCacheLoads();
1541}
1542
1543void Page::hiddenPageDOMTimerThrottlingStateChanged()
1544{
1545 // Disable & reengage to ensure state is updated.
1546 setTimerThrottlingState(TimerThrottlingState::Disabled);
1547 updateTimerThrottlingState();
1548}
1549
1550void Page::updateTimerThrottlingState()
1551{
1552 // Timer throttling disabled if page is visually active, or disabled by setting.
1553 if (!m_settings->hiddenPageDOMTimerThrottlingEnabled() || !(m_activityState & ActivityState::IsVisuallyIdle)) {
1554 setTimerThrottlingState(TimerThrottlingState::Disabled);
1555 return;
1556 }
1557
1558 // If the page is visible (but idle), there is any activity (loading, media playing, etc), or per setting,
1559 // we allow timer throttling, but not increasing timer throttling.
1560 if (!m_settings->hiddenPageDOMTimerThrottlingAutoIncreases()
1561 || m_activityState.containsAny({ActivityState::IsVisible, ActivityState::IsAudible, ActivityState::IsLoading, ActivityState::IsCapturingMedia })) {
1562 setTimerThrottlingState(TimerThrottlingState::Enabled);
1563 return;
1564 }
1565
1566 // If we get here increasing timer throttling is enabled.
1567 setTimerThrottlingState(TimerThrottlingState::EnabledIncreasing);
1568}
1569
1570void Page::setTimerThrottlingState(TimerThrottlingState state)
1571{
1572 if (state == m_timerThrottlingState)
1573 return;
1574
1575 m_timerThrottlingState = state;
1576 m_timerThrottlingStateLastChangedTime = MonotonicTime::now();
1577
1578 updateDOMTimerAlignmentInterval();
1579
1580 // When throttling is disabled, release all throttled timers.
1581 if (state == TimerThrottlingState::Disabled) {
1582 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1583 if (auto* document = frame->document())
1584 document->didChangeTimerAlignmentInterval();
1585 }
1586 }
1587}
1588
1589void Page::setDOMTimerAlignmentIntervalIncreaseLimit(Seconds limit)
1590{
1591 m_domTimerAlignmentIntervalIncreaseLimit = limit;
1592
1593 // If (m_domTimerAlignmentIntervalIncreaseLimit < m_domTimerAlignmentInterval) then we need
1594 // to update m_domTimerAlignmentInterval, if greater then need to restart the increase timer.
1595 if (m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing)
1596 updateDOMTimerAlignmentInterval();
1597}
1598
1599void Page::updateDOMTimerAlignmentInterval()
1600{
1601 bool needsIncreaseTimer = false;
1602
1603 switch (m_timerThrottlingState) {
1604 case TimerThrottlingState::Disabled:
1605 m_domTimerAlignmentInterval = isLowPowerModeEnabled() ? DOMTimer::defaultAlignmentIntervalInLowPowerMode() : DOMTimer::defaultAlignmentInterval();
1606 break;
1607
1608 case TimerThrottlingState::Enabled:
1609 m_domTimerAlignmentInterval = DOMTimer::hiddenPageAlignmentInterval();
1610 break;
1611
1612 case TimerThrottlingState::EnabledIncreasing:
1613 // For pages in prerender state maximum throttling kicks in immediately.
1614 if (m_isPrerender)
1615 m_domTimerAlignmentInterval = m_domTimerAlignmentIntervalIncreaseLimit;
1616 else {
1617 ASSERT(!!m_timerThrottlingStateLastChangedTime);
1618 m_domTimerAlignmentInterval = MonotonicTime::now() - m_timerThrottlingStateLastChangedTime;
1619 // If we're below the limit, set the timer. If above, clamp to limit.
1620 if (m_domTimerAlignmentInterval < m_domTimerAlignmentIntervalIncreaseLimit)
1621 needsIncreaseTimer = true;
1622 else
1623 m_domTimerAlignmentInterval = m_domTimerAlignmentIntervalIncreaseLimit;
1624 }
1625 // Alignment interval should not be less than DOMTimer::hiddenPageAlignmentInterval().
1626 m_domTimerAlignmentInterval = std::max(m_domTimerAlignmentInterval, DOMTimer::hiddenPageAlignmentInterval());
1627 }
1628
1629 // If throttling is enabled, auto-increasing of throttling is enabled, and the auto-increase
1630 // limit has not yet been reached, and then arm the timer to consider an increase. Time to wait
1631 // between increases is equal to the current throttle time. Since alinment interval increases
1632 // exponentially, time between steps is exponential too.
1633 if (!needsIncreaseTimer)
1634 m_domTimerAlignmentIntervalIncreaseTimer.stop();
1635 else if (!m_domTimerAlignmentIntervalIncreaseTimer.isActive())
1636 m_domTimerAlignmentIntervalIncreaseTimer.startOneShot(m_domTimerAlignmentInterval);
1637}
1638
1639void Page::domTimerAlignmentIntervalIncreaseTimerFired()
1640{
1641 ASSERT(m_settings->hiddenPageDOMTimerThrottlingAutoIncreases());
1642 ASSERT(m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing);
1643 ASSERT(m_domTimerAlignmentInterval < m_domTimerAlignmentIntervalIncreaseLimit);
1644
1645 // Alignment interval is increased to equal the time the page has been throttled, to a limit.
1646 updateDOMTimerAlignmentInterval();
1647}
1648
1649void Page::dnsPrefetchingStateChanged()
1650{
1651 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1652 if (!frame->document())
1653 continue;
1654 frame->document()->initDNSPrefetch();
1655 }
1656}
1657
1658Vector<Ref<PluginViewBase>> Page::pluginViews()
1659{
1660 Vector<Ref<PluginViewBase>> views;
1661 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1662 auto* view = frame->view();
1663 if (!view)
1664 break;
1665 for (auto& widget : view->children()) {
1666 if (is<PluginViewBase>(widget))
1667 views.append(downcast<PluginViewBase>(widget.get()));
1668 }
1669 }
1670 return views;
1671}
1672
1673void Page::storageBlockingStateChanged()
1674{
1675 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1676 if (!frame->document())
1677 continue;
1678 frame->document()->storageBlockingStateDidChange();
1679 }
1680
1681 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1682 // from below storageBlockingStateChanged does not affect their lifetime.
1683 for (auto& view : pluginViews())
1684 view->storageBlockingStateChanged();
1685}
1686
1687void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled)
1688{
1689 // Don't allow changing the legacy private browsing state if we have set a session ID.
1690 ASSERT(m_sessionID == PAL::SessionID::defaultSessionID() || m_sessionID == PAL::SessionID::legacyPrivateSessionID());
1691
1692 setSessionID(privateBrowsingEnabled ? PAL::SessionID::legacyPrivateSessionID() : PAL::SessionID::defaultSessionID());
1693}
1694
1695void Page::updateIsPlayingMedia(uint64_t sourceElementID)
1696{
1697 MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
1698 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1699 if (Document* document = frame->document())
1700 state |= document->mediaState();
1701 }
1702
1703 if (state == m_mediaState)
1704 return;
1705
1706 m_mediaState = state;
1707
1708 chrome().client().isPlayingMediaDidChange(state, sourceElementID);
1709}
1710
1711void Page::schedulePlaybackControlsManagerUpdate()
1712{
1713#if ENABLE(VIDEO)
1714 if (!m_playbackControlsManagerUpdateTimer.isActive())
1715 m_playbackControlsManagerUpdateTimer.startOneShot(0_s);
1716#endif
1717}
1718
1719#if ENABLE(VIDEO)
1720void Page::playbackControlsManagerUpdateTimerFired()
1721{
1722 if (auto bestMediaElement = HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager(MediaElementSession::PlaybackControlsPurpose::ControlsManager))
1723 chrome().client().setUpPlaybackControlsManager(*bestMediaElement);
1724 else
1725 chrome().client().clearPlaybackControlsManager();
1726}
1727#endif
1728
1729void Page::setMuted(MediaProducer::MutedStateFlags muted)
1730{
1731 if (m_mutedState == muted)
1732 return;
1733
1734 m_mutedState = muted;
1735
1736 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1737 if (!frame->document())
1738 continue;
1739 frame->document()->pageMutedStateDidChange();
1740 }
1741}
1742
1743void Page::stopMediaCapture()
1744{
1745#if ENABLE(MEDIA_STREAM)
1746 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1747 if (!frame->document())
1748 continue;
1749
1750 frame->document()->stopMediaCapture();
1751 }
1752#endif
1753}
1754
1755void Page::stopAllMediaPlayback()
1756{
1757#if ENABLE(VIDEO)
1758 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1759 if (auto* document = frame->document())
1760 document->stopAllMediaPlayback();
1761 }
1762#endif
1763}
1764
1765void Page::suspendAllMediaPlayback()
1766{
1767#if ENABLE(VIDEO)
1768 ASSERT(!m_mediaPlaybackIsSuspended);
1769 if (m_mediaPlaybackIsSuspended)
1770 return;
1771
1772 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1773 if (auto* document = frame->document())
1774 document->suspendAllMediaPlayback();
1775 }
1776
1777 m_mediaPlaybackIsSuspended = true;
1778#endif
1779}
1780
1781void Page::resumeAllMediaPlayback()
1782{
1783#if ENABLE(VIDEO)
1784 ASSERT(m_mediaPlaybackIsSuspended);
1785 if (!m_mediaPlaybackIsSuspended)
1786 return;
1787 m_mediaPlaybackIsSuspended = false;
1788
1789 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1790 if (auto* document = frame->document())
1791 document->resumeAllMediaPlayback();
1792 }
1793#endif
1794}
1795
1796void Page::suspendAllMediaBuffering()
1797{
1798#if ENABLE(VIDEO)
1799 ASSERT(!m_mediaBufferingIsSuspended);
1800 if (m_mediaBufferingIsSuspended)
1801 return;
1802 m_mediaBufferingIsSuspended = true;
1803
1804 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1805 if (auto* document = frame->document())
1806 document->suspendAllMediaBuffering();
1807 }
1808#endif
1809}
1810
1811void Page::resumeAllMediaBuffering()
1812{
1813#if ENABLE(VIDEO)
1814 if (!m_mediaBufferingIsSuspended)
1815 return;
1816 m_mediaBufferingIsSuspended = false;
1817
1818 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1819 if (auto* document = frame->document())
1820 document->resumeAllMediaBuffering();
1821 }
1822#endif
1823}
1824
1825#if ENABLE(MEDIA_SESSION)
1826void Page::handleMediaEvent(MediaEventType eventType)
1827{
1828 switch (eventType) {
1829 case MediaEventType::PlayPause:
1830 MediaSessionManager::singleton().togglePlayback();
1831 break;
1832 case MediaEventType::TrackNext:
1833 MediaSessionManager::singleton().skipToNextTrack();
1834 break;
1835 case MediaEventType::TrackPrevious:
1836 MediaSessionManager::singleton().skipToPreviousTrack();
1837 break;
1838 }
1839}
1840
1841void Page::setVolumeOfMediaElement(double volume, uint64_t elementID)
1842{
1843 if (HTMLMediaElement* element = HTMLMediaElement::elementWithID(elementID))
1844 element->setVolume(volume, ASSERT_NO_EXCEPTION);
1845}
1846#endif
1847
1848#if !ASSERT_DISABLED
1849void Page::checkSubframeCountConsistency() const
1850{
1851 ASSERT(m_subframeCount >= 0);
1852
1853 int subframeCount = 0;
1854 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1855 ++subframeCount;
1856
1857 ASSERT(m_subframeCount + 1 == subframeCount);
1858}
1859#endif
1860
1861void Page::resumeAnimatingImages()
1862{
1863 // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1864 // require that we repaint animated images to kickstart the animation loop.
1865 if (FrameView* view = mainFrame().view())
1866 view->resumeVisibleImageAnimationsIncludingSubframes();
1867}
1868
1869void Page::setActivityState(OptionSet<ActivityState::Flag> activityState)
1870{
1871 auto changed = m_activityState ^ activityState;
1872 if (!changed)
1873 return;
1874
1875 auto oldActivityState = m_activityState;
1876
1877 bool wasVisibleAndActive = isVisibleAndActive();
1878 m_activityState = activityState;
1879
1880 m_focusController->setActivityState(activityState);
1881
1882 if (changed & ActivityState::IsVisible)
1883 setIsVisibleInternal(activityState.contains(ActivityState::IsVisible));
1884 if (changed & ActivityState::IsInWindow)
1885 setIsInWindowInternal(activityState.contains(ActivityState::IsInWindow));
1886 if (changed & ActivityState::IsVisuallyIdle)
1887 setIsVisuallyIdleInternal(activityState.contains(ActivityState::IsVisuallyIdle));
1888 if (changed & ActivityState::WindowIsActive) {
1889 if (auto* view = m_mainFrame->view())
1890 view->updateTiledBackingAdaptiveSizing();
1891 }
1892
1893 if (changed.containsAny({ActivityState::IsVisible, ActivityState::IsVisuallyIdle, ActivityState::IsAudible, ActivityState::IsLoading, ActivityState::IsCapturingMedia }))
1894 updateTimerThrottlingState();
1895
1896 for (auto* observer : m_activityStateChangeObservers)
1897 observer->activityStateDidChange(oldActivityState, m_activityState);
1898
1899 if (wasVisibleAndActive != isVisibleAndActive())
1900 PlatformMediaSessionManager::updateNowPlayingInfoIfNecessary();
1901
1902 if (m_performanceMonitor)
1903 m_performanceMonitor->activityStateChanged(oldActivityState, activityState);
1904}
1905
1906bool Page::isVisibleAndActive() const
1907{
1908 return m_activityState.contains(ActivityState::IsVisible) && m_activityState.contains(ActivityState::WindowIsActive);
1909}
1910
1911bool Page::isWindowActive() const
1912{
1913 return m_activityState.contains(ActivityState::WindowIsActive);
1914}
1915
1916void Page::setIsVisible(bool isVisible)
1917{
1918 auto state = m_activityState;
1919
1920 if (isVisible) {
1921 state.remove(ActivityState::IsVisuallyIdle);
1922 state.add({ ActivityState::IsVisible, ActivityState::IsVisibleOrOccluded });
1923 } else {
1924 state.add(ActivityState::IsVisuallyIdle);
1925 state.remove({ ActivityState::IsVisible, ActivityState::IsVisibleOrOccluded });
1926 }
1927 setActivityState(state);
1928}
1929
1930enum class SVGAnimationsState { Paused, Resumed };
1931static inline void setSVGAnimationsState(Page& page, SVGAnimationsState state)
1932{
1933 for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
1934 auto* document = frame->document();
1935 if (!document)
1936 continue;
1937
1938 if (!document->svgExtensions())
1939 continue;
1940
1941 if (state == SVGAnimationsState::Paused)
1942 document->accessSVGExtensions().pauseAnimations();
1943 else
1944 document->accessSVGExtensions().unpauseAnimations();
1945 }
1946}
1947
1948void Page::setIsVisibleInternal(bool isVisible)
1949{
1950 // FIXME: The visibility state should be stored on the top-level document.
1951 // https://bugs.webkit.org/show_bug.cgi?id=116769
1952
1953 if (isVisible) {
1954 m_isPrerender = false;
1955
1956 resumeScriptedAnimations();
1957#if PLATFORM(IOS_FAMILY)
1958 resumeDeviceMotionAndOrientationUpdates();
1959#endif
1960
1961 if (FrameView* view = mainFrame().view())
1962 view->show();
1963
1964 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
1965 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1966 forEachDocument([&] (Document& document) {
1967 if (auto* timeline = document.existingTimeline())
1968 timeline->resumeAnimations();
1969 });
1970 } else
1971 mainFrame().animation().resumeAnimations();
1972 }
1973
1974 setSVGAnimationsState(*this, SVGAnimationsState::Resumed);
1975
1976 resumeAnimatingImages();
1977
1978 if (m_navigationToLogWhenVisible) {
1979 logNavigation(m_navigationToLogWhenVisible.value());
1980 m_navigationToLogWhenVisible = WTF::nullopt;
1981 }
1982 }
1983
1984 if (!isVisible) {
1985 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
1986 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1987 forEachDocument([&] (Document& document) {
1988 if (auto* timeline = document.existingTimeline())
1989 timeline->suspendAnimations();
1990 });
1991 } else
1992 mainFrame().animation().suspendAnimations();
1993 }
1994
1995 setSVGAnimationsState(*this, SVGAnimationsState::Paused);
1996
1997#if PLATFORM(IOS_FAMILY)
1998 suspendDeviceMotionAndOrientationUpdates();
1999#endif
2000
2001 suspendScriptedAnimations();
2002
2003 if (FrameView* view = mainFrame().view())
2004 view->hide();
2005 }
2006
2007 Vector<Ref<Document>> documents;
2008 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
2009 documents.append(*frame->document());
2010
2011 for (auto& document : documents)
2012 document->visibilityStateChanged();
2013}
2014
2015void Page::setIsPrerender()
2016{
2017 m_isPrerender = true;
2018 updateDOMTimerAlignmentInterval();
2019}
2020
2021VisibilityState Page::visibilityState() const
2022{
2023 if (isVisible())
2024 return VisibilityState::Visible;
2025 if (m_isPrerender)
2026 return VisibilityState::Prerender;
2027 return VisibilityState::Hidden;
2028}
2029
2030void Page::setHeaderHeight(int headerHeight)
2031{
2032 if (headerHeight == m_headerHeight)
2033 return;
2034
2035 m_headerHeight = headerHeight;
2036
2037 FrameView* frameView = mainFrame().view();
2038 if (!frameView)
2039 return;
2040
2041 RenderView* renderView = frameView->renderView();
2042 if (!renderView)
2043 return;
2044
2045 frameView->setNeedsLayoutAfterViewConfigurationChange();
2046 frameView->setNeedsCompositingGeometryUpdate();
2047}
2048
2049void Page::setFooterHeight(int footerHeight)
2050{
2051 if (footerHeight == m_footerHeight)
2052 return;
2053
2054 m_footerHeight = footerHeight;
2055
2056 FrameView* frameView = mainFrame().view();
2057 if (!frameView)
2058 return;
2059
2060 RenderView* renderView = frameView->renderView();
2061 if (!renderView)
2062 return;
2063
2064 frameView->setNeedsLayoutAfterViewConfigurationChange();
2065 frameView->setNeedsCompositingGeometryUpdate();
2066}
2067
2068void Page::incrementNestedRunLoopCount()
2069{
2070 m_nestedRunLoopCount++;
2071}
2072
2073void Page::decrementNestedRunLoopCount()
2074{
2075 ASSERT(m_nestedRunLoopCount);
2076 if (m_nestedRunLoopCount <= 0)
2077 return;
2078
2079 m_nestedRunLoopCount--;
2080
2081 if (!m_nestedRunLoopCount && m_unnestCallback) {
2082 callOnMainThread([this] {
2083 if (insideNestedRunLoop())
2084 return;
2085
2086 // This callback may destruct the Page.
2087 if (m_unnestCallback) {
2088 auto callback = WTFMove(m_unnestCallback);
2089 callback();
2090 }
2091 });
2092 }
2093}
2094
2095void Page::whenUnnested(WTF::Function<void()>&& callback)
2096{
2097 ASSERT(!m_unnestCallback);
2098
2099 m_unnestCallback = WTFMove(callback);
2100}
2101
2102#if ENABLE(REMOTE_INSPECTOR)
2103bool Page::remoteInspectionAllowed() const
2104{
2105 return m_inspectorDebuggable->remoteDebuggingAllowed();
2106}
2107
2108void Page::setRemoteInspectionAllowed(bool allowed)
2109{
2110 m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
2111}
2112
2113String Page::remoteInspectionNameOverride() const
2114{
2115 return m_inspectorDebuggable->nameOverride();
2116}
2117
2118void Page::setRemoteInspectionNameOverride(const String& name)
2119{
2120 m_inspectorDebuggable->setNameOverride(name);
2121}
2122
2123void Page::remoteInspectorInformationDidChange() const
2124{
2125 m_inspectorDebuggable->update();
2126}
2127#endif
2128
2129void Page::addLayoutMilestones(OptionSet<LayoutMilestone> milestones)
2130{
2131 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
2132 m_requestedLayoutMilestones.add(milestones);
2133}
2134
2135void Page::removeLayoutMilestones(OptionSet<LayoutMilestone> milestones)
2136{
2137 m_requestedLayoutMilestones.remove(milestones);
2138}
2139
2140Color Page::pageExtendedBackgroundColor() const
2141{
2142 FrameView* frameView = mainFrame().view();
2143 if (!frameView)
2144 return Color();
2145
2146 RenderView* renderView = frameView->renderView();
2147 if (!renderView)
2148 return Color();
2149
2150 return renderView->compositor().rootExtendedBackgroundColor();
2151}
2152
2153// These are magical constants that might be tweaked over time.
2154static const double gMinimumPaintedAreaRatio = 0.1;
2155static const double gMaximumUnpaintedAreaRatio = 0.04;
2156
2157bool Page::isCountingRelevantRepaintedObjects() const
2158{
2159 return m_isCountingRelevantRepaintedObjects && m_requestedLayoutMilestones.contains(DidHitRelevantRepaintedObjectsAreaThreshold);
2160}
2161
2162void Page::startCountingRelevantRepaintedObjects()
2163{
2164 // Reset everything in case we didn't hit the threshold last time.
2165 resetRelevantPaintedObjectCounter();
2166
2167 m_isCountingRelevantRepaintedObjects = true;
2168}
2169
2170void Page::resetRelevantPaintedObjectCounter()
2171{
2172 m_isCountingRelevantRepaintedObjects = false;
2173 m_relevantUnpaintedRenderObjects.clear();
2174 m_topRelevantPaintedRegion = Region();
2175 m_bottomRelevantPaintedRegion = Region();
2176 m_relevantUnpaintedRegion = Region();
2177}
2178
2179static LayoutRect relevantViewRect(RenderView* view)
2180{
2181 LayoutRect viewRect = view->viewRect();
2182
2183 float relevantViewRectWidth = 980;
2184#if PLATFORM(WATCHOS)
2185 // FIXME(186051): Consider limiting the relevant rect width to the view width everywhere.
2186 relevantViewRectWidth = std::min<float>(viewRect.width().toFloat(), relevantViewRectWidth);
2187#endif
2188
2189 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
2190 // a certain relevant amount of content has been drawn to the screen. This is the rect that
2191 // has been determined to be relevant in the context of this goal. We may choose to tweak
2192 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
2193 // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
2194 LayoutRect relevantViewRect { 0, 0, relevantViewRectWidth, 1300 };
2195 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
2196 if (viewRect.width() > relevantViewRect.width())
2197 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
2198
2199 return relevantViewRect;
2200}
2201
2202void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
2203{
2204 if (!isCountingRelevantRepaintedObjects())
2205 return;
2206
2207 // Objects inside sub-frames are not considered to be relevant.
2208 if (&object->frame() != &mainFrame())
2209 return;
2210
2211 LayoutRect relevantRect = relevantViewRect(&object->view());
2212
2213 // The objects are only relevant if they are being painted within the viewRect().
2214 if (!objectPaintRect.intersects(snappedIntRect(relevantRect)))
2215 return;
2216
2217 IntRect snappedPaintRect = snappedIntRect(objectPaintRect);
2218
2219 // If this object was previously counted as an unpainted object, remove it from that HashSet
2220 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
2221 if (m_relevantUnpaintedRenderObjects.remove(object))
2222 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
2223
2224 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
2225 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
2226 // no content beneath that.
2227 LayoutRect topRelevantRect = relevantRect;
2228 topRelevantRect.contract(LayoutSize(0_lu, relevantRect.height() / 2));
2229 LayoutRect bottomRelevantRect = topRelevantRect;
2230 bottomRelevantRect.setY(relevantRect.height() / 2);
2231
2232 // If the rect straddles both Regions, split it appropriately.
2233 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
2234 IntRect topIntersection = snappedPaintRect;
2235 topIntersection.intersect(snappedIntRect(topRelevantRect));
2236 m_topRelevantPaintedRegion.unite(topIntersection);
2237
2238 IntRect bottomIntersection = snappedPaintRect;
2239 bottomIntersection.intersect(snappedIntRect(bottomRelevantRect));
2240 m_bottomRelevantPaintedRegion.unite(bottomIntersection);
2241 } else if (topRelevantRect.intersects(snappedPaintRect))
2242 m_topRelevantPaintedRegion.unite(snappedPaintRect);
2243 else
2244 m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
2245
2246 float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
2247 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
2248 float viewArea = relevantRect.width() * relevantRect.height();
2249
2250 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
2251 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
2252 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
2253
2254 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
2255 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
2256 m_isCountingRelevantRepaintedObjects = false;
2257 resetRelevantPaintedObjectCounter();
2258 if (Frame* frame = &mainFrame())
2259 frame->loader().didReachLayoutMilestone(DidHitRelevantRepaintedObjectsAreaThreshold);
2260 }
2261}
2262
2263void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
2264{
2265 if (!isCountingRelevantRepaintedObjects())
2266 return;
2267
2268 // The objects are only relevant if they are being painted within the relevantViewRect().
2269 if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view()))))
2270 return;
2271
2272 m_relevantUnpaintedRenderObjects.add(object);
2273 m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
2274}
2275
2276void Page::suspendDeviceMotionAndOrientationUpdates()
2277{
2278 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2279 if (Document* document = frame->document())
2280 document->suspendDeviceMotionAndOrientationUpdates();
2281 }
2282}
2283
2284void Page::resumeDeviceMotionAndOrientationUpdates()
2285{
2286 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2287 if (Document* document = frame->document())
2288 document->resumeDeviceMotionAndOrientationUpdates();
2289 }
2290}
2291
2292void Page::suspendActiveDOMObjectsAndAnimations()
2293{
2294 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
2295 frame->suspendActiveDOMObjectsAndAnimations();
2296}
2297
2298void Page::resumeActiveDOMObjectsAndAnimations()
2299{
2300 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
2301 frame->resumeActiveDOMObjectsAndAnimations();
2302
2303 resumeAnimatingImages();
2304}
2305
2306bool Page::hasSeenAnyPlugin() const
2307{
2308 return !m_seenPlugins.isEmpty();
2309}
2310
2311bool Page::hasSeenPlugin(const String& serviceType) const
2312{
2313 return m_seenPlugins.contains(serviceType);
2314}
2315
2316void Page::sawPlugin(const String& serviceType)
2317{
2318 m_seenPlugins.add(serviceType);
2319}
2320
2321void Page::resetSeenPlugins()
2322{
2323 m_seenPlugins.clear();
2324}
2325
2326bool Page::hasSeenAnyMediaEngine() const
2327{
2328 return !m_seenMediaEngines.isEmpty();
2329}
2330
2331bool Page::hasSeenMediaEngine(const String& engineDescription) const
2332{
2333 return m_seenMediaEngines.contains(engineDescription);
2334}
2335
2336void Page::sawMediaEngine(const String& engineDescription)
2337{
2338 m_seenMediaEngines.add(engineDescription);
2339}
2340
2341void Page::resetSeenMediaEngines()
2342{
2343 m_seenMediaEngines.clear();
2344}
2345
2346void Page::hiddenPageCSSAnimationSuspensionStateChanged()
2347{
2348 if (!isVisible()) {
2349 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
2350 forEachDocument([&] (Document& document) {
2351 if (auto* timeline = document.existingTimeline()) {
2352 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
2353 timeline->suspendAnimations();
2354 else
2355 timeline->resumeAnimations();
2356 }
2357 });
2358 } else {
2359 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
2360 mainFrame().animation().suspendAnimations();
2361 else
2362 mainFrame().animation().resumeAnimations();
2363 }
2364 }
2365}
2366
2367#if ENABLE(VIDEO_TRACK)
2368void Page::captionPreferencesChanged()
2369{
2370 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2371 if (!frame->document())
2372 continue;
2373 frame->document()->captionPreferencesChanged();
2374 }
2375}
2376#endif
2377
2378void Page::forbidPrompts()
2379{
2380 ++m_forbidPromptsDepth;
2381}
2382
2383void Page::allowPrompts()
2384{
2385 ASSERT(m_forbidPromptsDepth);
2386 --m_forbidPromptsDepth;
2387}
2388
2389bool Page::arePromptsAllowed()
2390{
2391 return !m_forbidPromptsDepth;
2392}
2393
2394void Page::logNavigation(const Navigation& navigation)
2395{
2396 String navigationDescription;
2397 switch (navigation.type) {
2398 case FrameLoadType::Standard:
2399 navigationDescription = "standard"_s;
2400 break;
2401 case FrameLoadType::Back:
2402 navigationDescription = "back"_s;
2403 break;
2404 case FrameLoadType::Forward:
2405 navigationDescription = "forward"_s;
2406 break;
2407 case FrameLoadType::IndexedBackForward:
2408 navigationDescription = "indexedBackForward"_s;
2409 break;
2410 case FrameLoadType::Reload:
2411 navigationDescription = "reload"_s;
2412 break;
2413 case FrameLoadType::Same:
2414 navigationDescription = "same"_s;
2415 break;
2416 case FrameLoadType::ReloadFromOrigin:
2417 navigationDescription = "reloadFromOrigin"_s;
2418 break;
2419 case FrameLoadType::ReloadExpiredOnly:
2420 navigationDescription = "reloadRevalidatingExpired"_s;
2421 break;
2422 case FrameLoadType::Replace:
2423 case FrameLoadType::RedirectWithLockedBackForwardList:
2424 // Not logging those for now.
2425 return;
2426 }
2427 diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription, ShouldSample::No);
2428
2429 if (!navigation.domain.isEmpty())
2430 diagnosticLoggingClient().logDiagnosticMessageWithEnhancedPrivacy(DiagnosticLoggingKeys::domainVisitedKey(), navigation.domain.string(), ShouldSample::Yes);
2431}
2432
2433void Page::mainFrameLoadStarted(const URL& destinationURL, FrameLoadType type)
2434{
2435 Navigation navigation = { RegistrableDomain { destinationURL }, type };
2436
2437 // To avoid being too verbose, we only log navigations if the page is or becomes visible. This avoids logging non-user observable loads.
2438 if (!isVisible()) {
2439 m_navigationToLogWhenVisible = navigation;
2440 return;
2441 }
2442
2443 m_navigationToLogWhenVisible = WTF::nullopt;
2444 logNavigation(navigation);
2445}
2446
2447PluginInfoProvider& Page::pluginInfoProvider()
2448{
2449 return m_pluginInfoProvider;
2450}
2451
2452UserContentProvider& Page::userContentProvider()
2453{
2454 return m_userContentProvider;
2455}
2456
2457void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider)
2458{
2459 m_userContentProvider->removePage(*this);
2460 m_userContentProvider = WTFMove(userContentProvider);
2461 m_userContentProvider->addPage(*this);
2462
2463 invalidateInjectedStyleSheetCacheInAllFrames();
2464}
2465
2466void Page::setStorageNamespaceProvider(Ref<StorageNamespaceProvider>&& storageNamespaceProvider)
2467{
2468 m_storageNamespaceProvider->removePage(*this);
2469 m_storageNamespaceProvider = WTFMove(storageNamespaceProvider);
2470 m_storageNamespaceProvider->addPage(*this);
2471
2472 // This needs to reset all the local storage namespaces of all the pages.
2473}
2474
2475VisitedLinkStore& Page::visitedLinkStore()
2476{
2477 return m_visitedLinkStore;
2478}
2479
2480void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore)
2481{
2482 m_visitedLinkStore->removePage(*this);
2483 m_visitedLinkStore = WTFMove(visitedLinkStore);
2484 m_visitedLinkStore->addPage(*this);
2485
2486 invalidateStylesForAllLinks();
2487}
2488
2489PAL::SessionID Page::sessionID() const
2490{
2491 return m_sessionID;
2492}
2493
2494void Page::setSessionID(PAL::SessionID sessionID)
2495{
2496 ASSERT(sessionID.isValid());
2497
2498#if ENABLE(INDEXED_DATABASE)
2499 if (sessionID != m_sessionID)
2500 m_idbConnectionToServer = nullptr;
2501#endif
2502
2503 bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral());
2504
2505 m_sessionID = sessionID;
2506
2507 if (!privateBrowsingStateChanged)
2508 return;
2509
2510 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2511 if (!frame->document())
2512 continue;
2513 frame->document()->privateBrowsingStateDidChange();
2514 }
2515
2516 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
2517 // from below privateBrowsingStateChanged does not affect their lifetime.
2518
2519 for (auto& view : pluginViews())
2520 view->privateBrowsingStateChanged(sessionID.isEphemeral());
2521}
2522
2523#if ENABLE(WIRELESS_PLAYBACK_TARGET)
2524void Page::addPlaybackTargetPickerClient(uint64_t contextId)
2525{
2526 chrome().client().addPlaybackTargetPickerClient(contextId);
2527}
2528
2529void Page::removePlaybackTargetPickerClient(uint64_t contextId)
2530{
2531 chrome().client().removePlaybackTargetPickerClient(contextId);
2532}
2533
2534void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo, RouteSharingPolicy routeSharingPolicy, const String& routingContextUID)
2535{
2536#if PLATFORM(IOS_FAMILY)
2537 // FIXME: refactor iOS implementation.
2538 UNUSED_PARAM(contextId);
2539 UNUSED_PARAM(location);
2540 chrome().client().showPlaybackTargetPicker(isVideo, routeSharingPolicy, routingContextUID);
2541#else
2542 UNUSED_PARAM(routeSharingPolicy);
2543 UNUSED_PARAM(routingContextUID);
2544 chrome().client().showPlaybackTargetPicker(contextId, location, isVideo);
2545#endif
2546}
2547
2548void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
2549{
2550 chrome().client().playbackTargetPickerClientStateDidChange(contextId, state);
2551}
2552
2553void Page::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
2554{
2555 chrome().client().setMockMediaPlaybackTargetPickerEnabled(enabled);
2556}
2557
2558void Page::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetContext::State state)
2559{
2560 chrome().client().setMockMediaPlaybackTargetPickerState(name, state);
2561}
2562
2563void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
2564{
2565 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2566 if (!frame->document())
2567 continue;
2568 frame->document()->setPlaybackTarget(contextId, target.copyRef());
2569 }
2570}
2571
2572void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available)
2573{
2574 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2575 if (!frame->document())
2576 continue;
2577 frame->document()->playbackTargetAvailabilityDidChange(contextId, available);
2578 }
2579}
2580
2581void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
2582{
2583 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2584 if (!frame->document())
2585 continue;
2586 frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay);
2587 }
2588}
2589#endif
2590
2591WheelEventTestTrigger& Page::ensureTestTrigger()
2592{
2593 if (!m_testTrigger) {
2594 m_testTrigger = adoptRef(new WheelEventTestTrigger());
2595 // We need to update the scrolling coordinator so that the mainframe scrolling node can expect wheel event test triggers.
2596 if (auto* frameView = mainFrame().view()) {
2597 if (m_scrollingCoordinator)
2598 m_scrollingCoordinator->updateExpectsWheelEventTestTriggerWithFrameView(*frameView);
2599 }
2600 }
2601
2602 return *m_testTrigger;
2603}
2604
2605#if ENABLE(VIDEO)
2606void Page::setAllowsMediaDocumentInlinePlayback(bool flag)
2607{
2608 if (m_allowsMediaDocumentInlinePlayback == flag)
2609 return;
2610 m_allowsMediaDocumentInlinePlayback = flag;
2611
2612 Vector<Ref<Document>> documents;
2613 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
2614 documents.append(*frame->document());
2615
2616 for (auto& document : documents)
2617 document->allowsMediaDocumentInlinePlaybackChanged();
2618}
2619#endif
2620
2621#if ENABLE(INDEXED_DATABASE)
2622IDBClient::IDBConnectionToServer& Page::idbConnection()
2623{
2624 if (!m_idbConnectionToServer)
2625 m_idbConnectionToServer = &databaseProvider().idbConnectionToServerForSession(m_sessionID);
2626
2627 return *m_idbConnectionToServer;
2628}
2629
2630IDBClient::IDBConnectionToServer* Page::optionalIDBConnection()
2631{
2632 return m_idbConnectionToServer.get();
2633}
2634
2635void Page::clearIDBConnection()
2636{
2637 m_idbConnectionToServer = nullptr;
2638}
2639#endif
2640
2641#if ENABLE(RESOURCE_USAGE)
2642void Page::setResourceUsageOverlayVisible(bool visible)
2643{
2644 if (!visible) {
2645 m_resourceUsageOverlay = nullptr;
2646 return;
2647 }
2648
2649 if (!m_resourceUsageOverlay && m_settings->acceleratedCompositingEnabled())
2650 m_resourceUsageOverlay = std::make_unique<ResourceUsageOverlay>(*this);
2651}
2652#endif
2653
2654bool Page::isAlwaysOnLoggingAllowed() const
2655{
2656 return m_sessionID.isAlwaysOnLoggingAllowed();
2657}
2658
2659String Page::captionUserPreferencesStyleSheet()
2660{
2661 return m_captionUserPreferencesStyleSheet;
2662}
2663
2664void Page::setCaptionUserPreferencesStyleSheet(const String& styleSheet)
2665{
2666 if (m_captionUserPreferencesStyleSheet == styleSheet)
2667 return;
2668
2669 m_captionUserPreferencesStyleSheet = styleSheet;
2670}
2671
2672void Page::accessibilitySettingsDidChange()
2673{
2674 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2675 if (auto* document = frame->document()) {
2676 document->styleScope().evaluateMediaQueriesForAccessibilitySettingsChange();
2677 document->evaluateMediaQueryList();
2678 }
2679 }
2680}
2681
2682void Page::appearanceDidChange()
2683{
2684 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2685 auto* document = frame->document();
2686 if (!document)
2687 continue;
2688
2689 document->styleScope().didChangeStyleSheetEnvironment();
2690 document->styleScope().evaluateMediaQueriesForAppearanceChange();
2691 document->evaluateMediaQueryList();
2692 }
2693}
2694
2695void Page::setUnobscuredSafeAreaInsets(const FloatBoxExtent& insets)
2696{
2697 if (m_unobscuredSafeAreaInsets == insets)
2698 return;
2699
2700 m_unobscuredSafeAreaInsets = insets;
2701
2702 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2703 if (!frame->document())
2704 continue;
2705 frame->document()->constantProperties().didChangeSafeAreaInsets();
2706 }
2707}
2708
2709void Page::setUseSystemAppearance(bool value)
2710{
2711 if (m_useSystemAppearance == value)
2712 return;
2713
2714 m_useSystemAppearance = value;
2715
2716 appearanceDidChange();
2717
2718 for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2719 auto* document = frame->document();
2720 if (!document)
2721 continue;
2722
2723 // System apperance change may affect stylesheet parsing. We need to reparse.
2724 document->extensionStyleSheets().clearPageUserSheet();
2725 document->extensionStyleSheets().invalidateInjectedStyleSheetCache();
2726 }
2727}
2728
2729void Page::effectiveAppearanceDidChange(bool useDarkAppearance, bool useInactiveAppearance)
2730{
2731#if HAVE(OS_DARK_MODE_SUPPORT)
2732 if (m_useDarkAppearance == useDarkAppearance && m_useInactiveAppearance == useInactiveAppearance)
2733 return;
2734
2735 m_useDarkAppearance = useDarkAppearance;
2736 m_useInactiveAppearance = useInactiveAppearance;
2737
2738 InspectorInstrumentation::defaultAppearanceDidChange(*this, useDarkAppearance);
2739
2740 appearanceDidChange();
2741#else
2742 UNUSED_PARAM(useDarkAppearance);
2743
2744 if (m_useInactiveAppearance == useInactiveAppearance)
2745 return;
2746
2747 m_useInactiveAppearance = useInactiveAppearance;
2748
2749 appearanceDidChange();
2750#endif
2751}
2752
2753bool Page::useDarkAppearance() const
2754{
2755#if HAVE(OS_DARK_MODE_SUPPORT)
2756 FrameView* view = mainFrame().view();
2757 if (!view || !equalLettersIgnoringASCIICase(view->mediaType(), "screen"))
2758 return false;
2759 if (m_useDarkAppearanceOverride)
2760 return m_useDarkAppearanceOverride.value();
2761 return m_useDarkAppearance;
2762#else
2763 return false;
2764#endif
2765}
2766
2767void Page::setUseDarkAppearanceOverride(Optional<bool> valueOverride)
2768{
2769#if HAVE(OS_DARK_MODE_SUPPORT)
2770 if (valueOverride == m_useDarkAppearanceOverride)
2771 return;
2772
2773 m_useDarkAppearanceOverride = valueOverride;
2774
2775 appearanceDidChange();
2776#else
2777 UNUSED_PARAM(valueOverride);
2778#endif
2779}
2780
2781void Page::setFullscreenInsets(const FloatBoxExtent& insets)
2782{
2783 if (insets == m_fullscreenInsets)
2784 return;
2785 m_fullscreenInsets = insets;
2786
2787 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2788 if (!frame->document())
2789 continue;
2790 frame->document()->constantProperties().didChangeFullscreenInsets();
2791 }
2792}
2793
2794void Page::setFullscreenAutoHideDuration(Seconds duration)
2795{
2796 if (duration == m_fullscreenAutoHideDuration)
2797 return;
2798 m_fullscreenAutoHideDuration = duration;
2799 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2800 if (!frame->document())
2801 continue;
2802 frame->document()->constantProperties().setFullscreenAutoHideDuration(duration);
2803 }
2804}
2805
2806void Page::setFullscreenControlsHidden(bool hidden)
2807{
2808#if ENABLE(FULLSCREEN_API)
2809 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2810 if (!frame->document())
2811 continue;
2812 frame->document()->fullscreenManager().setFullscreenControlsHidden(hidden);
2813 }
2814#else
2815 UNUSED_PARAM(hidden);
2816#endif
2817}
2818
2819#if ENABLE(DATA_INTERACTION)
2820
2821bool Page::hasSelectionAtPosition(const FloatPoint& position) const
2822{
2823 auto currentSelection = m_mainFrame->selection().selection();
2824 if (!currentSelection.isRange())
2825 return false;
2826
2827 if (auto selectedRange = currentSelection.toNormalizedRange()) {
2828 Vector<SelectionRect> selectionRects;
2829 selectedRange->collectSelectionRects(selectionRects);
2830 for (auto selectionRect : selectionRects) {
2831 if (FloatRect(selectionRect.rect()).contains(position))
2832 return true;
2833 }
2834 }
2835
2836 return false;
2837}
2838
2839#endif
2840
2841void Page::disableICECandidateFiltering()
2842{
2843 m_shouldEnableICECandidateFilteringByDefault = false;
2844#if ENABLE(WEB_RTC)
2845 m_rtcController.disableICECandidateFilteringForAllOrigins();
2846#endif
2847}
2848
2849void Page::enableICECandidateFiltering()
2850{
2851 m_shouldEnableICECandidateFilteringByDefault = true;
2852#if ENABLE(WEB_RTC)
2853 m_rtcController.enableICECandidateFiltering();
2854#endif
2855}
2856
2857void Page::didChangeMainDocument()
2858{
2859#if ENABLE(WEB_RTC)
2860 m_rtcController.reset(m_shouldEnableICECandidateFilteringByDefault);
2861#endif
2862}
2863
2864RenderingUpdateScheduler& Page::renderingUpdateScheduler()
2865{
2866 if (!m_renderingUpdateScheduler)
2867 m_renderingUpdateScheduler = RenderingUpdateScheduler::create(*this);
2868 return *m_renderingUpdateScheduler;
2869}
2870
2871void Page::forEachDocument(const Function<void(Document&)>& functor)
2872{
2873 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
2874 if (!frame->document())
2875 continue;
2876
2877 functor(*frame->document());
2878 }
2879}
2880
2881void Page::applicationWillResignActive()
2882{
2883 forEachDocument([&] (Document& document) {
2884 document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
2885 listener.applicationWillResignActive();
2886 });
2887 });
2888}
2889
2890void Page::applicationDidEnterBackground()
2891{
2892 m_libWebRTCProvider->setActive(false);
2893}
2894
2895void Page::applicationWillEnterForeground()
2896{
2897 m_libWebRTCProvider->setActive(true);
2898}
2899
2900void Page::applicationDidBecomeActive()
2901{
2902 forEachDocument([&] (Document& document) {
2903 document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
2904 listener.applicationDidBecomeActive();
2905 });
2906 });
2907}
2908
2909#if PLATFORM(MAC)
2910ScrollLatchingState* Page::latchingState()
2911{
2912 if (m_latchingState.isEmpty())
2913 return nullptr;
2914
2915 return &m_latchingState.last();
2916}
2917
2918void Page::pushNewLatchingState()
2919{
2920 m_latchingState.append(ScrollLatchingState());
2921}
2922
2923void Page::resetLatchingState()
2924{
2925 m_latchingState.clear();
2926}
2927
2928void Page::popLatchingState()
2929{
2930 m_latchingState.removeLast();
2931}
2932
2933void Page::removeLatchingStateForTarget(Element& targetNode)
2934{
2935 if (m_latchingState.isEmpty())
2936 return;
2937
2938 m_latchingState.removeAllMatching([&targetNode] (ScrollLatchingState& state) {
2939 auto* wheelElement = state.wheelEventElement();
2940 if (!wheelElement)
2941 return false;
2942
2943 return targetNode.isEqualNode(wheelElement);
2944 });
2945}
2946#endif // PLATFORM(MAC)
2947
2948static void dispatchPrintEvent(Frame& mainFrame, const AtomicString& eventType)
2949{
2950 Vector<Ref<Frame>> frames;
2951 for (auto* frame = &mainFrame; frame; frame = frame->tree().traverseNext())
2952 frames.append(*frame);
2953
2954 for (auto& frame : frames) {
2955 if (auto* window = frame->window())
2956 window->dispatchEvent(Event::create(eventType, Event::CanBubble::No, Event::IsCancelable::No), window->document());
2957 }
2958}
2959
2960void Page::dispatchBeforePrintEvent()
2961{
2962 dispatchPrintEvent(m_mainFrame, eventNames().beforeprintEvent);
2963}
2964
2965void Page::dispatchAfterPrintEvent()
2966{
2967 dispatchPrintEvent(m_mainFrame, eventNames().afterprintEvent);
2968}
2969
2970#if ENABLE(APPLE_PAY)
2971void Page::setPaymentCoordinator(std::unique_ptr<PaymentCoordinator>&& paymentCoordinator)
2972{
2973 m_paymentCoordinator = WTFMove(paymentCoordinator);
2974}
2975#endif
2976
2977void Page::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
2978{
2979#if !RELEASE_LOG_DISABLED
2980 if (auto* channel = getLogChannel(channelName)) {
2981 channel->state = state;
2982 channel->level = level;
2983
2984#if USE(LIBWEBRTC)
2985 if (channel == &LogWebRTC && m_mainFrame->document())
2986 libWebRTCProvider().setEnableLogging(!m_mainFrame->document()->sessionID().isEphemeral());
2987#endif
2988 }
2989
2990 chrome().client().configureLoggingChannel(channelName, state, level);
2991#else
2992 UNUSED_PARAM(channelName);
2993 UNUSED_PARAM(state);
2994 UNUSED_PARAM(level);
2995#endif
2996}
2997
2998} // namespace WebCore
2999