1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_PRESENTATION_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_PRESENTATION_H_
11 #include "base/memory/scoped_vector.h"
12 #include "base/time/time.h"
13 #include "base/timer/timer.h"
14 #include "content/public/browser/web_contents_delegate.h"
15 #include "content/public/browser/web_contents_observer.h"
16 #include "content/public/browser/web_contents_user_data.h"
17 #include "ui/gfx/geometry/size.h"
21 namespace extensions
{
23 class OffscreenPresentation
; // Forward declaration. See below.
25 // Creates, owns, and manages all OffscreenPresentation instances created by the
26 // same extension background page. When the extension background page's
27 // WebContents is about to be destroyed, its associated
28 // OffscreenPresentationsOwner and all of its OffscreenPresentation instances
33 // OffscreenPresentationsOwner::Get(extension_contents)
34 // ->FindOrStartPresentation(start_url, presentation_id, size);
36 // This class operates exclusively on the UI thread and so is not thread-safe.
37 class OffscreenPresentationsOwner
38 : protected content::WebContentsUserData
<OffscreenPresentationsOwner
> {
40 ~OffscreenPresentationsOwner() override
;
42 // Returns the OffscreenPresentationsOwner instance associated with the given
43 // extension background page's WebContents. Never returns nullptr.
44 static OffscreenPresentationsOwner
* Get(
45 content::WebContents
* extension_web_contents
);
47 // Find a presentation, keyed by |start_url| and |presentation_id|. If found,
48 // return it. Otherwise, instantiate a new one and return that. If too many
49 // presentations have already been started, this method returns nullptr.
50 OffscreenPresentation
* FindOrStartPresentation(
51 const GURL
& start_url
,
52 const std::string
& presentation_id
,
53 const gfx::Size
& initial_size
);
56 friend class OffscreenPresentation
;
58 // Accessor to the extension background page's WebContents.
59 content::WebContents
* extension_web_contents() const {
60 return extension_web_contents_
;
63 // Shuts down and destroys the |presentation|.
64 void ClosePresentation(OffscreenPresentation
* presentation
);
67 friend class content::WebContentsUserData
<OffscreenPresentationsOwner
>;
69 explicit OffscreenPresentationsOwner(content::WebContents
* contents
);
71 // Returns the OffscreenPresentation that matches the given |start_url| and
72 // |presentation_id|, or nullptr if not found.
73 OffscreenPresentation
* FindPresentation(
74 const GURL
& start_url
, const std::string
& presentation_id
) const;
76 content::WebContents
* const extension_web_contents_
;
77 ScopedVector
<OffscreenPresentation
> presentations_
;
79 DISALLOW_COPY_AND_ASSIGN(OffscreenPresentationsOwner
);
82 // Owns and controls a WebContents instance containing a presentation page.
83 // Since the presentation page does not interact with the user in any direct
84 // way, the WebContents is not attached to any Browser window/UI, and all input
85 // and focusing capabilities are blocked.
87 // OffscreenPresentation is instantiated by OffscreenPresentationsOwner. An
88 // instance is shut down one of three ways:
90 // 1. When its WebContents::GetCapturerCount() returns to zero, indicating
91 // there are no more consumers of its captured content (e.g., when all
92 // MediaStreams have been closed). OffscreenPresentation will detect this
93 // case and initiate shutdown.
94 // 2. By the renderer, where the WebContents implementation will invoke the
95 // WebContentsDelegate::CloseContents() override. This occurs, for
96 // example, when a page calls window.close().
97 // 3. Automatically, when the extension background page's WebContents is
100 // This class operates exclusively on the UI thread and so is not thread-safe.
101 class OffscreenPresentation
: protected content::WebContentsDelegate
,
102 protected content::WebContentsObserver
{
104 ~OffscreenPresentation() final
;
106 const GURL
& start_url() const { return start_url_
; }
107 const std::string
& presentation_id() const { return presentation_id_
; }
109 // The presentation page's WebContents instance.
110 content::WebContents
* web_contents() const {
111 return presentation_web_contents_
.get();
115 friend class OffscreenPresentationsOwner
;
117 OffscreenPresentation(OffscreenPresentationsOwner
* owner
,
118 const GURL
& start_url
,
119 const std::string
& id
);
121 // Creates the WebContents instance containing the presentation page,
122 // configures it for off-screen rendering at the given |initial_size|, and
123 // navigates it to |start_url_|. This is invoked once by
124 // OffscreenPresentationsOwner just after construction.
125 void Start(const gfx::Size
& initial_size
);
127 // content::WebContentsDelegate overrides to provide the desired behaviors.
128 void CloseContents(content::WebContents
* source
) final
;
129 bool ShouldSuppressDialogs(content::WebContents
* source
) final
;
130 bool ShouldFocusLocationBarByDefault(content::WebContents
* source
) final
;
131 bool ShouldFocusPageAfterCrash() final
;
132 void CanDownload(const GURL
& url
,
133 const std::string
& request_method
,
134 const base::Callback
<void(bool)>& callback
) final
;
135 bool HandleContextMenu(const content::ContextMenuParams
& params
) final
;
136 bool PreHandleKeyboardEvent(content::WebContents
* source
,
137 const content::NativeWebKeyboardEvent
& event
,
138 bool* is_keyboard_shortcut
) final
;
139 bool PreHandleGestureEvent(content::WebContents
* source
,
140 const blink::WebGestureEvent
& event
) final
;
141 bool CanDragEnter(content::WebContents
* source
,
142 const content::DropData
& data
,
143 blink::WebDragOperationsMask operations_allowed
) final
;
144 bool ShouldCreateWebContents(
145 content::WebContents
* contents
,
147 int main_frame_route_id
,
148 WindowContainerType window_container_type
,
149 const std::string
& frame_name
,
150 const GURL
& target_url
,
151 const std::string
& partition_id
,
152 content::SessionStorageNamespace
* session_storage_namespace
) final
;
153 bool EmbedsFullscreenWidget() const final
;
154 void EnterFullscreenModeForTab(content::WebContents
* contents
,
155 const GURL
& origin
) final
;
156 void ExitFullscreenModeForTab(content::WebContents
* contents
) final
;
157 bool IsFullscreenForTabOrPending(
158 const content::WebContents
* contents
) const final
;
159 blink::WebDisplayMode
GetDisplayMode(
160 const content::WebContents
* contents
) const final
;
161 void RequestMediaAccessPermission(
162 content::WebContents
* contents
,
163 const content::MediaStreamRequest
& request
,
164 const content::MediaResponseCallback
& callback
) final
;
165 bool CheckMediaAccessPermission(content::WebContents
* contents
,
166 const GURL
& security_origin
,
167 content::MediaStreamType type
) final
;
169 // content::WebContentsObserver overrides
170 void DidShowFullscreenWidget(int routing_id
) final
;
173 bool in_fullscreen_mode() const {
174 return !non_fullscreen_size_
.IsEmpty();
177 // Called by |capture_poll_timer_| to automatically destroy this
178 // OffscreenPresentation when the capturer count returns to zero.
179 void DieIfContentCaptureEnded();
181 OffscreenPresentationsOwner
* const owner_
;
183 // The starting URL for this presentation, which may or may not match the
184 // current WebContents URL if navigations have occurred.
185 const GURL start_url_
;
187 // The presentation ID used to help uniquely identify this instance.
188 const std::string presentation_id_
;
190 // A non-shared off-the-record profile based on the profile of the extension
192 const scoped_ptr
<Profile
> profile_
;
194 // The WebContents containing the offscreen presentation page.
195 scoped_ptr
<content::WebContents
> presentation_web_contents_
;
197 // The time at which Start() finished creating |presentation_web_contents_|.
198 base::TimeTicks start_time_
;
200 // Set to the original size of the renderer just before entering fullscreen
201 // mode. When not in fullscreen mode, this is an empty size.
202 gfx::Size non_fullscreen_size_
;
204 // Poll timer to monitor the capturer count on |presentation_web_contents_|.
205 // When the capturer count returns to zero, this OffscreenPresentation is
206 // automatically destroyed.
207 // TODO(miu): Add a method to WebContentsObserver to report capturer count
208 // changes and get rid of this polling-based approach.
209 base::Timer capture_poll_timer_
;
211 // This is false until after the Start() method is called, and capture of the
212 // |presentation_web_contents_| is first detected.
213 bool content_capture_was_detected_
;
215 DISALLOW_COPY_AND_ASSIGN(OffscreenPresentation
);
218 } // namespace extensions
220 #endif // CHROME_BROWSER_EXTENSIONS_API_TAB_CAPTURE_OFFSCREEN_PRESENTATION_H_