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

Side by Side 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, 7 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 unified diff | Download patch
OLDNEW
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 15 matching lines...) Expand all
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30 #include "config.h" 30 #include "config.h"
31 #include "core/html/shadow/MediaControlElements.h" 31 #include "core/html/shadow/MediaControlElements.h"
32 32
33 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 33 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
34 #include "core/InputTypeNames.h" 34 #include "core/InputTypeNames.h"
35 #include "core/dom/DOMTokenList.h" 35 #include "core/dom/DOMTokenList.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/Element.h"
36 #include "core/dom/Fullscreen.h" 38 #include "core/dom/Fullscreen.h"
39 #include "core/dom/Text.h"
37 #include "core/dom/shadow/ShadowRoot.h" 40 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/MouseEvent.h" 41 #include "core/events/MouseEvent.h"
39 #include "core/frame/LocalFrame.h" 42 #include "core/frame/LocalFrame.h"
43 #include "core/html/HTMLHeadingElement.h"
44 #include "core/html/HTMLLabelElement.h"
40 #include "core/html/HTMLVideoElement.h" 45 #include "core/html/HTMLVideoElement.h"
41 #include "core/html/MediaController.h" 46 #include "core/html/MediaController.h"
42 #include "core/html/TimeRanges.h" 47 #include "core/html/TimeRanges.h"
43 #include "core/html/shadow/MediaControls.h" 48 #include "core/html/shadow/MediaControls.h"
49 #include "core/html/track/TextTrackList.h"
44 #include "core/layout/LayoutSlider.h" 50 #include "core/layout/LayoutSlider.h"
45 #include "core/layout/LayoutTheme.h" 51 #include "core/layout/LayoutTheme.h"
46 #include "core/layout/LayoutVideo.h" 52 #include "core/layout/LayoutVideo.h"
47 #include "core/page/EventHandler.h" 53 #include "core/page/EventHandler.h"
54 #include "platform/EventDispatchForbiddenScope.h"
48 #include "platform/RuntimeEnabledFeatures.h" 55 #include "platform/RuntimeEnabledFeatures.h"
56 #include "platform/text/PlatformLocale.h"
49 57
50 namespace blink { 58 namespace blink {
51 59
52 using namespace HTMLNames; 60 using namespace HTMLNames;
53 61
54 // This is the duration from mediaControls.css 62 // This is the duration from mediaControls.css
55 static const double fadeOutDuration = 0.3; 63 static const double fadeOutDuration = 0.3;
56 64
65 // 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.
66 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.
67
68 // 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 "
69 static const int trackIndexOffValue = -1;
70
57 static bool isUserInteractionEvent(Event* event) 71 static bool isUserInteractionEvent(Event* event)
58 { 72 {
59 const AtomicString& type = event->type(); 73 const AtomicString& type = event->type();
60 return type == EventTypeNames::mousedown 74 return type == EventTypeNames::mousedown
61 || type == EventTypeNames::mouseup 75 || type == EventTypeNames::mouseup
62 || type == EventTypeNames::click 76 || type == EventTypeNames::click
63 || type == EventTypeNames::dblclick 77 || type == EventTypeNames::dblclick
64 || event->isKeyboardEvent() 78 || event->isKeyboardEvent()
65 || event->isTouchEvent(); 79 || event->isTouchEvent();
66 } 80 }
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 button->setType(InputTypeNames::button); 349 button->setType(InputTypeNames::button);
336 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button", AtomicString::ConstructFromLiteral)); 350 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button", AtomicString::ConstructFromLiteral));
337 button->hide(); 351 button->hide();
338 return button.release(); 352 return button.release();
339 } 353 }
340 354
341 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() 355 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
342 { 356 {
343 bool captionsVisible = mediaElement().closedCaptionsVisible(); 357 bool captionsVisible = mediaElement().closedCaptionsVisible();
344 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton); 358 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton);
345 setChecked(captionsVisible);
346 } 359 }
347 360
348 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent) 361 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent)
349 { 362 {
350 if (event->type() == EventTypeNames::click) { 363 if (event->type() == EventTypeNames::click) {
351 mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVi sible()); 364 mediaControls().toggleTextTrackList();
352 setChecked(mediaElement().closedCaptionsVisible());
353 updateDisplayType(); 365 updateDisplayType();
354 event->setDefaultHandled(); 366 event->setDefaultHandled();
355 } 367 }
356 368
357 HTMLInputElement::defaultEventHandler(event); 369 HTMLInputElement::defaultEventHandler(event);
358 } 370 }
359 371
360 // ---------------------------- 372 // ----------------------------
361 373
374 MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls & mediaControls)
375 : MediaControlDivElement(mediaControls, MediaTextTrackList)
376 {
377 }
378
379 PassRefPtrWillBeRawPtr<MediaControlTextTrackListElement> MediaControlTextTrackLi stElement::create(MediaControls& mediaControls)
380 {
381 RefPtrWillBeRawPtr<MediaControlTextTrackListElement> element =
382 adoptRefWillBeNoop(new MediaControlTextTrackListElement(mediaControls));
383 element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track -list",
384 AtomicString::ConstructFromLiteral));
385 element->hide();
386 return element.release();
387 }
388
389 void MediaControlTextTrackListElement::defaultEventHandler(Event* event)
390 {
391 if (event->type() == EventTypeNames::change) {
392 // Identify which input element was selected and set track to showing
393 Node* target = event->target()->toNode();
394 if (!target || !target->isElementNode())
395 return;
396
397 bool validIndex;
398 int trackIndex = toElement(target)->getAttribute(trackIndexAttr).toInt(& validIndex);
399 ASSERT(validIndex);
400 if (trackIndex != trackIndexOffValue) {
401 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
402 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'
403 } else {
404 mediaElement().setClosedCaptionsVisible(false);
405 }
406
407 mediaControls().toggleTextTrackList();
408 event->setDefaultHandled();
409 }
410 HTMLDivElement::defaultEventHandler(event);
411 }
412
413 void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnab le)
414 {
415 TextTrackList* trackList = mediaElement().textTracks();
416 for (unsigned i = 0; i < trackList->length(); ++i) {
417 TextTrack* track = trackList->item(i);
418 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
419 continue;
420 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.
421 track->setMode(TextTrack::showingKeyword());
422 mediaElement().disableAutomaticTextTrackSelection();
philipj_slow 2015/05/05 14:36:57 This is the bit I'm saying should happen the same
423 } else if (track->mode() == TextTrack::showingKeyword()) {
424 track->setMode(TextTrack::disabledKeyword());
425 }
426 }
427 }
428
429 String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track)
430 {
431 if (!track)
432 return mediaElement().locale().queryString(WebLocalizedString::TextTrack sOff);
433
434 String trackLabel = track->label();
435
436 if (trackLabel.isEmpty())
437 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
438
439 if (trackLabel.isEmpty())
440 trackLabel = String(mediaElement().locale().queryString(WebLocalizedStri ng::TextTracksNoLabel));
441
442 // When the track kind is captions, add a captions marker to distinguish bet ween 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!
443 if (track->kind() == track->captionsKeyword())
444 trackLabel.append(mediaElement().locale().queryString(WebLocalizedString ::TextTracksCaptionsMarker));
445 return trackLabel;
446 }
447
448 RefPtrWillBeRawPtr<Element> MediaControlTextTrackListElement::createTextTrackLis tItem(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
449 {
450 Document& document = this->document();
451 int trackIndex = track ? track->trackIndex() : trackIndexOffValue;
452 RefPtrWillBeRawPtr<HTMLLabelElement> trackItem = HTMLLabelElement::create(do cument, 0);
453 trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-tra ck-list-item",
454 AtomicString::ConstructFromLiteral));
455 RefPtrWillBeRawPtr<HTMLInputElement> trackItemInput = HTMLInputElement::crea te(document, 0, false);
456 trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-tex t-track-list-item-input",
457 AtomicString::ConstructFromLiteral));
458 trackItemInput->setType(InputTypeNames::radio);
459 trackItemInput->setAttribute(trackIndexAttr, AtomicString::number(trackIndex ), ASSERT_NO_EXCEPTION);
460 if (!mediaElement().closedCaptionsVisible()) {
461 if (!track)
462 trackItemInput->setChecked(true);
463 } else {
464 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.
465 trackItemInput->setChecked(true);
466 }
467 trackItem->appendChild(trackItemInput);
468 trackItem->appendChild(Text::create(document, getTextTrackLabel(track)));
469 return trackItem;
470 }
471
472 void MediaControlTextTrackListElement::refreshTextTrackListMenu()
473 {
474 DEFINE_STATIC_LOCAL(const AtomicString, tracksSectionId, ("tracks-header", A tomicString::ConstructFromLiteral));
475 if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreRead y())
476 return;
477
478 removeChildren();
479
480 // Construct a menu for subtitles and captions
481 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
482 Document& document = this->document();
483 RefPtrWillBeRawPtr<HTMLHeadingElement> tracksHeader = HTMLHeadingElement::cr eate(h3Tag, document);
484 tracksHeader->setShadowPseudoId(AtomicString("-internal-media-controls-text- track-list-header",
485 AtomicString::ConstructFromLiteral));
486 RefPtrWillBeRawPtr<HTMLDivElement> tracksSection = HTMLDivElement::create(do cument);
487
488 tracksHeader->appendChild(Text::create(document,
489 mediaElement().locale().queryString(WebLocalizedString::TextTracksSubtit les)));
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
490 tracksHeader->setAttribute(idAttr, tracksSectionId);
491 tracksSection->setAttribute(roleAttr, radiogroupAttr.localName());
492 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.
493
494 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
495
496 TextTrackList* trackList = mediaElement().textTracks();
497 for (unsigned i = 0; i < trackList->length(); i++) {
498 TextTrack* track = trackList->item(i);
499 if (!track->isRenderable())
500 continue;
501 RefPtrWillBeRawPtr<Element> trackItem = createTextTrackListItem(track);
502 tracksSection->appendChild(trackItem);
503 }
504 appendChild(tracksHeader);
505 appendChild(tracksSection);
506 }
507
508 // ----------------------------
509
362 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols) 510 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols)
363 : MediaControlInputElement(mediaControls, MediaSlider) 511 : MediaControlInputElement(mediaControls, MediaSlider)
364 { 512 {
365 } 513 }
366 514
367 PassRefPtrWillBeRawPtr<MediaControlTimelineElement> MediaControlTimelineElement: :create(MediaControls& mediaControls) 515 PassRefPtrWillBeRawPtr<MediaControlTimelineElement> MediaControlTimelineElement: :create(MediaControls& mediaControls)
368 { 516 {
369 RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = adoptRefWillBeNoo p(new MediaControlTimelineElement(mediaControls)); 517 RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = adoptRefWillBeNoo p(new MediaControlTimelineElement(mediaControls));
370 timeline->ensureUserAgentShadowRoot(); 518 timeline->ensureUserAgentShadowRoot();
371 timeline->setType(InputTypeNames::range); 519 timeline->setType(InputTypeNames::range);
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 } 755 }
608 756
609 PassRefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurren tTimeDisplayElement::create(MediaControls& mediaControls) 757 PassRefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurren tTimeDisplayElement::create(MediaControls& mediaControls)
610 { 758 {
611 RefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> element = adoptRef WillBeNoop(new MediaControlCurrentTimeDisplayElement(mediaControls)); 759 RefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> element = adoptRef WillBeNoop(new MediaControlCurrentTimeDisplayElement(mediaControls));
612 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display", AtomicString::ConstructFromLiteral)); 760 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display", AtomicString::ConstructFromLiteral));
613 return element.release(); 761 return element.release();
614 } 762 }
615 763
616 } // namespace blink 764 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698