Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp

Issue 2830713003: [Media controls] Add rotate-to-fullscreen gesture behind flag (Closed)
Patch Set: Address review comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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.
4
5 #include "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h"
6
7 #include "core/dom/DocumentUserGestureToken.h"
8 #include "core/dom/ElementVisibilityObserver.h"
9 #include "core/events/Event.h"
10 #include "core/frame/LocalDOMWindow.h"
11 #include "core/html/HTMLVideoElement.h"
12 #include "core/page/ChromeClient.h"
13 #include "modules/media_controls/MediaControlsImpl.h"
14 #include "platform/UserGestureIndicator.h"
15 #include "public/platform/WebScreenInfo.h"
16
17 namespace blink {
18
19 namespace {
20
21 // Videos must be at least this big in both dimensions to qualify.
22 constexpr unsigned kMinSize = 200;
23
24 // At least this fraction of the video must be visible.
25 constexpr float kVisibilityThreshold = 0.75;
26
27 } // anonymous namespace
28
29 MediaControlsRotateToFullscreenDelegate::
30 MediaControlsRotateToFullscreenDelegate(HTMLVideoElement& video)
31 : EventListener(kCPPEventListenerType), video_element_(video) {}
32
33 void MediaControlsRotateToFullscreenDelegate::Attach() {
34 DCHECK(video_element_->isConnected());
35
36 LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow();
37 if (!dom_window)
38 return;
39
40 video_element_->addEventListener(EventTypeNames::play, this, true);
41 video_element_->addEventListener(EventTypeNames::pause, this, true);
42
43 // Listen to two different fullscreen events in order to make sure the new and
44 // old APIs are handled.
45 video_element_->addEventListener(EventTypeNames::webkitfullscreenchange, this,
46 true);
47 video_element_->GetDocument().addEventListener(
48 EventTypeNames::fullscreenchange, this, true);
49
50 current_screen_orientation_ = ComputeScreenOrientation();
51 // TODO(johnme): Check this is battery efficient (note that this doesn't need
52 // to receive events for 180 deg rotations).
53 dom_window->addEventListener(EventTypeNames::orientationchange, this, false);
54 }
55
56 void MediaControlsRotateToFullscreenDelegate::Detach() {
57 DCHECK(!video_element_->isConnected());
58
59 if (visibility_observer_) {
60 // TODO(johnme): Should I also call Stop in a prefinalizer?
61 visibility_observer_->Stop();
62 visibility_observer_ = nullptr;
63 is_visible_ = false;
64 }
65
66 video_element_->removeEventListener(EventTypeNames::play, this, true);
67 video_element_->removeEventListener(EventTypeNames::pause, this, true);
68
69 video_element_->removeEventListener(EventTypeNames::webkitfullscreenchange,
70 this, true);
71 video_element_->GetDocument().removeEventListener(
72 EventTypeNames::fullscreenchange, this, true);
73
74 LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow();
75 if (!dom_window)
76 return;
77 dom_window->removeEventListener(EventTypeNames::orientationchange, this,
78 false);
79 }
80
81 bool MediaControlsRotateToFullscreenDelegate::operator==(
82 const EventListener& other) const {
83 return this == &other;
84 }
85
86 void MediaControlsRotateToFullscreenDelegate::handleEvent(
87 ExecutionContext* execution_context,
88 Event* event) {
89 // LOG(INFO) << __PRETTY_FUNCTION__ << " type=" << event->type()
90 // << " visibility_observer_=" << visibility_observer_
91 // << " current_screen_orientation_="
92 // << static_cast<int>(current_screen_orientation_);
mlamouri (slow - plz ping) 2017/04/20 14:10:40 Will have to be cleaned-up same for the uncommente
kinuko 2017/04/25 06:30:58 Yeah, please clean up these before landing.
mlamouri (slow - plz ping) 2017/04/25 10:57:30 This is johnme@'s CL. I'm going to send a follow-u
johnme 2017/04/27 15:57:48 Removed this commented out LOG(INFO). Converted th
93
94 if (event->type() == EventTypeNames::play ||
95 event->type() == EventTypeNames::pause ||
96 event->type() == EventTypeNames::fullscreenchange ||
97 event->type() == EventTypeNames::webkitfullscreenchange) {
98 OnStateChange();
99 return;
100 }
101 if (event->type() == EventTypeNames::orientationchange) {
102 OnScreenOrientationChange();
103 return;
104 }
105
106 NOTREACHED();
107 }
108
109 void MediaControlsRotateToFullscreenDelegate::OnStateChange() {
110 // TODO(johnme): Check this aggressive disabling doesn't lead to race
111 // conditions where we briefly don't know if the video is visible.
112 bool needs_visibility_observer =
113 !video_element_->paused() && !video_element_->IsFullscreen();
114 LOG(INFO) << __FUNCTION__ << " " << !!visibility_observer_ << " -> "
115 << needs_visibility_observer;
116 if (needs_visibility_observer && !visibility_observer_) {
117 visibility_observer_ = new ElementVisibilityObserver(
118 video_element_,
119 WTF::Bind(&MediaControlsRotateToFullscreenDelegate::OnVisibilityChange,
120 WrapWeakPersistent(this)));
121 visibility_observer_->Start(kVisibilityThreshold);
122 } else if (!needs_visibility_observer && visibility_observer_) {
123 visibility_observer_->Stop();
124 visibility_observer_ = nullptr;
125 is_visible_ = false;
126 }
127 }
128
129 void MediaControlsRotateToFullscreenDelegate::OnVisibilityChange(
130 bool is_visible) {
131 LOG(INFO) << __FUNCTION__ << " " << is_visible_ << " -> " << is_visible;
132 is_visible_ = is_visible;
133 }
134
135 void MediaControlsRotateToFullscreenDelegate::OnScreenOrientationChange() {
136 SimpleOrientation previous_screen_orientation = current_screen_orientation_;
137 current_screen_orientation_ = ComputeScreenOrientation();
138 LOG(INFO) << __FUNCTION__ << " "
139 << static_cast<int>(previous_screen_orientation) << " -> "
140 << static_cast<int>(current_screen_orientation_);
141
142 // Only enable if native media controls are used.
143 if (!video_element_->ShouldShowControls())
144 return;
145
146 // To enter fullscreen, video must be visible and playing.
147 // TODO(johnme): If orientation changes whilst this tab is in the background,
148 // we'll get an orientationchange event when this tab next becomes active.
149 // Check that those events don't trigger rotate-to-fullscreen.
150 if (!video_element_->IsFullscreen() &&
151 (!is_visible_ || video_element_->paused())) {
152 return;
153 }
mlamouri (slow - plz ping) 2017/04/20 14:10:40 TODO: we should also not do this if the document i
johnme 2017/04/27 15:57:48 Fixed, and added tests EnterFailDocumentFullscreen
154
155 // Ignore (unexpected) events where we have incomplete information.
156 if (previous_screen_orientation == SimpleOrientation::kUnknown ||
157 current_screen_orientation_ == SimpleOrientation::kUnknown) {
158 return;
159 }
160
161 // Ignore 180 degree rotations between PortraitPrimary and PortraitSecondary,
162 // or between LandscapePrimary and LandscapeSecondary.
163 if (previous_screen_orientation == current_screen_orientation_)
mlamouri (slow - plz ping) 2017/04/20 14:10:40 I'm a bit worried about not doing anything for squ
johnme 2017/04/27 15:57:48 Good point. I've changed ComputeVideoOrientation()
164 return;
165
166 SimpleOrientation video_orientation = ComputeVideoOrientation();
167
168 // Ignore videos that are square/small/etc.
169 if (video_orientation == SimpleOrientation::kUnknown)
170 return;
171
172 MediaControlsImpl& media_controls =
173 *static_cast<MediaControlsImpl*>(video_element_->GetMediaControls());
174
175 {
176 UserGestureIndicator gesture(
177 DocumentUserGestureToken::Create(&video_element_->GetDocument()));
178
179 bool should_be_fullscreen =
180 current_screen_orientation_ == video_orientation;
181 if (should_be_fullscreen && !video_element_->IsFullscreen())
182 media_controls.EnterFullscreen();
183 else if (!should_be_fullscreen && video_element_->IsFullscreen())
184 media_controls.ExitFullscreen();
185 }
186 }
187
188 MediaControlsRotateToFullscreenDelegate::SimpleOrientation
189 MediaControlsRotateToFullscreenDelegate::ComputeVideoOrientation() const {
190 if (video_element_->getReadyState() == HTMLMediaElement::kHaveNothing)
191 return SimpleOrientation::kUnknown;
192
193 const unsigned width = video_element_->videoWidth();
194 const unsigned height = video_element_->videoHeight();
195
196 if (width < kMinSize || height < kMinSize)
197 return SimpleOrientation::kUnknown; // Too small, ignore this video.
198
199 if (width > height)
200 return SimpleOrientation::kLandscape;
201 if (height > width)
202 return SimpleOrientation::kPortrait;
203 return SimpleOrientation::kUnknown; // Square.
204 }
205
206 MediaControlsRotateToFullscreenDelegate::SimpleOrientation
207 MediaControlsRotateToFullscreenDelegate::ComputeScreenOrientation() const {
208 Frame* frame = video_element_->GetDocument().GetFrame();
209 if (!frame)
210 return SimpleOrientation::kUnknown;
211
212 switch (frame->GetChromeClient().GetScreenInfo().orientation_type) {
213 case kWebScreenOrientationPortraitPrimary:
214 case kWebScreenOrientationPortraitSecondary:
215 return SimpleOrientation::kPortrait;
216 case kWebScreenOrientationLandscapePrimary:
217 case kWebScreenOrientationLandscapeSecondary:
218 return SimpleOrientation::kLandscape;
219 case kWebScreenOrientationUndefined:
220 return SimpleOrientation::kUnknown;
221 }
222
223 NOTREACHED();
224 return SimpleOrientation::kUnknown;
225 }
226
227 DEFINE_TRACE(MediaControlsRotateToFullscreenDelegate) {
228 EventListener::Trace(visitor);
229 visitor->Trace(video_element_);
230 visitor->Trace(visibility_observer_);
231 }
232
233 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698