| 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 20 matching lines...) Expand all Loading... |
| 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/KeyboardEvent.h" |
| 39 #include "core/events/MouseEvent.h" | 39 #include "core/events/MouseEvent.h" |
| 40 #include "core/frame/LocalFrame.h" | 40 #include "core/frame/LocalFrame.h" |
| 41 #include "core/frame/Settings.h" | |
| 42 #include "core/frame/UseCounter.h" | 41 #include "core/frame/UseCounter.h" |
| 43 #include "core/html/HTMLAnchorElement.h" | |
| 44 #include "core/html/HTMLVideoElement.h" | 42 #include "core/html/HTMLVideoElement.h" |
| 45 #include "core/html/TimeRanges.h" | 43 #include "core/html/TimeRanges.h" |
| 46 #include "core/html/media/HTMLMediaElementControlsList.h" | |
| 47 #include "core/html/media/HTMLMediaSource.h" | |
| 48 #include "core/html/media/MediaControls.h" | 44 #include "core/html/media/MediaControls.h" |
| 49 #include "core/html/shadow/ShadowElementNames.h" | 45 #include "core/html/shadow/ShadowElementNames.h" |
| 50 #include "core/html/track/TextTrackList.h" | 46 #include "core/html/track/TextTrackList.h" |
| 51 #include "core/input/EventHandler.h" | 47 #include "core/input/EventHandler.h" |
| 52 #include "core/layout/LayoutBoxModelObject.h" | 48 #include "core/layout/LayoutBoxModelObject.h" |
| 53 #include "core/layout/api/LayoutSliderItem.h" | 49 #include "core/layout/api/LayoutSliderItem.h" |
| 54 #include "core/page/ChromeClient.h" | 50 #include "core/page/ChromeClient.h" |
| 55 #include "core/page/Page.h" | |
| 56 #include "platform/Histogram.h" | 51 #include "platform/Histogram.h" |
| 57 #include "platform/RuntimeEnabledFeatures.h" | 52 #include "platform/RuntimeEnabledFeatures.h" |
| 58 #include "public/platform/Platform.h" | 53 #include "public/platform/Platform.h" |
| 59 #include "public/platform/UserMetricsAction.h" | 54 #include "public/platform/UserMetricsAction.h" |
| 60 #include "public/platform/WebScreenInfo.h" | 55 #include "public/platform/WebScreenInfo.h" |
| 61 | 56 |
| 62 namespace blink { | 57 namespace blink { |
| 63 | 58 |
| 64 using namespace HTMLNames; | 59 using namespace HTMLNames; |
| 65 | 60 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 92 | 87 |
| 93 const AtomicString& type = event->type(); | 88 const AtomicString& type = event->type(); |
| 94 return type == EventTypeNames::mouseover || | 89 return type == EventTypeNames::mouseover || |
| 95 type == EventTypeNames::mouseout || | 90 type == EventTypeNames::mouseout || |
| 96 type == EventTypeNames::mousemove || | 91 type == EventTypeNames::mousemove || |
| 97 type == EventTypeNames::pointerover || | 92 type == EventTypeNames::pointerover || |
| 98 type == EventTypeNames::pointerout || | 93 type == EventTypeNames::pointerout || |
| 99 type == EventTypeNames::pointermove; | 94 type == EventTypeNames::pointermove; |
| 100 } | 95 } |
| 101 | 96 |
| 102 Element* ElementFromCenter(Element& element) { | |
| 103 ClientRect* client_rect = element.getBoundingClientRect(); | |
| 104 int center_x = | |
| 105 static_cast<int>((client_rect->left() + client_rect->right()) / 2); | |
| 106 int center_y = | |
| 107 static_cast<int>((client_rect->top() + client_rect->bottom()) / 2); | |
| 108 | |
| 109 return element.GetDocument().ElementFromPoint(center_x, center_y); | |
| 110 } | |
| 111 | |
| 112 } // anonymous namespace | 97 } // anonymous namespace |
| 113 | 98 |
| 114 // ---------------------------- | 99 // ---------------------------- |
| 115 MediaControlDownloadButtonElement::MediaControlDownloadButtonElement( | |
| 116 MediaControls& media_controls) | |
| 117 : MediaControlInputElement(media_controls, kMediaDownloadButton) {} | |
| 118 | |
| 119 MediaControlDownloadButtonElement* MediaControlDownloadButtonElement::Create( | |
| 120 MediaControls& media_controls) { | |
| 121 MediaControlDownloadButtonElement* button = | |
| 122 new MediaControlDownloadButtonElement(media_controls); | |
| 123 button->EnsureUserAgentShadowRoot(); | |
| 124 button->setType(InputTypeNames::button); | |
| 125 button->SetShadowPseudoId( | |
| 126 AtomicString("-internal-media-controls-download-button")); | |
| 127 button->SetIsWanted(false); | |
| 128 return button; | |
| 129 } | |
| 130 | |
| 131 WebLocalizedString::Name | |
| 132 MediaControlDownloadButtonElement::GetOverflowStringName() { | |
| 133 return WebLocalizedString::kOverflowMenuDownload; | |
| 134 } | |
| 135 | |
| 136 bool MediaControlDownloadButtonElement::ShouldDisplayDownloadButton() { | |
| 137 const KURL& url = MediaElement().currentSrc(); | |
| 138 | |
| 139 // Check page settings to see if download is disabled. | |
| 140 if (GetDocument().GetPage() && | |
| 141 GetDocument().GetPage()->GetSettings().GetHideDownloadUI()) | |
| 142 return false; | |
| 143 | |
| 144 // URLs that lead to nowhere are ignored. | |
| 145 if (url.IsNull() || url.IsEmpty()) | |
| 146 return false; | |
| 147 | |
| 148 // If we have no source, we can't download. | |
| 149 if (MediaElement().getNetworkState() == HTMLMediaElement::kNetworkEmpty || | |
| 150 MediaElement().getNetworkState() == HTMLMediaElement::kNetworkNoSource) { | |
| 151 return false; | |
| 152 } | |
| 153 | |
| 154 // Local files and blobs (including MSE) should not have a download button. | |
| 155 if (url.IsLocalFile() || url.ProtocolIs("blob")) | |
| 156 return false; | |
| 157 | |
| 158 // MediaStream can't be downloaded. | |
| 159 if (HTMLMediaElement::IsMediaStreamURL(url.GetString())) | |
| 160 return false; | |
| 161 | |
| 162 // MediaSource can't be downloaded. | |
| 163 if (HTMLMediaSource::Lookup(url)) | |
| 164 return false; | |
| 165 | |
| 166 // HLS stream shouldn't have a download button. | |
| 167 if (HTMLMediaElement::IsHLSURL(url)) | |
| 168 return false; | |
| 169 | |
| 170 // Infinite streams don't have a clear end at which to finish the download | |
| 171 // (would require adding UI to prompt for the duration to download). | |
| 172 if (MediaElement().duration() == std::numeric_limits<double>::infinity()) | |
| 173 return false; | |
| 174 | |
| 175 // The attribute disables the download button. | |
| 176 if (MediaElement().ControlsListInternal()->ShouldHideDownload()) { | |
| 177 UseCounter::Count(MediaElement().GetDocument(), | |
| 178 UseCounter::kHTMLMediaElementControlsListNoDownload); | |
| 179 return false; | |
| 180 } | |
| 181 | |
| 182 return true; | |
| 183 } | |
| 184 | |
| 185 void MediaControlDownloadButtonElement::SetIsWanted(bool wanted) { | |
| 186 MediaControlElement::SetIsWanted(wanted); | |
| 187 | |
| 188 if (!IsWanted()) | |
| 189 return; | |
| 190 | |
| 191 DCHECK(IsWanted()); | |
| 192 if (!show_use_counted_) { | |
| 193 show_use_counted_ = true; | |
| 194 RecordMetrics(DownloadActionMetrics::kShown); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 void MediaControlDownloadButtonElement::DefaultEventHandler(Event* event) { | |
| 199 const KURL& url = MediaElement().currentSrc(); | |
| 200 if (event->type() == EventTypeNames::click && | |
| 201 !(url.IsNull() || url.IsEmpty())) { | |
| 202 Platform::Current()->RecordAction( | |
| 203 UserMetricsAction("Media.Controls.Download")); | |
| 204 if (!click_use_counted_) { | |
| 205 click_use_counted_ = true; | |
| 206 RecordMetrics(DownloadActionMetrics::kClicked); | |
| 207 } | |
| 208 if (!anchor_) { | |
| 209 HTMLAnchorElement* anchor = HTMLAnchorElement::Create(GetDocument()); | |
| 210 anchor->setAttribute(HTMLNames::downloadAttr, ""); | |
| 211 anchor_ = anchor; | |
| 212 } | |
| 213 anchor_->SetURL(url); | |
| 214 anchor_->DispatchSimulatedClick(event); | |
| 215 } | |
| 216 MediaControlInputElement::DefaultEventHandler(event); | |
| 217 } | |
| 218 | |
| 219 DEFINE_TRACE(MediaControlDownloadButtonElement) { | |
| 220 visitor->Trace(anchor_); | |
| 221 MediaControlInputElement::Trace(visitor); | |
| 222 } | |
| 223 | |
| 224 void MediaControlDownloadButtonElement::RecordMetrics( | |
| 225 DownloadActionMetrics metric) { | |
| 226 DEFINE_STATIC_LOCAL(EnumerationHistogram, download_action_histogram, | |
| 227 ("Media.Controls.Download", | |
| 228 static_cast<int>(DownloadActionMetrics::kCount))); | |
| 229 download_action_histogram.Count(static_cast<int>(metric)); | |
| 230 } | |
| 231 | |
| 232 // ---------------------------- | |
| 233 | 100 |
| 234 MediaControlTimelineElement::MediaControlTimelineElement( | 101 MediaControlTimelineElement::MediaControlTimelineElement( |
| 235 MediaControls& media_controls) | 102 MediaControls& media_controls) |
| 236 : MediaControlInputElement(media_controls, kMediaSlider) {} | 103 : MediaControlInputElement(media_controls, kMediaSlider) {} |
| 237 | 104 |
| 238 MediaControlTimelineElement* MediaControlTimelineElement::Create( | 105 MediaControlTimelineElement* MediaControlTimelineElement::Create( |
| 239 MediaControls& media_controls) { | 106 MediaControls& media_controls) { |
| 240 MediaControlTimelineElement* timeline = | 107 MediaControlTimelineElement* timeline = |
| 241 new MediaControlTimelineElement(media_controls); | 108 new MediaControlTimelineElement(media_controls); |
| 242 timeline->EnsureUserAgentShadowRoot(); | 109 timeline->EnsureUserAgentShadowRoot(); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 | 281 |
| 415 setValue(String::Number(volume)); | 282 setValue(String::Number(volume)); |
| 416 if (LayoutObject* layout_object = this->GetLayoutObject()) | 283 if (LayoutObject* layout_object = this->GetLayoutObject()) |
| 417 layout_object->SetShouldDoFullPaintInvalidation(); | 284 layout_object->SetShouldDoFullPaintInvalidation(); |
| 418 } | 285 } |
| 419 | 286 |
| 420 bool MediaControlVolumeSliderElement::KeepEventInNode(Event* event) { | 287 bool MediaControlVolumeSliderElement::KeepEventInNode(Event* event) { |
| 421 return IsUserInteractionEventForSlider(event, GetLayoutObject()); | 288 return IsUserInteractionEventForSlider(event, GetLayoutObject()); |
| 422 } | 289 } |
| 423 | 290 |
| 424 // ---------------------------- | |
| 425 | |
| 426 MediaControlCastButtonElement::MediaControlCastButtonElement( | |
| 427 MediaControls& media_controls, | |
| 428 bool is_overlay_button) | |
| 429 : MediaControlInputElement(media_controls, kMediaCastOnButton), | |
| 430 is_overlay_button_(is_overlay_button) { | |
| 431 if (is_overlay_button_) | |
| 432 RecordMetrics(CastOverlayMetrics::kCreated); | |
| 433 SetIsPlayingRemotely(false); | |
| 434 } | |
| 435 | |
| 436 MediaControlCastButtonElement* MediaControlCastButtonElement::Create( | |
| 437 MediaControls& media_controls, | |
| 438 bool is_overlay_button) { | |
| 439 MediaControlCastButtonElement* button = | |
| 440 new MediaControlCastButtonElement(media_controls, is_overlay_button); | |
| 441 button->EnsureUserAgentShadowRoot(); | |
| 442 button->SetShadowPseudoId(is_overlay_button | |
| 443 ? "-internal-media-controls-overlay-cast-button" | |
| 444 : "-internal-media-controls-cast-button"); | |
| 445 button->setType(InputTypeNames::button); | |
| 446 return button; | |
| 447 } | |
| 448 | |
| 449 void MediaControlCastButtonElement::DefaultEventHandler(Event* event) { | |
| 450 if (event->type() == EventTypeNames::click) { | |
| 451 if (is_overlay_button_) | |
| 452 Platform::Current()->RecordAction( | |
| 453 UserMetricsAction("Media.Controls.CastOverlay")); | |
| 454 else | |
| 455 Platform::Current()->RecordAction( | |
| 456 UserMetricsAction("Media.Controls.Cast")); | |
| 457 | |
| 458 if (is_overlay_button_ && !click_use_counted_) { | |
| 459 click_use_counted_ = true; | |
| 460 RecordMetrics(CastOverlayMetrics::kClicked); | |
| 461 } | |
| 462 if (MediaElement().IsPlayingRemotely()) { | |
| 463 MediaElement().RequestRemotePlaybackControl(); | |
| 464 } else { | |
| 465 MediaElement().RequestRemotePlayback(); | |
| 466 } | |
| 467 } | |
| 468 MediaControlInputElement::DefaultEventHandler(event); | |
| 469 } | |
| 470 | |
| 471 void MediaControlCastButtonElement::SetIsPlayingRemotely( | |
| 472 bool is_playing_remotely) { | |
| 473 if (is_playing_remotely) { | |
| 474 if (is_overlay_button_) { | |
| 475 SetDisplayType(kMediaOverlayCastOnButton); | |
| 476 } else { | |
| 477 SetDisplayType(kMediaCastOnButton); | |
| 478 } | |
| 479 } else { | |
| 480 if (is_overlay_button_) { | |
| 481 SetDisplayType(kMediaOverlayCastOffButton); | |
| 482 } else { | |
| 483 SetDisplayType(kMediaCastOffButton); | |
| 484 } | |
| 485 } | |
| 486 UpdateOverflowString(); | |
| 487 } | |
| 488 | |
| 489 WebLocalizedString::Name | |
| 490 MediaControlCastButtonElement::GetOverflowStringName() { | |
| 491 if (MediaElement().IsPlayingRemotely()) | |
| 492 return WebLocalizedString::kOverflowMenuStopCast; | |
| 493 return WebLocalizedString::kOverflowMenuCast; | |
| 494 } | |
| 495 | |
| 496 void MediaControlCastButtonElement::TryShowOverlay() { | |
| 497 DCHECK(is_overlay_button_); | |
| 498 | |
| 499 SetIsWanted(true); | |
| 500 if (ElementFromCenter(*this) != &MediaElement()) { | |
| 501 SetIsWanted(false); | |
| 502 return; | |
| 503 } | |
| 504 | |
| 505 DCHECK(IsWanted()); | |
| 506 if (!show_use_counted_) { | |
| 507 show_use_counted_ = true; | |
| 508 RecordMetrics(CastOverlayMetrics::kShown); | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 bool MediaControlCastButtonElement::KeepEventInNode(Event* event) { | |
| 513 return IsUserInteractionEvent(event); | |
| 514 } | |
| 515 | |
| 516 void MediaControlCastButtonElement::RecordMetrics(CastOverlayMetrics metric) { | |
| 517 DCHECK(is_overlay_button_); | |
| 518 DEFINE_STATIC_LOCAL( | |
| 519 EnumerationHistogram, overlay_histogram, | |
| 520 ("Cast.Sender.Overlay", static_cast<int>(CastOverlayMetrics::kCount))); | |
| 521 overlay_histogram.Count(static_cast<int>(metric)); | |
| 522 } | |
| 523 | |
| 524 } // namespace blink | 291 } // namespace blink |
| OLD | NEW |