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 "modules/media_controls/MediaControlsImpl.h" | 5 #include "modules/media_controls/MediaControlsImpl.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <memory> | 8 #include <memory> |
9 #include "core/HTMLNames.h" | 9 #include "core/HTMLNames.h" |
10 #include "core/css/StylePropertySet.h" | 10 #include "core/css/StylePropertySet.h" |
11 #include "core/dom/ClientRect.h" | 11 #include "core/dom/ClientRect.h" |
12 #include "core/dom/Document.h" | 12 #include "core/dom/Document.h" |
13 #include "core/dom/ElementTraversal.h" | 13 #include "core/dom/ElementTraversal.h" |
14 #include "core/dom/StyleEngine.h" | 14 #include "core/dom/StyleEngine.h" |
15 #include "core/events/Event.h" | 15 #include "core/events/Event.h" |
16 #include "core/frame/Settings.h" | 16 #include "core/frame/Settings.h" |
17 #include "core/html/HTMLElement.h" | 17 #include "core/html/HTMLElement.h" |
18 #include "core/html/HTMLVideoElement.h" | 18 #include "core/html/HTMLVideoElement.h" |
19 #include "core/html/shadow/MediaControlElementTypes.h" | 19 #include "core/html/shadow/MediaControlElementTypes.h" |
20 #include "core/input/EventHandler.h" | 20 #include "core/input/EventHandler.h" |
21 #include "core/layout/LayoutObject.h" | 21 #include "core/layout/LayoutObject.h" |
22 #include "core/loader/EmptyClients.h" | 22 #include "core/loader/EmptyClients.h" |
23 #include "core/testing/DummyPageHolder.h" | 23 #include "core/testing/DummyPageHolder.h" |
24 #include "modules/media_controls/elements/MediaControlCurrentTimeDisplayElement.
h" | 24 #include "modules/media_controls/elements/MediaControlCurrentTimeDisplayElement.
h" |
25 #include "modules/media_controls/elements/MediaControlDownloadButtonElement.h" | 25 #include "modules/media_controls/elements/MediaControlDownloadButtonElement.h" |
26 #include "modules/media_controls/elements/MediaControlTimelineElement.h" | 26 #include "modules/media_controls/elements/MediaControlTimelineElement.h" |
27 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h" | 27 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h" |
| 28 #include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h" |
| 29 #include "modules/remoteplayback/RemotePlayback.h" |
28 #include "platform/heap/Handle.h" | 30 #include "platform/heap/Handle.h" |
29 #include "platform/testing/EmptyWebMediaPlayer.h" | 31 #include "platform/testing/EmptyWebMediaPlayer.h" |
30 #include "platform/testing/HistogramTester.h" | 32 #include "platform/testing/HistogramTester.h" |
31 #include "platform/testing/TestingPlatformSupport.h" | 33 #include "platform/testing/TestingPlatformSupport.h" |
32 #include "platform/testing/UnitTestHelpers.h" | 34 #include "platform/testing/UnitTestHelpers.h" |
33 #include "public/platform/WebMouseEvent.h" | 35 #include "public/platform/WebMouseEvent.h" |
34 #include "public/platform/WebScreenInfo.h" | 36 #include "public/platform/WebScreenInfo.h" |
35 #include "public/platform/WebSize.h" | 37 #include "public/platform/WebSize.h" |
36 #include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
" | 38 #include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
" |
37 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h" | 39 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h" |
(...skipping 15 matching lines...) Expand all Loading... |
53 | 55 |
54 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { | 56 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { |
55 public: | 57 public: |
56 // WebMediaPlayer overrides: | 58 // WebMediaPlayer overrides: |
57 WebTimeRanges Seekable() const override { return seekable_; } | 59 WebTimeRanges Seekable() const override { return seekable_; } |
58 bool HasVideo() const override { return true; } | 60 bool HasVideo() const override { return true; } |
59 | 61 |
60 WebTimeRanges seekable_; | 62 WebTimeRanges seekable_; |
61 }; | 63 }; |
62 | 64 |
63 class MockWebRemotePlaybackClient : public WebRemotePlaybackClient { | |
64 public: | |
65 void StateChanged(WebRemotePlaybackState) override {} | |
66 void AvailabilityChanged( | |
67 WebRemotePlaybackAvailability availability) override { | |
68 availability_ = availability; | |
69 } | |
70 void PromptCancelled() override {} | |
71 bool RemotePlaybackAvailable() const override { | |
72 return availability_ == WebRemotePlaybackAvailability::kDeviceAvailable; | |
73 } | |
74 | |
75 private: | |
76 WebRemotePlaybackAvailability availability_ = | |
77 WebRemotePlaybackAvailability::kUnknown; | |
78 }; | |
79 | |
80 class MockLayoutObject : public LayoutObject { | 65 class MockLayoutObject : public LayoutObject { |
81 public: | 66 public: |
82 MockLayoutObject(Node* node) : LayoutObject(node) {} | 67 MockLayoutObject(Node* node) : LayoutObject(node) {} |
83 | 68 |
84 const char* GetName() const override { return "MockLayoutObject"; } | 69 const char* GetName() const override { return "MockLayoutObject"; } |
85 void UpdateLayout() override {} | 70 void UpdateLayout() override {} |
86 FloatRect LocalBoundingBoxRectForAccessibility() const override { | 71 FloatRect LocalBoundingBoxRectForAccessibility() const override { |
87 return FloatRect(); | 72 return FloatRect(); |
88 } | 73 } |
89 }; | 74 }; |
90 | 75 |
91 class StubLocalFrameClient : public EmptyLocalFrameClient { | 76 class StubLocalFrameClient : public EmptyLocalFrameClient { |
92 public: | 77 public: |
93 static StubLocalFrameClient* Create() { return new StubLocalFrameClient; } | 78 static StubLocalFrameClient* Create() { return new StubLocalFrameClient; } |
94 | 79 |
95 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer( | 80 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer( |
96 HTMLMediaElement&, | 81 HTMLMediaElement&, |
97 const WebMediaPlayerSource&, | 82 const WebMediaPlayerSource&, |
98 WebMediaPlayerClient*) override { | 83 WebMediaPlayerClient*) override { |
99 return WTF::WrapUnique(new MockVideoWebMediaPlayer); | 84 return WTF::WrapUnique(new MockVideoWebMediaPlayer); |
100 } | 85 } |
101 | 86 |
102 WebRemotePlaybackClient* CreateWebRemotePlaybackClient( | 87 WebRemotePlaybackClient* CreateWebRemotePlaybackClient( |
103 HTMLMediaElement&) override { | 88 HTMLMediaElement& element) override { |
104 if (!remote_playback_client_) { | 89 return HTMLMediaElementRemotePlayback::remote(element); |
105 remote_playback_client_ = | |
106 WTF::WrapUnique(new MockWebRemotePlaybackClient); | |
107 } | |
108 return remote_playback_client_.get(); | |
109 } | 90 } |
110 | |
111 private: | |
112 std::unique_ptr<MockWebRemotePlaybackClient> remote_playback_client_; | |
113 }; | 91 }; |
114 | 92 |
115 Element* GetElementByShadowPseudoId(Node& root_node, | 93 Element* GetElementByShadowPseudoId(Node& root_node, |
116 const char* shadow_pseudo_id) { | 94 const char* shadow_pseudo_id) { |
117 for (Element& element : ElementTraversal::DescendantsOf(root_node)) { | 95 for (Element& element : ElementTraversal::DescendantsOf(root_node)) { |
118 if (element.ShadowPseudoId() == shadow_pseudo_id) | 96 if (element.ShadowPseudoId() == shadow_pseudo_id) |
119 return &element; | 97 return &element; |
120 } | 98 } |
121 return nullptr; | 99 return nullptr; |
122 } | 100 } |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 | 199 |
222 void SetReady() { | 200 void SetReady() { |
223 MediaControls().MediaElement().SetReadyState( | 201 MediaControls().MediaElement().SetReadyState( |
224 HTMLMediaElement::kHaveEnoughData); | 202 HTMLMediaElement::kHaveEnoughData); |
225 } | 203 } |
226 | 204 |
227 void MouseDownAt(WebFloatPoint pos); | 205 void MouseDownAt(WebFloatPoint pos); |
228 void MouseMoveTo(WebFloatPoint pos); | 206 void MouseMoveTo(WebFloatPoint pos); |
229 void MouseUpAt(WebFloatPoint pos); | 207 void MouseUpAt(WebFloatPoint pos); |
230 | 208 |
| 209 bool HasAvailabilityCallbacks(RemotePlayback* remote_playback) { |
| 210 return !remote_playback->availability_callbacks_.IsEmpty(); |
| 211 } |
| 212 |
231 private: | 213 private: |
232 std::unique_ptr<DummyPageHolder> page_holder_; | 214 std::unique_ptr<DummyPageHolder> page_holder_; |
233 Persistent<MediaControlsImpl> media_controls_; | 215 Persistent<MediaControlsImpl> media_controls_; |
234 HistogramTester histogram_tester_; | 216 HistogramTester histogram_tester_; |
235 }; | 217 }; |
236 | 218 |
237 void MediaControlsImplTest::MouseDownAt(WebFloatPoint pos) { | 219 void MediaControlsImplTest::MouseDownAt(WebFloatPoint pos) { |
238 WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown, | 220 WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown, |
239 pos /* client pos */, pos /* screen pos */, | 221 pos /* client pos */, pos /* screen pos */, |
240 WebPointerProperties::Button::kLeft, 1, | 222 WebPointerProperties::Button::kLeft, 1, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 Element* cast_button = GetElementByShadowPseudoId( | 324 Element* cast_button = GetElementByShadowPseudoId( |
343 MediaControls(), "-internal-media-controls-cast-button"); | 325 MediaControls(), "-internal-media-controls-cast-button"); |
344 ASSERT_NE(nullptr, cast_button); | 326 ASSERT_NE(nullptr, cast_button); |
345 | 327 |
346 ASSERT_FALSE(IsElementVisible(*cast_button)); | 328 ASSERT_FALSE(IsElementVisible(*cast_button)); |
347 SimulateRouteAvailable(); | 329 SimulateRouteAvailable(); |
348 ASSERT_TRUE(IsElementVisible(*cast_button)); | 330 ASSERT_TRUE(IsElementVisible(*cast_button)); |
349 | 331 |
350 MediaControls().MediaElement().SetBooleanAttribute( | 332 MediaControls().MediaElement().SetBooleanAttribute( |
351 HTMLNames::disableremoteplaybackAttr, true); | 333 HTMLNames::disableremoteplaybackAttr, true); |
| 334 testing::RunPendingTasks(); |
352 ASSERT_FALSE(IsElementVisible(*cast_button)); | 335 ASSERT_FALSE(IsElementVisible(*cast_button)); |
353 | 336 |
354 MediaControls().MediaElement().SetBooleanAttribute( | 337 MediaControls().MediaElement().SetBooleanAttribute( |
355 HTMLNames::disableremoteplaybackAttr, false); | 338 HTMLNames::disableremoteplaybackAttr, false); |
| 339 testing::RunPendingTasks(); |
356 ASSERT_TRUE(IsElementVisible(*cast_button)); | 340 ASSERT_TRUE(IsElementVisible(*cast_button)); |
357 } | 341 } |
358 | 342 |
359 TEST_F(MediaControlsImplTest, CastOverlayDefault) { | 343 TEST_F(MediaControlsImplTest, CastOverlayDefault) { |
360 Element* cast_overlay_button = GetElementByShadowPseudoId( | 344 Element* cast_overlay_button = GetElementByShadowPseudoId( |
361 MediaControls(), "-internal-media-controls-overlay-cast-button"); | 345 MediaControls(), "-internal-media-controls-overlay-cast-button"); |
362 ASSERT_NE(nullptr, cast_overlay_button); | 346 ASSERT_NE(nullptr, cast_overlay_button); |
363 | 347 |
364 SimulateRouteAvailable(); | 348 SimulateRouteAvailable(); |
365 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); | 349 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); |
366 } | 350 } |
367 | 351 |
368 TEST_F(MediaControlsImplTest, CastOverlayDisableRemotePlaybackAttr) { | 352 TEST_F(MediaControlsImplTest, CastOverlayDisableRemotePlaybackAttr) { |
369 Element* cast_overlay_button = GetElementByShadowPseudoId( | 353 Element* cast_overlay_button = GetElementByShadowPseudoId( |
370 MediaControls(), "-internal-media-controls-overlay-cast-button"); | 354 MediaControls(), "-internal-media-controls-overlay-cast-button"); |
371 ASSERT_NE(nullptr, cast_overlay_button); | 355 ASSERT_NE(nullptr, cast_overlay_button); |
372 | 356 |
373 ASSERT_FALSE(IsElementVisible(*cast_overlay_button)); | 357 ASSERT_FALSE(IsElementVisible(*cast_overlay_button)); |
374 SimulateRouteAvailable(); | 358 SimulateRouteAvailable(); |
375 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); | 359 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); |
376 | 360 |
377 MediaControls().MediaElement().SetBooleanAttribute( | 361 MediaControls().MediaElement().SetBooleanAttribute( |
378 HTMLNames::disableremoteplaybackAttr, true); | 362 HTMLNames::disableremoteplaybackAttr, true); |
| 363 testing::RunPendingTasks(); |
379 ASSERT_FALSE(IsElementVisible(*cast_overlay_button)); | 364 ASSERT_FALSE(IsElementVisible(*cast_overlay_button)); |
380 | 365 |
381 MediaControls().MediaElement().SetBooleanAttribute( | 366 MediaControls().MediaElement().SetBooleanAttribute( |
382 HTMLNames::disableremoteplaybackAttr, false); | 367 HTMLNames::disableremoteplaybackAttr, false); |
| 368 testing::RunPendingTasks(); |
383 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); | 369 ASSERT_TRUE(IsElementVisible(*cast_overlay_button)); |
384 } | 370 } |
385 | 371 |
386 TEST_F(MediaControlsImplTest, CastOverlayMediaControlsDisabled) { | 372 TEST_F(MediaControlsImplTest, CastOverlayMediaControlsDisabled) { |
387 Element* cast_overlay_button = GetElementByShadowPseudoId( | 373 Element* cast_overlay_button = GetElementByShadowPseudoId( |
388 MediaControls(), "-internal-media-controls-overlay-cast-button"); | 374 MediaControls(), "-internal-media-controls-overlay-cast-button"); |
389 ASSERT_NE(nullptr, cast_overlay_button); | 375 ASSERT_NE(nullptr, cast_overlay_button); |
390 | 376 |
391 EXPECT_FALSE(IsElementVisible(*cast_overlay_button)); | 377 EXPECT_FALSE(IsElementVisible(*cast_overlay_button)); |
392 SimulateRouteAvailable(); | 378 SimulateRouteAvailable(); |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 // Pressing a key prevents controls from hiding. | 826 // Pressing a key prevents controls from hiding. |
841 MediaControls().PanelElement()->DispatchEvent(Event::Create("keypress")); | 827 MediaControls().PanelElement()->DispatchEvent(Event::Create("keypress")); |
842 platform->RunForPeriodSeconds(2); | 828 platform->RunForPeriodSeconds(2); |
843 EXPECT_TRUE(IsElementVisible(*panel)); | 829 EXPECT_TRUE(IsElementVisible(*panel)); |
844 | 830 |
845 // Once user interaction stops, controls can hide. | 831 // Once user interaction stops, controls can hide. |
846 platform->RunForPeriodSeconds(2); | 832 platform->RunForPeriodSeconds(2); |
847 EXPECT_FALSE(IsElementVisible(*panel)); | 833 EXPECT_FALSE(IsElementVisible(*panel)); |
848 } | 834 } |
849 | 835 |
| 836 TEST_F(MediaControlsImplTest, |
| 837 RemovingFromDocumentRemovesListenersAndCallbacks) { |
| 838 auto page_holder = DummyPageHolder::Create(); |
| 839 |
| 840 HTMLMediaElement* element = |
| 841 HTMLVideoElement::Create(page_holder->GetDocument()); |
| 842 element->SetBooleanAttribute(HTMLNames::controlsAttr, true); |
| 843 page_holder->GetDocument().body()->AppendChild(element); |
| 844 |
| 845 RemotePlayback* remote_playback = |
| 846 HTMLMediaElementRemotePlayback::remote(*element); |
| 847 |
| 848 EXPECT_TRUE(remote_playback->HasEventListeners()); |
| 849 EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback)); |
| 850 |
| 851 WeakPersistent<HTMLMediaElement> weak_persistent_video = element; |
| 852 { |
| 853 Persistent<HTMLMediaElement> persistent_video = element; |
| 854 page_holder->GetDocument().body()->setInnerHTML(""); |
| 855 |
| 856 // When removed from the document, the event listeners should have been |
| 857 // dropped. |
| 858 EXPECT_FALSE(remote_playback->HasEventListeners()); |
| 859 EXPECT_FALSE(HasAvailabilityCallbacks(remote_playback)); |
| 860 } |
| 861 |
| 862 testing::RunPendingTasks(); |
| 863 |
| 864 ThreadState::Current()->CollectAllGarbage(); |
| 865 |
| 866 // It has been GC'd. |
| 867 EXPECT_EQ(nullptr, weak_persistent_video); |
| 868 } |
| 869 |
| 870 TEST_F(MediaControlsImplTest, |
| 871 ReInsertingInDocumentRestoresListenersAndCallbacks) { |
| 872 auto page_holder = DummyPageHolder::Create(); |
| 873 |
| 874 HTMLMediaElement* element = |
| 875 HTMLVideoElement::Create(page_holder->GetDocument()); |
| 876 element->SetBooleanAttribute(HTMLNames::controlsAttr, true); |
| 877 page_holder->GetDocument().body()->AppendChild(element); |
| 878 |
| 879 RemotePlayback* remote_playback = |
| 880 HTMLMediaElementRemotePlayback::remote(*element); |
| 881 |
| 882 // This should be a no-op. We keep a reference on the media element to avoid |
| 883 // an unexpected GC. |
| 884 { |
| 885 Persistent<HTMLMediaElement> video_holder = element; |
| 886 page_holder->GetDocument().body()->RemoveChild(element); |
| 887 page_holder->GetDocument().body()->AppendChild(video_holder.Get()); |
| 888 EXPECT_TRUE(remote_playback->HasEventListeners()); |
| 889 EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback)); |
| 890 } |
| 891 } |
| 892 |
850 } // namespace blink | 893 } // namespace blink |
OLD | NEW |