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/Document.h" | 12 #include "core/dom/Document.h" |
12 #include "core/dom/ElementTraversal.h" | 13 #include "core/dom/ElementTraversal.h" |
13 #include "core/dom/StyleEngine.h" | 14 #include "core/dom/StyleEngine.h" |
14 #include "core/events/Event.h" | 15 #include "core/events/Event.h" |
15 #include "core/frame/Settings.h" | 16 #include "core/frame/Settings.h" |
16 #include "core/html/HTMLElement.h" | 17 #include "core/html/HTMLElement.h" |
17 #include "core/html/HTMLVideoElement.h" | 18 #include "core/html/HTMLVideoElement.h" |
18 #include "core/html/shadow/MediaControlElementTypes.h" | 19 #include "core/html/shadow/MediaControlElementTypes.h" |
| 20 #include "core/input/EventHandler.h" |
19 #include "core/layout/LayoutObject.h" | 21 #include "core/layout/LayoutObject.h" |
20 #include "core/loader/EmptyClients.h" | 22 #include "core/loader/EmptyClients.h" |
21 #include "core/testing/DummyPageHolder.h" | 23 #include "core/testing/DummyPageHolder.h" |
22 #include "platform/heap/Handle.h" | 24 #include "platform/heap/Handle.h" |
23 #include "platform/testing/EmptyWebMediaPlayer.h" | 25 #include "platform/testing/EmptyWebMediaPlayer.h" |
24 #include "platform/testing/HistogramTester.h" | 26 #include "platform/testing/HistogramTester.h" |
25 #include "platform/testing/UnitTestHelpers.h" | 27 #include "platform/testing/UnitTestHelpers.h" |
| 28 #include "public/platform/WebMouseEvent.h" |
| 29 #include "public/platform/WebScreenInfo.h" |
26 #include "public/platform/WebSize.h" | 30 #include "public/platform/WebSize.h" |
27 #include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
" | 31 #include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
" |
28 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h" | 32 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h" |
29 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
30 | 34 |
31 namespace blink { | 35 namespace blink { |
32 | 36 |
33 namespace { | 37 namespace { |
34 | 38 |
| 39 class MockChromeClient : public EmptyChromeClient { |
| 40 public: |
| 41 // EmptyChromeClient overrides: |
| 42 WebScreenInfo screenInfo() const override { |
| 43 WebScreenInfo screenInfo; |
| 44 screenInfo.orientationType = WebScreenOrientationLandscapePrimary; |
| 45 return screenInfo; |
| 46 } |
| 47 }; |
| 48 |
35 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { | 49 class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer { |
36 public: | 50 public: |
37 // WebMediaPlayer overrides: | 51 // WebMediaPlayer overrides: |
38 WebTimeRanges seekable() const override { return m_seekable; } | 52 WebTimeRanges seekable() const override { return m_seekable; } |
39 bool hasVideo() const override { return true; } | 53 bool hasVideo() const override { return true; } |
40 | 54 |
41 WebTimeRanges m_seekable; | 55 WebTimeRanges m_seekable; |
42 }; | 56 }; |
43 | 57 |
44 class MockWebRemotePlaybackClient : public WebRemotePlaybackClient { | 58 class MockWebRemotePlaybackClient : public WebRemotePlaybackClient { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 Shown = 0, | 154 Shown = 0, |
141 Clicked, | 155 Clicked, |
142 Count // Keep last. | 156 Count // Keep last. |
143 }; | 157 }; |
144 | 158 |
145 } // namespace | 159 } // namespace |
146 | 160 |
147 class MediaControlsImplTest : public ::testing::Test { | 161 class MediaControlsImplTest : public ::testing::Test { |
148 protected: | 162 protected: |
149 virtual void SetUp() { | 163 virtual void SetUp() { |
150 m_pageHolder = DummyPageHolder::create(IntSize(800, 600), nullptr, | 164 Page::PageClients clients; |
| 165 fillWithEmptyClients(clients); |
| 166 clients.chromeClient = new MockChromeClient(); |
| 167 m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients, |
151 StubLocalFrameClient::create()); | 168 StubLocalFrameClient::create()); |
152 Document& document = this->document(); | |
153 | 169 |
154 document.write("<video>"); | 170 document().write("<video>"); |
155 HTMLVideoElement& video = | 171 HTMLVideoElement& video = |
156 toHTMLVideoElement(*document.querySelector("video")); | 172 toHTMLVideoElement(*document().querySelector("video")); |
157 m_mediaControls = static_cast<MediaControlsImpl*>(video.mediaControls()); | 173 m_mediaControls = static_cast<MediaControlsImpl*>(video.mediaControls()); |
158 | 174 |
159 // If scripts are not enabled, controls will always be shown. | 175 // If scripts are not enabled, controls will always be shown. |
160 m_pageHolder->frame().settings()->setScriptEnabled(true); | 176 m_pageHolder->frame().settings()->setScriptEnabled(true); |
161 } | 177 } |
162 | 178 |
163 void simulateRouteAvailabe() { | 179 void simulateRouteAvailabe() { |
164 m_mediaControls->mediaElement().remoteRouteAvailabilityChanged( | 180 m_mediaControls->mediaElement().remoteRouteAvailabilityChanged( |
165 WebRemotePlaybackAvailability::DeviceAvailable); | 181 WebRemotePlaybackAvailability::DeviceAvailable); |
166 } | 182 } |
(...skipping 23 matching lines...) Expand all Loading... |
190 void loadMediaWithDuration(double duration) { | 206 void loadMediaWithDuration(double duration) { |
191 mediaControls().mediaElement().setSrc("https://example.com/foo.mp4"); | 207 mediaControls().mediaElement().setSrc("https://example.com/foo.mp4"); |
192 testing::runPendingTasks(); | 208 testing::runPendingTasks(); |
193 WebTimeRange timeRange(0.0, duration); | 209 WebTimeRange timeRange(0.0, duration); |
194 webMediaPlayer()->m_seekable.assign(&timeRange, 1); | 210 webMediaPlayer()->m_seekable.assign(&timeRange, 1); |
195 mediaControls().mediaElement().durationChanged(duration, | 211 mediaControls().mediaElement().durationChanged(duration, |
196 false /* requestSeek */); | 212 false /* requestSeek */); |
197 simulateLoadedMetadata(); | 213 simulateLoadedMetadata(); |
198 } | 214 } |
199 | 215 |
| 216 void setReady() { |
| 217 mediaControls().mediaElement().setReadyState( |
| 218 HTMLMediaElement::kHaveEnoughData); |
| 219 } |
| 220 |
| 221 void mouseDownAt(WebFloatPoint pos); |
| 222 void mouseMoveTo(WebFloatPoint pos); |
| 223 void mouseUpAt(WebFloatPoint pos); |
| 224 |
200 private: | 225 private: |
201 std::unique_ptr<DummyPageHolder> m_pageHolder; | 226 std::unique_ptr<DummyPageHolder> m_pageHolder; |
202 Persistent<MediaControlsImpl> m_mediaControls; | 227 Persistent<MediaControlsImpl> m_mediaControls; |
203 HistogramTester m_histogramTester; | 228 HistogramTester m_histogramTester; |
204 }; | 229 }; |
205 | 230 |
| 231 void MediaControlsImplTest::mouseDownAt(WebFloatPoint pos) { |
| 232 WebMouseEvent mouseDownEvent(WebInputEvent::MouseDown, pos /* client pos */, |
| 233 pos /* screen pos */, |
| 234 WebPointerProperties::Button::Left, 1, |
| 235 WebInputEvent::Modifiers::LeftButtonDown, |
| 236 WebInputEvent::TimeStampForTesting); |
| 237 mouseDownEvent.setFrameScale(1); |
| 238 document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); |
| 239 } |
| 240 |
| 241 void MediaControlsImplTest::mouseMoveTo(WebFloatPoint pos) { |
| 242 WebMouseEvent mouseMoveEvent(WebInputEvent::MouseMove, pos /* client pos */, |
| 243 pos /* screen pos */, |
| 244 WebPointerProperties::Button::Left, 1, |
| 245 WebInputEvent::Modifiers::LeftButtonDown, |
| 246 WebInputEvent::TimeStampForTesting); |
| 247 mouseMoveEvent.setFrameScale(1); |
| 248 document().frame()->eventHandler().handleMouseMoveEvent(mouseMoveEvent, {}); |
| 249 } |
| 250 |
| 251 void MediaControlsImplTest::mouseUpAt(WebFloatPoint pos) { |
| 252 WebMouseEvent mouseUpEvent( |
| 253 WebMouseEvent::MouseUp, pos /* client pos */, pos /* screen pos */, |
| 254 WebPointerProperties::Button::Left, 1, WebInputEvent::NoModifiers, |
| 255 WebInputEvent::TimeStampForTesting); |
| 256 mouseUpEvent.setFrameScale(1); |
| 257 document().frame()->eventHandler().handleMouseReleaseEvent(mouseUpEvent); |
| 258 } |
| 259 |
206 TEST_F(MediaControlsImplTest, HideAndShow) { | 260 TEST_F(MediaControlsImplTest, HideAndShow) { |
207 mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, | 261 mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, |
208 true); | 262 true); |
209 | 263 |
210 Element* panel = getElementByShadowPseudoId(mediaControls(), | 264 Element* panel = getElementByShadowPseudoId(mediaControls(), |
211 "-webkit-media-controls-panel"); | 265 "-webkit-media-controls-panel"); |
212 ASSERT_NE(nullptr, panel); | 266 ASSERT_NE(nullptr, panel); |
213 | 267 |
214 ASSERT_TRUE(isElementVisible(*panel)); | 268 ASSERT_TRUE(isElementVisible(*panel)); |
215 mediaControls().hide(); | 269 mediaControls().hide(); |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 // Download button should not be displayed for HLS streams. | 528 // Download button should not be displayed for HLS streams. |
475 mediaControls().mediaElement().setSrc("https://example.com/foo.m3u8"); | 529 mediaControls().mediaElement().setSrc("https://example.com/foo.m3u8"); |
476 testing::runPendingTasks(); | 530 testing::runPendingTasks(); |
477 simulateLoadedMetadata(); | 531 simulateLoadedMetadata(); |
478 EXPECT_FALSE(isElementVisible(*downloadButton)); | 532 EXPECT_FALSE(isElementVisible(*downloadButton)); |
479 } | 533 } |
480 | 534 |
481 TEST_F(MediaControlsImplTest, TimelineSeekToRoundedEnd) { | 535 TEST_F(MediaControlsImplTest, TimelineSeekToRoundedEnd) { |
482 ensureSizing(); | 536 ensureSizing(); |
483 | 537 |
484 MediaControlTimelineElement* timeline = | |
485 static_cast<MediaControlTimelineElement*>(getElementByShadowPseudoId( | |
486 mediaControls(), "-webkit-media-controls-timeline")); | |
487 ASSERT_NE(nullptr, timeline); | |
488 | |
489 // Tests the case where the real length of the video, |exactDuration|, gets | 538 // Tests the case where the real length of the video, |exactDuration|, gets |
490 // rounded up slightly to |roundedUpDuration| when setting the timeline's | 539 // rounded up slightly to |roundedUpDuration| when setting the timeline's |
491 // |max| attribute (crbug.com/695065). | 540 // |max| attribute (crbug.com/695065). |
492 double exactDuration = 596.586667; | 541 double exactDuration = 596.586667; |
493 double roundedUpDuration = 596.587; | 542 double roundedUpDuration = 596.587; |
494 loadMediaWithDuration(exactDuration); | 543 loadMediaWithDuration(exactDuration); |
495 | 544 |
496 // Simulate a click slightly past the end of the track of the timeline's | 545 // Simulate a click slightly past the end of the track of the timeline's |
497 // underlying <input type="range">. This would set the |value| to the |max| | 546 // underlying <input type="range">. This would set the |value| to the |max| |
498 // attribute, which can be slightly rounded relative to the duration. | 547 // attribute, which can be slightly rounded relative to the duration. |
| 548 MediaControlTimelineElement* timeline = mediaControls().timelineElement(); |
499 timeline->setValueAsNumber(roundedUpDuration, ASSERT_NO_EXCEPTION); | 549 timeline->setValueAsNumber(roundedUpDuration, ASSERT_NO_EXCEPTION); |
500 ASSERT_EQ(roundedUpDuration, timeline->valueAsNumber()); | 550 ASSERT_EQ(roundedUpDuration, timeline->valueAsNumber()); |
501 EXPECT_EQ(0.0, mediaControls().mediaElement().currentTime()); | 551 EXPECT_EQ(0.0, mediaControls().mediaElement().currentTime()); |
502 timeline->dispatchInputEvent(); | 552 timeline->dispatchInputEvent(); |
503 EXPECT_EQ(exactDuration, mediaControls().mediaElement().currentTime()); | 553 EXPECT_EQ(exactDuration, mediaControls().mediaElement().currentTime()); |
504 } | 554 } |
505 | 555 |
506 TEST_F(MediaControlsImplTest, TimelineImmediatelyUpdatesCurrentTime) { | 556 TEST_F(MediaControlsImplTest, TimelineImmediatelyUpdatesCurrentTime) { |
507 ensureSizing(); | 557 ensureSizing(); |
508 | 558 |
509 MediaControlTimelineElement* timeline = | |
510 static_cast<MediaControlTimelineElement*>(getElementByShadowPseudoId( | |
511 mediaControls(), "-webkit-media-controls-timeline")); | |
512 ASSERT_NE(nullptr, timeline); | |
513 MediaControlCurrentTimeDisplayElement* currentTimeDisplay = | 559 MediaControlCurrentTimeDisplayElement* currentTimeDisplay = |
514 static_cast<MediaControlCurrentTimeDisplayElement*>( | 560 static_cast<MediaControlCurrentTimeDisplayElement*>( |
515 getElementByShadowPseudoId( | 561 getElementByShadowPseudoId( |
516 mediaControls(), "-webkit-media-controls-current-time-display")); | 562 mediaControls(), "-webkit-media-controls-current-time-display")); |
517 ASSERT_NE(nullptr, currentTimeDisplay); | |
518 | 563 |
519 double duration = 600; | 564 double duration = 600; |
520 loadMediaWithDuration(duration); | 565 loadMediaWithDuration(duration); |
521 | 566 |
522 // Simulate seeking the underlying range to 50%. Current time display should | 567 // Simulate seeking the underlying range to 50%. Current time display should |
523 // update synchronously (rather than waiting for media to finish seeking). | 568 // update synchronously (rather than waiting for media to finish seeking). |
524 timeline->setValueAsNumber(duration / 2, ASSERT_NO_EXCEPTION); | 569 mediaControls().timelineElement()->setValueAsNumber(duration / 2, |
525 timeline->dispatchInputEvent(); | 570 ASSERT_NO_EXCEPTION); |
| 571 mediaControls().timelineElement()->dispatchInputEvent(); |
526 EXPECT_EQ(duration / 2, currentTimeDisplay->currentValue()); | 572 EXPECT_EQ(duration / 2, currentTimeDisplay->currentValue()); |
527 } | 573 } |
528 | 574 |
529 TEST_F(MediaControlsImplTest, VolumeSliderPaintInvalidationOnInput) { | 575 TEST_F(MediaControlsImplTest, VolumeSliderPaintInvalidationOnInput) { |
530 ensureSizing(); | 576 ensureSizing(); |
531 | 577 |
532 MediaControlVolumeSliderElement* volumeSlider = | 578 Element* volumeSlider = mediaControls().volumeSliderElement(); |
533 static_cast<MediaControlVolumeSliderElement*>(getElementByShadowPseudoId( | |
534 mediaControls(), "-webkit-media-controls-volume-slider")); | |
535 ASSERT_NE(nullptr, volumeSlider); | |
536 | |
537 HTMLElement* element = volumeSlider; | |
538 | 579 |
539 MockLayoutObject layoutObject; | 580 MockLayoutObject layoutObject; |
540 LayoutObject* prevLayoutObject = volumeSlider->layoutObject(); | 581 LayoutObject* prevLayoutObject = volumeSlider->layoutObject(); |
541 volumeSlider->setLayoutObject(&layoutObject); | 582 volumeSlider->setLayoutObject(&layoutObject); |
542 | 583 |
543 Event* event = Event::create(EventTypeNames::input); | 584 Event* event = Event::create(EventTypeNames::input); |
544 element->defaultEventHandler(event); | 585 volumeSlider->defaultEventHandler(event); |
545 EXPECT_EQ(1, layoutObject.fullPaintInvalidationCallCount()); | 586 EXPECT_EQ(1, layoutObject.fullPaintInvalidationCallCount()); |
546 | 587 |
547 event = Event::create(EventTypeNames::input); | 588 event = Event::create(EventTypeNames::input); |
548 element->defaultEventHandler(event); | 589 volumeSlider->defaultEventHandler(event); |
549 EXPECT_EQ(2, layoutObject.fullPaintInvalidationCallCount()); | 590 EXPECT_EQ(2, layoutObject.fullPaintInvalidationCallCount()); |
550 | 591 |
551 event = Event::create(EventTypeNames::input); | 592 event = Event::create(EventTypeNames::input); |
552 element->defaultEventHandler(event); | 593 volumeSlider->defaultEventHandler(event); |
553 EXPECT_EQ(3, layoutObject.fullPaintInvalidationCallCount()); | 594 EXPECT_EQ(3, layoutObject.fullPaintInvalidationCallCount()); |
554 | 595 |
555 volumeSlider->setLayoutObject(prevLayoutObject); | 596 volumeSlider->setLayoutObject(prevLayoutObject); |
556 } | 597 } |
557 | 598 |
| 599 TEST_F(MediaControlsImplTest, TimelineMetricsWidth) { |
| 600 mediaControls().mediaElement().setSrc("https://example.com/foo.mp4"); |
| 601 testing::runPendingTasks(); |
| 602 setReady(); |
| 603 ensureSizing(); |
| 604 testing::runPendingTasks(); |
| 605 |
| 606 MediaControlTimelineElement* timeline = mediaControls().timelineElement(); |
| 607 ASSERT_TRUE(isElementVisible(*timeline)); |
| 608 ASSERT_LT(0, timeline->getBoundingClientRect()->width()); |
| 609 |
| 610 mediaControls().mediaElement().play(); |
| 611 testing::runPendingTasks(); |
| 612 |
| 613 histogramTester().expectUniqueSample( |
| 614 "Media.Timeline.Width.InlineLandscape", |
| 615 timeline->getBoundingClientRect()->width(), 1); |
| 616 histogramTester().expectTotalCount("Media.Timeline.Width.InlinePortrait", 0); |
| 617 histogramTester().expectTotalCount("Media.Timeline.Width.FullscreenLandscape", |
| 618 0); |
| 619 histogramTester().expectTotalCount("Media.Timeline.Width.FullscreenPortrait", |
| 620 0); |
| 621 } |
| 622 |
| 623 TEST_F(MediaControlsImplTest, TimelineMetricsClick) { |
| 624 double duration = 540; // 9 minutes |
| 625 loadMediaWithDuration(duration); |
| 626 ensureSizing(); |
| 627 testing::runPendingTasks(); |
| 628 |
| 629 ASSERT_TRUE(isElementVisible(*mediaControls().timelineElement())); |
| 630 ClientRect* timelineRect = |
| 631 mediaControls().timelineElement()->getBoundingClientRect(); |
| 632 ASSERT_LT(0, timelineRect->width()); |
| 633 |
| 634 EXPECT_EQ(0, mediaControls().mediaElement().currentTime()); |
| 635 |
| 636 WebFloatPoint trackCenter(timelineRect->left() + timelineRect->width() / 2, |
| 637 timelineRect->top() + timelineRect->height() / 2); |
| 638 mouseDownAt(trackCenter); |
| 639 mouseUpAt(trackCenter); |
| 640 testing::runPendingTasks(); |
| 641 |
| 642 EXPECT_LE(0.49 * duration, mediaControls().mediaElement().currentTime()); |
| 643 EXPECT_GE(0.51 * duration, mediaControls().mediaElement().currentTime()); |
| 644 |
| 645 histogramTester().expectUniqueSample("Media.Timeline.SeekType.128_255", |
| 646 0 /* SeekType::kClick */, 1); |
| 647 histogramTester().expectTotalCount( |
| 648 "Media.Timeline.DragGestureDuration.128_255", 0); |
| 649 histogramTester().expectTotalCount("Media.Timeline.DragPercent.128_255", 0); |
| 650 histogramTester().expectTotalCount( |
| 651 "Media.Timeline.DragSumAbsTimeDelta.128_255", 0); |
| 652 histogramTester().expectTotalCount("Media.Timeline.DragTimeDelta.128_255", 0); |
| 653 } |
| 654 |
| 655 TEST_F(MediaControlsImplTest, TimelineMetricsDragFromCurrentPosition) { |
| 656 double duration = 540; // 9 minutes |
| 657 loadMediaWithDuration(duration); |
| 658 ensureSizing(); |
| 659 testing::runPendingTasks(); |
| 660 |
| 661 ASSERT_TRUE(isElementVisible(*mediaControls().timelineElement())); |
| 662 ClientRect* timelineRect = |
| 663 mediaControls().timelineElement()->getBoundingClientRect(); |
| 664 ASSERT_LT(0, timelineRect->width()); |
| 665 |
| 666 EXPECT_EQ(0, mediaControls().mediaElement().currentTime()); |
| 667 |
| 668 float y = timelineRect->top() + timelineRect->height() / 2; |
| 669 WebFloatPoint thumb(timelineRect->left(), y); |
| 670 WebFloatPoint trackTwoThirds( |
| 671 timelineRect->left() + timelineRect->width() * 2 / 3, y); |
| 672 mouseDownAt(thumb); |
| 673 mouseMoveTo(trackTwoThirds); |
| 674 mouseUpAt(trackTwoThirds); |
| 675 |
| 676 EXPECT_LE(0.66 * duration, mediaControls().mediaElement().currentTime()); |
| 677 EXPECT_GE(0.68 * duration, mediaControls().mediaElement().currentTime()); |
| 678 |
| 679 histogramTester().expectUniqueSample( |
| 680 "Media.Timeline.SeekType.128_255", |
| 681 1 /* SeekType::kDragFromCurrentPosition */, 1); |
| 682 histogramTester().expectTotalCount( |
| 683 "Media.Timeline.DragGestureDuration.128_255", 1); |
| 684 histogramTester().expectUniqueSample("Media.Timeline.DragPercent.128_255", |
| 685 47 /* [60.0%, 70.0%) */, 1); |
| 686 histogramTester().expectUniqueSample( |
| 687 "Media.Timeline.DragSumAbsTimeDelta.128_255", 16 /* [4m, 8m) */, 1); |
| 688 histogramTester().expectUniqueSample("Media.Timeline.DragTimeDelta.128_255", |
| 689 40 /* [4m, 8m) */, 1); |
| 690 } |
| 691 |
| 692 TEST_F(MediaControlsImplTest, TimelineMetricsDragFromElsewhere) { |
| 693 double duration = 540; // 9 minutes |
| 694 loadMediaWithDuration(duration); |
| 695 ensureSizing(); |
| 696 testing::runPendingTasks(); |
| 697 |
| 698 ASSERT_TRUE(isElementVisible(*mediaControls().timelineElement())); |
| 699 ClientRect* timelineRect = |
| 700 mediaControls().timelineElement()->getBoundingClientRect(); |
| 701 ASSERT_LT(0, timelineRect->width()); |
| 702 |
| 703 EXPECT_EQ(0, mediaControls().mediaElement().currentTime()); |
| 704 |
| 705 float y = timelineRect->top() + timelineRect->height() / 2; |
| 706 WebFloatPoint trackOneThird( |
| 707 timelineRect->left() + timelineRect->width() * 1 / 3, y); |
| 708 WebFloatPoint trackTwoThirds( |
| 709 timelineRect->left() + timelineRect->width() * 2 / 3, y); |
| 710 mouseDownAt(trackOneThird); |
| 711 mouseMoveTo(trackTwoThirds); |
| 712 mouseUpAt(trackTwoThirds); |
| 713 |
| 714 EXPECT_LE(0.66 * duration, mediaControls().mediaElement().currentTime()); |
| 715 EXPECT_GE(0.68 * duration, mediaControls().mediaElement().currentTime()); |
| 716 |
| 717 histogramTester().expectUniqueSample("Media.Timeline.SeekType.128_255", |
| 718 2 /* SeekType::kDragFromElsewhere */, 1); |
| 719 histogramTester().expectTotalCount( |
| 720 "Media.Timeline.DragGestureDuration.128_255", 1); |
| 721 histogramTester().expectUniqueSample("Media.Timeline.DragPercent.128_255", |
| 722 42 /* [30.0%, 35.0%) */, 1); |
| 723 histogramTester().expectUniqueSample( |
| 724 "Media.Timeline.DragSumAbsTimeDelta.128_255", 15 /* [2m, 4m) */, 1); |
| 725 histogramTester().expectUniqueSample("Media.Timeline.DragTimeDelta.128_255", |
| 726 39 /* [2m, 4m) */, 1); |
| 727 } |
| 728 |
| 729 TEST_F(MediaControlsImplTest, TimelineMetricsDragBackAndForth) { |
| 730 double duration = 540; // 9 minutes |
| 731 loadMediaWithDuration(duration); |
| 732 ensureSizing(); |
| 733 testing::runPendingTasks(); |
| 734 |
| 735 ASSERT_TRUE(isElementVisible(*mediaControls().timelineElement())); |
| 736 ClientRect* timelineRect = |
| 737 mediaControls().timelineElement()->getBoundingClientRect(); |
| 738 ASSERT_LT(0, timelineRect->width()); |
| 739 |
| 740 EXPECT_EQ(0, mediaControls().mediaElement().currentTime()); |
| 741 |
| 742 float y = timelineRect->top() + timelineRect->height() / 2; |
| 743 WebFloatPoint trackTwoThirds( |
| 744 timelineRect->left() + timelineRect->width() * 2 / 3, y); |
| 745 WebFloatPoint trackEnd(timelineRect->left() + timelineRect->width(), y); |
| 746 WebFloatPoint trackOneThird( |
| 747 timelineRect->left() + timelineRect->width() * 1 / 3, y); |
| 748 mouseDownAt(trackTwoThirds); |
| 749 mouseMoveTo(trackEnd); |
| 750 mouseMoveTo(trackOneThird); |
| 751 mouseUpAt(trackOneThird); |
| 752 |
| 753 EXPECT_LE(0.32 * duration, mediaControls().mediaElement().currentTime()); |
| 754 EXPECT_GE(0.34 * duration, mediaControls().mediaElement().currentTime()); |
| 755 |
| 756 histogramTester().expectUniqueSample("Media.Timeline.SeekType.128_255", |
| 757 2 /* SeekType::kDragFromElsewhere */, 1); |
| 758 histogramTester().expectTotalCount( |
| 759 "Media.Timeline.DragGestureDuration.128_255", 1); |
| 760 histogramTester().expectUniqueSample("Media.Timeline.DragPercent.128_255", |
| 761 8 /* (-35.0%, -30.0%] */, 1); |
| 762 histogramTester().expectUniqueSample( |
| 763 "Media.Timeline.DragSumAbsTimeDelta.128_255", 17 /* [8m, 15m) */, 1); |
| 764 histogramTester().expectUniqueSample("Media.Timeline.DragTimeDelta.128_255", |
| 765 9 /* (-4m, -2m] */, 1); |
| 766 } |
| 767 |
558 } // namespace blink | 768 } // namespace blink |
OLD | NEW |