OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 17 matching lines...) Expand all Loading... | |
28 */ | 28 */ |
29 | 29 |
30 #include "core/html/shadow/MediaControlElements.h" | 30 #include "core/html/shadow/MediaControlElements.h" |
31 | 31 |
32 #include "bindings/core/v8/ExceptionState.h" | 32 #include "bindings/core/v8/ExceptionState.h" |
33 #include "core/InputTypeNames.h" | 33 #include "core/InputTypeNames.h" |
34 #include "core/dom/ClientRect.h" | 34 #include "core/dom/ClientRect.h" |
35 #include "core/dom/TaskRunnerHelper.h" | 35 #include "core/dom/TaskRunnerHelper.h" |
36 #include "core/dom/Text.h" | 36 #include "core/dom/Text.h" |
37 #include "core/dom/shadow/ShadowRoot.h" | 37 #include "core/dom/shadow/ShadowRoot.h" |
38 #include "core/events/KeyboardEvent.h" | |
38 #include "core/events/MouseEvent.h" | 39 #include "core/events/MouseEvent.h" |
39 #include "core/frame/LocalFrame.h" | 40 #include "core/frame/LocalFrame.h" |
40 #include "core/frame/Settings.h" | 41 #include "core/frame/Settings.h" |
41 #include "core/frame/UseCounter.h" | 42 #include "core/frame/UseCounter.h" |
42 #include "core/html/HTMLAnchorElement.h" | 43 #include "core/html/HTMLAnchorElement.h" |
43 #include "core/html/HTMLLabelElement.h" | 44 #include "core/html/HTMLLabelElement.h" |
44 #include "core/html/HTMLMediaSource.h" | 45 #include "core/html/HTMLMediaSource.h" |
45 #include "core/html/HTMLSpanElement.h" | 46 #include "core/html/HTMLSpanElement.h" |
46 #include "core/html/HTMLVideoElement.h" | 47 #include "core/html/HTMLVideoElement.h" |
47 #include "core/html/TimeRanges.h" | 48 #include "core/html/TimeRanges.h" |
48 #include "core/html/shadow/MediaControls.h" | 49 #include "core/html/shadow/MediaControls.h" |
50 #include "core/html/shadow/ShadowElementNames.h" | |
49 #include "core/html/track/TextTrackList.h" | 51 #include "core/html/track/TextTrackList.h" |
50 #include "core/input/EventHandler.h" | 52 #include "core/input/EventHandler.h" |
53 #include "core/layout/LayoutBoxModelObject.h" | |
51 #include "core/layout/api/LayoutSliderItem.h" | 54 #include "core/layout/api/LayoutSliderItem.h" |
55 #include "core/page/ChromeClient.h" | |
52 #include "core/page/Page.h" | 56 #include "core/page/Page.h" |
53 #include "platform/EventDispatchForbiddenScope.h" | 57 #include "platform/EventDispatchForbiddenScope.h" |
54 #include "platform/Histogram.h" | 58 #include "platform/Histogram.h" |
55 #include "platform/RuntimeEnabledFeatures.h" | 59 #include "platform/RuntimeEnabledFeatures.h" |
56 #include "platform/text/PlatformLocale.h" | 60 #include "platform/text/PlatformLocale.h" |
57 #include "public/platform/Platform.h" | 61 #include "public/platform/Platform.h" |
58 #include "public/platform/UserMetricsAction.h" | 62 #include "public/platform/UserMetricsAction.h" |
63 #include "public/platform/WebScreenInfo.h" | |
59 | 64 |
60 namespace blink { | 65 namespace blink { |
61 | 66 |
62 using namespace HTMLNames; | 67 using namespace HTMLNames; |
63 | 68 |
64 namespace { | 69 namespace { |
65 | 70 |
66 // This is the duration from mediaControls.css | 71 // This is the duration from mediaControls.css |
67 const double fadeOutDuration = 0.3; | 72 const double fadeOutDuration = 0.3; |
68 | 73 |
(...skipping 18 matching lines...) Expand all Loading... | |
87 // Sliders (the volume control and timeline) need to capture some additional | 92 // Sliders (the volume control and timeline) need to capture some additional |
88 // events used when dragging the thumb. | 93 // events used when dragging the thumb. |
89 bool isUserInteractionEventForSlider(Event* event, LayoutObject* layoutObject) { | 94 bool isUserInteractionEventForSlider(Event* event, LayoutObject* layoutObject) { |
90 // It is unclear if this can be converted to isUserInteractionEvent(), since | 95 // It is unclear if this can be converted to isUserInteractionEvent(), since |
91 // mouse* events seem to be eaten during a drag anyway. crbug.com/516416 . | 96 // mouse* events seem to be eaten during a drag anyway. crbug.com/516416 . |
92 if (isUserInteractionEvent(event)) | 97 if (isUserInteractionEvent(event)) |
93 return true; | 98 return true; |
94 | 99 |
95 // Some events are only captured during a slider drag. | 100 // Some events are only captured during a slider drag. |
96 LayoutSliderItem slider = LayoutSliderItem(toLayoutSlider(layoutObject)); | 101 LayoutSliderItem slider = LayoutSliderItem(toLayoutSlider(layoutObject)); |
102 // TODO(crbug.com/695459#c1): LayoutSliderItem::inDragMode is incorrectly | |
103 // false for drags that start from the track instead of the thumb. | |
104 // Use SliderThumbElement::m_inDragMode and | |
105 // SliderContainerElement::m_touchStarted instead. | |
97 if (!slider.isNull() && !slider.inDragMode()) | 106 if (!slider.isNull() && !slider.inDragMode()) |
98 return false; | 107 return false; |
99 | 108 |
100 const AtomicString& type = event->type(); | 109 const AtomicString& type = event->type(); |
101 return type == EventTypeNames::mouseover || | 110 return type == EventTypeNames::mouseover || |
102 type == EventTypeNames::mouseout || | 111 type == EventTypeNames::mouseout || |
103 type == EventTypeNames::mousemove || | 112 type == EventTypeNames::mousemove || |
104 type == EventTypeNames::pointerover || | 113 type == EventTypeNames::pointerover || |
105 type == EventTypeNames::pointerout || | 114 type == EventTypeNames::pointerout || |
106 type == EventTypeNames::pointermove; | 115 type == EventTypeNames::pointermove; |
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
783 | 792 |
784 void MediaControlTimelineElement::defaultEventHandler(Event* event) { | 793 void MediaControlTimelineElement::defaultEventHandler(Event* event) { |
785 if (event->isMouseEvent() && | 794 if (event->isMouseEvent() && |
786 toMouseEvent(event)->button() != | 795 toMouseEvent(event)->button() != |
787 static_cast<short>(WebPointerProperties::Button::Left)) | 796 static_cast<short>(WebPointerProperties::Button::Left)) |
788 return; | 797 return; |
789 | 798 |
790 if (!isConnected() || !document().isActive()) | 799 if (!isConnected() || !document().isActive()) |
791 return; | 800 return; |
792 | 801 |
793 if (event->type() == EventTypeNames::mousedown) { | 802 // TODO(crbug.com/706504): These should listen for pointerdown/up. |
794 Platform::current()->recordAction( | 803 if (event->type() == EventTypeNames::mousedown) |
795 UserMetricsAction("Media.Controls.ScrubbingBegin")); | |
796 mediaControls().beginScrubbing(); | 804 mediaControls().beginScrubbing(); |
805 if (event->type() == EventTypeNames::mouseup) | |
806 mediaControls().endScrubbing(); | |
807 | |
808 // Only respond to main button of primary pointer(s). | |
809 if (event->isPointerEvent() && toPointerEvent(event)->isPrimary() && | |
810 toPointerEvent(event)->button() == | |
811 static_cast<short>(WebPointerProperties::Button::Left)) { | |
812 if (event->type() == EventTypeNames::pointerdown) { | |
813 Platform::current()->recordAction( | |
814 UserMetricsAction("Media.Controls.ScrubbingBegin")); | |
815 mediaControls().beginScrubbing(); | |
816 Element* thumb = userAgentShadowRoot()->getElementById( | |
817 ShadowElementNames::sliderThumb()); | |
818 bool startedFromThumb = thumb && thumb == event->target()->toNode(); | |
819 m_metrics.startGesture(startedFromThumb); | |
820 } | |
821 if (event->type() == EventTypeNames::pointerup) { | |
822 Platform::current()->recordAction( | |
823 UserMetricsAction("Media.Controls.ScrubbingEnd")); | |
824 mediaControls().endScrubbing(); | |
825 m_metrics.recordEndGesture(timelineWidth(), mediaElement().duration()); | |
826 } | |
797 } | 827 } |
798 | 828 |
799 if (event->type() == EventTypeNames::mouseup) { | 829 if (event->type() == EventTypeNames::keydown) { |
800 Platform::current()->recordAction( | 830 m_metrics.startKey(); |
801 UserMetricsAction("Media.Controls.ScrubbingEnd")); | 831 } |
802 mediaControls().endScrubbing(); | 832 if (event->type() == EventTypeNames::keyup && event->isKeyboardEvent()) { |
833 m_metrics.recordEndKey(timelineWidth(), toKeyboardEvent(event)->keyCode()); | |
803 } | 834 } |
804 | 835 |
805 MediaControlInputElement::defaultEventHandler(event); | 836 MediaControlInputElement::defaultEventHandler(event); |
806 | 837 |
807 if (event->type() != EventTypeNames::input) | 838 if (event->type() != EventTypeNames::input) |
808 return; | 839 return; |
809 | 840 |
810 double time = value().toDouble(); | 841 double time = value().toDouble(); |
811 | 842 |
812 double duration = mediaElement().duration(); | 843 double duration = mediaElement().duration(); |
813 // Workaround for floating point error - it's possible for this element's max | 844 // Workaround for floating point error - it's possible for this element's max |
814 // attribute to be rounded to a value slightly higher than the duration. If | 845 // attribute to be rounded to a value slightly higher than the duration. If |
815 // this happens and scrubber is dragged near the max, seek to duration. | 846 // this happens and scrubber is dragged near the max, seek to duration. |
816 if (time > duration) | 847 if (time > duration) |
817 time = duration; | 848 time = duration; |
818 | 849 |
850 m_metrics.onInput(mediaElement().currentTime(), time); | |
851 | |
819 // FIXME: This will need to take the timeline offset into consideration | 852 // FIXME: This will need to take the timeline offset into consideration |
820 // once that concept is supported, see https://crbug.com/312699 | 853 // once that concept is supported, see https://crbug.com/312699 |
821 if (mediaElement().seekable()->contain(time)) | 854 if (mediaElement().seekable()->contain(time)) |
822 mediaElement().setCurrentTime(time); | 855 mediaElement().setCurrentTime(time); |
823 | 856 |
824 // Provide immediate feedback (without waiting for media to seek) to make it | 857 // Provide immediate feedback (without waiting for media to seek) to make it |
825 // easier for user to seek to a precise time. | 858 // easier for user to seek to a precise time. |
826 mediaControls().updateCurrentTimeDisplay(); | 859 mediaControls().updateCurrentTimeDisplay(); |
827 } | 860 } |
828 | 861 |
829 bool MediaControlTimelineElement::willRespondToMouseClickEvents() { | 862 bool MediaControlTimelineElement::willRespondToMouseClickEvents() { |
830 return isConnected() && document().isActive(); | 863 return isConnected() && document().isActive(); |
831 } | 864 } |
832 | 865 |
833 void MediaControlTimelineElement::setPosition(double currentTime) { | 866 void MediaControlTimelineElement::setPosition(double currentTime) { |
834 setValue(String::number(currentTime)); | 867 setValue(String::number(currentTime)); |
835 | 868 |
836 if (LayoutObject* layoutObject = this->layoutObject()) | 869 if (LayoutObject* layoutObject = this->layoutObject()) |
837 layoutObject->setShouldDoFullPaintInvalidation(); | 870 layoutObject->setShouldDoFullPaintInvalidation(); |
838 } | 871 } |
839 | 872 |
840 void MediaControlTimelineElement::setDuration(double duration) { | 873 void MediaControlTimelineElement::setDuration(double duration) { |
841 setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0); | 874 setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0); |
842 | 875 |
843 if (LayoutObject* layoutObject = this->layoutObject()) | 876 if (LayoutObject* layoutObject = this->layoutObject()) |
844 layoutObject->setShouldDoFullPaintInvalidation(); | 877 layoutObject->setShouldDoFullPaintInvalidation(); |
845 } | 878 } |
846 | 879 |
880 void MediaControlTimelineElement::recordWidthOnFirstPlay() { | |
881 Frame* frame = document().frame(); | |
882 if (!frame) | |
883 return; | |
884 bool isPortrait; | |
885 switch (frame->chromeClient().screenInfo().orientationType) { | |
886 case WebScreenOrientationPortraitPrimary: | |
887 case WebScreenOrientationPortraitSecondary: | |
888 isPortrait = true; | |
889 break; | |
890 case WebScreenOrientationLandscapePrimary: | |
891 case WebScreenOrientationLandscapeSecondary: | |
892 isPortrait = false; | |
893 break; | |
894 case WebScreenOrientationUndefined: | |
895 return; // Skip UMA in the unlikely event we fail to detect orientation. | |
896 } | |
897 m_metrics.recordWidthOnFirstPlay(mediaElement().isFullscreen(), isPortrait, | |
898 timelineWidth()); | |
mlamouri (slow - plz ping)
2017/03/30 21:43:00
I would have a slight preference to pass the orien
johnme
2017/03/31 13:47:23
Done.
| |
899 } | |
900 | |
847 bool MediaControlTimelineElement::keepEventInNode(Event* event) { | 901 bool MediaControlTimelineElement::keepEventInNode(Event* event) { |
848 return isUserInteractionEventForSlider(event, layoutObject()); | 902 return isUserInteractionEventForSlider(event, layoutObject()); |
849 } | 903 } |
850 | 904 |
905 int MediaControlTimelineElement::timelineWidth() { | |
906 if (LayoutBoxModelObject* box = layoutBoxModelObject()) | |
907 return box->offsetWidth().round(); | |
908 return 0; | |
909 } | |
910 | |
851 // ---------------------------- | 911 // ---------------------------- |
852 | 912 |
853 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement( | 913 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement( |
854 MediaControls& mediaControls) | 914 MediaControls& mediaControls) |
855 : MediaControlInputElement(mediaControls, MediaVolumeSlider) {} | 915 : MediaControlInputElement(mediaControls, MediaVolumeSlider) {} |
856 | 916 |
857 MediaControlVolumeSliderElement* MediaControlVolumeSliderElement::create( | 917 MediaControlVolumeSliderElement* MediaControlVolumeSliderElement::create( |
858 MediaControls& mediaControls) { | 918 MediaControls& mediaControls) { |
859 MediaControlVolumeSliderElement* slider = | 919 MediaControlVolumeSliderElement* slider = |
860 new MediaControlVolumeSliderElement(mediaControls); | 920 new MediaControlVolumeSliderElement(mediaControls); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1098 MediaControlCurrentTimeDisplayElement* | 1158 MediaControlCurrentTimeDisplayElement* |
1099 MediaControlCurrentTimeDisplayElement::create(MediaControls& mediaControls) { | 1159 MediaControlCurrentTimeDisplayElement::create(MediaControls& mediaControls) { |
1100 MediaControlCurrentTimeDisplayElement* element = | 1160 MediaControlCurrentTimeDisplayElement* element = |
1101 new MediaControlCurrentTimeDisplayElement(mediaControls); | 1161 new MediaControlCurrentTimeDisplayElement(mediaControls); |
1102 element->setShadowPseudoId( | 1162 element->setShadowPseudoId( |
1103 AtomicString("-webkit-media-controls-current-time-display")); | 1163 AtomicString("-webkit-media-controls-current-time-display")); |
1104 return element; | 1164 return element; |
1105 } | 1165 } |
1106 | 1166 |
1107 } // namespace blink | 1167 } // namespace blink |
OLD | NEW |