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

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: Rebase and lgtm nits 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"
48 #include "public/platform/Platform.h" 54 #include "public/platform/Platform.h"
49 #include "public/platform/UserMetricsAction.h" 55 #include "public/platform/UserMetricsAction.h"
50 56
51 namespace blink { 57 namespace blink {
52 58
53 using namespace HTMLNames; 59 using namespace HTMLNames;
54 60
55 namespace { 61 namespace {
56 62
57 // This is the duration from mediaControls.css 63 // This is the duration from mediaControls.css
58 const double fadeOutDuration = 0.3; 64 const double fadeOutDuration = 0.3;
59 65
66 const QualifiedName& trackIndexAttrName()
67 {
68 // Save the track index in an attribute to avoid holding a pointer to the te xt track.
69 DEFINE_STATIC_LOCAL(QualifiedName, trackIndexAttr, (nullAtom, "data-track-in dex", nullAtom));
70 return trackIndexAttr;
71 }
72
73 // When specified as trackIndex, disable text tracks.
74 const int trackIndexOffValue = -1;
75
60 bool isUserInteractionEvent(Event* event) 76 bool isUserInteractionEvent(Event* event)
61 { 77 {
62 const AtomicString& type = event->type(); 78 const AtomicString& type = event->type();
63 return type == EventTypeNames::mousedown 79 return type == EventTypeNames::mousedown
64 || type == EventTypeNames::mouseup 80 || type == EventTypeNames::mouseup
65 || type == EventTypeNames::click 81 || type == EventTypeNames::click
66 || type == EventTypeNames::dblclick 82 || type == EventTypeNames::dblclick
67 || event->isKeyboardEvent() 83 || event->isKeyboardEvent()
68 || event->isTouchEvent(); 84 || event->isTouchEvent();
69 } 85 }
(...skipping 19 matching lines...) Expand all
89 105
90 Element* elementFromCenter(Element& element) 106 Element* elementFromCenter(Element& element)
91 { 107 {
92 ClientRect* clientRect = element.getBoundingClientRect(); 108 ClientRect* clientRect = element.getBoundingClientRect();
93 int centerX = static_cast<int>((clientRect->left() + clientRect->right()) / 2); 109 int centerX = static_cast<int>((clientRect->left() + clientRect->right()) / 2);
94 int centerY = static_cast<int>((clientRect->top() + clientRect->bottom()) / 2); 110 int centerY = static_cast<int>((clientRect->top() + clientRect->bottom()) / 2);
95 111
96 return element.document().elementFromPoint(centerX , centerY); 112 return element.document().elementFromPoint(centerX , centerY);
97 } 113 }
98 114
115 bool hasDuplicateLabel(TextTrack* currentTrack)
116 {
117 DCHECK(currentTrack);
118 TextTrackList* trackList = currentTrack->trackList();
119 // The runtime of this method is quadratic but since there are usually very few text tracks it won't
120 // affect the performance much.
121 String currentTrackLabel = currentTrack->label();
122 for (unsigned i = 0; i < trackList->length(); i++) {
123 TextTrack* track = trackList->anonymousIndexedGetter(i);
124 if (currentTrack != track && currentTrackLabel == track->label())
125 return true;
126 }
127 return false;
128 }
129
99 } // anonymous namespace 130 } // anonymous namespace
100 131
101 MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls) 132 MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
102 : MediaControlDivElement(mediaControls, MediaControlsPanel) 133 : MediaControlDivElement(mediaControls, MediaControlsPanel)
103 , m_isDisplayed(false) 134 , m_isDisplayed(false)
104 , m_opaque(true) 135 , m_opaque(true)
105 , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired) 136 , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
106 { 137 {
107 } 138 }
108 139
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 MediaControlToggleClosedCaptionsButtonElement* button = new MediaControlTogg leClosedCaptionsButtonElement(mediaControls); 395 MediaControlToggleClosedCaptionsButtonElement* button = new MediaControlTogg leClosedCaptionsButtonElement(mediaControls);
365 button->ensureUserAgentShadowRoot(); 396 button->ensureUserAgentShadowRoot();
366 button->setType(InputTypeNames::button); 397 button->setType(InputTypeNames::button);
367 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button")); 398 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button"));
368 button->setIsWanted(false); 399 button->setIsWanted(false);
369 return button; 400 return button;
370 } 401 }
371 402
372 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() 403 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
373 { 404 {
374 bool captionsVisible = mediaElement().closedCaptionsVisible(); 405 bool captionsVisible = mediaElement().textTracksVisible();
375 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton); 406 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton);
376 setChecked(captionsVisible);
377 } 407 }
378 408
379 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent) 409 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent)
380 { 410 {
381 if (event->type() == EventTypeNames::click) { 411 if (event->type() == EventTypeNames::click) {
382 if (mediaElement().closedCaptionsVisible()) 412 mediaControls().toggleTextTrackList();
383 Platform::current()->recordAction(UserMetricsAction("Media.Controls. ClosedCaptionHide"));
384 else
385 Platform::current()->recordAction(UserMetricsAction("Media.Controls. ClosedCaptionShow"));
386 mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVi sible());
387 setChecked(mediaElement().closedCaptionsVisible());
388 updateDisplayType(); 413 updateDisplayType();
389 event->setDefaultHandled(); 414 event->setDefaultHandled();
390 } 415 }
391 416
392 HTMLInputElement::defaultEventHandler(event); 417 HTMLInputElement::defaultEventHandler(event);
393 } 418 }
394 419
395 // ---------------------------- 420 // ----------------------------
396 421
422 MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls & mediaControls)
423 : MediaControlDivElement(mediaControls, MediaTextTrackList)
424 {
425 }
426
427 MediaControlTextTrackListElement* MediaControlTextTrackListElement::create(Media Controls& mediaControls)
428 {
429 MediaControlTextTrackListElement* element = new MediaControlTextTrackListEle ment(mediaControls);
430 element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track -list"));
431 element->setIsWanted(false);
432 return element;
433 }
434
435 void MediaControlTextTrackListElement::defaultEventHandler(Event* event)
436 {
437 if (event->type() == EventTypeNames::change) {
438 // Identify which input element was selected and set track to showing
439 Node* target = event->target()->toNode();
440 if (!target || !target->isElementNode())
441 return;
442
443 disableShowingTextTracks();
444 int trackIndex = toElement(target)->getIntegralAttribute(trackIndexAttrN ame());
445 if (trackIndex != trackIndexOffValue) {
446 ASSERT(trackIndex >= 0);
447 showTextTrackAtIndex(trackIndex);
448 mediaElement().disableAutomaticTextTrackSelection();
449 }
450
451 mediaControls().toggleTextTrackList();
452 event->setDefaultHandled();
453 }
454 MediaControlDivElement::defaultEventHandler(event);
455 }
456
457 void MediaControlTextTrackListElement::setVisible(bool visible)
458 {
459 if (visible) {
460 setIsWanted(true);
461 refreshTextTrackListMenu();
462 } else {
463 setIsWanted(false);
464 }
465 }
466
467 void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnab le)
468 {
469 TextTrackList* trackList = mediaElement().textTracks();
470 if (indexToEnable >= trackList->length())
471 return;
472 TextTrack* track = trackList->anonymousIndexedGetter(indexToEnable);
473 if (track && track->canBeRendered())
474 track->setMode(TextTrack::showingKeyword());
475 }
476
477 void MediaControlTextTrackListElement::disableShowingTextTracks()
478 {
479 TextTrackList* trackList = mediaElement().textTracks();
480 for (unsigned i = 0; i < trackList->length(); ++i) {
481 TextTrack* track = trackList->anonymousIndexedGetter(i);
482 if (track->mode() == TextTrack::showingKeyword())
483 track->setMode(TextTrack::disabledKeyword());
484 }
485 }
486
487 String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track)
488 {
489 if (!track)
490 return mediaElement().locale().queryString(WebLocalizedString::TextTrack sOff);
491
492 String trackLabel = track->label();
493
494 if (trackLabel.isEmpty())
495 trackLabel = String(mediaElement().locale().queryString(WebLocalizedStri ng::TextTracksNoLabel));
496
497 return trackLabel;
498 }
499
500 // TextTrack parameter when passed in as a nullptr, creates the "Off" list item in the track list.
501 Element* MediaControlTextTrackListElement::createTextTrackListItem(TextTrack* tr ack)
502 {
503 int trackIndex = track ? track->trackIndex() : trackIndexOffValue;
504 HTMLLabelElement* trackItem = HTMLLabelElement::create(document(), nullptr);
505 trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-tra ck-list-item"));
506 HTMLInputElement* trackItemInput = HTMLInputElement::create(document(), null ptr, false);
507 trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-tex t-track-list-item-input"));
508 trackItemInput->setType(InputTypeNames::checkbox);
509 trackItemInput->setIntegralAttribute(trackIndexAttrName(), trackIndex);
510 if (!mediaElement().textTracksVisible()) {
511 if (!track)
512 trackItemInput->setChecked(true);
513 } else {
514 // If there are multiple text tracks set to showing, they must all have
515 // checkmarks displayed.
516 if (track && track->mode() == TextTrack::showingKeyword())
517 trackItemInput->setChecked(true);
518 }
519
520 trackItem->appendChild(trackItemInput);
521 String trackLabel = getTextTrackLabel(track);
522 trackItem->appendChild(Text::create(document(), trackLabel));
523 // Add a track kind marker icon if there are multiple tracks with the same l abel or if the track has no label.
524 if (track && (track->label().isEmpty() || hasDuplicateLabel(track))) {
525 HTMLSpanElement* trackKindMarker = HTMLSpanElement::create(document());
526 if (track->kind() == track->captionsKeyword()) {
527 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-captions"));
528 } else {
529 ASSERT(track->kind() == track->subtitlesKeyword());
530 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-subtitles"));
531 }
532 trackItem->appendChild(trackKindMarker);
533 }
534 return trackItem;
535 }
536
537 void MediaControlTextTrackListElement::refreshTextTrackListMenu()
538 {
539 if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreRead y())
540 return;
541
542 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
543 removeChildren(OmitSubtreeModifiedEvent);
544
545 // Construct a menu for subtitles and captions
546 // Pass in a nullptr to createTextTrackListItem to create the "Off" track it em.
547 appendChild(createTextTrackListItem(nullptr));
548
549 TextTrackList* trackList = mediaElement().textTracks();
550 for (unsigned i = 0; i < trackList->length(); i++) {
551 TextTrack* track = trackList->anonymousIndexedGetter(i);
552 if (!track->canBeRendered())
553 continue;
554 appendChild(createTextTrackListItem(track));
555 }
556 }
557
558 // ----------------------------
559
397 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols) 560 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols)
398 : MediaControlInputElement(mediaControls, MediaSlider) 561 : MediaControlInputElement(mediaControls, MediaSlider)
399 { 562 {
400 } 563 }
401 564
402 MediaControlTimelineElement* MediaControlTimelineElement::create(MediaControls& mediaControls) 565 MediaControlTimelineElement* MediaControlTimelineElement::create(MediaControls& mediaControls)
403 { 566 {
404 MediaControlTimelineElement* timeline = new MediaControlTimelineElement(medi aControls); 567 MediaControlTimelineElement* timeline = new MediaControlTimelineElement(medi aControls);
405 timeline->ensureUserAgentShadowRoot(); 568 timeline->ensureUserAgentShadowRoot();
406 timeline->setType(InputTypeNames::range); 569 timeline->setType(InputTypeNames::range);
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 } 854 }
692 855
693 MediaControlCurrentTimeDisplayElement* MediaControlCurrentTimeDisplayElement::cr eate(MediaControls& mediaControls) 856 MediaControlCurrentTimeDisplayElement* MediaControlCurrentTimeDisplayElement::cr eate(MediaControls& mediaControls)
694 { 857 {
695 MediaControlCurrentTimeDisplayElement* element = new MediaControlCurrentTime DisplayElement(mediaControls); 858 MediaControlCurrentTimeDisplayElement* element = new MediaControlCurrentTime DisplayElement(mediaControls);
696 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display")); 859 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display"));
697 return element; 860 return element;
698 } 861 }
699 862
700 } // namespace blink 863 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698