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

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: Use __func__ instead per styleguide Created 3 years, 7 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/dom/Fullscreen.h"
10 #include "core/events/Event.h"
11 #include "core/frame/LocalDOMWindow.h"
12 #include "core/html/HTMLVideoElement.h"
13 #include "core/page/ChromeClient.h"
14 #include "modules/media_controls/MediaControlsImpl.h"
15 #include "platform/UserGestureIndicator.h"
16 #include "public/platform/WebScreenInfo.h"
17
18 namespace blink {
19
20 namespace {
21
22 // Videos must be at least this big in both dimensions to qualify.
23 constexpr unsigned kMinSize = 200;
24
25 // At least this fraction of the video must be visible.
26 constexpr float kVisibilityThreshold = 0.75;
27
28 } // anonymous namespace
29
30 MediaControlsRotateToFullscreenDelegate::
31 MediaControlsRotateToFullscreenDelegate(HTMLVideoElement& video)
32 : EventListener(kCPPEventListenerType), video_element_(video) {}
33
34 void MediaControlsRotateToFullscreenDelegate::Attach() {
35 DCHECK(video_element_->isConnected());
36
37 LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow();
38 if (!dom_window)
39 return;
40
41 video_element_->addEventListener(EventTypeNames::play, this, true);
42 video_element_->addEventListener(EventTypeNames::pause, this, true);
43
44 // Listen to two different fullscreen events in order to make sure the new and
45 // old APIs are handled.
46 video_element_->addEventListener(EventTypeNames::webkitfullscreenchange, this,
47 true);
48 video_element_->GetDocument().addEventListener(
49 EventTypeNames::fullscreenchange, this, true);
50
51 current_screen_orientation_ = ComputeScreenOrientation();
52 // TODO(johnme): Check this is battery efficient (note that this doesn't need
53 // to receive events for 180 deg rotations).
54 dom_window->addEventListener(EventTypeNames::orientationchange, this, false);
55 }
56
57 void MediaControlsRotateToFullscreenDelegate::Detach() {
58 DCHECK(!video_element_->isConnected());
59
60 if (visibility_observer_) {
61 // TODO(johnme): Should I also call Stop in a prefinalizer?
62 visibility_observer_->Stop();
63 visibility_observer_ = nullptr;
64 is_visible_ = false;
65 }
66
67 video_element_->removeEventListener(EventTypeNames::play, this, true);
68 video_element_->removeEventListener(EventTypeNames::pause, this, true);
69
70 video_element_->removeEventListener(EventTypeNames::webkitfullscreenchange,
71 this, true);
72 video_element_->GetDocument().removeEventListener(
73 EventTypeNames::fullscreenchange, this, true);
74
75 LocalDOMWindow* dom_window = video_element_->GetDocument().domWindow();
76 if (!dom_window)
77 return;
78 dom_window->removeEventListener(EventTypeNames::orientationchange, this,
79 false);
80 }
81
82 bool MediaControlsRotateToFullscreenDelegate::operator==(
83 const EventListener& other) const {
84 return this == &other;
85 }
86
87 void MediaControlsRotateToFullscreenDelegate::handleEvent(
88 ExecutionContext* execution_context,
89 Event* event) {
90 if (event->type() == EventTypeNames::play ||
91 event->type() == EventTypeNames::pause ||
92 event->type() == EventTypeNames::fullscreenchange ||
93 event->type() == EventTypeNames::webkitfullscreenchange) {
94 OnStateChange();
95 return;
96 }
97 if (event->type() == EventTypeNames::orientationchange) {
98 OnScreenOrientationChange();
99 return;
100 }
101
102 NOTREACHED();
103 }
104
105 void MediaControlsRotateToFullscreenDelegate::OnStateChange() {
106 // TODO(johnme): Check this aggressive disabling doesn't lead to race
107 // conditions where we briefly don't know if the video is visible.
108 bool needs_visibility_observer =
109 !video_element_->paused() && !video_element_->IsFullscreen();
110 DVLOG(3) << __func__ << " " << !!visibility_observer_ << " -> "
111 << needs_visibility_observer;
112
113 if (needs_visibility_observer && !visibility_observer_) {
114 visibility_observer_ = new ElementVisibilityObserver(
115 video_element_,
116 WTF::Bind(&MediaControlsRotateToFullscreenDelegate::OnVisibilityChange,
117 WrapWeakPersistent(this)));
118 visibility_observer_->Start(kVisibilityThreshold);
119 } else if (!needs_visibility_observer && visibility_observer_) {
120 visibility_observer_->Stop();
121 visibility_observer_ = nullptr;
122 is_visible_ = false;
123 }
124 }
125
126 void MediaControlsRotateToFullscreenDelegate::OnVisibilityChange(
127 bool is_visible) {
128 DVLOG(3) << __func__ << " " << is_visible_ << " -> " << is_visible;
129 is_visible_ = is_visible;
130 }
131
132 void MediaControlsRotateToFullscreenDelegate::OnScreenOrientationChange() {
133 SimpleOrientation previous_screen_orientation = current_screen_orientation_;
134 current_screen_orientation_ = ComputeScreenOrientation();
135 DVLOG(3) << __func__ << " " << static_cast<int>(previous_screen_orientation)
136 << " -> " << static_cast<int>(current_screen_orientation_);
137
138 // Only enable if native media controls are used.
139 if (!video_element_->ShouldShowControls())
140 return;
141
142 // Don't enter/exit fullscreen if some other element is fullscreen.
143 Element* fullscreen_element =
144 Fullscreen::CurrentFullScreenElementFrom(video_element_->GetDocument());
145 if (fullscreen_element && fullscreen_element != video_element_)
146 return;
147
148 // To enter fullscreen, video must be visible and playing.
149 // TODO(johnme): If orientation changes whilst this tab is in the background,
150 // we'll get an orientationchange event when this tab next becomes active.
151 // Check that those events don't trigger rotate-to-fullscreen.
152 if (!video_element_->IsFullscreen() &&
153 (!is_visible_ || video_element_->paused())) {
154 return;
155 }
156
157 // Ignore (unexpected) events where we have incomplete information.
158 if (previous_screen_orientation == SimpleOrientation::kUnknown ||
159 current_screen_orientation_ == SimpleOrientation::kUnknown) {
160 return;
161 }
162
163 // Ignore 180 degree rotations between PortraitPrimary and PortraitSecondary,
164 // or between LandscapePrimary and LandscapeSecondary.
165 if (previous_screen_orientation == current_screen_orientation_)
166 return;
167
168 SimpleOrientation video_orientation = ComputeVideoOrientation();
169
170 // Ignore videos that are square/small/etc.
171 if (video_orientation == SimpleOrientation::kUnknown)
172 return;
173
174 MediaControlsImpl& media_controls =
175 *static_cast<MediaControlsImpl*>(video_element_->GetMediaControls());
176
177 {
178 UserGestureIndicator gesture(
179 DocumentUserGestureToken::Create(&video_element_->GetDocument()));
180
181 bool should_be_fullscreen =
182 current_screen_orientation_ == video_orientation;
183 if (should_be_fullscreen && !video_element_->IsFullscreen())
184 media_controls.EnterFullscreen();
185 else if (!should_be_fullscreen && video_element_->IsFullscreen())
186 media_controls.ExitFullscreen();
187 }
188 }
189
190 MediaControlsRotateToFullscreenDelegate::SimpleOrientation
191 MediaControlsRotateToFullscreenDelegate::ComputeVideoOrientation() const {
192 if (video_element_->getReadyState() == HTMLMediaElement::kHaveNothing)
193 return SimpleOrientation::kUnknown;
194
195 const unsigned width = video_element_->videoWidth();
196 const unsigned height = video_element_->videoHeight();
197
198 if (width < kMinSize || height < kMinSize)
199 return SimpleOrientation::kUnknown; // Too small, ignore this video.
200
201 if (width >= height)
202 return SimpleOrientation::kLandscape; // Includes square videos.
203 return SimpleOrientation::kPortrait;
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