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
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_TAB_H_
#define CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_TAB_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "ui/gfx/geometry/size.h"
class Profile;
namespace extensions {
class OffscreenTab; // Forward declaration. See below.
// Creates, owns, and manages all OffscreenTab instances created by the same
// extension background page. When the extension background page's WebContents
// is about to be destroyed, its associated OffscreenTabsOwner and all of its
// OffscreenTab instances are destroyed.
//
// Usage:
//
// OffscreenTabsOwner::Get(extension_contents)
// ->OpenNewTab(start_url, size, std::string());
//
// This class operates exclusively on the UI thread and so is not thread-safe.
class OffscreenTabsOwner
: protected content::WebContentsUserData<OffscreenTabsOwner> {
public:
~OffscreenTabsOwner() final;
// Returns the OffscreenTabsOwner instance associated with the given extension
// background page's WebContents. Never returns nullptr.
static OffscreenTabsOwner* Get(content::WebContents* extension_web_contents);
// Instantiate a new offscreen tab and navigate it to |start_url|. The new
// tab's main frame will start out with the given |initial_size| in DIP
// coordinates. If too many offscreen tabs are already running, nothing
// happens and nullptr is returned.
//
// If |optional_presentation_id| is non-empty, the offscreen tab is registered
// for use by the Media Router (chrome/browser/media/router/...) as the
// receiving browsing context for the W3C Presentation API.
OffscreenTab* OpenNewTab(
const GURL& start_url,
const gfx::Size& initial_size,
const std::string& optional_presentation_id);
protected:
friend class OffscreenTab;
// Accessor to the extension background page's WebContents.
content::WebContents* extension_web_contents() const {
return extension_web_contents_;
}
// Shuts down and destroys the |tab|.
void DestroyTab(OffscreenTab* tab);
private:
friend class content::WebContentsUserData<OffscreenTabsOwner>;
explicit OffscreenTabsOwner(content::WebContents* extension_web_contents);
content::WebContents* const extension_web_contents_;
ScopedVector<OffscreenTab> tabs_;
DISALLOW_COPY_AND_ASSIGN(OffscreenTabsOwner);
};
// Owns and controls a sandboxed WebContents instance hosting the rendering
// engine for an offscreen tab. Since the offscreen tab does not interact with
// the user in any direct way, the WebContents is not attached to any Browser
// window/UI, and any input and focusing capabilities are blocked.
//
// OffscreenTab is instantiated by OffscreenTabsOwner. An instance is shut down
// one of three ways:
//
// 1. When its WebContents::GetCapturerCount() returns to zero, indicating
// there are no more consumers of its captured content (e.g., when all
// MediaStreams have been closed). OffscreenTab will auto-detect this case
// and self-destruct.
// 2. By the renderer, where the WebContents implementation will invoke the
// WebContentsDelegate::CloseContents() override. This occurs, for
// example, when a page calls window.close().
// 3. Automatically, when the extension background page's WebContents is
// destroyed.
//
// This class operates exclusively on the UI thread and so is not thread-safe.
class OffscreenTab : protected content::WebContentsDelegate,
protected content::WebContentsObserver {
public:
~OffscreenTab() final;
// The WebContents instance hosting the rendering engine for this
// OffscreenTab.
content::WebContents* web_contents() const {
return offscreen_tab_web_contents_.get();
}
protected:
friend class OffscreenTabsOwner;
explicit OffscreenTab(OffscreenTabsOwner* owner);
// Creates the WebContents instance containing the offscreen tab's page,
// configures it for offscreen rendering at the given |initial_size|, and
// navigates it to |start_url|. This is invoked once by OffscreenTabsOwner
// just after construction.
void Start(const GURL& start_url,
const gfx::Size& initial_size,
const std::string& optional_presentation_id);
// content::WebContentsDelegate overrides to provide the desired behaviors.
void CloseContents(content::WebContents* source) final;
bool ShouldSuppressDialogs(content::WebContents* source) final;
bool ShouldFocusLocationBarByDefault(content::WebContents* source) final;
bool ShouldFocusPageAfterCrash() final;
void CanDownload(const GURL& url,
const std::string& request_method,
const base::Callback<void(bool)>& callback) final;
bool HandleContextMenu(const content::ContextMenuParams& params) final;
bool PreHandleKeyboardEvent(content::WebContents* source,
const content::NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) final;
bool PreHandleGestureEvent(content::WebContents* source,
const blink::WebGestureEvent& event) final;
bool CanDragEnter(content::WebContents* source,
const content::DropData& data,
blink::WebDragOperationsMask operations_allowed) final;
bool ShouldCreateWebContents(
content::WebContents* contents,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
WindowContainerType window_container_type,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) final;
bool EmbedsFullscreenWidget() const final;
void EnterFullscreenModeForTab(content::WebContents* contents,
const GURL& origin) final;
void ExitFullscreenModeForTab(content::WebContents* contents) final;
bool IsFullscreenForTabOrPending(
const content::WebContents* contents) const final;
blink::WebDisplayMode GetDisplayMode(
const content::WebContents* contents) const final;
void RequestMediaAccessPermission(
content::WebContents* contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) final;
bool CheckMediaAccessPermission(content::WebContents* contents,
const GURL& security_origin,
content::MediaStreamType type) final;
// content::WebContentsObserver overrides
void DidShowFullscreenWidget(int routing_id) final;
private:
bool in_fullscreen_mode() const {
return !non_fullscreen_size_.IsEmpty();
}
// Called by |capture_poll_timer_| to automatically destroy this OffscreenTab
// when the capturer count returns to zero.
void DieIfContentCaptureEnded();
OffscreenTabsOwner* const owner_;
// The initial navigation URL, which may or may not match the current URL if
// page-initiated navigations have occurred.
GURL start_url_;
// A non-shared off-the-record profile based on the profile of the extension
// background page.
const scoped_ptr<Profile> profile_;
// The WebContents containing the off-screen tab's page.
scoped_ptr<content::WebContents> offscreen_tab_web_contents_;
// The time at which Start() finished creating |offscreen_tab_web_contents_|.
base::TimeTicks start_time_;
// Set to the original size of the renderer just before entering fullscreen
// mode. When not in fullscreen mode, this is an empty size.
gfx::Size non_fullscreen_size_;
// Poll timer to monitor the capturer count on |offscreen_tab_web_contents_|.
// When the capturer count returns to zero, this OffscreenTab is automatically
// destroyed.
//
// TODO(miu): Add a method to WebContentsObserver to report capturer count
// changes and get rid of this polling-based approach.
// http://crbug.com/540965
base::Timer capture_poll_timer_;
// This is false until after the Start() method is called, and capture of the
// |offscreen_tab_web_contents_| is first detected.
bool content_capture_was_detected_;
DISALLOW_COPY_AND_ASSIGN(OffscreenTab);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_TAB_H_
|