| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "core/html/shadow/MediaControlsOrientationLockDelegate.h" | |
| 6 | |
| 7 #include "core/dom/Document.h" | |
| 8 #include "core/dom/DocumentUserGestureToken.h" | |
| 9 #include "core/dom/Fullscreen.h" | |
| 10 #include "core/frame/ScreenOrientationController.h" | |
| 11 #include "core/html/HTMLAudioElement.h" | |
| 12 #include "core/html/HTMLVideoElement.h" | |
| 13 #include "core/html/shadow/MediaControls.h" | |
| 14 #include "core/loader/EmptyClients.h" | |
| 15 #include "core/testing/DummyPageHolder.h" | |
| 16 #include "platform/UserGestureIndicator.h" | |
| 17 #include "platform/testing/EmptyWebMediaPlayer.h" | |
| 18 #include "platform/testing/UnitTestHelpers.h" | |
| 19 #include "public/platform/WebSize.h" | |
| 20 #include "public/platform/modules/screen_orientation/WebLockOrientationCallback.
h" | |
| 21 #include "testing/gmock/include/gmock/gmock.h" | |
| 22 #include "testing/gtest/include/gtest/gtest.h" | |
| 23 | |
| 24 using ::testing::_; | |
| 25 using ::testing::Return; | |
| 26 | |
| 27 namespace blink { | |
| 28 | |
| 29 namespace { | |
| 30 | |
| 31 // WebLockOrientationCallback implementation that will not react to a success | |
| 32 // nor a failure. | |
| 33 class DummyScreenOrientationCallback : public WebLockOrientationCallback { | |
| 34 public: | |
| 35 void onSuccess() override {} | |
| 36 void onError(WebLockOrientationError) override {} | |
| 37 }; | |
| 38 | |
| 39 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { | |
| 40 public: | |
| 41 bool hasVideo() const override { return true; } | |
| 42 | |
| 43 MOCK_CONST_METHOD0(naturalSize, WebSize()); | |
| 44 }; | |
| 45 | |
| 46 class MockChromeClient : public EmptyChromeClient { | |
| 47 public: | |
| 48 MOCK_CONST_METHOD0(screenInfo, WebScreenInfo()); | |
| 49 }; | |
| 50 | |
| 51 class StubLocalFrameClient : public EmptyLocalFrameClient { | |
| 52 public: | |
| 53 static StubLocalFrameClient* create() { return new StubLocalFrameClient; } | |
| 54 | |
| 55 std::unique_ptr<WebMediaPlayer> createWebMediaPlayer( | |
| 56 HTMLMediaElement&, | |
| 57 const WebMediaPlayerSource&, | |
| 58 WebMediaPlayerClient*) override { | |
| 59 return WTF::wrapUnique(new MockVideoWebMediaPlayer()); | |
| 60 } | |
| 61 }; | |
| 62 | |
| 63 class MockScreenOrientationController final | |
| 64 : public ScreenOrientationController { | |
| 65 WTF_MAKE_NONCOPYABLE(MockScreenOrientationController); | |
| 66 | |
| 67 public: | |
| 68 static MockScreenOrientationController* provideTo(LocalFrame& frame) { | |
| 69 MockScreenOrientationController* controller = | |
| 70 new MockScreenOrientationController(frame); | |
| 71 ScreenOrientationController::provideTo(frame, controller); | |
| 72 return controller; | |
| 73 } | |
| 74 | |
| 75 MOCK_METHOD1(lock, void(WebScreenOrientationLockType)); | |
| 76 MOCK_METHOD0(mockUnlock, void()); | |
| 77 | |
| 78 DEFINE_INLINE_VIRTUAL_TRACE() { ScreenOrientationController::trace(visitor); } | |
| 79 | |
| 80 private: | |
| 81 explicit MockScreenOrientationController(LocalFrame& frame) | |
| 82 : ScreenOrientationController(frame) {} | |
| 83 | |
| 84 void lock(WebScreenOrientationLockType type, | |
| 85 std::unique_ptr<WebLockOrientationCallback>) override { | |
| 86 m_locked = true; | |
| 87 lock(type); | |
| 88 } | |
| 89 | |
| 90 void unlock() override { | |
| 91 m_locked = false; | |
| 92 mockUnlock(); | |
| 93 } | |
| 94 | |
| 95 void notifyOrientationChanged() override {} | |
| 96 | |
| 97 bool maybeHasActiveLock() const override { return m_locked; } | |
| 98 | |
| 99 bool m_locked = false; | |
| 100 }; | |
| 101 | |
| 102 } // anonymous namespace | |
| 103 | |
| 104 class MediaControlsOrientationLockDelegateTest : public ::testing::Test { | |
| 105 protected: | |
| 106 void SetUp() override { | |
| 107 m_previousVideoFullscreenOrientationLockValue = | |
| 108 RuntimeEnabledFeatures::videoFullscreenOrientationLockEnabled(); | |
| 109 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(true); | |
| 110 | |
| 111 m_chromeClient = new MockChromeClient(); | |
| 112 | |
| 113 Page::PageClients clients; | |
| 114 fillWithEmptyClients(clients); | |
| 115 clients.chromeClient = m_chromeClient.get(); | |
| 116 | |
| 117 m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients, | |
| 118 StubLocalFrameClient::create()); | |
| 119 | |
| 120 document().write("<body><video></body>"); | |
| 121 m_video = toHTMLVideoElement(*document().querySelector("video")); | |
| 122 | |
| 123 m_screenOrientationController = | |
| 124 MockScreenOrientationController::provideTo(m_pageHolder->frame()); | |
| 125 } | |
| 126 | |
| 127 void TearDown() override { | |
| 128 ::testing::Mock::VerifyAndClear(&screenOrientationController()); | |
| 129 | |
| 130 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled( | |
| 131 m_previousVideoFullscreenOrientationLockValue); | |
| 132 } | |
| 133 | |
| 134 static bool hasDelegate(const MediaControls& mediaControls) { | |
| 135 return !!mediaControls.m_orientationLockDelegate; | |
| 136 } | |
| 137 | |
| 138 void simulateEnterFullscreen() { | |
| 139 UserGestureIndicator gesture(DocumentUserGestureToken::create(&document())); | |
| 140 | |
| 141 Fullscreen::requestFullscreen(video()); | |
| 142 Fullscreen::from(document()).didEnterFullscreen(); | |
| 143 testing::runPendingTasks(); | |
| 144 } | |
| 145 | |
| 146 void simulateExitFullscreen() { | |
| 147 Fullscreen::exitFullscreen(document()); | |
| 148 Fullscreen::from(document()).didExitFullscreen(); | |
| 149 testing::runPendingTasks(); | |
| 150 } | |
| 151 | |
| 152 void simulateOrientationLock() { | |
| 153 ScreenOrientationController* controller = | |
| 154 ScreenOrientationController::from(*document().frame()); | |
| 155 controller->lock(WebScreenOrientationLockLandscape, | |
| 156 WTF::wrapUnique(new DummyScreenOrientationCallback)); | |
| 157 EXPECT_TRUE(controller->maybeHasActiveLock()); | |
| 158 } | |
| 159 | |
| 160 void simulateVideoReadyState(HTMLMediaElement::ReadyState state) { | |
| 161 video().setReadyState(state); | |
| 162 } | |
| 163 | |
| 164 void simulateVideoNetworkState(HTMLMediaElement::NetworkState state) { | |
| 165 video().setNetworkState(state); | |
| 166 } | |
| 167 | |
| 168 void checkStatePendingFullscreen() const { | |
| 169 EXPECT_EQ(MediaControlsOrientationLockDelegate::State::PendingFullscreen, | |
| 170 m_video->mediaControls()->m_orientationLockDelegate->m_state); | |
| 171 } | |
| 172 | |
| 173 void checkStatePendingMetadata() const { | |
| 174 EXPECT_EQ(MediaControlsOrientationLockDelegate::State::PendingMetadata, | |
| 175 m_video->mediaControls()->m_orientationLockDelegate->m_state); | |
| 176 } | |
| 177 | |
| 178 void checkStateMaybeLockedFullscreen() const { | |
| 179 EXPECT_EQ( | |
| 180 MediaControlsOrientationLockDelegate::State::MaybeLockedFullscreen, | |
| 181 m_video->mediaControls()->m_orientationLockDelegate->m_state); | |
| 182 } | |
| 183 | |
| 184 bool delegateWillUnlockFullscreen() const { | |
| 185 return m_video->mediaControls() | |
| 186 ->m_orientationLockDelegate->m_shouldUnlockOrientation; | |
| 187 } | |
| 188 | |
| 189 WebScreenOrientationLockType computeOrientationLock() const { | |
| 190 return m_video->mediaControls() | |
| 191 ->m_orientationLockDelegate->computeOrientationLock(); | |
| 192 } | |
| 193 | |
| 194 MockChromeClient& chromeClient() const { return *m_chromeClient; } | |
| 195 | |
| 196 HTMLVideoElement& video() const { return *m_video; } | |
| 197 Document& document() const { return m_pageHolder->document(); } | |
| 198 MockScreenOrientationController& screenOrientationController() const { | |
| 199 return *m_screenOrientationController; | |
| 200 } | |
| 201 MockVideoWebMediaPlayer& mockWebMediaPlayer() const { | |
| 202 return *static_cast<MockVideoWebMediaPlayer*>(video().webMediaPlayer()); | |
| 203 } | |
| 204 | |
| 205 private: | |
| 206 bool m_previousVideoFullscreenOrientationLockValue; | |
| 207 std::unique_ptr<DummyPageHolder> m_pageHolder; | |
| 208 Persistent<HTMLVideoElement> m_video; | |
| 209 Persistent<MockScreenOrientationController> m_screenOrientationController; | |
| 210 Persistent<MockChromeClient> m_chromeClient; | |
| 211 }; | |
| 212 | |
| 213 TEST_F(MediaControlsOrientationLockDelegateTest, DelegateRequiresFlag) { | |
| 214 // Flag on by default. | |
| 215 EXPECT_TRUE(hasDelegate(*video().mediaControls())); | |
| 216 | |
| 217 // Same with flag off. | |
| 218 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(false); | |
| 219 HTMLVideoElement* video = HTMLVideoElement::create(document()); | |
| 220 document().body()->appendChild(video); | |
| 221 EXPECT_FALSE(hasDelegate(*video->mediaControls())); | |
| 222 } | |
| 223 | |
| 224 TEST_F(MediaControlsOrientationLockDelegateTest, DelegateRequiresVideo) { | |
| 225 HTMLAudioElement* audio = HTMLAudioElement::create(document()); | |
| 226 document().body()->appendChild(audio); | |
| 227 EXPECT_FALSE(hasDelegate(*audio->mediaControls())); | |
| 228 } | |
| 229 | |
| 230 TEST_F(MediaControlsOrientationLockDelegateTest, InitialState) { | |
| 231 checkStatePendingFullscreen(); | |
| 232 } | |
| 233 | |
| 234 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenNoMetadata) { | |
| 235 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0); | |
| 236 | |
| 237 simulateEnterFullscreen(); | |
| 238 | |
| 239 checkStatePendingMetadata(); | |
| 240 } | |
| 241 | |
| 242 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenNoMetadata) { | |
| 243 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0); | |
| 244 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0); | |
| 245 | |
| 246 simulateEnterFullscreen(); | |
| 247 // State set to PendingMetadata. | |
| 248 simulateExitFullscreen(); | |
| 249 | |
| 250 checkStatePendingFullscreen(); | |
| 251 } | |
| 252 | |
| 253 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenWithMetadata) { | |
| 254 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 255 | |
| 256 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1); | |
| 257 EXPECT_FALSE(delegateWillUnlockFullscreen()); | |
| 258 | |
| 259 simulateEnterFullscreen(); | |
| 260 | |
| 261 EXPECT_TRUE(delegateWillUnlockFullscreen()); | |
| 262 checkStateMaybeLockedFullscreen(); | |
| 263 } | |
| 264 | |
| 265 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenWithMetadata) { | |
| 266 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 267 | |
| 268 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1); | |
| 269 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(1); | |
| 270 | |
| 271 simulateEnterFullscreen(); | |
| 272 // State set to MaybeLockedFullscreen. | |
| 273 simulateExitFullscreen(); | |
| 274 | |
| 275 EXPECT_FALSE(delegateWillUnlockFullscreen()); | |
| 276 checkStatePendingFullscreen(); | |
| 277 } | |
| 278 | |
| 279 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenAfterPageLock) { | |
| 280 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 281 simulateOrientationLock(); | |
| 282 | |
| 283 EXPECT_FALSE(delegateWillUnlockFullscreen()); | |
| 284 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0); | |
| 285 | |
| 286 simulateEnterFullscreen(); | |
| 287 | |
| 288 EXPECT_FALSE(delegateWillUnlockFullscreen()); | |
| 289 checkStateMaybeLockedFullscreen(); | |
| 290 } | |
| 291 | |
| 292 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenAfterPageLock) { | |
| 293 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 294 simulateOrientationLock(); | |
| 295 | |
| 296 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0); | |
| 297 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0); | |
| 298 | |
| 299 simulateEnterFullscreen(); | |
| 300 // State set to MaybeLockedFullscreen. | |
| 301 simulateExitFullscreen(); | |
| 302 | |
| 303 EXPECT_FALSE(delegateWillUnlockFullscreen()); | |
| 304 checkStatePendingFullscreen(); | |
| 305 } | |
| 306 | |
| 307 TEST_F(MediaControlsOrientationLockDelegateTest, | |
| 308 ReceivedMetadataAfterExitingFullscreen) { | |
| 309 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1); | |
| 310 | |
| 311 simulateEnterFullscreen(); | |
| 312 // State set to PendingMetadata. | |
| 313 | |
| 314 // Set up the WebMediaPlayer instance. | |
| 315 video().setSrc("http://example.com"); | |
| 316 testing::runPendingTasks(); | |
| 317 | |
| 318 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle); | |
| 319 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 320 testing::runPendingTasks(); | |
| 321 | |
| 322 checkStateMaybeLockedFullscreen(); | |
| 323 } | |
| 324 | |
| 325 TEST_F(MediaControlsOrientationLockDelegateTest, ReceivedMetadataLater) { | |
| 326 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0); | |
| 327 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0); | |
| 328 | |
| 329 simulateEnterFullscreen(); | |
| 330 // State set to PendingMetadata. | |
| 331 simulateExitFullscreen(); | |
| 332 | |
| 333 // Set up the WebMediaPlayer instance. | |
| 334 video().setSrc("http://example.com"); | |
| 335 testing::runPendingTasks(); | |
| 336 | |
| 337 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle); | |
| 338 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 339 testing::runPendingTasks(); | |
| 340 | |
| 341 checkStatePendingFullscreen(); | |
| 342 } | |
| 343 | |
| 344 TEST_F(MediaControlsOrientationLockDelegateTest, ComputeOrientationLock) { | |
| 345 // Set up the WebMediaPlayer instance. | |
| 346 video().setSrc("http://example.com"); | |
| 347 testing::runPendingTasks(); | |
| 348 | |
| 349 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle); | |
| 350 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata); | |
| 351 | |
| 352 EXPECT_CALL(mockWebMediaPlayer(), naturalSize()) | |
| 353 .Times(14) // Each `computeOrientationLock` calls the method twice. | |
| 354 .WillOnce(Return(WebSize(100, 50))) | |
| 355 .WillOnce(Return(WebSize(100, 50))) | |
| 356 .WillOnce(Return(WebSize(50, 100))) | |
| 357 .WillOnce(Return(WebSize(50, 100))) | |
| 358 .WillRepeatedly(Return(WebSize(100, 100))); | |
| 359 | |
| 360 // 100x50 | |
| 361 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock()); | |
| 362 | |
| 363 // 50x100 | |
| 364 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock()); | |
| 365 | |
| 366 // 100x100 has more subtilities, it depends on the current screen orientation. | |
| 367 WebScreenInfo screenInfo; | |
| 368 screenInfo.orientationType = WebScreenOrientationUndefined; | |
| 369 EXPECT_CALL(chromeClient(), screenInfo()) | |
| 370 .Times(1) | |
| 371 .WillOnce(Return(screenInfo)); | |
| 372 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock()); | |
| 373 | |
| 374 screenInfo.orientationType = WebScreenOrientationPortraitPrimary; | |
| 375 EXPECT_CALL(chromeClient(), screenInfo()) | |
| 376 .Times(1) | |
| 377 .WillOnce(Return(screenInfo)); | |
| 378 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock()); | |
| 379 | |
| 380 screenInfo.orientationType = WebScreenOrientationPortraitPrimary; | |
| 381 EXPECT_CALL(chromeClient(), screenInfo()) | |
| 382 .Times(1) | |
| 383 .WillOnce(Return(screenInfo)); | |
| 384 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock()); | |
| 385 | |
| 386 screenInfo.orientationType = WebScreenOrientationLandscapePrimary; | |
| 387 EXPECT_CALL(chromeClient(), screenInfo()) | |
| 388 .Times(1) | |
| 389 .WillOnce(Return(screenInfo)); | |
| 390 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock()); | |
| 391 | |
| 392 screenInfo.orientationType = WebScreenOrientationLandscapeSecondary; | |
| 393 EXPECT_CALL(chromeClient(), screenInfo()) | |
| 394 .Times(1) | |
| 395 .WillOnce(Return(screenInfo)); | |
| 396 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock()); | |
| 397 } | |
| 398 | |
| 399 } // namespace blink | |
| OLD | NEW |