1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
content / browser / renderer_host / delegated_frame_host.h [blame]
// 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_DELEGATED_FRAME_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_
#include <stdint.h>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "components/viz/client/frame_evictor.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_timing_details_map.h"
#include "components/viz/common/hit_test/hit_test_query.h"
#include "components/viz/host/host_frame_sink_client.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/common/content_export.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
#include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom.h"
#include "third_party/blink/public/common/page/content_to_visible_time_reporter.h"
#include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom-forward.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace content {
class DelegatedFrameHost;
// The DelegatedFrameHostClient is the interface from the DelegatedFrameHost,
// which manages delegated frames, and the ui::Compositor being used to
// display them.
class CONTENT_EXPORT DelegatedFrameHostClient {
public:
virtual ~DelegatedFrameHostClient() {}
virtual ui::Layer* DelegatedFrameHostGetLayer() const = 0;
virtual bool DelegatedFrameHostIsVisible() const = 0;
// Returns the color that the resize gutters should be drawn with.
virtual SkColor DelegatedFrameHostGetGutterColor() const = 0;
virtual void OnFrameTokenChanged(uint32_t frame_token,
base::TimeTicks activation_time) = 0;
virtual float GetDeviceScaleFactor() const = 0;
virtual void InvalidateLocalSurfaceIdOnEviction() = 0;
virtual viz::FrameEvictorClient::EvictIds CollectSurfaceIdsForEviction() = 0;
virtual bool ShouldShowStaleContentOnEviction() = 0;
};
// The DelegatedFrameHost is used to host all of the RenderWidgetHostView state
// and functionality that is associated with delegated frames being sent from
// the RenderWidget. The DelegatedFrameHost will push these changes through to
// the ui::Compositor associated with its DelegatedFrameHostClient.
class CONTENT_EXPORT DelegatedFrameHost
: public ui::CompositorObserver,
public viz::FrameEvictorClient,
public viz::HostFrameSinkClient {
public:
enum class FrameEvictionState {
kNotStarted = 0, // Frame eviction is ready.
kPendingEvictionRequests // Frame eviction is paused with pending requests.
};
class Observer {
public:
virtual void OnFrameEvictionStateChanged(FrameEvictionState new_state) = 0;
protected:
virtual ~Observer() = default;
};
// |should_register_frame_sink_id| flag indicates whether DelegatedFrameHost
// is responsible for registering the associated FrameSinkId with the
// compositor or not. This is set only on non-aura platforms, since aura is
// responsible for doing the appropriate [un]registration.
DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
DelegatedFrameHostClient* client,
bool should_register_frame_sink_id);
DelegatedFrameHost(const DelegatedFrameHost&) = delete;
DelegatedFrameHost& operator=(const DelegatedFrameHost&) = delete;
~DelegatedFrameHost() override;
void AddObserverForTesting(Observer* observer);
void RemoveObserverForTesting(Observer* observer);
// ui::CompositorObserver implementation.
void OnCompositingShuttingDown(ui::Compositor* compositor) override;
void ClearFallbackSurfaceForCommitPending();
void ResetFallbackToFirstNavigationSurface();
// viz::HostFrameSinkClient implementation.
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
void OnFrameTokenChanged(uint32_t frame_token,
base::TimeTicks activation_time) override;
// Public interface exposed to RenderWidgetHostView.
// kOccluded means the native window for the host was
// occluded/hidden, kOther is for other causes, e.g., a tab became a
// background tab.
enum class HiddenCause { kOccluded, kOther };
void WasHidden(HiddenCause cause);
// TODO(ccameron): Include device scale factor here.
void WasShown(const viz::LocalSurfaceId& local_surface_id,
const gfx::Size& dip_size,
blink::mojom::RecordContentToVisibleTimeRequestPtr
record_tab_switch_time_request);
// Called to request the presentation time for the next frame or cancel any
// requests when the RenderWidget's visibility state is not changing. If the
// visibility state is changing call WasHidden or WasShown instead.
void RequestSuccessfulPresentationTimeForNextFrame(
blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request);
void CancelSuccessfulPresentationTimeRequest();
void EmbedSurface(const viz::LocalSurfaceId& local_surface_id,
const gfx::Size& dip_size,
cc::DeadlinePolicy deadline_policy);
bool HasSavedFrame() const;
void AttachToCompositor(ui::Compositor* compositor);
void DetachFromCompositor();
// Copies |src_subrect| from the compositing surface into a bitmap (first
// overload) or texture (second overload). |output_size| specifies the size of
// the output bitmap or texture.
// Note: |src_subrect| is specified in DIP dimensions while |output_size|
// expects pixels. If |src_subrect| is empty, the entire surface area is
// copied.
void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback);
void CopyFromCompositingSurfaceAsTexture(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
viz::CopyOutputRequest::CopyOutputRequestCallback callback);
bool CanCopyFromCompositingSurface() const;
const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
// FrameEvictorClient:
// Returns the surface id for the most recently embedded surface.
viz::SurfaceId GetCurrentSurfaceId() const override;
bool HasPrimarySurface() const;
bool HasFallbackSurface() const;
viz::SurfaceId GetFallbackSurfaceIdForTesting() const;
void OnCompositingDidCommitForTesting(ui::Compositor* compositor) {
OnCompositingDidCommit(compositor);
}
gfx::Size CurrentFrameSizeInDipForTesting() const {
return current_frame_size_in_dip_;
}
void DidNavigate();
// Navigation to a different page than the current one has begun. Caches the
// current LocalSurfaceId information so that old content can be evicted if
// navigation fails to complete.
void DidNavigateMainFramePreCommit();
// Called when the page has just entered BFCache.
void DidEnterBackForwardCache();
void WindowTitleChanged(const std::string& title);
// If our SurfaceLayer doesn't have a fallback, use the fallback info of
// |other|.
void TakeFallbackContentFrom(DelegatedFrameHost* other);
base::WeakPtr<DelegatedFrameHost> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
const ui::Layer* stale_content_layer() const {
return stale_content_layer_.get();
}
FrameEvictionState frame_eviction_state() const {
return frame_eviction_state_;
}
const viz::FrameEvictor* GetFrameEvictorForTesting() const {
return frame_evictor_.get();
}
viz::SurfaceId GetPreNavigationSurfaceIdForTesting() const {
return GetPreNavigationSurfaceId();
}
viz::SurfaceId GetFirstSurfaceIdAfterNavigationForTesting() const;
void SetIsFrameSinkIdOwner(bool is_owner);
// This is used to evict also the UI compositor if native occlusion is
// enabled. This only makes sense on desktop platforms where the UI compositor
// corresponds to a browser window, and native occlusion is supported.
static bool ShouldIncludeUiCompositorForEviction();
private:
friend class DelegatedFrameHostClient;
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionNormal);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionRejected);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionNone);
FRIEND_TEST_ALL_PREFIXES(NoCompositingRenderWidgetHostViewBrowserTest,
BFCachedSurfaceShouldNotBeEvicted);
// FrameEvictorClient implementation.
void EvictDelegatedFrame(
const std::vector<viz::SurfaceId>& surface_ids) override;
viz::FrameEvictorClient::EvictIds CollectSurfaceIdsForEviction()
const override;
viz::SurfaceId GetPreNavigationSurfaceId() const override;
void DidCopyStaleContent(std::unique_ptr<viz::CopyOutputResult> result);
void ContinueDelegatedFrameEviction(
const std::vector<viz::SurfaceId>& surface_ids);
SkColor GetGutterColor() const;
void CopyFromCompositingSurfaceInternal(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
viz::CopyOutputRequest::ResultFormat format,
viz::CopyOutputRequest::ResultDestination destination,
viz::CopyOutputRequest::CopyOutputRequestCallback callback);
void SetFrameEvictionStateAndNotifyObservers(
FrameEvictionState frame_eviction_state);
const viz::FrameSinkId frame_sink_id_;
const raw_ptr<DelegatedFrameHostClient> client_;
const bool should_register_frame_sink_id_;
raw_ptr<ui::Compositor> compositor_ = nullptr;
// The LocalSurfaceId of the currently embedded surface.
//
// TODO(crbug.com/40274223): this value is a copy of what the browser
// wants to embed. The source of truth is stored else where. We should
// consider de-dup this ID.
viz::LocalSurfaceId local_surface_id_;
// The size of the above surface (updated at the same time).
gfx::Size surface_dip_size_;
// In non-surface sync, this is the size of the most recently activated
// surface (which is suitable for calculating gutter size). In surface sync,
// this is most recent size set in EmbedSurface.
// TODO(ccameron): The meaning of "current" should be made more clear here.
gfx::Size current_frame_size_in_dip_;
const raw_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_;
std::unique_ptr<viz::FrameEvictor> frame_evictor_;
viz::LocalSurfaceId first_local_surface_id_after_navigation_;
// While navigating we have no active |local_surface_id_|. Track the one from
// before a navigation, because if the navigation fails to complete, we will
// need to evict its surface. If the old page enters BFCache, this id is used
// to restore `local_surface_id_`.
viz::LocalSurfaceId pre_navigation_local_surface_id_;
// The fallback ID for BFCache restore. It is set when `this` enters the
// BFCache and is cleared when resize-while-hidden (which supplies with a
// latest fallback ID) or after it is used in `EmbedSurface`.
viz::LocalSurfaceId bfcache_fallback_;
FrameEvictionState frame_eviction_state_ = FrameEvictionState::kNotStarted;
// Layer responsible for displaying the stale content for the DFHC when the
// actual web content frame has been evicted. This will be reset when a new
// compositor frame is submitted.
std::unique_ptr<ui::Layer> stale_content_layer_;
blink::ContentToVisibleTimeReporter tab_switch_time_recorder_;
// Speculative RenderWidgetHostViews can start with a FrameSinkId owned by the
// currently committed RenderWidgetHostView. Ownership is transferred when the
// navigation is committed. This bit tracks whether this DelegatedFrameHost
// owns its FrameSinkId.
bool owns_frame_sink_id_ = false;
base::ObserverList<Observer>::Unchecked observers_;
base::WeakPtrFactory<DelegatedFrameHost> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_