OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/html/shadow/MediaControls.h" | 5 #include "core/html/shadow/MediaControls.h" |
6 | 6 |
7 #include "core/HTMLNames.h" | 7 #include "core/HTMLNames.h" |
8 #include "core/css/StylePropertySet.h" | 8 #include "core/css/StylePropertySet.h" |
9 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
10 #include "core/dom/ElementTraversal.h" | 10 #include "core/dom/ElementTraversal.h" |
11 #include "core/dom/StyleEngine.h" | 11 #include "core/dom/StyleEngine.h" |
12 #include "core/frame/Settings.h" | 12 #include "core/frame/Settings.h" |
13 #include "core/html/HTMLVideoElement.h" | 13 #include "core/html/HTMLVideoElement.h" |
| 14 #include "core/loader/EmptyClients.h" |
14 #include "core/testing/DummyPageHolder.h" | 15 #include "core/testing/DummyPageHolder.h" |
15 #include "platform/heap/Handle.h" | 16 #include "platform/heap/Handle.h" |
| 17 #include "platform/testing/UnitTestHelpers.h" |
| 18 #include "public/platform/WebMediaPlayer.h" |
| 19 #include "public/platform/WebSize.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
17 #include <memory> | 21 #include <memory> |
18 | 22 |
19 namespace blink { | 23 namespace blink { |
20 | 24 |
21 namespace { | 25 namespace { |
22 | 26 |
| 27 class MockVideoWebMediaPlayer : public WebMediaPlayer { |
| 28 public: |
| 29 void load(LoadType, const WebMediaPlayerSource&, CORSMode) override{}; |
| 30 void play() override{}; |
| 31 void pause() override{}; |
| 32 bool supportsSave() const override { return false; }; |
| 33 void seek(double seconds) override{}; |
| 34 void setRate(double) override{}; |
| 35 void setVolume(double) override{}; |
| 36 WebTimeRanges buffered() const override { return WebTimeRanges(); }; |
| 37 WebTimeRanges seekable() const override { return WebTimeRanges(); }; |
| 38 void setSinkId(const WebString& sinkId, |
| 39 const WebSecurityOrigin&, |
| 40 WebSetSinkIdCallbacks*) override{}; |
| 41 bool hasVideo() const override { return true; }; |
| 42 bool hasAudio() const override { return false; }; |
| 43 WebSize naturalSize() const override { return WebSize(0, 0); }; |
| 44 bool paused() const override { return false; }; |
| 45 bool seeking() const override { return false; }; |
| 46 double duration() const override { return 0.0; }; |
| 47 double currentTime() const override { return 0.0; }; |
| 48 NetworkState getNetworkState() const override { return NetworkStateEmpty; }; |
| 49 ReadyState getReadyState() const override { return ReadyStateHaveNothing; }; |
| 50 WebString getErrorMessage() override { return WebString(); }; |
| 51 bool didLoadingProgress() override { return false; }; |
| 52 bool hasSingleSecurityOrigin() const override { return true; }; |
| 53 bool didPassCORSAccessCheck() const override { return true; }; |
| 54 double mediaTimeForTimeValue(double timeValue) const override { |
| 55 return timeValue; |
| 56 }; |
| 57 unsigned decodedFrameCount() const override { return 0; }; |
| 58 unsigned droppedFrameCount() const override { return 0; }; |
| 59 size_t audioDecodedByteCount() const override { return 0; }; |
| 60 size_t videoDecodedByteCount() const override { return 0; }; |
| 61 void paint(WebCanvas*, const WebRect&, SkPaint&) override{}; |
| 62 }; |
| 63 |
| 64 class StubFrameLoaderClient : public EmptyFrameLoaderClient { |
| 65 public: |
| 66 static StubFrameLoaderClient* create() { return new StubFrameLoaderClient; } |
| 67 |
| 68 std::unique_ptr<WebMediaPlayer> createWebMediaPlayer( |
| 69 HTMLMediaElement&, |
| 70 const WebMediaPlayerSource&, |
| 71 WebMediaPlayerClient*) override { |
| 72 return wrapUnique(new MockVideoWebMediaPlayer); |
| 73 } |
| 74 }; |
| 75 |
23 Element* getElementByShadowPseudoId(Node& rootNode, | 76 Element* getElementByShadowPseudoId(Node& rootNode, |
24 const char* shadowPseudoId) { | 77 const char* shadowPseudoId) { |
25 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { | 78 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { |
26 if (element.shadowPseudoId() == shadowPseudoId) | 79 if (element.shadowPseudoId() == shadowPseudoId) |
27 return &element; | 80 return &element; |
28 } | 81 } |
29 return nullptr; | 82 return nullptr; |
30 } | 83 } |
31 | 84 |
32 bool isElementVisible(Element& element) { | 85 bool isElementVisible(Element& element) { |
33 const StylePropertySet* inlineStyle = element.inlineStyle(); | 86 const StylePropertySet* inlineStyle = element.inlineStyle(); |
34 | 87 |
35 if (!inlineStyle) | 88 if (!inlineStyle) |
36 return true; | 89 return true; |
37 | 90 |
38 if (inlineStyle->getPropertyValue(CSSPropertyDisplay) == "none") | 91 if (inlineStyle->getPropertyValue(CSSPropertyDisplay) == "none") |
39 return false; | 92 return false; |
40 | 93 |
41 if (inlineStyle->hasProperty(CSSPropertyOpacity) && | 94 if (inlineStyle->hasProperty(CSSPropertyOpacity) && |
42 inlineStyle->getPropertyValue(CSSPropertyOpacity).toDouble() == 0.0) | 95 inlineStyle->getPropertyValue(CSSPropertyOpacity).toDouble() == 0.0) { |
43 return false; | 96 return false; |
| 97 } |
44 | 98 |
45 if (inlineStyle->getPropertyValue(CSSPropertyVisibility) == "hidden") | 99 if (inlineStyle->getPropertyValue(CSSPropertyVisibility) == "hidden") |
46 return false; | 100 return false; |
47 | 101 |
48 if (Element* parent = element.parentElement()) | 102 if (Element* parent = element.parentElement()) |
49 return isElementVisible(*parent); | 103 return isElementVisible(*parent); |
50 | 104 |
51 return true; | 105 return true; |
52 } | 106 } |
53 | 107 |
54 } // namespace | 108 } // namespace |
55 | 109 |
56 class MediaControlsTest : public testing::Test { | 110 class MediaControlsTest : public ::testing::Test { |
57 protected: | 111 protected: |
58 virtual void SetUp() { | 112 virtual void SetUp() { |
59 m_pageHolder = DummyPageHolder::create(IntSize(800, 600)); | 113 m_pageHolder = DummyPageHolder::create(IntSize(800, 600), nullptr, |
| 114 StubFrameLoaderClient::create()); |
60 Document& document = this->document(); | 115 Document& document = this->document(); |
61 | 116 |
62 document.write("<video>"); | 117 document.write("<video>"); |
63 HTMLVideoElement& video = | 118 HTMLVideoElement& video = |
64 toHTMLVideoElement(*document.querySelector("video")); | 119 toHTMLVideoElement(*document.querySelector("video")); |
65 m_mediaControls = video.mediaControls(); | 120 m_mediaControls = video.mediaControls(); |
66 | 121 |
67 // If scripts are not enabled, controls will always be shown. | 122 // If scripts are not enabled, controls will always be shown. |
68 m_pageHolder->frame().settings()->setScriptEnabled(true); | 123 m_pageHolder->frame().settings()->setScriptEnabled(true); |
69 } | 124 } |
70 | 125 |
71 void simulateRouteAvailabe() { | 126 void simulateRouteAvailabe() { |
72 m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(true); | 127 m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(true); |
73 } | 128 } |
74 | 129 |
75 void ensureLayout() { | 130 void ensureLayout() { |
76 // Force a relayout, so that the controls know the width. Otherwise, | 131 // Force a relayout, so that the controls know the width. Otherwise, |
77 // they don't know if, for example, the cast button will fit. | 132 // they don't know if, for example, the cast button will fit. |
78 m_mediaControls->mediaElement().clientWidth(); | 133 m_mediaControls->mediaElement().clientWidth(); |
79 } | 134 } |
80 | 135 |
| 136 void simulateHideMediaControlsTimerFired() { |
| 137 m_mediaControls->hideMediaControlsTimerFired(nullptr); |
| 138 } |
| 139 |
81 MediaControls& mediaControls() { return *m_mediaControls; } | 140 MediaControls& mediaControls() { return *m_mediaControls; } |
82 Document& document() { return m_pageHolder->document(); } | 141 Document& document() { return m_pageHolder->document(); } |
83 | 142 |
84 private: | 143 private: |
85 std::unique_ptr<DummyPageHolder> m_pageHolder; | 144 std::unique_ptr<DummyPageHolder> m_pageHolder; |
86 Persistent<MediaControls> m_mediaControls; | 145 Persistent<MediaControls> m_mediaControls; |
87 }; | 146 }; |
88 | 147 |
89 TEST_F(MediaControlsTest, HideAndShow) { | 148 TEST_F(MediaControlsTest, HideAndShow) { |
90 mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, | 149 mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 HTMLNames::disableremoteplaybackAttr, true); | 251 HTMLNames::disableremoteplaybackAttr, true); |
193 simulateRouteAvailabe(); | 252 simulateRouteAvailabe(); |
194 ASSERT_FALSE(isElementVisible(*castOverlayButton)); | 253 ASSERT_FALSE(isElementVisible(*castOverlayButton)); |
195 | 254 |
196 mediaControls().mediaElement().setBooleanAttribute( | 255 mediaControls().mediaElement().setBooleanAttribute( |
197 HTMLNames::disableremoteplaybackAttr, false); | 256 HTMLNames::disableremoteplaybackAttr, false); |
198 mediaControls().reset(); | 257 mediaControls().reset(); |
199 ASSERT_TRUE(isElementVisible(*castOverlayButton)); | 258 ASSERT_TRUE(isElementVisible(*castOverlayButton)); |
200 } | 259 } |
201 | 260 |
| 261 TEST_F(MediaControlsTest, KeepControlsVisibleIfOverflowListVisible) { |
| 262 Element* overflowList = getElementByShadowPseudoId( |
| 263 mediaControls(), "-internal-media-controls-overflow-menu-list"); |
| 264 ASSERT_NE(nullptr, overflowList); |
| 265 |
| 266 Element* panel = getElementByShadowPseudoId(mediaControls(), |
| 267 "-webkit-media-controls-panel"); |
| 268 ASSERT_NE(nullptr, panel); |
| 269 |
| 270 mediaControls().mediaElement().setSrc("http://example.com"); |
| 271 mediaControls().mediaElement().play(); |
| 272 testing::runPendingTasks(); |
| 273 |
| 274 mediaControls().show(); |
| 275 mediaControls().toggleOverflowMenu(); |
| 276 EXPECT_TRUE(isElementVisible(*overflowList)); |
| 277 |
| 278 simulateHideMediaControlsTimerFired(); |
| 279 EXPECT_TRUE(isElementVisible(*overflowList)); |
| 280 EXPECT_TRUE(isElementVisible(*panel)); |
| 281 } |
| 282 |
202 } // namespace blink | 283 } // namespace blink |
OLD | NEW |