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

Side by Side Diff: third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp

Issue 1079323002: Support text track selection in video controls (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed UX comment on displaying icons only for duplicate labels and rebase Created 4 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 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 14 matching lines...) Expand all
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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 "core/html/shadow/MediaControlElements.h" 30 #include "core/html/shadow/MediaControlElements.h"
31 31
32 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 32 #include "bindings/core/v8/ExceptionStatePlaceholder.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/Text.h"
35 #include "core/dom/shadow/ShadowRoot.h" 36 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/events/MouseEvent.h" 37 #include "core/events/MouseEvent.h"
37 #include "core/frame/LocalFrame.h" 38 #include "core/frame/LocalFrame.h"
39 #include "core/html/HTMLLabelElement.h"
38 #include "core/html/HTMLMediaSource.h" 40 #include "core/html/HTMLMediaSource.h"
41 #include "core/html/HTMLSpanElement.h"
39 #include "core/html/HTMLVideoElement.h" 42 #include "core/html/HTMLVideoElement.h"
40 #include "core/html/TimeRanges.h" 43 #include "core/html/TimeRanges.h"
41 #include "core/html/shadow/MediaControls.h" 44 #include "core/html/shadow/MediaControls.h"
45 #include "core/html/track/TextTrackList.h"
42 #include "core/input/EventHandler.h" 46 #include "core/input/EventHandler.h"
43 #include "core/layout/LayoutTheme.h" 47 #include "core/layout/LayoutTheme.h"
44 #include "core/layout/LayoutVideo.h" 48 #include "core/layout/LayoutVideo.h"
45 #include "core/layout/api/LayoutSliderItem.h" 49 #include "core/layout/api/LayoutSliderItem.h"
50 #include "platform/EventDispatchForbiddenScope.h"
46 #include "platform/Histogram.h" 51 #include "platform/Histogram.h"
47 #include "platform/RuntimeEnabledFeatures.h" 52 #include "platform/RuntimeEnabledFeatures.h"
53 #include "platform/text/PlatformLocale.h"
54 #include "public/platform/Platform.h"
48 55
49 namespace blink { 56 namespace blink {
50 57
51 using namespace HTMLNames; 58 using namespace HTMLNames;
52 59
53 namespace { 60 namespace {
54 61
55 // This is the duration from mediaControls.css 62 // This is the duration from mediaControls.css
56 const double fadeOutDuration = 0.3; 63 const double fadeOutDuration = 0.3;
57 64
65 const QualifiedName& trackIndexAttrName()
66 {
67 // Save the track index in an attribute to avoid holding a pointer to the te xt track.
68 DEFINE_STATIC_LOCAL(QualifiedName, trackIndexAttr, (nullAtom, "data-track-in dex", nullAtom));
69 return trackIndexAttr;
70 }
71
72 // When specified as trackIndex, disable text tracks.
73 const int trackIndexOffValue = -1;
74
58 bool isUserInteractionEvent(Event* event) 75 bool isUserInteractionEvent(Event* event)
59 { 76 {
60 const AtomicString& type = event->type(); 77 const AtomicString& type = event->type();
61 return type == EventTypeNames::mousedown 78 return type == EventTypeNames::mousedown
62 || type == EventTypeNames::mouseup 79 || type == EventTypeNames::mouseup
63 || type == EventTypeNames::click 80 || type == EventTypeNames::click
64 || type == EventTypeNames::dblclick 81 || type == EventTypeNames::dblclick
65 || event->isKeyboardEvent() 82 || event->isKeyboardEvent()
66 || event->isTouchEvent(); 83 || event->isTouchEvent();
67 } 84 }
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 RawPtr<MediaControlToggleClosedCaptionsButtonElement> button = new MediaCont rolToggleClosedCaptionsButtonElement(mediaControls); 368 RawPtr<MediaControlToggleClosedCaptionsButtonElement> button = new MediaCont rolToggleClosedCaptionsButtonElement(mediaControls);
352 button->ensureUserAgentShadowRoot(); 369 button->ensureUserAgentShadowRoot();
353 button->setType(InputTypeNames::button); 370 button->setType(InputTypeNames::button);
354 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button")); 371 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button"));
355 button->setIsWanted(false); 372 button->setIsWanted(false);
356 return button.release(); 373 return button.release();
357 } 374 }
358 375
359 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() 376 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
360 { 377 {
361 bool captionsVisible = mediaElement().closedCaptionsVisible(); 378 bool captionsVisible = mediaElement().textTracksVisible();
362 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton); 379 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton);
363 setChecked(captionsVisible);
364 } 380 }
365 381
366 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent) 382 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent)
367 { 383 {
368 if (event->type() == EventTypeNames::click) { 384 if (event->type() == EventTypeNames::click) {
369 mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVi sible()); 385 mediaControls().toggleTextTrackList();
370 setChecked(mediaElement().closedCaptionsVisible());
371 updateDisplayType(); 386 updateDisplayType();
372 event->setDefaultHandled(); 387 event->setDefaultHandled();
373 } 388 }
374 389
375 HTMLInputElement::defaultEventHandler(event); 390 HTMLInputElement::defaultEventHandler(event);
376 } 391 }
377 392
378 // ---------------------------- 393 // ----------------------------
379 394
395 MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls & mediaControls)
396 : MediaControlDivElement(mediaControls, MediaTextTrackList)
397 {
398 }
399
400 RawPtr<MediaControlTextTrackListElement> MediaControlTextTrackListElement::creat e(MediaControls& mediaControls)
401 {
402 RawPtr<MediaControlTextTrackListElement> element = new MediaControlTextTrack ListElement(mediaControls);
403 element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track -list"));
404 element->setIsWanted(false);
405 return element.release();
406 }
407
408 void MediaControlTextTrackListElement::defaultEventHandler(Event* event)
409 {
410 if (event->type() == EventTypeNames::change) {
411 // Identify which input element was selected and set track to showing
412 Node* target = event->target()->toNode();
413 if (!target || !target->isElementNode())
414 return;
415
416 disableShowingTextTracks();
417 int trackIndex = toElement(target)->getIntegralAttribute(trackIndexAttrN ame());
418 if (trackIndex != trackIndexOffValue) {
419 ASSERT(trackIndex >= 0);
420 showTextTrackAtIndex(trackIndex);
421 mediaElement().disableAutomaticTextTrackSelection();
422 }
423
424 mediaControls().toggleTextTrackList();
425 event->setDefaultHandled();
426 }
427 MediaControlDivElement::defaultEventHandler(event);
428 }
429
430 void MediaControlTextTrackListElement::setVisible(bool visible)
431 {
432 if (visible) {
433 setIsWanted(true);
434 refreshTextTrackListMenu();
435 } else {
436 setIsWanted(false);
437 }
438 }
439
440 void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnab le)
441 {
442 TextTrackList* trackList = mediaElement().textTracks();
443 if (indexToEnable >= trackList->length())
444 return;
445 TextTrack* track = trackList->anonymousIndexedGetter(indexToEnable);
446 if (track && track->canBeRendered())
447 track->setMode(TextTrack::showingKeyword());
448 }
449
450 void MediaControlTextTrackListElement::disableShowingTextTracks()
451 {
452 TextTrackList* trackList = mediaElement().textTracks();
453 for (unsigned i = 0; i < trackList->length(); ++i) {
454 TextTrack* track = trackList->anonymousIndexedGetter(i);
455 if (track->mode() == TextTrack::showingKeyword())
456 track->setMode(TextTrack::disabledKeyword());
457 }
458 }
459
460 String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track)
461 {
462 if (!track)
463 return mediaElement().locale().queryString(WebLocalizedString::TextTrack sOff);
464
465 String trackLabel = track->label();
466
467 if (trackLabel.isEmpty())
468 trackLabel = String(mediaElement().locale().queryString(WebLocalizedStri ng::TextTracksNoLabel));
469
470 return trackLabel;
471 }
472
473 bool MediaControlTextTrackListElement::shouldDisplayTrackKindMarker(TextTrack* c urrentTrack, String currentTrackLabel)
philipj_slow 2016/04/19 15:21:09 How about just a free helper function hasDuplicate
srivats 2016/04/19 23:19:02 Done.
474 {
475 if (currentTrackLabel == String(mediaElement().locale().queryString(WebLocal izedString::TextTracksNoLabel)))
476 return true;
477 TextTrackList* trackList = mediaElement().textTracks();
478 for (unsigned i = 0; i < trackList->length(); i++) {
philipj_slow 2016/04/19 15:21:09 This will be O(n^2) in the number of tracks which
srivats 2016/04/19 23:19:02 Done.
479 TextTrack* track = trackList->anonymousIndexedGetter(i);
480 if (currentTrack == track)
481 continue;
482 if (currentTrackLabel == track->label())
483 return true;
484 }
485 return false;
486 }
487
488 // TextTrack parameter when passed in as a nullptr, creates the "Off" list item in the track list.
489 RawPtr<Element> MediaControlTextTrackListElement::createTextTrackListItem(TextTr ack* track)
490 {
491 int trackIndex = track ? track->trackIndex() : trackIndexOffValue;
492 RawPtr<HTMLLabelElement> trackItem = HTMLLabelElement::create(document(), nu llptr);
493 trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-tra ck-list-item"));
494 RawPtr<HTMLInputElement> trackItemInput = HTMLInputElement::create(document( ), nullptr, false);
495 trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-tex t-track-list-item-input"));
496 trackItemInput->setType(InputTypeNames::checkbox);
497 trackItemInput->setIntegralAttribute(trackIndexAttrName(), trackIndex);
498 if (!mediaElement().textTracksVisible()) {
499 if (!track)
500 trackItemInput->setChecked(true);
501 } else {
502 // If there are multiple text tracks set to showing, they must all have
503 // checkmarks displayed.
504 if (track && track->mode() == TextTrack::showingKeyword())
505 trackItemInput->setChecked(true);
506 }
507
508 trackItem->appendChild(trackItemInput);
509 String trackLabel = getTextTrackLabel(track);
510 trackItem->appendChild(Text::create(document(), trackLabel));
511 // Add a track kind marker icon if there are multiple tracks with the same l abel.
512 if (track && shouldDisplayTrackKindMarker(track, trackLabel)) {
513 RawPtr<HTMLSpanElement> trackKindMarker = HTMLSpanElement::create(docume nt());
514 if (track->kind() == track->captionsKeyword()) {
515 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-captions"));
516 } else {
517 ASSERT(track->kind() == track->subtitlesKeyword());
518 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-subtitles"));
519 }
520 trackItem->appendChild(trackKindMarker);
521 }
522 return trackItem;
523 }
524
525 void MediaControlTextTrackListElement::refreshTextTrackListMenu()
526 {
527 if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreRead y())
528 return;
529
530 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
531 removeChildren(OmitSubtreeModifiedEvent);
532
533 // Construct a menu for subtitles and captions
534 // Pass in a nullptr to createTextTrackListItem to create the "Off" track it em.
535 appendChild(createTextTrackListItem(nullptr));
536
537 TextTrackList* trackList = mediaElement().textTracks();
538 for (unsigned i = 0; i < trackList->length(); i++) {
539 TextTrack* track = trackList->anonymousIndexedGetter(i);
540 if (!track->canBeRendered())
541 continue;
542 appendChild(createTextTrackListItem(track));
543 }
544 }
545
546 // ----------------------------
547
380 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols) 548 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols)
381 : MediaControlInputElement(mediaControls, MediaSlider) 549 : MediaControlInputElement(mediaControls, MediaSlider)
382 { 550 {
383 } 551 }
384 552
385 RawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaCon trols& mediaControls) 553 RawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaCon trols& mediaControls)
386 { 554 {
387 RawPtr<MediaControlTimelineElement> timeline = new MediaControlTimelineEleme nt(mediaControls); 555 RawPtr<MediaControlTimelineElement> timeline = new MediaControlTimelineEleme nt(mediaControls);
388 timeline->ensureUserAgentShadowRoot(); 556 timeline->ensureUserAgentShadowRoot();
389 timeline->setType(InputTypeNames::range); 557 timeline->setType(InputTypeNames::range);
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 } 824 }
657 825
658 RawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElem ent::create(MediaControls& mediaControls) 826 RawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElem ent::create(MediaControls& mediaControls)
659 { 827 {
660 RawPtr<MediaControlCurrentTimeDisplayElement> element = new MediaControlCurr entTimeDisplayElement(mediaControls); 828 RawPtr<MediaControlCurrentTimeDisplayElement> element = new MediaControlCurr entTimeDisplayElement(mediaControls);
661 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display")); 829 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display"));
662 return element.release(); 830 return element.release();
663 } 831 }
664 832
665 } // namespace blink 833 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698