Chromium Code Reviews| 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 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 | |
| OLD | NEW |