| 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 |