2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All
4 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved.
5 * (http://www.torchmobile.com/)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "third_party/blink/renderer/core/page/page.h"
24 #include "base/compiler_specific.h"
25 #include "base/feature_list.h"
26 #include "third_party/blink/public/common/features.h"
27 #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
28 #include "third_party/blink/public/platform/platform.h"
31 #include "third_party/blink/public/platform/web_runtime_features.h"
34 #include "third_party/blink/public/web/blink.h"
35 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
36 #include "third_party/blink/renderer/core/core_export.h"
37 #include "third_party/blink/renderer/core/css/media_feature_overrides.h"
38 #include "third_party/blink/renderer/core/css/style_change_reason.h"
39 #include "third_party/blink/renderer/core/css/style_engine.h"
40 #include "third_party/blink/renderer/core/css/vision_deficiency.h"
41 #include "third_party/blink/renderer/core/dom/events/event.h"
42 #include "third_party/blink/renderer/core/dom/node_rare_data.h"
43 #include "third_party/blink/renderer/core/dom/visited_link_state.h"
44 #include "third_party/blink/renderer/core/editing/drag_caret.h"
45 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
46 #include "third_party/blink/renderer/core/frame/browser_controls.h"
47 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
48 #include "third_party/blink/renderer/core/frame/frame_console.h"
49 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
50 #include "third_party/blink/renderer/core/frame/local_frame.h"
51 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
52 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
53 #include "third_party/blink/renderer/core/frame/page_scale_constraints.h"
54 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
55 #include "third_party/blink/renderer/core/frame/remote_frame.h"
56 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
57 #include "third_party/blink/renderer/core/frame/settings.h"
58 #include "third_party/blink/renderer/core/frame/viewport_data.h"
59 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
60 #include "third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.h"
61 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
62 #include "third_party/blink/renderer/core/html/portal/document_portals.h"
63 #include "third_party/blink/renderer/core/inspector/console_message.h"
64 #include "third_party/blink/renderer/core/inspector/console_message_storage.h"
65 #include "third_party/blink/renderer/core/inspector/inspector_issue_storage.h"
66 #include "third_party/blink/renderer/core/layout/layout_view.h"
67 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
68 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
69 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
70 #include "third_party/blink/renderer/core/page/chrome_client.h"
71 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
72 #include "third_party/blink/renderer/core/page/drag_controller.h"
73 #include "third_party/blink/renderer/core/page/focus_controller.h"
74 #include "third_party/blink/renderer/core/page/link_highlight.h"
75 #include "third_party/blink/renderer/core/page/page_animator.h"
76 #include "third_party/blink/renderer/core/page/page_hidden_state.h"
77 #include "third_party/blink/renderer/core/page/plugin_data.h"
78 #include "third_party/blink/renderer/core/page/plugins_changed_observer.h"
79 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
80 #include "third_party/blink/renderer/core/page/scoped_browsing_context_group_pauser.h"
81 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
82 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
83 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
84 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
85 #include "third_party/blink/renderer/core/page/validation_message_client_impl.h"
86 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
87 #include "third_party/blink/renderer/core/preferences/preference_overrides.h"
88 #include "third_party/blink/renderer/core/probe/core_probes.h"
89 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
90 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_mobile.h"
91 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
92 #include "third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h"
93 #include "third_party/blink/renderer/platform/bindings/source_location.h"
94 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
95 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
96 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
97 #include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h"
98 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
99 #include "third_party/skia/include/core/SkColor.h"
104 // This seems like a reasonable upper bound, and otherwise mutually
105 // recursive frameset pages can quickly bring the program to its knees
106 // with exponential growth in the number of frames.
107 const int kMaxNumberOfFrames = 1000;
109 // It is possible to use a reduced frame limit for testing, but only two values
110 // are permitted, the default or reduced limit.
111 const int kTenFrames = 10;
113 bool g_limit_max_frames_to_ten_for_testing = false;
117 // Function defined in third_party/blink/public/web/blink.h.
118 void ResetPluginCache(bool reload_pages) {
119 // At this point we already know that the browser has refreshed its list, so
120 // it is not necessary to force it to be regenerated.
121 DCHECK(!reload_pages);
122 Page::ResetPluginData();
125 // Set of all live pages; includes internal Page objects that are
126 // not observable from scripts.
127 static Page::PageSet& AllPages() {
128 DEFINE_STATIC_LOCAL(Persistent<Page::PageSet>, pages,
129 (MakeGarbageCollected<Page::PageSet>()));
133 Page::PageSet& Page::OrdinaryPages() {
134 DEFINE_STATIC_LOCAL(Persistent<Page::PageSet>, pages,
135 (MakeGarbageCollected<Page::PageSet>()));
139 void Page::InsertOrdinaryPageForTesting(Page* page) {
140 OrdinaryPages().insert(page);
143 HeapVector<Member<Page>> Page::RelatedPages() {
144 HeapVector<Member<Page>> result;
145 Page* ptr = next_related_page_;
146 while (ptr != this) {
147 result.push_back(ptr);
148 ptr = ptr->next_related_page_;
153 Page* Page::CreateNonOrdinary(ChromeClient& chrome_client,
154 AgentGroupScheduler& agent_group_scheduler) {
155 return MakeGarbageCollected<Page>(
156 base::PassKey<Page>(), chrome_client, agent_group_scheduler,
157 BrowsingContextGroupInfo::CreateUnique(), /*is_ordinary=*/false);
160 Page* Page::CreateOrdinary(
161 ChromeClient& chrome_client,
163 AgentGroupScheduler& agent_group_scheduler,
164 const BrowsingContextGroupInfo& browsing_context_group_info) {
165 Page* page = MakeGarbageCollected<Page>(
166 base::PassKey<Page>(), chrome_client, agent_group_scheduler,
167 browsing_context_group_info, /*is_ordinary=*/true);
170 // Before: ... -> opener -> next -> ...
171 // After: ... -> opener -> page -> next -> ...
172 Page* next = opener->next_related_page_;
173 opener->next_related_page_ = page;
174 page->prev_related_page_ = opener;
175 page->next_related_page_ = next;
176 next->prev_related_page_ = page;
179 OrdinaryPages().insert(page);
181 bool should_pause = false;
182 if (base::FeatureList::IsEnabled(
183 features::kPausePagesPerBrowsingContextGroup)) {
184 should_pause = ScopedBrowsingContextGroupPauser::IsActive(*page);
186 should_pause = ScopedPagePauser::IsActive();
189 page->SetPaused(true);
195 Page::Page(base::PassKey<Page>,
196 ChromeClient& chrome_client,
197 AgentGroupScheduler& agent_group_scheduler,
198 const BrowsingContextGroupInfo& browsing_context_group_info,
200 : SettingsDelegate(std::make_unique<Settings>()),
201 main_frame_(nullptr),
202 agent_group_scheduler_(agent_group_scheduler),
203 animator_(MakeGarbageCollected<PageAnimator>(*this)),
204 autoscroll_controller_(MakeGarbageCollected<AutoscrollController>(*this)),
205 chrome_client_(&chrome_client),
206 drag_caret_(MakeGarbageCollected<DragCaret>()),
207 drag_controller_(MakeGarbageCollected<DragController>(this)),
208 focus_controller_(MakeGarbageCollected<FocusController>(this)),
209 context_menu_controller_(
210 MakeGarbageCollected<ContextMenuController>(this)),
211 page_scale_constraints_set_(
212 MakeGarbageCollected<PageScaleConstraintsSet>(this)),
213 pointer_lock_controller_(
214 MakeGarbageCollected<PointerLockController>(this)),
215 browser_controls_(MakeGarbageCollected<BrowserControls>(*this)),
216 console_message_storage_(MakeGarbageCollected<ConsoleMessageStorage>()),
217 global_root_scroller_controller_(
218 MakeGarbageCollected<TopDocumentRootScrollerController>(*this)),
219 visual_viewport_(MakeGarbageCollected<VisualViewport>(*this)),
220 link_highlight_(MakeGarbageCollected<LinkHighlight>(*this)),
221 plugin_data_(nullptr),
222 // TODO(pdr): Initialize |validation_message_client_| lazily.
223 validation_message_client_(
224 MakeGarbageCollected<ValidationMessageClientImpl>(*this)),
225 opened_by_dom_(false),
226 tab_key_cycles_through_elements_(true),
227 inspector_device_scale_factor_override_(1),
228 lifecycle_state_(mojom::blink::PageLifecycleState::New()),
229 is_ordinary_(is_ordinary),
230 is_cursor_visible_(true),
232 next_related_page_(this),
233 prev_related_page_(this),
235 #if BUILDFLAG(IS_TIZEN)
236 m_isSuspended(false),
238 web_text_autosizer_page_info_({0, 0, 1.f}),
239 v8_compile_hints_producer_(
240 MakeGarbageCollected<
241 v8_compile_hints::V8CrowdsourcedCompileHintsProducer>(this)),
242 v8_compile_hints_consumer_(
243 MakeGarbageCollected<
244 v8_compile_hints::V8CrowdsourcedCompileHintsConsumer>()),
245 browsing_context_group_info_(browsing_context_group_info) {
246 DCHECK(!AllPages().Contains(this));
247 AllPages().insert(this);
249 page_scheduler_ = agent_group_scheduler_->CreatePageScheduler(this);
250 // The scheduler should be set before the main frame.
251 DCHECK(!main_frame_);
252 if (auto* virtual_time_controller =
253 page_scheduler_->GetVirtualTimeController()) {
254 history_navigation_virtual_time_pauser_ =
255 virtual_time_controller->CreateWebScopedVirtualTimePauser(
257 WebScopedVirtualTimePauser::VirtualTaskDuration::kInstant);
262 // WillBeDestroyed() must be called before Page destruction.
263 DCHECK(!main_frame_);
266 void Page::CloseSoon() {
267 // Make sure this Page can no longer be found by JS.
270 // TODO(dcheng): Try to remove this in a followup, it's not obviously needed.
271 if (auto* main_local_frame = DynamicTo<LocalFrame>(main_frame_.Get()))
272 main_local_frame->Loader().StopAllLoaders(/*abort_client=*/true);
274 GetChromeClient().CloseWindowSoon();
277 ViewportDescription Page::GetViewportDescription() const {
278 return MainFrame() && MainFrame()->IsLocalFrame() &&
279 DeprecatedLocalMainFrame()->GetDocument()
280 ? DeprecatedLocalMainFrame()
283 .GetViewportDescription()
284 : ViewportDescription();
287 ScrollingCoordinator* Page::GetScrollingCoordinator() {
288 if (!scrolling_coordinator_ && settings_->GetAcceleratedCompositingEnabled())
289 scrolling_coordinator_ = MakeGarbageCollected<ScrollingCoordinator>(this);
291 return scrolling_coordinator_.Get();
294 PageScaleConstraintsSet& Page::GetPageScaleConstraintsSet() {
295 return *page_scale_constraints_set_;
298 const PageScaleConstraintsSet& Page::GetPageScaleConstraintsSet() const {
299 return *page_scale_constraints_set_;
302 BrowserControls& Page::GetBrowserControls() {
303 return *browser_controls_;
306 const BrowserControls& Page::GetBrowserControls() const {
307 return *browser_controls_;
310 ConsoleMessageStorage& Page::GetConsoleMessageStorage() {
311 return *console_message_storage_;
314 const ConsoleMessageStorage& Page::GetConsoleMessageStorage() const {
315 return *console_message_storage_;
318 InspectorIssueStorage& Page::GetInspectorIssueStorage() {
319 return inspector_issue_storage_;
322 const InspectorIssueStorage& Page::GetInspectorIssueStorage() const {
323 return inspector_issue_storage_;
326 TopDocumentRootScrollerController& Page::GlobalRootScrollerController() const {
327 return *global_root_scroller_controller_;
330 VisualViewport& Page::GetVisualViewport() {
331 return *visual_viewport_;
334 const VisualViewport& Page::GetVisualViewport() const {
335 return *visual_viewport_;
338 LinkHighlight& Page::GetLinkHighlight() {
339 return *link_highlight_;
342 void Page::SetMainFrame(Frame* main_frame) {
343 // TODO(https://crbug.com/952836): Assert that this is only called during
344 // initialization or swaps between local and remote frames.
345 main_frame_ = main_frame;
347 page_scheduler_->SetIsMainFrameLocal(main_frame->IsLocalFrame());
350 LocalFrame* Page::DeprecatedLocalMainFrame() const {
351 return To<LocalFrame>(main_frame_.Get());
354 void Page::DocumentDetached(Document* document) {
355 pointer_lock_controller_->DocumentDetached(document);
356 context_menu_controller_->DocumentDetached(document);
357 if (validation_message_client_)
358 validation_message_client_->DocumentDetached(*document);
360 GetChromeClient().DocumentDetached(*document);
363 bool Page::OpenedByDOM() const {
364 return opened_by_dom_;
367 void Page::SetOpenedByDOM() {
368 opened_by_dom_ = true;
371 SpatialNavigationController& Page::GetSpatialNavigationController() {
372 if (!spatial_navigation_controller_) {
373 spatial_navigation_controller_ =
374 MakeGarbageCollected<SpatialNavigationController>(*this);
376 return *spatial_navigation_controller_;
379 void Page::UsesOverlayScrollbarsChanged() {
380 for (Page* page : AllPages()) {
381 for (Frame* frame = page->MainFrame(); frame;
382 frame = frame->Tree().TraverseNext()) {
383 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
384 local_frame->View()->UsesOverlayScrollbarsChanged();
389 void Page::PlatformColorsChanged() {
390 for (const Page* page : AllPages()) {
391 for (Frame* frame = page->MainFrame(); frame;
392 frame = frame->Tree().TraverseNext()) {
393 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
394 local_frame->GetDocument()->PlatformColorsChanged();
395 if (LayoutView* view = local_frame->ContentLayoutObject())
396 view->InvalidatePaintForViewAndDescendants();
402 void Page::ColorSchemeChanged() {
403 for (const Page* page : AllPages())
404 for (Frame* frame = page->MainFrame(); frame;
405 frame = frame->Tree().TraverseNext()) {
406 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
407 local_frame->GetDocument()->ColorSchemeChanged();
411 void Page::ColorProvidersChanged() {
412 for (Page* page : AllPages())
413 page->InvalidatePaint();
416 void Page::InitialStyleChanged() {
417 for (Frame* frame = MainFrame(); frame;
418 frame = frame->Tree().TraverseNext()) {
419 auto* local_frame = DynamicTo<LocalFrame>(frame);
422 local_frame->GetDocument()->GetStyleEngine().InitialStyleChanged();
426 PluginData* Page::GetPluginData() {
428 plugin_data_ = MakeGarbageCollected<PluginData>();
430 plugin_data_->UpdatePluginList();
431 return plugin_data_.Get();
434 void Page::ResetPluginData() {
435 for (Page* page : AllPages()) {
436 if (page->plugin_data_) {
437 page->plugin_data_->ResetPluginData();
438 page->NotifyPluginsChanged();
443 static void RestoreSVGImageAnimations() {
444 for (const Page* page : AllPages()) {
445 if (auto* svg_image_chrome_client =
446 DynamicTo<SVGImageChromeClient>(page->GetChromeClient()))
447 svg_image_chrome_client->RestoreAnimationIfNeeded();
451 void Page::SetValidationMessageClientForTesting(
452 ValidationMessageClient* client) {
453 validation_message_client_ = client;
456 void Page::SetPaused(bool paused) {
457 if (paused == paused_)
461 for (Frame* frame = MainFrame(); frame;
462 frame = frame->Tree().TraverseNext()) {
463 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
464 local_frame->OnPageLifecycleStateUpdated();
469 void Page::SetDefaultPageScaleLimits(float min_scale, float max_scale) {
470 PageScaleConstraints new_defaults =
471 GetPageScaleConstraintsSet().DefaultConstraints();
472 new_defaults.minimum_scale = min_scale;
473 new_defaults.maximum_scale = max_scale;
475 if (new_defaults == GetPageScaleConstraintsSet().DefaultConstraints())
478 GetPageScaleConstraintsSet().SetDefaultConstraints(new_defaults);
479 GetPageScaleConstraintsSet().ComputeFinalConstraints();
480 GetPageScaleConstraintsSet().SetNeedsReset(true);
482 if (!MainFrame() || !MainFrame()->IsLocalFrame())
485 LocalFrameView* root_view = DeprecatedLocalMainFrame()->View();
490 root_view->SetNeedsLayout();
493 void Page::SetUserAgentPageScaleConstraints(
494 const PageScaleConstraints& new_constraints) {
495 if (new_constraints == GetPageScaleConstraintsSet().UserAgentConstraints())
498 GetPageScaleConstraintsSet().SetUserAgentConstraints(new_constraints);
500 if (!MainFrame() || !MainFrame()->IsLocalFrame())
503 LocalFrameView* root_view = DeprecatedLocalMainFrame()->View();
508 root_view->SetNeedsLayout();
511 void Page::SetPageScaleFactor(float scale) {
512 GetVisualViewport().SetScale(scale);
515 float Page::PageScaleFactor() const {
516 return GetVisualViewport().Scale();
519 void Page::AllVisitedStateChanged(bool invalidate_visited_link_hashes) {
520 for (const Page* page : OrdinaryPages()) {
521 for (Frame* frame = page->main_frame_; frame;
522 frame = frame->Tree().TraverseNext()) {
523 if (auto* main_local_frame = DynamicTo<LocalFrame>(frame))
524 main_local_frame->GetDocument()
525 ->GetVisitedLinkState()
526 .InvalidateStyleForAllLinks(invalidate_visited_link_hashes);
531 void Page::VisitedStateChanged(LinkHash link_hash) {
532 for (const Page* page : OrdinaryPages()) {
533 for (Frame* frame = page->main_frame_; frame;
534 frame = frame->Tree().TraverseNext()) {
535 if (auto* main_local_frame = DynamicTo<LocalFrame>(frame))
536 main_local_frame->GetDocument()
537 ->GetVisitedLinkState()
538 .InvalidateStyleForLink(link_hash);
543 void Page::SetVisibilityState(
544 mojom::blink::PageVisibilityState visibility_state,
545 bool is_initial_state) {
546 if (lifecycle_state_->visibility == visibility_state)
549 // Are we entering / leaving a state that would map to the "visible" state, in
550 // the `document.visibilityState` sense?
551 const bool was_visible = lifecycle_state_->visibility ==
552 mojom::blink::PageVisibilityState::kVisible;
553 const bool is_visible =
554 visibility_state == mojom::blink::PageVisibilityState::kVisible;
556 lifecycle_state_->visibility = visibility_state;
558 if (is_initial_state)
561 for (auto observer : page_visibility_observer_set_) {
562 observer->PageVisibilityChanged();
566 if (lifecycle_state_->visibility ==
567 mojom::blink::PageVisibilityState::kVisible) {
568 RestoreSVGImageAnimations();
570 // If we're eliding visibility transitions between the two `kHidden*`
571 // states, then we never get here unless one state was `kVisible` and the
572 // other was not. However, if we aren't eliding those transitions, then we
573 // need to do so now; from the Frame's point of view, nothing is changing if
574 // this is a change between the two `kHidden*` states. Both map to "hidden"
575 // in the sense of `document.visibilityState`, and dispatching an event when
576 // the web-exposed state hasn't changed is confusing.
578 // This check could be enabled for both cases, and the result in the
579 // "eliding" case shouldn't change. It's not, just to be safe, since this
580 // is intended as a fall-back to previous behavior.
581 if (!RuntimeEnabledFeatures::DispatchHiddenVisibilityTransitionsEnabled() ||
582 was_visible || is_visible) {
583 main_frame_->DidChangeVisibilityState();
588 mojom::blink::PageVisibilityState Page::GetVisibilityState() const {
589 return lifecycle_state_->visibility;
592 bool Page::IsPageVisible() const {
593 return lifecycle_state_->visibility ==
594 mojom::blink::PageVisibilityState::kVisible;
597 bool Page::DispatchedPagehideAndStillHidden() {
598 return lifecycle_state_->pagehide_dispatch !=
599 mojom::blink::PagehideDispatch::kNotDispatched;
602 bool Page::DispatchedPagehidePersistedAndStillHidden() {
603 return lifecycle_state_->pagehide_dispatch ==
604 mojom::blink::PagehideDispatch::kDispatchedPersisted;
607 void Page::OnSetPageFrozen(bool frozen) {
608 if (frozen_ == frozen)
612 for (Frame* frame = main_frame_.Get(); frame;
613 frame = frame->Tree().TraverseNext()) {
614 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
615 local_frame->OnPageLifecycleStateUpdated();
620 bool Page::IsCursorVisible() const {
621 return is_cursor_visible_;
625 int Page::MaxNumberOfFrames() {
626 if (UNLIKELY(g_limit_max_frames_to_ten_for_testing))
628 return kMaxNumberOfFrames;
632 void Page::SetMaxNumberOfFramesToTenForTesting(bool enabled) {
633 g_limit_max_frames_to_ten_for_testing = enabled;
637 void CheckFrameCountConsistency(int expected_frame_count, Frame* frame) {
638 DCHECK_GE(expected_frame_count, 0);
640 int actual_frame_count = 0;
642 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
643 if (auto* portals = DocumentPortals::Get(*local_frame->GetDocument())) {
644 actual_frame_count += static_cast<int>(portals->GetPortals().size());
648 for (; frame; frame = frame->Tree().TraverseNext()) {
649 ++actual_frame_count;
651 // Check the ``DocumentFencedFrames`` on every local frame beneath
652 // the ``frame`` to get an accurate count (i.e. if an iframe embeds
653 // a fenced frame and creates a new ``DocumentFencedFrames`` object).
654 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
655 if (auto* fenced_frames =
656 DocumentFencedFrames::Get(*local_frame->GetDocument())) {
657 actual_frame_count +=
658 static_cast<int>(fenced_frames->GetFencedFrames().size());
663 DCHECK_EQ(expected_frame_count, actual_frame_count);
667 int Page::SubframeCount() const {
669 CheckFrameCountConsistency(subframe_count_ + 1, MainFrame());
671 return subframe_count_;
674 void Page::SettingsChanged(ChangeType change_type) {
675 switch (change_type) {
676 case ChangeType::kStyle:
677 InitialStyleChanged();
679 case ChangeType::kViewportDescription:
680 if (MainFrame() && MainFrame()->IsLocalFrame()) {
681 DeprecatedLocalMainFrame()
684 .UpdateViewportDescription();
685 // The text autosizer has dependencies on the viewport. Viewport
686 // description only applies to the main frame. On a viewport description
687 // change; any changes will be calculated starting from the local main
688 // frame renderer and propagated to the OOPIF renderers.
689 TextAutosizer::UpdatePageInfoInAllFrames(MainFrame());
692 case ChangeType::kViewportPaintProperties:
693 if (GetVisualViewport().IsActiveViewport()) {
694 GetVisualViewport().SetNeedsPaintPropertyUpdate();
695 GetVisualViewport().InitializeScrollbars();
697 if (auto* local_frame = DynamicTo<LocalFrame>(MainFrame())) {
698 if (LocalFrameView* view = local_frame->View())
699 view->SetNeedsPaintPropertyUpdate();
702 case ChangeType::kDNSPrefetching:
703 for (Frame* frame = MainFrame(); frame;
704 frame = frame->Tree().TraverseNext()) {
705 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
706 local_frame->GetDocument()->InitDNSPrefetch();
709 case ChangeType::kImageLoading:
710 for (Frame* frame = MainFrame(); frame;
711 frame = frame->Tree().TraverseNext()) {
712 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
713 local_frame->GetDocument()->Fetcher()->SetImagesEnabled(
714 GetSettings().GetImagesEnabled());
715 local_frame->GetDocument()->Fetcher()->SetAutoLoadImages(
716 GetSettings().GetLoadsImagesAutomatically());
720 case ChangeType::kTextAutosizing:
723 // We need to update even for remote main frames since this setting
724 // could be changed via InternalSettings.
725 TextAutosizer::UpdatePageInfoInAllFrames(MainFrame());
727 case ChangeType::kFontFamily:
728 for (Frame* frame = MainFrame(); frame;
729 frame = frame->Tree().TraverseNext()) {
730 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
731 local_frame->GetDocument()
733 .UpdateGenericFontFamilySettings();
736 case ChangeType::kAcceleratedCompositing:
737 UpdateAcceleratedCompositingSettings();
739 case ChangeType::kMediaQuery:
740 for (Frame* frame = MainFrame(); frame;
741 frame = frame->Tree().TraverseNext()) {
742 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
743 local_frame->GetDocument()->MediaQueryAffectingValueChanged(
744 MediaValueChange::kOther);
748 case ChangeType::kAccessibilityState:
749 if (!MainFrame() || !MainFrame()->IsLocalFrame()) {
752 DeprecatedLocalMainFrame()->GetDocument()->RefreshAccessibilityTree();
754 case ChangeType::kViewportStyle: {
755 auto* main_local_frame = DynamicTo<LocalFrame>(MainFrame());
756 if (!main_local_frame)
758 if (Document* doc = main_local_frame->GetDocument())
759 doc->GetStyleEngine().ViewportStyleSettingChanged();
762 case ChangeType::kTextTrackKindUserPreference:
763 for (Frame* frame = MainFrame(); frame;
764 frame = frame->Tree().TraverseNext()) {
765 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
766 Document* doc = local_frame->GetDocument();
768 HTMLMediaElement::SetTextTrackKindUserPreferenceForAllMediaElements(
773 case ChangeType::kDOMWorlds: {
774 if (!GetSettings().GetForceMainWorldInitialization())
776 for (Frame* frame = MainFrame(); frame;
777 frame = frame->Tree().TraverseNext()) {
778 if (auto* window = DynamicTo<LocalDOMWindow>(frame->DomWindow())) {
779 // Forcibly instantiate WindowProxy.
780 window->GetScriptController().WindowProxy(
781 DOMWrapperWorld::MainWorld());
786 case ChangeType::kMediaControls:
787 for (Frame* frame = MainFrame(); frame;
788 frame = frame->Tree().TraverseNext()) {
789 auto* local_frame = DynamicTo<LocalFrame>(frame);
792 Document* doc = local_frame->GetDocument();
794 HTMLMediaElement::OnMediaControlsEnabledChange(doc);
797 case ChangeType::kPlugins: {
798 NotifyPluginsChanged();
801 case ChangeType::kHighlightAds: {
802 for (Frame* frame = MainFrame(); frame;
803 frame = frame->Tree().TraverseNext()) {
804 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
805 local_frame->UpdateAdHighlight();
809 case ChangeType::kPaint: {
813 case ChangeType::kScrollbarLayout: {
814 for (Frame* frame = MainFrame(); frame;
815 frame = frame->Tree().TraverseNext()) {
816 auto* local_frame = DynamicTo<LocalFrame>(frame);
819 // Iterate through all of the scrollable areas and mark their layout
820 // objects for layout.
821 if (LocalFrameView* view = local_frame->View()) {
822 if (const auto* scrollable_areas = view->UserScrollableAreas()) {
823 for (const auto& scrollable_area : *scrollable_areas) {
824 if (scrollable_area->ScrollsOverflow()) {
825 if (auto* layout_box = scrollable_area->GetLayoutBox()) {
826 layout_box->SetNeedsLayout(
827 layout_invalidation_reason::kScrollbarChanged);
836 case ChangeType::kColorScheme:
837 InvalidateColorScheme();
839 case ChangeType::kSpatialNavigation:
840 if (spatial_navigation_controller_ ||
841 GetSettings().GetSpatialNavigationEnabled()) {
842 GetSpatialNavigationController().OnSpatialNavigationSettingChanged();
845 case ChangeType::kUniversalAccess: {
846 if (!GetSettings().GetAllowUniversalAccessFromFileURLs())
848 for (Frame* frame = MainFrame(); frame;
849 frame = frame->Tree().TraverseNext()) {
850 // If we got granted universal access from file urls we need to grant
851 // any outstanding security origin cross agent cluster access since
852 // newly allocated agent clusters will be the universal agent.
853 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
854 auto* window = local_frame->DomWindow();
855 window->GetMutableSecurityOrigin()->GrantCrossAgentClusterAccess();
860 case ChangeType::kVisionDeficiency: {
861 if (auto* main_local_frame = DynamicTo<LocalFrame>(MainFrame()))
862 main_local_frame->GetDocument()->VisionDeficiencyChanged();
865 #if BUILDFLAG(IS_EFL)
866 case ChangeType::kTizenVersionChange: {
867 WebRuntimeFeatures::SetTizenCompatibilityModeEnabled(
868 GetSettings().TizenCompatibilityModeEnabled());
875 void Page::InvalidateColorScheme() {
876 for (Frame* frame = MainFrame(); frame;
877 frame = frame->Tree().TraverseNext()) {
878 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
879 local_frame->GetDocument()->ColorSchemeChanged();
883 void Page::InvalidatePaint() {
884 for (Frame* frame = MainFrame(); frame;
885 frame = frame->Tree().TraverseNext()) {
886 auto* local_frame = DynamicTo<LocalFrame>(frame);
889 if (LayoutView* view = local_frame->ContentLayoutObject())
890 view->InvalidatePaintForViewAndDescendants();
894 void Page::NotifyPluginsChanged() const {
895 HeapVector<Member<PluginsChangedObserver>, 32> observers(
896 plugins_changed_observers_);
897 for (PluginsChangedObserver* observer : observers)
898 observer->PluginsChanged();
901 void Page::UpdateAcceleratedCompositingSettings() {
902 for (Frame* frame = MainFrame(); frame;
903 frame = frame->Tree().TraverseNext()) {
904 auto* local_frame = DynamicTo<LocalFrame>(frame);
907 // Mark all scrollable areas as needing a paint property update because the
908 // compositing reasons may have changed.
909 if (const auto* areas = local_frame->View()->UserScrollableAreas()) {
910 for (const auto& scrollable_area : *areas) {
911 if (scrollable_area->ScrollsOverflow()) {
912 if (auto* layout_box = scrollable_area->GetLayoutBox())
913 layout_box->SetNeedsPaintPropertyUpdate();
920 void Page::DidCommitLoad(LocalFrame* frame) {
921 if (main_frame_ == frame) {
922 GetConsoleMessageStorage().Clear();
923 GetInspectorIssueStorage().Clear();
924 // TODO(loonybear): Most of this doesn't appear to take into account that
925 // each SVGImage gets it's own Page instance.
926 GetDeprecation().ClearSuppression();
927 // Need to reset visual viewport position here since before commit load we
928 // would update the previous history item, Page::didCommitLoad is called
929 // after a new history item is created in FrameLoader.
930 // See crbug.com/642279
931 GetVisualViewport().SetScrollOffset(ScrollOffset(),
932 mojom::blink::ScrollType::kProgrammatic,
933 mojom::blink::ScrollBehavior::kInstant,
934 ScrollableArea::ScrollCallback());
936 // crbug/1312107: If DevTools has "Highlight ad frames" checked when the
937 // main frame is refreshed or the ad frame is navigated to a different
938 // process, DevTools calls `Settings::SetHighlightAds` so early that the
939 // local frame is still in provisional state (not swapped in). Explicitly
940 // invalidate the settings here as `Page::DidCommitLoad` is only fired after
941 // the navigation is committed, at which point the local frame must already
944 // This explicit update is placed outside the above if-block to accommodate
945 // iframes. The iframes share the same Page (frame tree) as the main frame,
946 // but local frame swap can happen to any of the iframes.
948 // TODO(crbug/1357763): Properly apply the settings when the local frame
949 // becomes the main frame of the page (i.e. when the navigation is
951 frame->UpdateAdHighlight();
952 GetLinkHighlight().ResetForPageNavigation();
955 void Page::AcceptLanguagesChanged() {
956 HeapVector<Member<LocalFrame>> frames;
958 // Even though we don't fire an event from here, the LocalDOMWindow's will
959 // fire an event so we keep the frames alive until we are done.
960 for (Frame* frame = MainFrame(); frame;
961 frame = frame->Tree().TraverseNext()) {
962 if (auto* local_frame = DynamicTo<LocalFrame>(frame))
963 frames.push_back(local_frame);
966 for (unsigned i = 0; i < frames.size(); ++i)
967 frames[i]->DomWindow()->AcceptLanguagesChanged();
970 void Page::Trace(Visitor* visitor) const {
971 visitor->Trace(animator_);
972 visitor->Trace(autoscroll_controller_);
973 visitor->Trace(chrome_client_);
974 visitor->Trace(drag_caret_);
975 visitor->Trace(drag_controller_);
976 visitor->Trace(focus_controller_);
977 visitor->Trace(context_menu_controller_);
978 visitor->Trace(page_scale_constraints_set_);
979 visitor->Trace(page_visibility_observer_set_);
980 visitor->Trace(pointer_lock_controller_);
981 visitor->Trace(scrolling_coordinator_);
982 visitor->Trace(browser_controls_);
983 visitor->Trace(console_message_storage_);
984 visitor->Trace(global_root_scroller_controller_);
985 visitor->Trace(visual_viewport_);
986 visitor->Trace(link_highlight_);
987 visitor->Trace(spatial_navigation_controller_);
988 visitor->Trace(main_frame_);
989 visitor->Trace(previous_main_frame_for_local_swap_);
990 visitor->Trace(plugin_data_);
991 visitor->Trace(validation_message_client_);
992 visitor->Trace(plugins_changed_observers_);
993 visitor->Trace(next_related_page_);
994 visitor->Trace(prev_related_page_);
995 visitor->Trace(agent_group_scheduler_);
996 visitor->Trace(v8_compile_hints_producer_);
997 visitor->Trace(v8_compile_hints_consumer_);
998 Supplementable<Page>::Trace(visitor);
1001 void Page::DidInitializeCompositing(cc::AnimationHost& host) {
1002 GetLinkHighlight().AnimationHostInitialized(host);
1005 void Page::WillStopCompositing() {
1006 GetLinkHighlight().WillCloseAnimationHost();
1007 // We may have disconnected the associated LayerTreeHost during
1008 // the frame lifecycle so ensure the PageAnimator is reset to the
1010 animator_->SetSuppressFrameRequestsWorkaroundFor704763Only(false);
1013 void Page::WillBeDestroyed() {
1014 Frame* main_frame = main_frame_;
1016 // TODO(https://crbug.com/838348): Sadly, there are situations where Blink may
1017 // attempt to detach a main frame twice due to a bug. That rewinds
1018 // FrameLifecycle from kDetached to kDetaching, but GetPage() will already be
1019 // null. Since Detach() has already happened, just skip the actual Detach()
1020 // call to try to limit the side effects of this bug on the rest of frame
1022 if (main_frame->GetPage()) {
1023 main_frame->Detach(FrameDetachType::kRemove);
1026 DCHECK(AllPages().Contains(this));
1027 AllPages().erase(this);
1028 OrdinaryPages().erase(this);
1031 // Before: ... -> prev -> this -> next -> ...
1032 // After: ... -> prev -> next -> ...
1033 // (this is ok even if |this| is the only element on the list).
1034 Page* prev = prev_related_page_;
1035 Page* next = next_related_page_;
1036 next->prev_related_page_ = prev;
1037 prev->next_related_page_ = next;
1038 prev_related_page_ = nullptr;
1039 next_related_page_ = nullptr;
1042 if (scrolling_coordinator_)
1043 scrolling_coordinator_->WillBeDestroyed();
1045 GetChromeClient().ChromeDestroyed();
1046 if (validation_message_client_)
1047 validation_message_client_->WillBeDestroyed();
1048 main_frame_ = nullptr;
1050 for (auto observer : page_visibility_observer_set_) {
1051 observer->ObserverSetWillBeCleared();
1053 page_visibility_observer_set_.clear();
1055 page_scheduler_ = nullptr;
1058 void Page::RegisterPluginsChangedObserver(PluginsChangedObserver* observer) {
1059 plugins_changed_observers_.insert(observer);
1062 ScrollbarTheme& Page::GetScrollbarTheme() const {
1063 if (settings_->GetForceAndroidOverlayScrollbar())
1064 return ScrollbarThemeOverlayMobile::GetInstance();
1066 // Ensures that renderer preferences are set.
1067 DCHECK(main_frame_);
1068 return ScrollbarTheme::GetTheme();
1071 AgentGroupScheduler& Page::GetAgentGroupScheduler() const {
1072 return *agent_group_scheduler_;
1075 PageScheduler* Page::GetPageScheduler() const {
1076 DCHECK(page_scheduler_);
1077 return page_scheduler_.get();
1080 bool Page::IsOrdinary() const {
1081 return is_ordinary_;
1084 void Page::ReportIntervention(const String& text) {
1085 if (LocalFrame* local_frame = DeprecatedLocalMainFrame()) {
1086 auto* message = MakeGarbageCollected<ConsoleMessage>(
1087 mojom::ConsoleMessageSource::kOther,
1088 mojom::ConsoleMessageLevel::kWarning, text,
1089 std::make_unique<SourceLocation>(String(), String(), 0, 0, nullptr));
1090 local_frame->GetDocument()->AddConsoleMessage(message);
1094 bool Page::RequestBeginMainFrameNotExpected(bool new_state) {
1095 if (!main_frame_ || !main_frame_->IsLocalFrame())
1098 chrome_client_->RequestBeginMainFrameNotExpected(*DeprecatedLocalMainFrame(),
1103 void Page::AddAutoplayFlags(int32_t value) {
1104 autoplay_flags_ |= value;
1107 void Page::ClearAutoplayFlags() {
1108 autoplay_flags_ = 0;
1111 int32_t Page::AutoplayFlags() const {
1112 return autoplay_flags_;
1115 void Page::SetInsidePortal(bool inside_portal) {
1116 if (inside_portal_ == inside_portal)
1119 inside_portal_ = inside_portal;
1121 if (MainFrame() && MainFrame()->IsLocalFrame())
1122 DeprecatedLocalMainFrame()->PortalStateChanged();
1125 bool Page::InsidePortal() const {
1126 return inside_portal_;
1129 void Page::SetIsMainFrameFencedFrameRoot() {
1130 is_fenced_frame_tree_ = true;
1133 bool Page::IsMainFrameFencedFrameRoot() const {
1134 return is_fenced_frame_tree_;
1137 void Page::SetMediaFeatureOverride(const AtomicString& media_feature,
1138 const String& value) {
1139 if (!media_feature_overrides_) {
1142 media_feature_overrides_ = std::make_unique<MediaFeatureOverrides>();
1144 media_feature_overrides_->SetOverride(media_feature, value);
1145 if (media_feature == "prefers-color-scheme" ||
1146 media_feature == "forced-colors")
1147 SettingsChanged(ChangeType::kColorScheme);
1149 SettingsChanged(ChangeType::kMediaQuery);
1152 void Page::ClearMediaFeatureOverrides() {
1153 media_feature_overrides_.reset();
1154 SettingsChanged(ChangeType::kMediaQuery);
1155 SettingsChanged(ChangeType::kColorScheme);
1158 void Page::SetPreferenceOverride(const AtomicString& media_feature,
1159 const String& value) {
1160 if (!preference_overrides_) {
1161 if (value.empty()) {
1164 preference_overrides_ = std::make_unique<PreferenceOverrides>();
1166 preference_overrides_->SetOverride(media_feature, value);
1167 if (media_feature == "prefers-color-scheme") {
1168 SettingsChanged(ChangeType::kColorScheme);
1170 SettingsChanged(ChangeType::kMediaQuery);
1174 void Page::ClearPreferenceOverrides() {
1175 preference_overrides_.reset();
1176 SettingsChanged(ChangeType::kMediaQuery);
1177 SettingsChanged(ChangeType::kColorScheme);
1180 void Page::SetVisionDeficiency(VisionDeficiency new_vision_deficiency) {
1181 if (new_vision_deficiency != vision_deficiency_) {
1182 vision_deficiency_ = new_vision_deficiency;
1183 SettingsChanged(ChangeType::kVisionDeficiency);
1187 #if BUILDFLAG(IS_TIZEN)
1188 void Page::SetIsSuspended(bool isSuspended) {
1189 m_isSuspended = isSuspended;
1193 void Page::Animate(base::TimeTicks monotonic_frame_begin_time) {
1194 GetAutoscrollController().Animate();
1195 Animator().ServiceScriptedAnimations(monotonic_frame_begin_time);
1196 // The ValidationMessage overlay manages its own internal Page that isn't
1197 // hooked up the normal BeginMainFrame flow, so we manually tick its
1199 GetValidationMessageClient().ServiceScriptedAnimations(
1200 monotonic_frame_begin_time);
1203 void Page::UpdateLifecycle(LocalFrame& root,
1204 WebLifecycleUpdate requested_update,
1205 DocumentUpdateReason reason) {
1206 if (requested_update == WebLifecycleUpdate::kLayout) {
1207 Animator().UpdateLifecycleToLayoutClean(root, reason);
1208 } else if (requested_update == WebLifecycleUpdate::kPrePaint) {
1209 Animator().UpdateLifecycleToPrePaintClean(root, reason);
1211 Animator().UpdateAllLifecyclePhases(root, reason);
1215 #if BUILDFLAG(IS_EFL)
1216 void Page::SetLongPollingGlobalTimeout(uint64_t timeout) {
1217 long_polling_global_timeout_ = timeout;
1221 const base::UnguessableToken& Page::BrowsingContextGroupToken() {
1222 return browsing_context_group_info_.browsing_context_group_token;
1225 const base::UnguessableToken& Page::CoopRelatedGroupToken() {
1226 return browsing_context_group_info_.coop_related_group_token;
1229 void Page::UpdateBrowsingContextGroup(
1230 const blink::BrowsingContextGroupInfo& browsing_context_group_info) {
1231 if (browsing_context_group_info_ == browsing_context_group_info) {
1235 if (base::FeatureList::IsEnabled(
1236 features::kPausePagesPerBrowsingContextGroup) &&
1237 ScopedBrowsingContextGroupPauser::IsActive(*this)) {
1242 browsing_context_group_info_ = browsing_context_group_info;
1244 if (base::FeatureList::IsEnabled(
1245 features::kPausePagesPerBrowsingContextGroup) &&
1246 ScopedBrowsingContextGroupPauser::IsActive(*this)) {
1251 void Page::SetAttributionSupport(
1252 network::mojom::AttributionSupport attribution_support) {
1253 attribution_support_ = attribution_support;
1256 template class CORE_TEMPLATE_EXPORT Supplement<Page>;
1258 const char InternalSettingsPageSupplementBase::kSupplementName[] =
1262 void Page::PrepareForLeakDetection() {
1263 // Internal settings are ScriptWrappable and thus may retain documents
1264 // depending on whether the garbage collector(s) are able to find the settings
1265 // object through the Page supplement. Prepares for leak detection by removing
1266 // all InternalSetting objects from Pages.
1267 for (Page* page : OrdinaryPages()) {
1268 page->RemoveSupplement<InternalSettingsPageSupplementBase>();
1270 // V8CrowdsourcedCompileHintsProducer keeps v8::Script objects alive until
1271 // the page becomes interactive. Give it a chance to clean up.
1272 page->v8_compile_hints_producer_->ClearData();
1276 // Ensure the 10 bits reserved for connected frame count in NodeRareData are
1278 static_assert(kMaxNumberOfFrames <
1279 (1 << NodeRareData::kConnectedFrameCountBits),
1280 "Frame limit should fit in rare data count");
1281 static_assert(kTenFrames < kMaxNumberOfFrames,
1282 "Reduced frame limit for testing should actually be lower");
1284 } // namespace blink