OLD | NEW |
---|---|
(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 | |
OLD | NEW |