Index: Source/core/html/shadow/MediaControlElements.cpp |
diff --git a/Source/core/html/shadow/MediaControlElements.cpp b/Source/core/html/shadow/MediaControlElements.cpp |
index 3e2c7537ea26df6c70a25bb2dc7c27e768fc543f..c775ab4d55376b5d10388832ea2e58a6095979e0 100644 |
--- a/Source/core/html/shadow/MediaControlElements.cpp |
+++ b/Source/core/html/shadow/MediaControlElements.cpp |
@@ -33,6 +33,9 @@ |
#include "bindings/core/v8/ExceptionStatePlaceholder.h" |
#include "core/InputTypeNames.h" |
#include "core/dom/DOMTokenList.h" |
+#include "core/dom/Document.h" |
+#include "core/dom/Element.h" |
+#include "core/dom/Text.h" |
#include "core/dom/shadow/ShadowRoot.h" |
#include "core/events/MouseEvent.h" |
#include "core/frame/LocalFrame.h" |
@@ -40,11 +43,14 @@ |
#include "core/html/MediaController.h" |
#include "core/html/TimeRanges.h" |
#include "core/html/shadow/MediaControls.h" |
+#include "core/html/track/TextTrackList.h" |
#include "core/layout/LayoutSlider.h" |
#include "core/layout/LayoutTheme.h" |
#include "core/layout/LayoutVideo.h" |
#include "core/page/EventHandler.h" |
+#include "platform/EventDispatchForbiddenScope.h" |
#include "platform/RuntimeEnabledFeatures.h" |
+#include "platform/text/PlatformLocale.h" |
namespace blink { |
@@ -53,6 +59,12 @@ using namespace HTMLNames; |
// This is the duration from mediaControls.css |
static const double fadeOutDuration = 0.3; |
+// track index attribute specifies trackIndex for text track list elements |
+static const char trackIndexAttr[] = "x-webkit-track-index"; |
+ |
+// when specified as trackIndex, disable text tracks |
+static const int trackIndexOffValue = -1; |
+ |
static bool isUserInteractionEvent(Event* event) |
{ |
const AtomicString& type = event->type(); |
@@ -341,14 +353,12 @@ void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() |
{ |
bool captionsVisible = mediaElement().closedCaptionsVisible(); |
setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); |
- setChecked(captionsVisible); |
} |
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) |
{ |
if (event->type() == EventTypeNames::click) { |
- mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVisible()); |
- setChecked(mediaElement().closedCaptionsVisible()); |
+ mediaControls().toggleTextTrackList(); |
updateDisplayType(); |
event->setDefaultHandled(); |
} |
@@ -358,6 +368,155 @@ void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e |
// ---------------------------- |
+MediaControlTextTrackListContainerElement::MediaControlTextTrackListContainerElement(MediaControls& mediaControls) |
+ : MediaControlDivElement(mediaControls, MediaTextTrackListContainer) |
+{ |
+} |
+ |
+PassRefPtrWillBeRawPtr<MediaControlTextTrackListContainerElement> |
+ MediaControlTextTrackListContainerElement::create(MediaControls& mediaControls) |
+{ |
+ RefPtrWillBeRawPtr<MediaControlTextTrackListContainerElement> element = |
+ adoptRefWillBeNoop(new MediaControlTextTrackListContainerElement(mediaControls)); |
+ element->setShadowPseudoId(AtomicString("-webkit-media-controls-text-track-list-container", |
+ AtomicString::ConstructFromLiteral)); |
+ element->hide(); |
+ return element.release(); |
+} |
+ |
+// ---------------------------- |
+ |
+MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls& mediaControls) |
+ : MediaControlDivElement(mediaControls, MediaTextTrackList) |
+{ |
+} |
+ |
+PassRefPtrWillBeRawPtr<MediaControlTextTrackListElement> MediaControlTextTrackListElement::create(MediaControls& mediaControls) |
+{ |
+ RefPtrWillBeRawPtr<MediaControlTextTrackListElement> element = |
+ adoptRefWillBeNoop(new MediaControlTextTrackListElement(mediaControls)); |
+ element->setShadowPseudoId(AtomicString("-webkit-media-controls-text-track-list", |
+ AtomicString::ConstructFromLiteral)); |
+ return element.release(); |
+} |
+ |
+void MediaControlTextTrackListElement::defaultEventHandler(Event* event) |
+{ |
+ if (event->type() == EventTypeNames::change) { |
+ // Identify which input element was selected and set track to showing |
+ Node* target = event->target()->toNode(); |
+ if (!target || !target->isElementNode()) |
+ return; |
+ |
+ bool validIndex; |
+ int trackIndex = toElement(target)->getAttribute(trackIndexAttr).toInt(&validIndex); |
+ if (!validIndex) |
+ return; |
+ if (trackIndex != trackIndexOffValue) { |
+ showTextTrackAtIndex(trackIndex); |
+ mediaElement().setClosedCaptionsVisible(true); |
+ } else { |
+ mediaElement().setClosedCaptionsVisible(false); |
+ } |
+ |
+ mediaControls().toggleTextTrackList(); |
+ event->setDefaultHandled(); |
+ } |
+ HTMLDivElement::defaultEventHandler(event); |
+} |
+ |
+void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned index) |
+{ |
+ TextTrackList* trackList = mediaElement().textTracks(); |
+ for (unsigned i = 0; i < trackList->length(); ++i) { |
+ TextTrack* track = trackList->item(i); |
+ if (track->mode() == TextTrack::showingKeyword()) |
+ track->setMode(TextTrack::disabledKeyword()); |
+ } |
+ |
+ if (index < trackList->length()) { |
+ trackList->item(index)->setMode(TextTrack::showingKeyword()); |
+ mediaElement().setAutomaticTextTrackSelection(false); |
+ } |
+} |
+ |
+String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track) |
+{ |
+ String trackLabel = track->label(); |
+ |
+ if (trackLabel.isEmpty()) |
+ trackLabel = track->language(); |
+ |
+ if (trackLabel.isEmpty()) |
+ trackLabel = String(mediaElement().locale().queryString(WebLocalizedString::TextTracksNoLabel)); |
+ |
+ // When the track kind is captions, add a captions marker to distinguish between captions and subtitles. |
+ if (track->kind() == track->captionsKeyword()) |
+ trackLabel.append(mediaElement().locale().queryString(WebLocalizedString::TextTracksCaptionsMarker)); |
+ return trackLabel; |
+} |
+ |
+RefPtrWillBeRawPtr<Element> MediaControlTextTrackListElement::createTextTrackListItem(const String& trackDisplayText, int trackIndex, bool isShowing) |
+{ |
+ Document& document = this->document(); |
+ RefPtrWillBeRawPtr<Element> trackItem = document.createElement(labelTag, false); |
+ trackItem->setShadowPseudoId(AtomicString("-webkit-media-controls-text-track-list-item", |
+ AtomicString::ConstructFromLiteral)); |
+ RefPtrWillBeRawPtr<Element> trackItemInput = document.createElement(inputTag, false); |
+ trackItemInput->setShadowPseudoId(AtomicString("-webkit-media-controls-text-track-list-item-input", |
+ AtomicString::ConstructFromLiteral)); |
+ trackItemInput->setAttribute(typeAttr, InputTypeNames::radio); |
+ trackItemInput->setAttribute(nameAttr, AtomicString("tracks", AtomicString::ConstructFromLiteral)); |
+ trackItemInput->setAttribute(trackIndexAttr, AtomicString::number(trackIndex), ASSERT_NO_EXCEPTION); |
+ if (!mediaElement().closedCaptionsVisible()) { |
+ if (trackIndex == trackIndexOffValue) |
+ toHTMLInputElement(trackItemInput)->setChecked(true); |
+ } else { |
+ if (trackIndex >= 0 && isShowing) |
+ toHTMLInputElement(trackItemInput)->setChecked(true); |
+ } |
+ trackItem->appendChild(trackItemInput); |
+ trackItem->appendChild(document.createTextNode(trackDisplayText)); |
+ return trackItem; |
+} |
+ |
+void MediaControlTextTrackListElement::refreshTextTrackListMenu() |
+{ |
+ DEFINE_STATIC_LOCAL(const AtomicString, tracksSectionId, ("tracks-header", AtomicString::ConstructFromLiteral)); |
+ if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreReady()) |
+ return; |
+ |
+ removeChildren(); |
+ |
+ // Construct a menu for subtitles and captions |
+ EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents; |
+ Document& document = this->document(); |
+ RefPtrWillBeRawPtr<Element> tracksHeader = document.createElement(h3Tag, false); |
+ tracksHeader->setShadowPseudoId(AtomicString("-webkit-media-controls-text-track-list-header", |
+ AtomicString::ConstructFromLiteral)); |
+ RefPtrWillBeRawPtr<Element> tracksSection = document.createElement(divTag, false); |
+ |
+ tracksHeader->appendChild(document.createTextNode(mediaElement().locale().queryString(WebLocalizedString::TextTracksSubtitlesCC))); |
+ tracksHeader->setAttribute(idAttr, tracksSectionId); |
+ tracksSection->setAttribute(roleAttr, radiogroupAttr.localName()); |
+ tracksSection->setAttribute(aria_labeledbyAttr, tracksSectionId); |
+ |
+ String textTracksOffLabel = mediaElement().locale().queryString(WebLocalizedString::TextTracksOff); |
+ tracksSection->appendChild(createTextTrackListItem(textTracksOffLabel, trackIndexOffValue, false)); |
+ |
+ TextTrackList* trackList = mediaElement().textTracks(); |
+ for (unsigned i = 0; i < trackList->length(); i++) { |
+ TextTrack* track = trackList->item(i); |
+ RefPtrWillBeRawPtr<Element> trackItem = |
+ createTextTrackListItem(getTextTrackLabel(track), i, track->mode() == TextTrack::showingKeyword()); |
+ tracksSection->appendChild(trackItem); |
+ } |
+ appendChild(tracksHeader); |
+ appendChild(tracksSection); |
+} |
+ |
+// ---------------------------- |
+ |
MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls) |
: MediaControlInputElement(mediaControls, MediaSlider) |
{ |