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

Side by Side Diff: third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegateTest.cpp

Issue 2556573003: Media: lock orientation when <video> goes fullscreen. (Closed)
Patch Set: review comments Created 4 years 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
« no previous file with comments | « third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegate.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/UnitTestHelpers.h"
18 #include "public/platform/WebMediaPlayer.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 WebMediaPlayer {
40 public:
41 void load(LoadType, const WebMediaPlayerSource&, CORSMode) override{};
42 void play() override{};
43 void pause() override{};
44 bool supportsSave() const override { return false; };
45 void seek(double seconds) override{};
46 void setRate(double) override{};
47 void setVolume(double) override{};
48 WebTimeRanges buffered() const override { return WebTimeRanges(); };
49 WebTimeRanges seekable() const override { return WebTimeRanges(); };
50 void setSinkId(const WebString& sinkId,
51 const WebSecurityOrigin&,
52 WebSetSinkIdCallbacks*) override{};
53 bool hasVideo() const override { return true; };
54 bool hasAudio() const override { return false; };
55 bool paused() const override { return false; };
56 bool seeking() const override { return false; };
57 double duration() const override { return 0.0; };
58 double currentTime() const override { return 0.0; };
59 NetworkState getNetworkState() const override { return NetworkStateEmpty; };
60 ReadyState getReadyState() const override { return ReadyStateHaveNothing; };
61 WebString getErrorMessage() override { return WebString(); };
62 bool didLoadingProgress() override { return false; };
63 bool hasSingleSecurityOrigin() const override { return true; };
64 bool didPassCORSAccessCheck() const override { return true; };
65 double mediaTimeForTimeValue(double timeValue) const override {
66 return timeValue;
67 };
68 unsigned decodedFrameCount() const override { return 0; };
69 unsigned droppedFrameCount() const override { return 0; };
70 size_t audioDecodedByteCount() const override { return 0; };
71 size_t videoDecodedByteCount() const override { return 0; };
72 void paint(WebCanvas*, const WebRect&, SkPaint&) override{};
73
74 MOCK_CONST_METHOD0(naturalSize, WebSize());
75 };
76
77 class MockChromeClient : public EmptyChromeClient {
78 public:
79 MOCK_CONST_METHOD0(screenInfo, WebScreenInfo());
80 };
81
82 class StubFrameLoaderClient : public EmptyFrameLoaderClient {
83 public:
84 static StubFrameLoaderClient* create() { return new StubFrameLoaderClient; }
85
86 std::unique_ptr<WebMediaPlayer> createWebMediaPlayer(
87 HTMLMediaElement&,
88 const WebMediaPlayerSource&,
89 WebMediaPlayerClient*) override {
90 return WTF::wrapUnique(new MockVideoWebMediaPlayer());
91 }
92 };
93
94 class MockScreenOrientationController final
95 : public GarbageCollectedFinalized<MockScreenOrientationController>,
96 public ScreenOrientationController {
97 USING_GARBAGE_COLLECTED_MIXIN(MockScreenOrientationController);
98 WTF_MAKE_NONCOPYABLE(MockScreenOrientationController);
99
100 public:
101 static MockScreenOrientationController* provideTo(LocalFrame& frame) {
102 MockScreenOrientationController* controller =
103 new MockScreenOrientationController();
104 ScreenOrientationController::provideTo(frame, controller);
105 return controller;
106 }
107
108 MOCK_METHOD1(lock, void(WebScreenOrientationLockType));
109 MOCK_METHOD0(mockUnlock, void());
110
111 DEFINE_INLINE_VIRTUAL_TRACE() { Supplement<LocalFrame>::trace(visitor); }
112
113 private:
114 MockScreenOrientationController() = default;
115
116 void lock(WebScreenOrientationLockType type,
117 std::unique_ptr<WebLockOrientationCallback>) override {
118 m_locked = true;
119 lock(type);
120 }
121
122 void unlock() override {
123 m_locked = false;
124 mockUnlock();
125 }
126
127 bool maybeHasActiveLock() const override { return m_locked; }
128
129 bool m_locked = false;
130 };
131
132 } // anonymous namespace
133
134 class MediaControlsOrientationLockDelegateTest : public ::testing::Test {
135 protected:
136 void SetUp() override {
137 m_previousVideoFullscreenOrientationLockValue =
138 RuntimeEnabledFeatures::videoFullscreenOrientationLockEnabled();
139 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(true);
140
141 m_chromeClient = new MockChromeClient();
142
143 Page::PageClients clients;
144 fillWithEmptyClients(clients);
145 clients.chromeClient = m_chromeClient.get();
146
147 m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients,
148 StubFrameLoaderClient::create());
149
150 document().write("<body><video></body>");
151 m_video = toHTMLVideoElement(*document().querySelector("video"));
152
153 m_screenOrientationController =
154 MockScreenOrientationController::provideTo(m_pageHolder->frame());
155 }
156
157 void TearDown() override {
158 ::testing::Mock::VerifyAndClear(&screenOrientationController());
159
160 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(
161 m_previousVideoFullscreenOrientationLockValue);
162 }
163
164 static bool hasDelegate(const MediaControls& mediaControls) {
165 return !!mediaControls.m_orientationLockDelegate;
166 }
167
168 void simulateEnterFullscreen() {
169 UserGestureIndicator gesture(DocumentUserGestureToken::create(&document()));
170
171 Fullscreen::requestFullscreen(video());
172 Fullscreen::from(document()).didEnterFullscreen();
173 testing::runPendingTasks();
174 }
175
176 void simulateExitFullscreen() {
177 Fullscreen::exitFullscreen(document());
178 Fullscreen::from(document()).didExitFullscreen();
179 testing::runPendingTasks();
180 }
181
182 void simulateOrientationLock() {
183 ScreenOrientationController* controller =
184 ScreenOrientationController::from(*document().frame());
185 controller->lock(WebScreenOrientationLockLandscape,
186 WTF::wrapUnique(new DummyScreenOrientationCallback));
187 EXPECT_TRUE(controller->maybeHasActiveLock());
188 }
189
190 void simulateVideoReadyState(HTMLMediaElement::ReadyState state) {
191 video().setReadyState(state);
192 }
193
194 void simulateVideoNetworkState(HTMLMediaElement::NetworkState state) {
195 video().setNetworkState(state);
196 }
197
198 void checkStatePendingFullscreen() const {
199 EXPECT_EQ(MediaControlsOrientationLockDelegate::State::PendingFullscreen,
200 m_video->mediaControls()->m_orientationLockDelegate->m_state);
201 }
202
203 void checkStatePendingMetadata() const {
204 EXPECT_EQ(MediaControlsOrientationLockDelegate::State::PendingMetadata,
205 m_video->mediaControls()->m_orientationLockDelegate->m_state);
206 }
207
208 void checkStateMaybeLockedFullscreen() const {
209 EXPECT_EQ(
210 MediaControlsOrientationLockDelegate::State::MaybeLockedFullscreen,
211 m_video->mediaControls()->m_orientationLockDelegate->m_state);
212 }
213
214 bool delegateWillUnlockFullscreen() const {
215 return m_video->mediaControls()
216 ->m_orientationLockDelegate->m_shouldUnlockOrientation;
217 }
218
219 WebScreenOrientationLockType computeOrientationLock() const {
220 return m_video->mediaControls()
221 ->m_orientationLockDelegate->computeOrientationLock();
222 }
223
224 MockChromeClient& chromeClient() const { return *m_chromeClient; }
225
226 HTMLVideoElement& video() const { return *m_video; }
227 Document& document() const { return m_pageHolder->document(); }
228 MockScreenOrientationController& screenOrientationController() const {
229 return *m_screenOrientationController;
230 }
231 MockVideoWebMediaPlayer& mockWebMediaPlayer() const {
232 return *static_cast<MockVideoWebMediaPlayer*>(video().webMediaPlayer());
233 }
234
235 private:
236 bool m_previousVideoFullscreenOrientationLockValue;
237 std::unique_ptr<DummyPageHolder> m_pageHolder;
238 Persistent<HTMLVideoElement> m_video;
239 Persistent<MockScreenOrientationController> m_screenOrientationController;
240 Persistent<MockChromeClient> m_chromeClient;
241 };
242
243 TEST_F(MediaControlsOrientationLockDelegateTest, DelegateRequiresFlag) {
244 // Flag on by default.
245 EXPECT_TRUE(hasDelegate(*video().mediaControls()));
246
247 // Same with flag off.
248 RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(false);
249 HTMLVideoElement* video = HTMLVideoElement::create(document());
250 document().body()->appendChild(video);
251 EXPECT_FALSE(hasDelegate(*video->mediaControls()));
252 }
253
254 TEST_F(MediaControlsOrientationLockDelegateTest, DelegateRequiresVideo) {
255 HTMLAudioElement* audio = HTMLAudioElement::create(document());
256 document().body()->appendChild(audio);
257 EXPECT_FALSE(hasDelegate(*audio->mediaControls()));
258 }
259
260 TEST_F(MediaControlsOrientationLockDelegateTest, InitialState) {
261 checkStatePendingFullscreen();
262 }
263
264 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenNoMetadata) {
265 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0);
266
267 simulateEnterFullscreen();
268
269 checkStatePendingMetadata();
270 }
271
272 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenNoMetadata) {
273 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0);
274 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0);
275
276 simulateEnterFullscreen();
277 // State set to PendingMetadata.
278 simulateExitFullscreen();
279
280 checkStatePendingFullscreen();
281 }
282
283 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenWithMetadata) {
284 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
285
286 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1);
287 EXPECT_FALSE(delegateWillUnlockFullscreen());
288
289 simulateEnterFullscreen();
290
291 EXPECT_TRUE(delegateWillUnlockFullscreen());
292 checkStateMaybeLockedFullscreen();
293 }
294
295 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenWithMetadata) {
296 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
297
298 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1);
299 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(1);
300
301 simulateEnterFullscreen();
302 // State set to MaybeLockedFullscreen.
303 simulateExitFullscreen();
304
305 EXPECT_FALSE(delegateWillUnlockFullscreen());
306 checkStatePendingFullscreen();
307 }
308
309 TEST_F(MediaControlsOrientationLockDelegateTest, EnterFullscreenAfterPageLock) {
310 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
311 simulateOrientationLock();
312
313 EXPECT_FALSE(delegateWillUnlockFullscreen());
314 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0);
315
316 simulateEnterFullscreen();
317
318 EXPECT_FALSE(delegateWillUnlockFullscreen());
319 checkStateMaybeLockedFullscreen();
320 }
321
322 TEST_F(MediaControlsOrientationLockDelegateTest, LeaveFullscreenAfterPageLock) {
323 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
324 simulateOrientationLock();
325
326 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0);
327 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0);
328
329 simulateEnterFullscreen();
330 // State set to MaybeLockedFullscreen.
331 simulateExitFullscreen();
332
333 EXPECT_FALSE(delegateWillUnlockFullscreen());
334 checkStatePendingFullscreen();
335 }
336
337 TEST_F(MediaControlsOrientationLockDelegateTest,
338 ReceivedMetadataAfterExitingFullscreen) {
339 EXPECT_CALL(screenOrientationController(), lock(_)).Times(1);
340
341 simulateEnterFullscreen();
342 // State set to PendingMetadata.
343
344 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle);
345 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
346 testing::runPendingTasks();
347
348 checkStateMaybeLockedFullscreen();
349 }
350
351 TEST_F(MediaControlsOrientationLockDelegateTest, ReceivedMetadataLater) {
352 EXPECT_CALL(screenOrientationController(), lock(_)).Times(0);
353 EXPECT_CALL(screenOrientationController(), mockUnlock()).Times(0);
354
355 simulateEnterFullscreen();
356 // State set to PendingMetadata.
357 simulateExitFullscreen();
358
359 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle);
360 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
361 testing::runPendingTasks();
362
363 checkStatePendingFullscreen();
364 }
365
366 TEST_F(MediaControlsOrientationLockDelegateTest, ComputeOrientationLock) {
367 // Set up the WebMediaPlayer instance.
368 video().setSrc("http://example.com");
369 testing::runPendingTasks();
370
371 simulateVideoNetworkState(HTMLMediaElement::kNetworkIdle);
372 simulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
373
374 EXPECT_CALL(mockWebMediaPlayer(), naturalSize())
375 .Times(14) // Each `computeOrientationLock` calls the method twice.
376 .WillOnce(Return(WebSize(100, 50)))
377 .WillOnce(Return(WebSize(100, 50)))
378 .WillOnce(Return(WebSize(50, 100)))
379 .WillOnce(Return(WebSize(50, 100)))
380 .WillRepeatedly(Return(WebSize(100, 100)));
381
382 // 100x50
383 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock());
384
385 // 50x100
386 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock());
387
388 // 100x100 has more subtilities, it depends on the current screen orientation.
389 WebScreenInfo screenInfo;
390 screenInfo.orientationType = WebScreenOrientationUndefined;
391 EXPECT_CALL(chromeClient(), screenInfo())
392 .Times(1)
393 .WillOnce(Return(screenInfo));
394 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock());
395
396 screenInfo.orientationType = WebScreenOrientationPortraitPrimary;
397 EXPECT_CALL(chromeClient(), screenInfo())
398 .Times(1)
399 .WillOnce(Return(screenInfo));
400 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock());
401
402 screenInfo.orientationType = WebScreenOrientationPortraitPrimary;
403 EXPECT_CALL(chromeClient(), screenInfo())
404 .Times(1)
405 .WillOnce(Return(screenInfo));
406 EXPECT_EQ(WebScreenOrientationLockPortrait, computeOrientationLock());
407
408 screenInfo.orientationType = WebScreenOrientationLandscapePrimary;
409 EXPECT_CALL(chromeClient(), screenInfo())
410 .Times(1)
411 .WillOnce(Return(screenInfo));
412 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock());
413
414 screenInfo.orientationType = WebScreenOrientationLandscapeSecondary;
415 EXPECT_CALL(chromeClient(), screenInfo())
416 .Times(1)
417 .WillOnce(Return(screenInfo));
418 EXPECT_EQ(WebScreenOrientationLockLandscape, computeOrientationLock());
419 }
420
421 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegate.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698