| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CONTENT_BROWSER_RENDERER_HOST_CROSS_PROCESS_FRAME_CONNECTOR_H_ |
| #define CONTENT_BROWSER_RENDERER_HOST_CROSS_PROCESS_FRAME_CONNECTOR_H_ |
| |
| #include <stdint.h> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "cc/input/touch_action.h" |
| #include "components/input/child_frame_input_helper.h" |
| #include "components/viz/common/quads/compositor_frame.h" |
| #include "components/viz/common/surfaces/local_surface_id.h" |
| #include "components/viz/common/surfaces/surface_id.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/visibility.h" |
| #include "third_party/blink/public/common/frame/frame_visual_properties.h" |
| #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-forward.h" |
| #include "third_party/blink/public/mojom/frame/lifecycle.mojom.h" |
| #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom.h" |
| #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" |
| #include "third_party/blink/public/mojom/input/pointer_lock_result.mojom-shared.h" |
| #include "ui/display/screen_infos.h" |
| #include "ui/gfx/geometry/rect.h" |
| |
| namespace blink { |
| struct FrameVisualProperties; |
| } // namespace blink |
| |
| namespace cc { |
| class RenderFrameMetadata; |
| } |
| |
| namespace input { |
| class RenderWidgetHostViewInput; |
| } // namespace input |
| |
| namespace ui { |
| class Cursor; |
| } |
| |
| namespace viz { |
| class SurfaceInfo; |
| } // namespace viz |
| |
| namespace content { |
| class RenderFrameHostImpl; |
| class RenderFrameProxyHost; |
| class RenderWidgetHostViewBase; |
| class RenderWidgetHostViewChildFrame; |
| |
| // CrossProcessFrameConnector provides the platform view abstraction for |
| // RenderWidgetHostViewChildFrame allowing RWHVChildFrame to remain ignorant |
| // of RenderFrameHost. |
| // |
| // The RenderWidgetHostView of an out-of-process child frame needs to |
| // communicate with the RenderFrameProxyHost representing this frame in the |
| // process of the parent frame. For example, assume you have this page: |
| // |
| // ----------------- |
| // | frame 1 | |
| // | ----------- | |
| // | | frame 2 | | |
| // | ----------- | |
| // ----------------- |
| // |
| // If frames 1 and 2 are in process A and B, there are 4 hosts: |
| // A1 - RFH for frame 1 in process A |
| // B1 - RFPH for frame 1 in process B |
| // A2 - RFPH for frame 2 in process A |
| // B2 - RFH for frame 2 in process B |
| // |
| // B2, having a parent frame in a different process, will have a |
| // RenderWidgetHostViewChildFrame. This RenderWidgetHostViewChildFrame needs |
| // to communicate with A2 because the embedding frame represents the platform |
| // that the child frame is rendering into -- it needs information necessary for |
| // compositing child frame textures, and also can pass platform messages such as |
| // view resizing. CrossProcessFrameConnector bridges between B2's |
| // RenderWidgetHostViewChildFrame and A2 to allow for this communication. |
| // (Note: B1 is only mentioned for completeness. It is not needed in this |
| // example.) |
| // |
| // CrossProcessFrameConnector objects are owned by the RenderFrameProxyHost |
| // in the child frame's RenderFrameHostManager corresponding to the parent's |
| // SiteInstance, A2 in the picture above. When a child frame navigates in a new |
| // process, SetView() is called to update to the new view. |
| // |
| class CONTENT_EXPORT CrossProcessFrameConnector |
| : public input::ChildFrameInputHelper::Delegate { |
| public: |
| // |frame_proxy_in_parent_renderer| corresponds to A2 in the example above. |
| explicit CrossProcessFrameConnector( |
| RenderFrameProxyHost* frame_proxy_in_parent_renderer); |
| |
| CrossProcessFrameConnector(const CrossProcessFrameConnector&) = delete; |
| CrossProcessFrameConnector& operator=(const CrossProcessFrameConnector&) = |
| delete; |
| |
| ~CrossProcessFrameConnector() override; |
| |
| // |view| corresponds to B2's RenderWidgetHostViewChildFrame in the example |
| // above. |
| RenderWidgetHostViewChildFrame* get_view_for_testing() { return view_; } |
| |
| void SetView(RenderWidgetHostViewChildFrame* view, bool allow_paint_holding); |
| |
| // Returns the parent RenderWidgetHostView or nullptr if it doesn't have one. |
| virtual RenderWidgetHostViewBase* GetParentRenderWidgetHostView(); |
| |
| // Returns the view for the top-level frame under the same WebContents. |
| virtual RenderWidgetHostViewBase* GetRootRenderWidgetHostView(); |
| |
| // Notify the frame connector that the renderer process has terminated. |
| void RenderProcessGone(); |
| |
| // Provide the SurfaceInfo to the embedder, which becomes a reference to the |
| // current view's Surface that is included in higher-level compositor |
| // frames. This is virtual to be overridden in tests. |
| virtual void FirstSurfaceActivation(const viz::SurfaceInfo& surface_info) {} |
| |
| // Sends the given intrinsic sizing information from a sub-frame to |
| // its corresponding remote frame in the parent frame's renderer. |
| void SendIntrinsicSizingInfoToParent(blink::mojom::IntrinsicSizingInfoPtr); |
| |
| // Record and apply new visual properties for the subframe. If 'propagate' is |
| // true, the new properties will be sent to the subframe's renderer process. |
| void SynchronizeVisualProperties( |
| const blink::FrameVisualProperties& visual_properties, |
| bool propagate = true); |
| |
| // ChildFrameInputHelper::Delegate implementation. |
| input::RenderWidgetHostViewInput* GetParentViewInput() override; |
| input::RenderWidgetHostViewInput* GetRootViewInput() override; |
| |
| double css_zoom_factor() const { return last_received_css_zoom_factor_; } |
| |
| // Return the size of the CompositorFrame to use in the child renderer. |
| const gfx::Size& local_frame_size_in_pixels() const { |
| return local_frame_size_in_pixels_; |
| } |
| |
| // Return the size of the CompositorFrame to use in the child renderer in DIP. |
| // This is used to set the layout size of the child renderer. |
| const gfx::Size& local_frame_size_in_dip() const { |
| return local_frame_size_in_dip_; |
| } |
| |
| // Return the rect in DIP that the RenderWidgetHostViewChildFrame's content |
| // will render into. |
| const gfx::Rect& rect_in_parent_view_in_dip() const { |
| return rect_in_parent_view_in_dip_; |
| } |
| |
| // Return the latest capture sequence number for this subframe. |
| uint32_t capture_sequence_number() const { return capture_sequence_number_; } |
| |
| // Request that the platform change the mouse cursor when the mouse is |
| // positioned over this view's content. |
| void UpdateCursor(const ui::Cursor& cursor); |
| |
| // These values are written to logs. Do not renumber or delete existing items; |
| // add new entries to the end of the list. |
| enum class RootViewFocusState { |
| // RootView is NULL. |
| kNullView = 0, |
| // Root View is already focused. |
| kFocused = 1, |
| // Root View is not focused at TouchStart. Calls |
| // RenderWidgetHostViewChildFrame::Focus() to focus it. |
| kNotFocused = 2, |
| kMaxValue = kNotFocused |
| }; |
| |
| // Determines whether the root RenderWidgetHostView (and thus the current |
| // page) has focus. We need a tri-state enum as a return variable to |
| // differentiate between the cases where root view is NULL and when it's |
| // actually focused/unfocused. No behaviour change expected in focus handling. |
| RootViewFocusState HasFocus(); |
| |
| // Cause the root RenderWidgetHostView to become focused. |
| void FocusRootView(); |
| |
| // Locks the mouse pointer, if |request_unadjusted_movement_| is true, try |
| // setting the unadjusted movement mode. Returns true if mouse pointer is |
| // locked. |
| blink::mojom::PointerLockResult LockPointer(bool request_unadjusted_movement); |
| |
| // Change the current pointer lock to match the unadjusted movement option |
| // given. |
| blink::mojom::PointerLockResult ChangePointerLock( |
| bool request_unadjusted_movement); |
| |
| // Unlocks the mouse pointer if it is locked. |
| void UnlockPointer(); |
| |
| // Returns the state of the frame's intersection with the top-level viewport. |
| const blink::mojom::ViewportIntersectionState& intersection_state() const { |
| return intersection_state_; |
| } |
| |
| // Returns the viz::LocalSurfaceId propagated from the parent to be |
| // used by this child frame. |
| const viz::LocalSurfaceId& local_surface_id() const { |
| return local_surface_id_; |
| } |
| |
| // Returns the ScreenInfos propagated from the parent to be used by this |
| // child frame. |
| const display::ScreenInfos& screen_infos() const { return screen_infos_; } |
| |
| // Informs the parent the child will enter auto-resize mode, automatically |
| // resizing itself to the provided |min_size| and |max_size| constraints. |
| void EnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size); |
| |
| // Turns off auto-resize mode. |
| void DisableAutoResize(); |
| |
| // Determines whether the current view's content is inert, either because |
| // an HTMLDialogElement is being modally displayed in a higher-level frame, |
| // or because the inert attribute has been specified. |
| bool IsInert() const; |
| |
| // Returns the inherited effective touch action property that should be |
| // applied to any nested child RWHVCFs inside the caller RWHVCF. |
| cc::TouchAction InheritedEffectiveTouchAction() const; |
| |
| // Determines whether the RenderWidgetHostViewChildFrame is hidden due to |
| // a higher-level embedder being hidden. This is distinct from the |
| // RenderWidgetHostImpl being hidden, which is a property set when |
| // RenderWidgetHostView::Hide() is called on the current view. |
| bool IsHidden() const; |
| |
| // IsThrottled() indicates that the frame is outside of it's parent frame's |
| // visible viewport, and should be render throttled. |
| bool IsThrottled() const; |
| // IsSubtreeThrottled() indicates that IsThrottled() is true for one of this |
| // frame's ancestors, which means this frame must also be throttled. |
| bool IsSubtreeThrottled() const; |
| // IsDisplayLocked() indicates that a DOM ancestor of this frame's owning |
| // <iframe> element in the parent frame is currently display locked; or that |
| // IsDisplayLocked() is true for one of this frame's ancestors; which means |
| // this frame should be render throttled. |
| bool IsDisplayLocked() const; |
| |
| // Called by RenderWidgetHostViewChildFrame when the child frame has updated |
| // its visual properties and its viz::LocalSurfaceId has changed. |
| void DidUpdateVisualProperties(const cc::RenderFrameMetadata& metadata); |
| |
| bool has_size() const { return has_size_; } |
| |
| // Called by RenderWidgetHostViewChildFrame to update the visibility of any |
| // nested child RWHVCFs inside it. |
| void SetVisibilityForChildViews(bool visible) const; |
| |
| // Called to resize the child renderer's CompositorFrame. |
| // |local_frame_size| is in pixels if zoom-for-dsf is enabled, and in DIP |
| // if not. |
| void SetLocalFrameSize(const gfx::Size& local_frame_size); |
| |
| // Called to resize the child renderer. |rect_in_parent_view| is in physical |
| // pixels. |
| void SetRectInParentView(const gfx::Rect& rect_in_parent_view); |
| |
| void SetIsInert(bool inert); |
| |
| // Handlers for messages received from the parent frame called |
| // from RenderFrameProxyHost to be sent to |view_|. |
| void OnSetInheritedEffectiveTouchAction(cc::TouchAction); |
| void OnVisibilityChanged(blink::mojom::FrameVisibility visibility); |
| |
| // Exposed for tests. |
| RenderWidgetHostViewBase* GetRootRenderWidgetHostViewForTesting() { |
| return GetRootRenderWidgetHostView(); |
| } |
| |
| void UpdateRenderThrottlingStatus(bool is_throttled, |
| bool subtree_throttled, |
| bool display_locked); |
| void UpdateViewportIntersection( |
| const blink::mojom::ViewportIntersectionState& intersection_state, |
| const std::optional<blink::FrameVisualProperties>& visual_properties); |
| |
| // These enums back crashed frame histograms - see MaybeLogCrash() and |
| // MaybeLogShownCrash() below. Please do not modify or remove existing enum |
| // values. When adding new values, please also update enums.xml. See |
| // enums.xml for descriptions of enum values. |
| enum class CrashVisibility { |
| kCrashedWhileVisible = 0, |
| kShownAfterCrashing = 1, |
| kNeverVisibleAfterCrash = 2, |
| kShownWhileAncestorIsLoading = 3, |
| kMaxValue = kShownWhileAncestorIsLoading |
| }; |
| |
| enum class ShownAfterCrashingReason { |
| kTabWasShown = 0, |
| kViewportIntersection = 1, |
| kVisibility = 2, |
| kViewportIntersectionAfterTabWasShown = 3, |
| kVisibilityAfterTabWasShown = 4, |
| kMaxValue = kVisibilityAfterTabWasShown |
| }; |
| |
| // Returns whether the child widget is actually visible to the user. This is |
| // different from the IsHidden override, and takes into account viewport |
| // intersection as well as the visibility of the RenderFrameHostDelegate. |
| bool IsVisible(); |
| |
| // This function is called by the RenderFrameHostDelegate to signal that it |
| // became visible. This is called after any navigations resulting from |
| // visibility changes have been queued (e.g. if needs-reload was set). |
| void DelegateWasShown(); |
| |
| // Handlers for messages received from the parent frame. |
| void OnSynchronizeVisualProperties( |
| const blink::FrameVisualProperties& visual_properties); |
| |
| blink::mojom::FrameVisibility visibility() const { return visibility_; } |
| |
| void set_child_frame_crash_shown_closure_for_testing( |
| base::OnceClosure closure) { |
| child_frame_crash_shown_closure_for_testing_ = std::move(closure); |
| } |
| |
| // Returns the embedder's visibility. |
| Visibility EmbedderVisibility(); |
| |
| protected: |
| friend class MockCrossProcessFrameConnector; |
| friend class SitePerProcessBrowserTestBase; |
| |
| FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewChildFrameZoomForDSFTest, |
| CompositorViewportPixelSize); |
| |
| // Resets the rect and the viz::LocalSurfaceId of the connector to ensure the |
| // unguessable surface ID is not reused after a cross-process navigation. |
| void ResetRectInParentView(); |
| |
| // Logs the Stability.ChildFrameCrash.Visibility metric after checking that a |
| // crash has indeed happened and checking that the crash has not already been |
| // logged in UMA. Returns true if this metric was actually logged. |
| bool MaybeLogCrash(CrashVisibility visibility); |
| |
| // Check if a crashed child frame has become visible, and if so, log the |
| // Stability.ChildFrameCrash.Visibility.ShownAfterCrashing* metrics. |
| void MaybeLogShownCrash(ShownAfterCrashingReason reason); |
| |
| void UpdateViewportIntersectionInternal( |
| const blink::mojom::ViewportIntersectionState& intersection_state, |
| bool include_visual_properties); |
| |
| // The RenderWidgetHostView for the frame. Initially nullptr. |
| raw_ptr<RenderWidgetHostViewChildFrame> view_ = nullptr; |
| |
| // This is here rather than in the implementation class so that |
| // intersection_state() can return a reference. |
| blink::mojom::ViewportIntersectionState intersection_state_; |
| |
| display::ScreenInfos screen_infos_; |
| gfx::Size local_frame_size_in_dip_; |
| gfx::Size local_frame_size_in_pixels_; |
| gfx::Rect rect_in_parent_view_in_dip_; |
| |
| viz::LocalSurfaceId local_surface_id_; |
| |
| bool has_size_ = false; |
| |
| uint32_t capture_sequence_number_ = 0u; |
| |
| // Gets the current RenderFrameHost for the |
| // |frame_proxy_in_parent_renderer_|'s (i.e., the child frame's) |
| // FrameTreeNode. This corresponds to B2 in the class-level comment |
| // above for CrossProcessFrameConnector. |
| RenderFrameHostImpl* current_child_frame_host() const; |
| |
| // The RenderFrameProxyHost that routes messages to the parent frame's |
| // renderer process. |
| // Can be nullptr in tests. |
| raw_ptr<RenderFrameProxyHost> frame_proxy_in_parent_renderer_; |
| |
| bool is_inert_ = false; |
| cc::TouchAction inherited_effective_touch_action_ = cc::TouchAction::kAuto; |
| |
| bool is_throttled_ = false; |
| bool subtree_throttled_ = false; |
| bool display_locked_ = false; |
| |
| // Visibility state of the corresponding frame owner element in parent process |
| // which is set through CSS or scrolling. |
| blink::mojom::FrameVisibility visibility_ = |
| blink::mojom::FrameVisibility::kRenderedInViewport; |
| |
| // Used to make sure we only log UMA once per renderer crash. |
| bool is_crash_already_logged_ = false; |
| |
| // Used to make sure that MaybeLogCrash only logs the UMA in case of an actual |
| // crash (in case it is called from the destructor of |
| // CrossProcessFrameConnector or when WebContentsImpl::WasShown is called). |
| bool has_crashed_ = false; |
| |
| // Remembers whether or not the RenderFrameHostDelegate (i.e., tab) was |
| // shown after a crash. This is only used when recording renderer crashes. |
| bool delegate_was_shown_after_crash_ = false; |
| |
| // The last pre-transform frame size received from the parent renderer. |
| // |last_received_local_frame_size_| may be in DIP if use zoom for DSF is |
| // off. |
| gfx::Size last_received_local_frame_size_; |
| |
| // The last zoom level received from parent renderer, which is used to check |
| // if a new surface is created in case of zoom level change. |
| double last_received_zoom_level_ = 0.0; |
| |
| // Represents CSS zoom applied to the embedding element in the parent. |
| double last_received_css_zoom_factor_ = 1.0; |
| |
| // Closure that will be run whenever a sad frame is shown and its visibility |
| // metrics have been logged. Used for testing only. |
| base::OnceClosure child_frame_crash_shown_closure_for_testing_; |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_RENDERER_HOST_CROSS_PROCESS_FRAME_CONNECTOR_H_ |