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

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: 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 const unsigned kMinSize = 200;
23
24 // At least this fraction of the video must be visible.
25 const float kVisibilityThreshold = 0.75;
26
27 } // anonymous namespace
28
29 MediaControlsRotateToFullscreenDelegate::
30 MediaControlsRotateToFullscreenDelegate(HTMLVideoElement& video)
31 : EventListener(kCPPEventListenerType), video_element_(video) {}
mlamouri (slow - plz ping) 2017/04/19 17:10:46 I guess removing Attach() above was intended then?
johnme 2017/04/19 18:21:28 Yes, see https://crbug.com/713275 as above. I kept
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_);
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: Does orientationchange get delivered to background tabs? Perhaps we
148 // should also check for at least page visibility before exiting?
mlamouri (slow - plz ping) 2017/04/19 17:10:46 No, it's not. A background tab doesn't receive eve
johnme 2017/04/19 18:21:28 Good point. Changed TODO to: // TODO(johnme): If
149 if (!video_element_->IsFullscreen() &&
150 (!is_visible_ || video_element_->paused())) {
151 return;
152 }
153
154 // Ignore (unexpected) events where we have incomplete information.
155 if (previous_screen_orientation == SimpleOrientation::kUnknown ||
156 current_screen_orientation_ == SimpleOrientation::kUnknown) {
157 return;
158 }
159
160 // Ignore 180 degree rotations between PortraitPrimary and PortraitSecondary,
161 // or between LandscapePrimary and LandscapeSecondary.
162 if (previous_screen_orientation == current_screen_orientation_)
163 return;
164
165 SimpleOrientation video_orientation = ComputeVideoOrientation();
166
167 // Ignore videos that are square/small/etc.
168 if (video_orientation == SimpleOrientation::kUnknown)
169 return;
170
171 MediaControlsImpl& media_controls =
172 *static_cast<MediaControlsImpl*>(video_element_->GetMediaControls());
173
174 {
175 UserGestureIndicator gesture(
176 DocumentUserGestureToken::Create(&video_element_->GetDocument()));
177
178 bool should_be_fullscreen =
179 current_screen_orientation_ == video_orientation;
180 if (should_be_fullscreen && !video_element_->IsFullscreen())
181 media_controls.EnterFullscreen();
182 else if (!should_be_fullscreen && video_element_->IsFullscreen())
183 media_controls.ExitFullscreen();
184 }
185 }
186
187 MediaControlsRotateToFullscreenDelegate::SimpleOrientation
188 MediaControlsRotateToFullscreenDelegate::ComputeVideoOrientation() const {
189 if (video_element_->getReadyState() == HTMLMediaElement::kHaveNothing)
190 return SimpleOrientation::kUnknown;
191
192 const unsigned width = video_element_->videoWidth();
193 const unsigned height = video_element_->videoHeight();
194
195 if (width < kMinSize || height < kMinSize)
196 return SimpleOrientation::kUnknown; // Too small, ignore this video.
197
198 if (width > height)
199 return SimpleOrientation::kLandscape;
200 if (height > width)
201 return SimpleOrientation::kPortrait;
202 return SimpleOrientation::kUnknown; // Square.
203 }
204
205 MediaControlsRotateToFullscreenDelegate::SimpleOrientation
206 MediaControlsRotateToFullscreenDelegate::ComputeScreenOrientation() const {
207 Frame* frame = video_element_->GetDocument().GetFrame();
208 if (!frame)
209 return SimpleOrientation::kUnknown;
210
211 switch (frame->GetChromeClient().GetScreenInfo().orientation_type) {
212 case kWebScreenOrientationPortraitPrimary:
213 case kWebScreenOrientationPortraitSecondary:
214 return SimpleOrientation::kPortrait;
215 case kWebScreenOrientationLandscapePrimary:
216 case kWebScreenOrientationLandscapeSecondary:
217 return SimpleOrientation::kLandscape;
218 case kWebScreenOrientationUndefined:
219 return SimpleOrientation::kUnknown;
220 }
221
222 NOTREACHED();
223 return SimpleOrientation::kUnknown;
224 }
225
226 DEFINE_TRACE(MediaControlsRotateToFullscreenDelegate) {
227 EventListener::Trace(visitor);
228 visitor->Trace(video_element_);
229 visitor->Trace(visibility_observer_);
230 }
231
232 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698