| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/elements/MediaControlCastButtonElement.h" | 5 #include "modules/media_controls/elements/MediaControlCastButtonElement.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptState.h" |
| 8 #include "bindings/core/v8/ToV8.h" |
| 7 #include "core/InputTypeNames.h" | 9 #include "core/InputTypeNames.h" |
| 8 #include "core/dom/ClientRect.h" | 10 #include "core/dom/ClientRect.h" |
| 9 #include "core/events/Event.h" | 11 #include "core/events/Event.h" |
| 12 #include "core/frame/Settings.h" |
| 10 #include "core/html/HTMLMediaElement.h" | 13 #include "core/html/HTMLMediaElement.h" |
| 14 #include "core/html/media/HTMLMediaElementControlsList.h" |
| 11 #include "modules/media_controls/MediaControlsImpl.h" | 15 #include "modules/media_controls/MediaControlsImpl.h" |
| 12 #include "modules/media_controls/elements/MediaControlElementsHelper.h" | 16 #include "modules/media_controls/elements/MediaControlElementsHelper.h" |
| 17 #include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h" |
| 18 #include "modules/remoteplayback/RemotePlayback.h" |
| 13 #include "platform/Histogram.h" | 19 #include "platform/Histogram.h" |
| 20 #include "platform/wtf/Functional.h" |
| 14 #include "public/platform/Platform.h" | 21 #include "public/platform/Platform.h" |
| 15 | 22 |
| 16 namespace blink { | 23 namespace blink { |
| 17 | 24 |
| 18 namespace { | |
| 19 | |
| 20 Element* ElementFromCenter(Element& element) { | |
| 21 ClientRect* client_rect = element.getBoundingClientRect(); | |
| 22 int center_x = | |
| 23 static_cast<int>((client_rect->left() + client_rect->right()) / 2); | |
| 24 int center_y = | |
| 25 static_cast<int>((client_rect->top() + client_rect->bottom()) / 2); | |
| 26 | |
| 27 return element.GetDocument().ElementFromPoint(center_x, center_y); | |
| 28 } | |
| 29 | |
| 30 } // anonymous namespace | |
| 31 | |
| 32 MediaControlCastButtonElement::MediaControlCastButtonElement( | 25 MediaControlCastButtonElement::MediaControlCastButtonElement( |
| 33 MediaControlsImpl& media_controls, | 26 MediaControlsImpl& media_controls, |
| 34 bool is_overlay_button) | 27 bool is_overlay_button) |
| 35 : MediaControlInputElement(media_controls, kMediaCastOnButton), | 28 : MediaControlInputElement(media_controls, kMediaCastOnButton), |
| 36 is_overlay_button_(is_overlay_button) { | 29 is_overlay_button_(is_overlay_button) { |
| 37 EnsureUserAgentShadowRoot(); | 30 EnsureUserAgentShadowRoot(); |
| 38 SetShadowPseudoId(is_overlay_button | 31 SetShadowPseudoId(is_overlay_button |
| 39 ? "-internal-media-controls-overlay-cast-button" | 32 ? "-internal-media-controls-overlay-cast-button" |
| 40 : "-internal-media-controls-cast-button"); | 33 : "-internal-media-controls-cast-button"); |
| 41 setType(InputTypeNames::button); | 34 setType(InputTypeNames::button); |
| 42 | 35 |
| 43 if (is_overlay_button_) | 36 if (is_overlay_button_) |
| 44 RecordMetrics(CastOverlayMetrics::kCreated); | 37 RecordMetrics(CastOverlayMetrics::kCreated); |
| 45 SetIsPlayingRemotely(false); | |
| 46 } | |
| 47 | 38 |
| 48 void MediaControlCastButtonElement::TryShowOverlay() { | 39 UpdateDisplayType(); |
| 49 DCHECK(is_overlay_button_); | |
| 50 | |
| 51 SetIsWanted(true); | |
| 52 if (ElementFromCenter(*this) != &MediaElement()) { | |
| 53 SetIsWanted(false); | |
| 54 return; | |
| 55 } | |
| 56 | |
| 57 DCHECK(IsWanted()); | |
| 58 if (!show_use_counted_) { | |
| 59 show_use_counted_ = true; | |
| 60 RecordMetrics(CastOverlayMetrics::kShown); | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 void MediaControlCastButtonElement::SetIsPlayingRemotely( | |
| 65 bool is_playing_remotely) { | |
| 66 if (is_playing_remotely) { | |
| 67 if (is_overlay_button_) { | |
| 68 SetDisplayType(kMediaOverlayCastOnButton); | |
| 69 } else { | |
| 70 SetDisplayType(kMediaCastOnButton); | |
| 71 } | |
| 72 } else { | |
| 73 if (is_overlay_button_) { | |
| 74 SetDisplayType(kMediaOverlayCastOffButton); | |
| 75 } else { | |
| 76 SetDisplayType(kMediaCastOffButton); | |
| 77 } | |
| 78 } | |
| 79 UpdateOverflowString(); | |
| 80 } | 40 } |
| 81 | 41 |
| 82 bool MediaControlCastButtonElement::WillRespondToMouseClickEvents() { | 42 bool MediaControlCastButtonElement::WillRespondToMouseClickEvents() { |
| 83 return true; | 43 return true; |
| 84 } | 44 } |
| 85 | 45 |
| 86 WebLocalizedString::Name | 46 WebLocalizedString::Name |
| 87 MediaControlCastButtonElement::GetOverflowStringName() { | 47 MediaControlCastButtonElement::GetOverflowStringName() { |
| 88 if (MediaElement().IsPlayingRemotely()) | 48 if (IsPlayingRemotely()) |
| 89 return WebLocalizedString::kOverflowMenuStopCast; | 49 return WebLocalizedString::kOverflowMenuStopCast; |
| 90 return WebLocalizedString::kOverflowMenuCast; | 50 return WebLocalizedString::kOverflowMenuCast; |
| 91 } | 51 } |
| 92 | 52 |
| 93 bool MediaControlCastButtonElement::HasOverflowButton() { | 53 bool MediaControlCastButtonElement::HasOverflowButton() { |
| 94 return true; | 54 return true; |
| 95 } | 55 } |
| 96 | 56 |
| 97 void MediaControlCastButtonElement::DefaultEventHandler(Event* event) { | 57 void MediaControlCastButtonElement::DefaultEventHandler(Event* event) { |
| 98 if (event->type() == EventTypeNames::click) { | 58 if (event->type() == EventTypeNames::click) { |
| 99 if (is_overlay_button_) { | 59 if (is_overlay_button_) { |
| 100 Platform::Current()->RecordAction( | 60 Platform::Current()->RecordAction( |
| 101 UserMetricsAction("Media.Controls.CastOverlay")); | 61 UserMetricsAction("Media.Controls.CastOverlay")); |
| 62 |
| 63 if (!click_use_counted_) { |
| 64 click_use_counted_ = true; |
| 65 RecordMetrics(CastOverlayMetrics::kClicked); |
| 66 } |
| 102 } else { | 67 } else { |
| 103 Platform::Current()->RecordAction( | 68 Platform::Current()->RecordAction( |
| 104 UserMetricsAction("Media.Controls.Cast")); | 69 UserMetricsAction("Media.Controls.Cast")); |
| 105 } | 70 } |
| 106 | 71 |
| 107 if (is_overlay_button_ && !click_use_counted_) { | 72 RemotePlayback* remote = |
| 108 click_use_counted_ = true; | 73 HTMLMediaElementRemotePlayback::remote(MediaElement()); |
| 109 RecordMetrics(CastOverlayMetrics::kClicked); | 74 if (remote) |
| 110 } | 75 remote->PromptInternal(); |
| 111 if (MediaElement().IsPlayingRemotely()) { | |
| 112 MediaElement().RequestRemotePlaybackControl(); | |
| 113 } else { | |
| 114 MediaElement().RequestRemotePlayback(); | |
| 115 } | |
| 116 } | 76 } |
| 117 MediaControlInputElement::DefaultEventHandler(event); | 77 MediaControlInputElement::DefaultEventHandler(event); |
| 118 } | 78 } |
| 119 | 79 |
| 80 void MediaControlCastButtonElement::UpdateDisplayType() { |
| 81 if (IsPlayingRemotely()) { |
| 82 if (is_overlay_button_) |
| 83 SetDisplayType(kMediaOverlayCastOnButton); |
| 84 else |
| 85 SetDisplayType(kMediaCastOnButton); |
| 86 } else { |
| 87 if (is_overlay_button_) |
| 88 SetDisplayType(kMediaOverlayCastOffButton); |
| 89 else |
| 90 SetDisplayType(kMediaCastOffButton); |
| 91 } |
| 92 UpdateOverflowString(); |
| 93 } |
| 94 |
| 95 void MediaControlCastButtonElement::SetIsWanted(bool wanted) { |
| 96 if (wanted == IsWanted()) |
| 97 return; |
| 98 |
| 99 MediaControlElement::SetIsWanted(wanted); |
| 100 if (IsWanted() && is_overlay_button_ && !show_use_counted_) { |
| 101 show_use_counted_ = true; |
| 102 RecordMetrics(CastOverlayMetrics::kShown); |
| 103 } |
| 104 } |
| 105 |
| 106 bool MediaControlCastButtonElement::ShouldShow() { |
| 107 if (MediaElement().FastHasAttribute(HTMLNames::disableremoteplaybackAttr)) |
| 108 return false; |
| 109 |
| 110 // Explicitly do not show cast button when the MediaControlsEnabled setting is |
| 111 // false to make sure the overlay does not appear. |
| 112 Document& document = MediaElement().GetDocument(); |
| 113 if (document.GetSettings() && |
| 114 !document.GetSettings()->GetMediaControlsEnabled()) { |
| 115 return false; |
| 116 } |
| 117 |
| 118 // The page disabled the button via the attribute. |
| 119 if (MediaElement().ControlsListInternal()->ShouldHideRemotePlayback()) { |
| 120 UseCounter::Count( |
| 121 document, UseCounter::kHTMLMediaElementControlsListNoRemotePlayback); |
| 122 return false; |
| 123 } |
| 124 |
| 125 RemotePlayback* remote = |
| 126 HTMLMediaElementRemotePlayback::remote(MediaElement()); |
| 127 if (!remote || !remote->RemotePlaybackAvailable()) |
| 128 return false; |
| 129 |
| 130 if (is_overlay_button_) { |
| 131 // TODO(avayvod): Do we still need to hide the button for autoplay/paused |
| 132 // videos? Check for IsAutoplayingMuted() here instead? |
| 133 if (MediaElement().Autoplay() && MediaElement().paused()) |
| 134 return false; |
| 135 |
| 136 // Don't show the overlay button if it would cover something on top of the |
| 137 // media element. |
| 138 if (UnderlyingElement() != &MediaElement()) |
| 139 return false; |
| 140 } |
| 141 |
| 142 return true; |
| 143 } |
| 144 |
| 120 bool MediaControlCastButtonElement::KeepEventInNode(Event* event) { | 145 bool MediaControlCastButtonElement::KeepEventInNode(Event* event) { |
| 121 return MediaControlElementsHelper::IsUserInteractionEvent(event); | 146 return MediaControlElementsHelper::IsUserInteractionEvent(event); |
| 122 } | 147 } |
| 123 | 148 |
| 124 void MediaControlCastButtonElement::RecordMetrics(CastOverlayMetrics metric) { | 149 void MediaControlCastButtonElement::RecordMetrics(CastOverlayMetrics metric) { |
| 125 DCHECK(is_overlay_button_); | 150 DCHECK(is_overlay_button_); |
| 126 DEFINE_STATIC_LOCAL( | 151 DEFINE_STATIC_LOCAL( |
| 127 EnumerationHistogram, overlay_histogram, | 152 EnumerationHistogram, overlay_histogram, |
| 128 ("Cast.Sender.Overlay", static_cast<int>(CastOverlayMetrics::kCount))); | 153 ("Cast.Sender.Overlay", static_cast<int>(CastOverlayMetrics::kCount))); |
| 129 overlay_histogram.Count(static_cast<int>(metric)); | 154 overlay_histogram.Count(static_cast<int>(metric)); |
| 130 } | 155 } |
| 131 | 156 |
| 157 bool MediaControlCastButtonElement::IsPlayingRemotely() const { |
| 158 RemotePlayback* remote = |
| 159 HTMLMediaElementRemotePlayback::remote(MediaElement()); |
| 160 return remote && remote->GetState() != WebRemotePlaybackState::kDisconnected; |
| 161 } |
| 162 |
| 163 Element* MediaControlCastButtonElement::UnderlyingElement() { |
| 164 DCHECK(is_overlay_button_); |
| 165 MediaControlElement::SetIsWanted(true); |
| 166 ClientRect* client_rect = getBoundingClientRect(); |
| 167 MediaControlElement::SetIsWanted(false); |
| 168 int center_x = |
| 169 static_cast<int>((client_rect->left() + client_rect->right()) / 2); |
| 170 int center_y = |
| 171 static_cast<int>((client_rect->top() + client_rect->bottom()) / 2); |
| 172 |
| 173 return GetDocument().ElementFromPoint(center_x, center_y); |
| 174 } |
| 175 |
| 132 } // namespace blink | 176 } // namespace blink |
| OLD | NEW |