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

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

Powered by Google App Engine
This is Rietveld 408576698