| 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 | 9 |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 11 #include "core/HTMLNames.h" | 11 #include "core/HTMLNames.h" |
| 12 #include "core/css/StylePropertySet.h" | 12 #include "core/css/StylePropertySet.h" |
| 13 #include "core/dom/Document.h" | 13 #include "core/dom/Document.h" |
| 14 #include "core/dom/ElementTraversal.h" | 14 #include "core/dom/ElementTraversal.h" |
| 15 #include "core/dom/StyleEngine.h" | 15 #include "core/dom/StyleEngine.h" |
| 16 #include "core/events/Event.h" | 16 #include "core/events/Event.h" |
| 17 #include "core/frame/Settings.h" | 17 #include "core/frame/Settings.h" |
| 18 #include "core/geometry/DOMRect.h" | 18 #include "core/geometry/DOMRect.h" |
| 19 #include "core/html/HTMLElement.h" | 19 #include "core/html/HTMLElement.h" |
| 20 #include "core/html/HTMLVideoElement.h" | 20 #include "core/html/HTMLVideoElement.h" |
| 21 #include "core/input/EventHandler.h" | 21 #include "core/input/EventHandler.h" |
| 22 #include "core/layout/LayoutObject.h" | 22 #include "core/layout/LayoutObject.h" |
| 23 #include "core/loader/EmptyClients.h" | 23 #include "core/loader/EmptyClients.h" |
| 24 #include "core/testing/DummyPageHolder.h" | 24 #include "core/testing/DummyPageHolder.h" |
| 25 #include "modules/media_controls/MediaDownloadInProductHelpManager.h" |
| 25 #include "modules/media_controls/elements/MediaControlCurrentTimeDisplayElement.
h" | 26 #include "modules/media_controls/elements/MediaControlCurrentTimeDisplayElement.
h" |
| 26 #include "modules/media_controls/elements/MediaControlDownloadButtonElement.h" | 27 #include "modules/media_controls/elements/MediaControlDownloadButtonElement.h" |
| 27 #include "modules/media_controls/elements/MediaControlTimelineElement.h" | 28 #include "modules/media_controls/elements/MediaControlTimelineElement.h" |
| 28 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h" | 29 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h" |
| 29 #include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h" | 30 #include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h" |
| 30 #include "modules/remoteplayback/RemotePlayback.h" | 31 #include "modules/remoteplayback/RemotePlayback.h" |
| 31 #include "platform/RuntimeEnabledFeatures.h" | 32 #include "platform/RuntimeEnabledFeatures.h" |
| 32 #include "platform/heap/Handle.h" | 33 #include "platform/heap/Handle.h" |
| 33 #include "platform/testing/EmptyWebMediaPlayer.h" | 34 #include "platform/testing/EmptyWebMediaPlayer.h" |
| 34 #include "platform/testing/HistogramTester.h" | 35 #include "platform/testing/HistogramTester.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 WebTimeRanges Seekable() const override { return seekable_; } | 70 WebTimeRanges Seekable() const override { return seekable_; } |
| 70 bool HasVideo() const override { return true; } | 71 bool HasVideo() const override { return true; } |
| 71 | 72 |
| 72 WebTimeRanges seekable_; | 73 WebTimeRanges seekable_; |
| 73 }; | 74 }; |
| 74 | 75 |
| 75 class MockLayoutObject : public LayoutObject { | 76 class MockLayoutObject : public LayoutObject { |
| 76 public: | 77 public: |
| 77 MockLayoutObject(Node* node) : LayoutObject(node) {} | 78 MockLayoutObject(Node* node) : LayoutObject(node) {} |
| 78 | 79 |
| 80 void SetVisible(bool visible) { visible_ = visible; } |
| 81 |
| 79 const char* GetName() const override { return "MockLayoutObject"; } | 82 const char* GetName() const override { return "MockLayoutObject"; } |
| 80 void UpdateLayout() override {} | 83 void UpdateLayout() override {} |
| 81 FloatRect LocalBoundingBoxRectForAccessibility() const override { | 84 FloatRect LocalBoundingBoxRectForAccessibility() const override { |
| 82 return FloatRect(); | 85 return FloatRect(); |
| 83 } | 86 } |
| 87 void AbsoluteQuads(Vector<FloatQuad>& quads, |
| 88 MapCoordinatesFlags mode) const override { |
| 89 if (!visible_) |
| 90 return; |
| 91 quads.push_back(FloatQuad(FloatRect(0.f, 0.f, 10.f, 10.f))); |
| 92 } |
| 93 |
| 94 private: |
| 95 bool visible_ = false; |
| 84 }; | 96 }; |
| 85 | 97 |
| 86 class StubLocalFrameClientForImpl : public EmptyLocalFrameClient { | 98 class StubLocalFrameClientForImpl : public EmptyLocalFrameClient { |
| 87 public: | 99 public: |
| 88 static StubLocalFrameClientForImpl* Create() { | 100 static StubLocalFrameClientForImpl* Create() { |
| 89 return new StubLocalFrameClientForImpl; | 101 return new StubLocalFrameClientForImpl; |
| 90 } | 102 } |
| 91 | 103 |
| 92 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer( | 104 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer( |
| 93 HTMLMediaElement&, | 105 HTMLMediaElement&, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 104 | 116 |
| 105 Element* GetElementByShadowPseudoId(Node& root_node, | 117 Element* GetElementByShadowPseudoId(Node& root_node, |
| 106 const char* shadow_pseudo_id) { | 118 const char* shadow_pseudo_id) { |
| 107 for (Element& element : ElementTraversal::DescendantsOf(root_node)) { | 119 for (Element& element : ElementTraversal::DescendantsOf(root_node)) { |
| 108 if (element.ShadowPseudoId() == shadow_pseudo_id) | 120 if (element.ShadowPseudoId() == shadow_pseudo_id) |
| 109 return &element; | 121 return &element; |
| 110 } | 122 } |
| 111 return nullptr; | 123 return nullptr; |
| 112 } | 124 } |
| 113 | 125 |
| 126 MediaControlDownloadButtonElement& GetDownloadButton( |
| 127 MediaControlsImpl& controls) { |
| 128 Element* element = GetElementByShadowPseudoId( |
| 129 controls, "-internal-media-controls-download-button"); |
| 130 return static_cast<MediaControlDownloadButtonElement&>(*element); |
| 131 } |
| 132 |
| 114 bool IsElementVisible(Element& element) { | 133 bool IsElementVisible(Element& element) { |
| 115 const StylePropertySet* inline_style = element.InlineStyle(); | 134 const StylePropertySet* inline_style = element.InlineStyle(); |
| 116 | 135 |
| 117 if (!inline_style) | 136 if (!inline_style) |
| 118 return true; | 137 return true; |
| 119 | 138 |
| 120 if (inline_style->GetPropertyValue(CSSPropertyDisplay) == "none") | 139 if (inline_style->GetPropertyValue(CSSPropertyDisplay) == "none") |
| 121 return false; | 140 return false; |
| 122 | 141 |
| 123 if (inline_style->HasProperty(CSSPropertyOpacity) && | 142 if (inline_style->HasProperty(CSSPropertyOpacity) && |
| (...skipping 27 matching lines...) Expand all Loading... |
| 151 | 170 |
| 152 InitializePage(); | 171 InitializePage(); |
| 153 } | 172 } |
| 154 | 173 |
| 155 void InitializePage() { | 174 void InitializePage() { |
| 156 Page::PageClients clients; | 175 Page::PageClients clients; |
| 157 FillWithEmptyClients(clients); | 176 FillWithEmptyClients(clients); |
| 158 clients.chrome_client = new MockChromeClientForImpl(); | 177 clients.chrome_client = new MockChromeClientForImpl(); |
| 159 page_holder_ = DummyPageHolder::Create( | 178 page_holder_ = DummyPageHolder::Create( |
| 160 IntSize(800, 600), &clients, StubLocalFrameClientForImpl::Create()); | 179 IntSize(800, 600), &clients, StubLocalFrameClientForImpl::Create()); |
| 180 GetDocument().GetSettings()->SetMediaDownloadInProductHelpEnabled( |
| 181 EnableDownloadInProductHelp()); |
| 161 | 182 |
| 162 GetDocument().write("<video>"); | 183 GetDocument().write("<video>"); |
| 163 HTMLVideoElement& video = | 184 HTMLVideoElement& video = |
| 164 toHTMLVideoElement(*GetDocument().QuerySelector("video")); | 185 toHTMLVideoElement(*GetDocument().QuerySelector("video")); |
| 165 media_controls_ = static_cast<MediaControlsImpl*>(video.GetMediaControls()); | 186 media_controls_ = static_cast<MediaControlsImpl*>(video.GetMediaControls()); |
| 166 | 187 |
| 167 // If scripts are not enabled, controls will always be shown. | 188 // If scripts are not enabled, controls will always be shown. |
| 168 page_holder_->GetFrame().GetSettings()->SetScriptEnabled(true); | 189 page_holder_->GetFrame().GetSettings()->SetScriptEnabled(true); |
| 169 } | 190 } |
| 170 | 191 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 } | 241 } |
| 221 | 242 |
| 222 void MouseDownAt(WebFloatPoint pos); | 243 void MouseDownAt(WebFloatPoint pos); |
| 223 void MouseMoveTo(WebFloatPoint pos); | 244 void MouseMoveTo(WebFloatPoint pos); |
| 224 void MouseUpAt(WebFloatPoint pos); | 245 void MouseUpAt(WebFloatPoint pos); |
| 225 | 246 |
| 226 bool HasAvailabilityCallbacks(RemotePlayback* remote_playback) { | 247 bool HasAvailabilityCallbacks(RemotePlayback* remote_playback) { |
| 227 return !remote_playback->availability_callbacks_.IsEmpty(); | 248 return !remote_playback->availability_callbacks_.IsEmpty(); |
| 228 } | 249 } |
| 229 | 250 |
| 251 virtual bool EnableDownloadInProductHelp() { return false; } |
| 252 |
| 230 private: | 253 private: |
| 231 std::unique_ptr<DummyPageHolder> page_holder_; | 254 std::unique_ptr<DummyPageHolder> page_holder_; |
| 232 Persistent<MediaControlsImpl> media_controls_; | 255 Persistent<MediaControlsImpl> media_controls_; |
| 233 HistogramTester histogram_tester_; | 256 HistogramTester histogram_tester_; |
| 234 }; | 257 }; |
| 235 | 258 |
| 236 void MediaControlsImplTest::MouseDownAt(WebFloatPoint pos) { | 259 void MediaControlsImplTest::MouseDownAt(WebFloatPoint pos) { |
| 237 WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown, | 260 WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown, |
| 238 pos /* client pos */, pos /* screen pos */, | 261 pos /* client pos */, pos /* screen pos */, |
| 239 WebPointerProperties::Button::kLeft, 1, | 262 WebPointerProperties::Button::kLeft, 1, |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 MediaControls(), "-internal-media-controls-download-button"); | 529 MediaControls(), "-internal-media-controls-download-button"); |
| 507 ASSERT_NE(nullptr, download_button); | 530 ASSERT_NE(nullptr, download_button); |
| 508 | 531 |
| 509 // Download button should not be displayed for HLS streams. | 532 // Download button should not be displayed for HLS streams. |
| 510 MediaControls().MediaElement().SetSrc("https://example.com/foo.m3u8"); | 533 MediaControls().MediaElement().SetSrc("https://example.com/foo.m3u8"); |
| 511 testing::RunPendingTasks(); | 534 testing::RunPendingTasks(); |
| 512 SimulateLoadedMetadata(); | 535 SimulateLoadedMetadata(); |
| 513 EXPECT_FALSE(IsElementVisible(*download_button)); | 536 EXPECT_FALSE(IsElementVisible(*download_button)); |
| 514 } | 537 } |
| 515 | 538 |
| 539 TEST_F(MediaControlsImplTest, DownloadButtonInProductHelpDisabled) { |
| 540 EXPECT_FALSE(MediaControls().DownloadInProductHelp()); |
| 541 } |
| 542 |
| 543 class MediaControlsImplInProductHelpTest : public MediaControlsImplTest { |
| 544 public: |
| 545 void SetUp() override { |
| 546 MediaControlsImplTest::SetUp(); |
| 547 ASSERT_TRUE(MediaControls().DownloadInProductHelp()); |
| 548 } |
| 549 |
| 550 MediaDownloadInProductHelpManager& Manager() { |
| 551 return *MediaControls().DownloadInProductHelp(); |
| 552 } |
| 553 |
| 554 void Play() { MediaControls().OnPlay(); } |
| 555 |
| 556 bool EnableDownloadInProductHelp() override { return true; } |
| 557 }; |
| 558 |
| 559 TEST_F(MediaControlsImplInProductHelpTest, DownloadButtonInProductHelp_Button) { |
| 560 EnsureSizing(); |
| 561 |
| 562 // Inject the LayoutObject for the button to override the rect returned in |
| 563 // visual viewport. |
| 564 MediaControlDownloadButtonElement& button = |
| 565 GetDownloadButton(MediaControls()); |
| 566 MockLayoutObject layout_object(&button); |
| 567 layout_object.SetVisible(true); |
| 568 button.SetLayoutObject(&layout_object); |
| 569 |
| 570 MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); |
| 571 testing::RunPendingTasks(); |
| 572 SimulateLoadedMetadata(); |
| 573 Play(); |
| 574 |
| 575 // Load above should have made the button wanted, which should trigger showing |
| 576 // in-product help. |
| 577 EXPECT_TRUE(Manager().IsShowingInProductHelp()); |
| 578 |
| 579 // Disable the download button, which dismisses the in-product-help. |
| 580 button.SetIsWanted(false); |
| 581 EXPECT_FALSE(Manager().IsShowingInProductHelp()); |
| 582 |
| 583 // Toggle again. In-product help is shown only once. |
| 584 button.SetIsWanted(true); |
| 585 EXPECT_FALSE(Manager().IsShowingInProductHelp()); |
| 586 |
| 587 button.SetLayoutObject(nullptr); |
| 588 } |
| 589 |
| 590 TEST_F(MediaControlsImplInProductHelpTest, |
| 591 DownloadButtonInProductHelp_ControlsVisibility) { |
| 592 EnsureSizing(); |
| 593 |
| 594 // Inject the LayoutObject for the button to override the rect returned in |
| 595 // visual viewport. |
| 596 MediaControlDownloadButtonElement& button = |
| 597 GetDownloadButton(MediaControls()); |
| 598 MockLayoutObject layout_object(&button); |
| 599 layout_object.SetVisible(true); |
| 600 button.SetLayoutObject(&layout_object); |
| 601 |
| 602 // The in-product-help should not be shown while the controls are hidden. |
| 603 MediaControls().Hide(); |
| 604 MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); |
| 605 testing::RunPendingTasks(); |
| 606 SimulateLoadedMetadata(); |
| 607 Play(); |
| 608 |
| 609 ASSERT_TRUE(button.IsWanted()); |
| 610 EXPECT_FALSE(Manager().IsShowingInProductHelp()); |
| 611 |
| 612 // Showing the controls initiates showing in-product-help. |
| 613 MediaControls().MaybeShow(); |
| 614 EXPECT_TRUE(Manager().IsShowingInProductHelp()); |
| 615 |
| 616 // Hiding the controls dismissed in-product-help. |
| 617 MediaControls().Hide(); |
| 618 EXPECT_FALSE(Manager().IsShowingInProductHelp()); |
| 619 |
| 620 button.SetLayoutObject(nullptr); |
| 621 } |
| 622 |
| 623 TEST_F(MediaControlsImplInProductHelpTest, |
| 624 DownloadButtonInProductHelp_ButtonVisibility) { |
| 625 EnsureSizing(); |
| 626 |
| 627 // Inject the LayoutObject for the button to override the rect returned in |
| 628 // visual viewport. |
| 629 MediaControlDownloadButtonElement& button = |
| 630 GetDownloadButton(MediaControls()); |
| 631 MockLayoutObject layout_object(&button); |
| 632 button.SetLayoutObject(&layout_object); |
| 633 |
| 634 // The in-product-help should not be shown while the button is hidden. |
| 635 layout_object.SetVisible(false); |
| 636 MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); |
| 637 testing::RunPendingTasks(); |
| 638 SimulateLoadedMetadata(); |
| 639 Play(); |
| 640 |
| 641 ASSERT_TRUE(button.IsWanted()); |
| 642 EXPECT_FALSE(Manager().IsShowingInProductHelp()); |
| 643 |
| 644 // Make the button visible to show in-product-help. |
| 645 layout_object.SetVisible(true); |
| 646 button.SetIsWanted(false); |
| 647 button.SetIsWanted(true); |
| 648 EXPECT_TRUE(Manager().IsShowingInProductHelp()); |
| 649 |
| 650 button.SetLayoutObject(nullptr); |
| 651 } |
| 652 |
| 516 TEST_F(MediaControlsImplTest, TimelineSeekToRoundedEnd) { | 653 TEST_F(MediaControlsImplTest, TimelineSeekToRoundedEnd) { |
| 517 EnsureSizing(); | 654 EnsureSizing(); |
| 518 | 655 |
| 519 // Tests the case where the real length of the video, |exact_duration|, gets | 656 // Tests the case where the real length of the video, |exact_duration|, gets |
| 520 // rounded up slightly to |rounded_up_duration| when setting the timeline's | 657 // rounded up slightly to |rounded_up_duration| when setting the timeline's |
| 521 // |max| attribute (crbug.com/695065). | 658 // |max| attribute (crbug.com/695065). |
| 522 double exact_duration = 596.586667; | 659 double exact_duration = 596.586667; |
| 523 double rounded_up_duration = 596.587; | 660 double rounded_up_duration = 596.587; |
| 524 LoadMediaWithDuration(exact_duration); | 661 LoadMediaWithDuration(exact_duration); |
| 525 | 662 |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 852 { | 989 { |
| 853 Persistent<HTMLMediaElement> video_holder = element; | 990 Persistent<HTMLMediaElement> video_holder = element; |
| 854 page_holder->GetDocument().body()->RemoveChild(element); | 991 page_holder->GetDocument().body()->RemoveChild(element); |
| 855 page_holder->GetDocument().body()->AppendChild(video_holder.Get()); | 992 page_holder->GetDocument().body()->AppendChild(video_holder.Get()); |
| 856 EXPECT_TRUE(remote_playback->HasEventListeners()); | 993 EXPECT_TRUE(remote_playback->HasEventListeners()); |
| 857 EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback)); | 994 EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback)); |
| 858 } | 995 } |
| 859 } | 996 } |
| 860 | 997 |
| 861 } // namespace blink | 998 } // namespace blink |
| OLD | NEW |