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