Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(938)

Unified Diff: Source/core/html/shadow/MediaControlElements.cpp

Issue 1082533002: Support text track selection in video controls (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/html/shadow/MediaControlElements.cpp
diff --git a/Source/core/html/shadow/MediaControlElements.cpp b/Source/core/html/shadow/MediaControlElements.cpp
index c66ef9e0741eaa2fc9ac05c002b2042be9c8fdac..90e9aa90e11a11ab687e872cf96097a2507cec2d 100644
--- a/Source/core/html/shadow/MediaControlElements.cpp
+++ b/Source/core/html/shadow/MediaControlElements.cpp
@@ -33,19 +33,27 @@
#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/Fullscreen.h"
+#include "core/dom/Text.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/events/MouseEvent.h"
#include "core/frame/LocalFrame.h"
+#include "core/html/HTMLHeadingElement.h"
+#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLVideoElement.h"
#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 {
@@ -54,6 +62,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
philipj_slow 2015/05/05 14:36:57 This comment doesn't explain what this is for. AFA
srivats 2016/02/23 01:39:26 Done.
+static const char trackIndexAttr[] = "data-webkit-track-index";
philipj_slow 2015/05/05 14:36:57 Since the element is inaccessible to the outside,
srivats 2016/02/23 01:39:27 Done.
+
+// when specified as trackIndex, disable text tracks
philipj_slow 2015/05/05 14:36:57 Is a special value really needed for this, couldn'
srivats 2016/02/23 01:39:26 The -1 id helps with testing mostly to track the "
+static const int trackIndexOffValue = -1;
+
static bool isUserInteractionEvent(Event* event)
{
const AtomicString& type = event->type();
@@ -342,14 +356,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();
}
@@ -359,6 +371,142 @@ void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e
// ----------------------------
+MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls& mediaControls)
+ : MediaControlDivElement(mediaControls, MediaTextTrackList)
+{
+}
+
+PassRefPtrWillBeRawPtr<MediaControlTextTrackListElement> MediaControlTextTrackListElement::create(MediaControls& mediaControls)
+{
+ RefPtrWillBeRawPtr<MediaControlTextTrackListElement> element =
+ adoptRefWillBeNoop(new MediaControlTextTrackListElement(mediaControls));
+ element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list",
+ AtomicString::ConstructFromLiteral));
+ element->hide();
+ 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);
+ ASSERT(validIndex);
+ if (trackIndex != trackIndexOffValue) {
+ showTextTrackAtIndex(trackIndex);
philipj_slow 2015/05/05 14:36:56 What happens if the text tracks change while this
srivats 2016/02/23 01:39:27 I tested this out by removing a track using the co
philipj_slow 2016/03/01 11:21:04 Refreshing the menu also seems wrong, maybe the us
+ mediaElement().setClosedCaptionsVisible(true);
philipj_slow 2015/05/05 14:36:57 I think setClosedCaptionsVisible() needs to change
fs 2015/05/05 15:32:44 I agree with this, but I think we need a "step" in
philipj_slow 2015/05/06 09:28:43 Ahem, will get to that review too...
srivats 2016/02/23 01:39:27 Not using setClosedCaptionsVisible anymore and it'
+ } else {
+ mediaElement().setClosedCaptionsVisible(false);
+ }
+
+ mediaControls().toggleTextTrackList();
+ event->setDefaultHandled();
+ }
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnable)
+{
+ TextTrackList* trackList = mediaElement().textTracks();
+ for (unsigned i = 0; i < trackList->length(); ++i) {
+ TextTrack* track = trackList->item(i);
+ if (!track->isRenderable())
philipj_slow 2015/05/05 14:36:57 Is this really needed?
fs 2015/05/05 15:32:44 I probably suggested this in one of the earlier CL
+ continue;
+ if (i == indexToEnable && indexToEnable < trackList->length()) {
philipj_slow 2015/05/05 14:36:57 The indexToEnable < trackList->length() check coul
srivats 2016/02/23 01:39:27 Done.
+ track->setMode(TextTrack::showingKeyword());
+ mediaElement().disableAutomaticTextTrackSelection();
philipj_slow 2015/05/05 14:36:57 This is the bit I'm saying should happen the same
+ } else if (track->mode() == TextTrack::showingKeyword()) {
+ track->setMode(TextTrack::disabledKeyword());
+ }
+ }
+}
+
+String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track)
+{
+ if (!track)
+ return mediaElement().locale().queryString(WebLocalizedString::TextTracksOff);
+
+ String trackLabel = track->label();
+
+ if (trackLabel.isEmpty())
+ trackLabel = track->language();
philipj_slow 2015/05/05 14:36:56 This seems risky. People could use <track srclang=
fs 2015/05/05 15:32:44 ICU quite possibly have that data already. No idea
+
+ 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.
philipj_slow 2015/05/05 14:36:57 I'm not sure this will make sense in all languages
fs 2015/05/05 15:32:44 Since it is localized, it could well be "" for Swe
srivats 2016/02/23 01:39:27 UX suggested I use icons here to differentiate bet
philipj_slow 2016/03/01 11:21:04 And I really like that new subtitles icon!
+ if (track->kind() == track->captionsKeyword())
+ trackLabel.append(mediaElement().locale().queryString(WebLocalizedString::TextTracksCaptionsMarker));
+ return trackLabel;
+}
+
+RefPtrWillBeRawPtr<Element> MediaControlTextTrackListElement::createTextTrackListItem(TextTrack* track)
philipj_slow 2015/05/05 14:36:57 This is a bit hard to understand, what does it mea
fs 2015/05/05 15:32:44 I believe I suggested to pass a track, because the
philipj_slow 2015/05/06 09:28:43 Sorry, I skipped the history and comments, so we'r
srivats 2016/02/23 01:39:26 Added a comment explaining what the nullptr is for
+{
+ Document& document = this->document();
+ int trackIndex = track ? track->trackIndex() : trackIndexOffValue;
+ RefPtrWillBeRawPtr<HTMLLabelElement> trackItem = HTMLLabelElement::create(document, 0);
+ trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-item",
+ AtomicString::ConstructFromLiteral));
+ RefPtrWillBeRawPtr<HTMLInputElement> trackItemInput = HTMLInputElement::create(document, 0, false);
+ trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-item-input",
+ AtomicString::ConstructFromLiteral));
+ trackItemInput->setType(InputTypeNames::radio);
+ trackItemInput->setAttribute(trackIndexAttr, AtomicString::number(trackIndex), ASSERT_NO_EXCEPTION);
+ if (!mediaElement().closedCaptionsVisible()) {
+ if (!track)
+ trackItemInput->setChecked(true);
+ } else {
+ if (track && track->mode() == TextTrack::showingKeyword())
philipj_slow 2015/05/05 14:36:57 If there are multiple tracks showing, I guess they
srivats 2016/02/23 01:39:27 Yes. I tested this case out.
+ trackItemInput->setChecked(true);
+ }
+ trackItem->appendChild(trackItemInput);
+ trackItem->appendChild(Text::create(document, getTextTrackLabel(track)));
+ 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<HTMLHeadingElement> tracksHeader = HTMLHeadingElement::create(h3Tag, document);
+ tracksHeader->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-header",
+ AtomicString::ConstructFromLiteral));
+ RefPtrWillBeRawPtr<HTMLDivElement> tracksSection = HTMLDivElement::create(document);
+
+ tracksHeader->appendChild(Text::create(document,
+ mediaElement().locale().queryString(WebLocalizedString::TextTracksSubtitles)));
philipj_slow 2015/05/05 14:36:57 Is this line needed at all? Even if it were change
srivats 2016/02/23 01:39:27 I got some UX feedback on this and they're fine wi
+ tracksHeader->setAttribute(idAttr, tracksSectionId);
+ tracksSection->setAttribute(roleAttr, radiogroupAttr.localName());
+ tracksSection->setAttribute(aria_labeledbyAttr, tracksSectionId);
philipj_slow 2015/05/05 14:36:56 Won't we end up with multiple elements with the sa
fs 2015/05/05 15:32:44 I think it would be weird if it wasn't scoped...
philipj_slow 2015/05/06 09:28:43 Yeah, it certainly would be, just want to make sur
srivats 2016/02/23 01:39:27 No more header.
+
+ tracksSection->appendChild(createTextTrackListItem(nullptr));
philipj_slow 2015/05/05 14:36:57 So this is where it looks a bit weird. Maybe if th
srivats 2016/02/23 01:39:26 I added a comment explaining what the nullptr is f
+
+ TextTrackList* trackList = mediaElement().textTracks();
+ for (unsigned i = 0; i < trackList->length(); i++) {
+ TextTrack* track = trackList->item(i);
+ if (!track->isRenderable())
+ continue;
+ RefPtrWillBeRawPtr<Element> trackItem = createTextTrackListItem(track);
+ tracksSection->appendChild(trackItem);
+ }
+ appendChild(tracksHeader);
+ appendChild(tracksSection);
+}
+
+// ----------------------------
+
MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
: MediaControlInputElement(mediaControls, MediaSlider)
{

Powered by Google App Engine
This is Rietveld 408576698