Support list of tracks in caption media controls
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Nov 2012 00:36:06 +0000 (00:36 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Nov 2012 00:36:06 +0000 (00:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=101669

Reviewed by Eric Carlson.

Attempt four of commit. The first two times caused build failures on Chromium. The third time
crashed the Windows test bot. It's also been rebased since r134488.

Add some new elements to the media control shadow DOM that display the list of available
tracks on an audio/video element. The UI is hidden by default everywhere but on Mac,
where it is given a very basic design. At the moment only the list of available tracks
are displayed; The followup bug will make the UI active: https://bugs.webkit.org/show_bug.cgi?id=101670

No new tests - this doesn't expose any testable surface.

* css/mediaControls.css: Added default rules that hide the new elements.
* css/mediaControlsQuickTime.css: Specific rules that give a basic rendering of the new track list.
* html/shadow/MediaControlElements.cpp:
(WebCore::MediaControlElement::isShowing): Tests for the visibility of a control.
(WebCore::MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement):
(WebCore::MediaControlClosedCaptionsContainerElement::create):
(WebCore::MediaControlClosedCaptionsContainerElement::shadowPseudoId):
(WebCore::MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement):
(WebCore::MediaControlToggleClosedCaptionsButtonElement::create): Now takes a reference to the media controls as a parameter.
(WebCore::MediaControlToggleClosedCaptionsButtonElement::updateDisplayType):
(WebCore::MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler):
(WebCore::MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId):
(WebCore::MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement): New element for holding a list of tracks to display.
* html/shadow/MediaControlElements.h:
(MediaControlElement):
(MediaControlToggleClosedCaptionsButtonElement):
(MediaControlClosedCaptionsContainerElement):
(MediaControlClosedCaptionsTrackListElement): Examines the media element to build a shadow DOM that lists all the tracks available.
* html/shadow/MediaControlsApple.cpp:
(WebCore::MediaControlsApple::MediaControlsApple):
(WebCore::MediaControlsApple::create): New track container and list elements created.
(WebCore::MediaControlsApple::setMediaController): Hook up the new elements to the controller..
(WebCore::MediaControlsApple::hide):
(WebCore::MediaControlsApple::makeTransparent):
(WebCore::MediaControlsApple::reset):
(WebCore::MediaControlsApple::reportedError):
(WebCore::MediaControlsApple::toggleClosedCaptionTrackList): Shows or hides the popup with the list of tracks.
(WebCore):
* html/shadow/MediaControlsApple.h:
(MediaControlsApple):
* html/shadow/MediaControlsChromium.cpp:
(WebCore::MediaControlsChromium::initializeControls): Pass in the controls as a parameter.
* html/shadow/MediaControls.h:
(MediaControls):
* platform/Language.cpp:
(WebCore::displayNameForLanguageLocale): New function to return a human-readable name for a locale, given the identifier input.
* platform/Language.h:
(WebCore):
* rendering/RenderMediaControls.cpp:
(WebCore::RenderMediaControls::paintMediaControlsPart): New enum values into switch.
* rendering/RenderMediaControlsChromium.cpp:
(WebCore::RenderMediaControlsChromium::paintMediaControlsPart): New enum values into switch.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@134507 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/css/mediaControls.css
Source/WebCore/css/mediaControlsQuickTime.css
Source/WebCore/html/shadow/MediaControlElements.cpp
Source/WebCore/html/shadow/MediaControlElements.h
Source/WebCore/html/shadow/MediaControls.h
Source/WebCore/html/shadow/MediaControlsApple.cpp
Source/WebCore/html/shadow/MediaControlsApple.h
Source/WebCore/html/shadow/MediaControlsChromium.cpp
Source/WebCore/platform/Language.cpp
Source/WebCore/platform/Language.h
Source/WebCore/rendering/RenderMediaControls.cpp
Source/WebCore/rendering/RenderMediaControlsChromium.cpp

index 41b9d99..97e8bd4 100644 (file)
@@ -1,3 +1,63 @@
+2012-11-13  Dean Jackson  <dino@apple.com>
+
+        Support list of tracks in caption media controls
+        https://bugs.webkit.org/show_bug.cgi?id=101669
+
+        Reviewed by Eric Carlson.
+
+        Attempt four of commit. The first two times caused build failures on Chromium. The third time
+        crashed the Windows test bot. It's also been rebased since r134488.
+
+        Add some new elements to the media control shadow DOM that display the list of available
+        tracks on an audio/video element. The UI is hidden by default everywhere but on Mac,
+        where it is given a very basic design. At the moment only the list of available tracks
+        are displayed; The followup bug will make the UI active: https://bugs.webkit.org/show_bug.cgi?id=101670
+
+        No new tests - this doesn't expose any testable surface.
+
+        * css/mediaControls.css: Added default rules that hide the new elements.
+        * css/mediaControlsQuickTime.css: Specific rules that give a basic rendering of the new track list.
+        * html/shadow/MediaControlElements.cpp:
+        (WebCore::MediaControlElement::isShowing): Tests for the visibility of a control.
+        (WebCore::MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement):
+        (WebCore::MediaControlClosedCaptionsContainerElement::create):
+        (WebCore::MediaControlClosedCaptionsContainerElement::shadowPseudoId):
+        (WebCore::MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement):
+        (WebCore::MediaControlToggleClosedCaptionsButtonElement::create): Now takes a reference to the media controls as a parameter.
+        (WebCore::MediaControlToggleClosedCaptionsButtonElement::updateDisplayType):
+        (WebCore::MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler):
+        (WebCore::MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId):
+        (WebCore::MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement): New element for holding a list of tracks to display.
+        * html/shadow/MediaControlElements.h:
+        (MediaControlElement):
+        (MediaControlToggleClosedCaptionsButtonElement):
+        (MediaControlClosedCaptionsContainerElement):
+        (MediaControlClosedCaptionsTrackListElement): Examines the media element to build a shadow DOM that lists all the tracks available.
+        * html/shadow/MediaControlsApple.cpp:
+        (WebCore::MediaControlsApple::MediaControlsApple):
+        (WebCore::MediaControlsApple::create): New track container and list elements created.
+        (WebCore::MediaControlsApple::setMediaController): Hook up the new elements to the controller..
+        (WebCore::MediaControlsApple::hide):
+        (WebCore::MediaControlsApple::makeTransparent):
+        (WebCore::MediaControlsApple::reset):
+        (WebCore::MediaControlsApple::reportedError):
+        (WebCore::MediaControlsApple::toggleClosedCaptionTrackList): Shows or hides the popup with the list of tracks.
+        (WebCore):
+        * html/shadow/MediaControlsApple.h:
+        (MediaControlsApple):
+        * html/shadow/MediaControlsChromium.cpp:
+        (WebCore::MediaControlsChromium::initializeControls): Pass in the controls as a parameter.
+        * html/shadow/MediaControls.h:
+        (MediaControls):
+        * platform/Language.cpp:
+        (WebCore::displayNameForLanguageLocale): New function to return a human-readable name for a locale, given the identifier input.
+        * platform/Language.h:
+        (WebCore):
+        * rendering/RenderMediaControls.cpp:
+        (WebCore::RenderMediaControls::paintMediaControlsPart): New enum values into switch.
+        * rendering/RenderMediaControlsChromium.cpp:
+        (WebCore::RenderMediaControlsChromium::paintMediaControlsPart): New enum values into switch.
+
 2012-11-13  Dimitri Glazkov  <dglazkov@chromium.org>
 
         Unreviewed, rolling out r134377.
index 6df0340..00efcbb 100644 (file)
@@ -187,6 +187,14 @@ audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-medi
     color: inherit;
 }
 
+audio::-webkit-media-controls-closed-captions-container, video::-webkit-media-controls-closed-captions-container {
+    display: none;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list, video::-webkit-media-controls-closed-captions-track-list {
+    display: none;
+}
+
 audio::-webkit-media-controls-volume-slider-mute-button, video::-webkit-media-controls-volume-slider-mute-button {
     -webkit-appearance: media-volume-slider-mute-button;
     display: none;
index 2eb908b..0075e2c 100644 (file)
@@ -188,17 +188,6 @@ audio::-webkit-media-controls-status-display, video::-webkit-media-controls-stat
     text-decoration: none;
 }
 
-audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button {
-    -webkit-appearance: media-toggle-closed-captions-button;
-    display: -webkit-box;
-    width: 16px;
-    height: 16px;
-    margin-left: 7px;
-    margin-right: 7px;
-    -webkit-box-ordinal-group: 3; /* between mute and fullscreen */
-    border: none !important;
-}
-
 audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container {
     -webkit-appearance: media-volume-slider-container;
     position: absolute;
@@ -239,3 +228,104 @@ audio::-webkit-media-controls-volume-slider-mute-button, video::-webkit-media-co
 
     border: none !important;
 }
+
+audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button {
+    -webkit-appearance: media-toggle-closed-captions-button;
+    display: -webkit-box;
+    width: 16px;
+    height: 16px;
+    margin-left: 7px;
+    margin-right: 7px;
+    -webkit-box-ordinal-group: 3; /* between mute and fullscreen */
+    border: none !important;
+}
+
+audio::-webkit-media-controls-closed-captions-container, video::-webkit-media-controls-closed-captions-container {
+    -webkit-appearance: media-closed-captions-container;
+    position: absolute;
+    display: block;
+    bottom: 29px;
+    margin-left: -155px;
+    z-index: 2;
+    width: 200px;
+    height: 250px;
+    background-color: rgba(0, 0, 0, 0.85);
+    border: 1px solid rgb(66, 66, 66);
+    border-radius: 8px;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list, video::-webkit-media-controls-closed-captions-track-list {
+    -webkit-appearance: media-closed-captions-track-list;
+    position: absolute;
+    display: block;
+    top: 5px;
+    left: 5px;
+    width: 190px;
+    height: 240px;
+    overflow-x: hidden;
+    overflow-y: scroll;
+    text-align: left;
+    font-family: "Helvetica Bold", "Helvetica";
+    font-weight: bold;
+    font-size: 9pt;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list h3,
+video::-webkit-media-controls-closed-captions-track-list h3 {
+    margin: 0;
+    color: #bbb;
+    text-shadow: 0 1px 0 black;
+    padding-left: 4px;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    border-bottom: 1px solid #555;
+    font-size: 9pt;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list ul,
+video::-webkit-media-controls-closed-captions-track-list ul {
+    list-style-type: none;
+    margin: 0 0 8px 0;
+    padding: 0;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list li,
+video::-webkit-media-controls-closed-captions-track-list li {
+    color: white;
+    text-shadow: 0 1px 0 black;
+    margin: 0;
+    padding-left: 24px;
+    padding-right: 10px;
+    padding-top: 0.35em;
+    padding-bottom: 0.3em;
+    width: 190px;
+    height: 2.0em;
+    border-bottom: 1px solid #555;
+    box-sizing: border-box;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    -webkit-text-overflow: ellipsis;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list li:hover,
+video::-webkit-media-controls-closed-captions-track-list li:hover {
+    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(79, 112, 245)), color-stop(1, rgb(28, 66, 245)));
+    border-bottom: 1px solid rgb(28, 66, 245);
+}
+
+audio::-webkit-media-controls-closed-captions-track-list li.selected,
+video::-webkit-media-controls-closed-captions-track-list li.selected {
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA9CAYAAADmgpoeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTBEQkI5QzgyMTc4MTFFMkJERDdBRjI3NEQwNzZERjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTBEQkI5QzkyMTc4MTFFMkJERDdBRjI3NEQwNzZERjAiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFMERCQjlDNjIxNzgxMUUyQkREN0FGMjc0RDA3NkRGMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFMERCQjlDNzIxNzgxMUUyQkREN0FGMjc0RDA3NkRGMCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqpWz0UAAAHPSURBVHja7JqBbYQwDEXdDRghI7BBGSEjZARGyAaMwAg3AtcJMkJug4xAUymqTggVO1yJbZ0lCyGd0D3Z/Pw4fICAWNfV5IvN+Zmzz2k2P7mX61fOx9M9X6Ccy0qLOWfHGcqt9Ji4V6oGyr2hGkD1GqG6nFEVVAGbNEIN6qAKWKCsU1KgRgLUIgXqRzASEiqydhQbME+oVi8FyhCqNYKUKGZVz3v1VC1MpLJlUVetUWO1AkgKgnUaJEFh161ZWrW8OsEoYJhqeWlQDlmtThpY1FitQWu1bhqVELsgi1NCr65aBNEYrmibefNnQrFBpuJ5tum2pFgdjOOeKMqFFA33n1CUQWXAwJXnHko8B1dAgkNOn/wVLzkVbnnBrNBcpWBUOH9i7bpxHontjsWQm0nLeSaxO8hEiFFsubCGmpZEnnH5lmCU8fNvSyLbsK0vJB7vLMhK8xiAEsXEN3MalXDUby3aOI1Kc5xeAMZve1L5mYKMo6CTLRmBa5xsSd4HDMQzY1kzjYqWFHMoTm1JB1KCuHCLG4QGdvuuC72kBYlx4OYTSI2D7c0MkuOPtc2C9NgRkgQaYkdIJtASm5F2rwnMsHfyJ+V/0gjWcWjDbwEGAN9/NX8H7V/FAAAAAElFTkSuQmCC');
+    background-repeat: no-repeat;
+    background-position: 0.5em 0.5em;
+    background-size: 1em 1em;
+}
+
+audio::-webkit-media-controls-closed-captions-track-list li.selected:hover,
+video::-webkit-media-controls-closed-captions-track-list li.selected:hover {
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA9CAYAAADmgpoeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTBEQkI5QzgyMTc4MTFFMkJERDdBRjI3NEQwNzZERjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTBEQkI5QzkyMTc4MTFFMkJERDdBRjI3NEQwNzZERjAiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFMERCQjlDNjIxNzgxMUUyQkREN0FGMjc0RDA3NkRGMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFMERCQjlDNzIxNzgxMUUyQkREN0FGMjc0RDA3NkRGMCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqpWz0UAAAHPSURBVHja7JqBbYQwDEXdDRghI7BBGSEjZARGyAaMwAg3AtcJMkJug4xAUymqTggVO1yJbZ0lCyGd0D3Z/Pw4fICAWNfV5IvN+Zmzz2k2P7mX61fOx9M9X6Ccy0qLOWfHGcqt9Ji4V6oGyr2hGkD1GqG6nFEVVAGbNEIN6qAKWKCsU1KgRgLUIgXqRzASEiqydhQbME+oVi8FyhCqNYKUKGZVz3v1VC1MpLJlUVetUWO1AkgKgnUaJEFh161ZWrW8OsEoYJhqeWlQDlmtThpY1FitQWu1bhqVELsgi1NCr65aBNEYrmibefNnQrFBpuJ5tum2pFgdjOOeKMqFFA33n1CUQWXAwJXnHko8B1dAgkNOn/wVLzkVbnnBrNBcpWBUOH9i7bpxHontjsWQm0nLeSaxO8hEiFFsubCGmpZEnnH5lmCU8fNvSyLbsK0vJB7vLMhK8xiAEsXEN3MalXDUby3aOI1Kc5xeAMZve1L5mYKMo6CTLRmBa5xsSd4HDMQzY1kzjYqWFHMoTm1JB1KCuHCLG4QGdvuuC72kBYlx4OYTSI2D7c0MkuOPtc2C9NgRkgQaYkdIJtASm5F2rwnMsHfyJ+V/0gjWcWjDbwEGAN9/NX8H7V/FAAAAAElFTkSuQmCC'), -webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(79, 112, 245)), color-stop(1, rgb(28, 66, 245)));
+    background-repeat: no-repeat, repeat;
+    background-position: 0.5em 0.5em, top left;
+    background-size: 1em 1em, 100% 100%;
+}
index fde8ba4..2128bc2 100644 (file)
@@ -43,6 +43,7 @@
 #include "HTMLMediaElement.h"
 #include "HTMLNames.h"
 #include "HTMLVideoElement.h"
+#include "Language.h"
 #include "LayoutRepainter.h"
 #include "LocalizedStrings.h"
 #include "MediaControls.h"
@@ -61,6 +62,9 @@
 #include "Settings.h"
 #include "StyleResolver.h"
 #include "Text.h"
+#if ENABLE(VIDEO_TRACK)
+#include "TextTrackList.h"
+#endif
 
 namespace WebCore {
 
@@ -113,6 +117,14 @@ void MediaControlElement::hide()
     setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
 }
 
+bool MediaControlElement::isShowing() const
+{
+    const StylePropertySet* propertySet = inlineStyle();
+    // Following the code from show() and hide() above, we only have
+    // to check for the presense of inline display.
+    return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay));
+}
+
 // ----------------------------
 
 inline MediaControlPanelElement::MediaControlPanelElement(Document* document)
@@ -850,25 +862,56 @@ const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId()
 
 // ----------------------------
 
-inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document)
+inline MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement(Document* document)
+    : MediaControlElement(document)
+{
+}
+
+PassRefPtr<MediaControlClosedCaptionsContainerElement> MediaControlClosedCaptionsContainerElement::create(Document* document)
+{
+    RefPtr<MediaControlClosedCaptionsContainerElement> element = adoptRef(new MediaControlClosedCaptionsContainerElement(document));
+    element->hide();
+    return element.release();
+}
+
+const AtomicString& MediaControlClosedCaptionsContainerElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-container", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document, MediaControls* controls)
     : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
+    , m_controls(controls)
 {
 }
 
-PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document)
+PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document, MediaControls* controls)
 {
-    RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document));
+    ASSERT(controls);
+
+    RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
     button->createShadowSubtree();
     button->setType("button");
     button->hide();
     return button.release();
 }
 
+void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
+{
+    setDisplayType(mediaController()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
+}
+
 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
 {
     if (event->type() == eventNames().clickEvent) {
+        // FIXME: This is now incorrectly doing two things at once: showing the list of captions and toggling display.
+        // https://bugs.webkit.org/show_bug.cgi?id=101670
         mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
         setChecked(mediaController()->closedCaptionsVisible());
+        m_controls->toggleClosedCaptionTrackList();
         updateDisplayType();
         event->setDefaultHandled();
     }
@@ -876,17 +919,117 @@ void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e
     HTMLInputElement::defaultEventHandler(event);
 }
 
-void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
+const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
 {
-    setDisplayType(mediaController()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
+    return id;
 }
 
-const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
+// ----------------------------
+
+inline MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement(Document* document)
+    : MediaControlElement(document)
 {
-    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
+}
+
+PassRefPtr<MediaControlClosedCaptionsTrackListElement> MediaControlClosedCaptionsTrackListElement::create(Document* document)
+{
+    RefPtr<MediaControlClosedCaptionsTrackListElement> element = adoptRef(new MediaControlClosedCaptionsTrackListElement(document));
+    return element.release();
+}
+
+void MediaControlClosedCaptionsTrackListElement::defaultEventHandler(Event* event)
+{
+    // FIXME: Hook this up to actual text tracks.
+    // https://bugs.webkit.org/show_bug.cgi?id=101670
+    UNUSED_PARAM(event);
+}
+
+const AtomicString& MediaControlClosedCaptionsTrackListElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-track-list", AtomicString::ConstructFromLiteral));
     return id;
 }
 
+void MediaControlClosedCaptionsTrackListElement::updateDisplay()
+{
+#if ENABLE(VIDEO_TRACK)
+    // Remove any existing content.
+    removeChildren();
+
+    if (!mediaController()->hasClosedCaptions())
+        return;
+
+    HTMLMediaElement* mediaElement = toParentMediaElement(this);
+    if (!mediaElement)
+        return;
+
+    TextTrackList* trackList = mediaElement->textTracks();
+
+    if (!trackList || !trackList->length())
+        return;
+
+    Document* doc = document();
+
+    RefPtr<Element> captionsSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
+    RefPtr<Element> captionsHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
+    captionsHeader->appendChild(doc->createTextNode("Closed Captions"));
+    captionsSection->appendChild(captionsHeader);
+    RefPtr<Element> captionsList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
+
+    RefPtr<Element> subtitlesSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
+    RefPtr<Element> subtitlesHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
+    subtitlesHeader->appendChild(doc->createTextNode("Subtitles"));
+    subtitlesSection->appendChild(subtitlesHeader);
+    RefPtr<Element> subtitlesList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
+
+    RefPtr<Element> trackItem;
+
+    trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
+    trackItem->appendChild(doc->createTextNode("Off"));
+    // FIXME: These lists are not yet live. Mark the Off entry as the selected one for now.
+    trackItem->setAttribute(classAttr, "selected");
+    captionsList->appendChild(trackItem);
+
+    trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
+    trackItem->appendChild(doc->createTextNode("Off"));
+    // FIXME: These lists are not yet live. Mark the Off entry as the selected one for now.
+    trackItem->setAttribute(classAttr, "selected");
+    subtitlesList->appendChild(trackItem);
+
+    bool hasCaptions = false;
+    bool hasSubtitles = false;
+
+    for (unsigned i = 0, length = trackList->length(); i < length; ++i) {
+        TextTrack* track = trackList->item(i);
+        trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
+        AtomicString labelText = track->label();
+        if (labelText.isNull() || labelText.isEmpty())
+            labelText = displayNameForLanguageLocale(track->language());
+        if (labelText.isNull() || labelText.isEmpty())
+            labelText = "No Label";
+
+        if (track->kind() == track->captionsKeyword()) {
+            hasCaptions = true;
+            captionsList->appendChild(trackItem);
+        }
+        if (track->kind() == track->subtitlesKeyword()) {
+            hasSubtitles = true;
+            subtitlesList->appendChild(trackItem);
+        }
+        trackItem->appendChild(doc->createTextNode(labelText));
+    }
+
+    captionsSection->appendChild(captionsList);
+    subtitlesSection->appendChild(subtitlesList);
+
+    if (hasCaptions)
+        appendChild(captionsSection);
+    if (hasSubtitles)
+        appendChild(subtitlesSection);
+#endif
+}
+
 // ----------------------------
 
 MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls)
index 66cb2da..c3fbc81 100644 (file)
@@ -75,6 +75,8 @@ enum MediaControlElementType {
     MediaTextTrackDisplay,
     MediaExitFullscreenButton,
     MediaOverlayPlayButton,
+    MediaClosedCaptionsContainer,
+    MediaClosedCaptionsTrackList,
 };
 
 HTMLMediaElement* toParentMediaElement(Node*);
@@ -88,6 +90,7 @@ class MediaControlElement : public HTMLDivElement {
 public:
     void hide();
     void show();
+    bool isShowing() const;
 
     virtual MediaControlElementType displayType() const = 0;
 
@@ -380,17 +383,51 @@ private:
 
 class MediaControlToggleClosedCaptionsButtonElement : public MediaControlInputElement {
 public:
-    static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(Document*);
+    static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(Document*, MediaControls*);
 
-    virtual void defaultEventHandler(Event*);
     virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+    virtual void defaultEventHandler(Event*);
     virtual void updateDisplayType();
 
 private:
-    MediaControlToggleClosedCaptionsButtonElement(Document*);
+    MediaControlToggleClosedCaptionsButtonElement(Document*, MediaControls*);
+    virtual const AtomicString& shadowPseudoId() const;
+
+    MediaControls* m_controls;
+};
+
+// ----------------------------
 
+class MediaControlClosedCaptionsContainerElement : public MediaControlElement {
+public:
+    static PassRefPtr<MediaControlClosedCaptionsContainerElement> create(Document*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+private:
+    MediaControlClosedCaptionsContainerElement(Document*);
+
+    virtual MediaControlElementType displayType() const { return MediaClosedCaptionsContainer; }
     virtual const AtomicString& shadowPseudoId() const;
-};    
+};
+
+// ----------------------------
+
+class MediaControlClosedCaptionsTrackListElement : public MediaControlElement {
+public:
+    static PassRefPtr<MediaControlClosedCaptionsTrackListElement> create(Document*);
+
+    virtual void defaultEventHandler(Event*);
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+    void updateDisplay();
+
+private:
+    MediaControlClosedCaptionsTrackListElement(Document*);
+
+    virtual MediaControlElementType displayType() const { return MediaClosedCaptionsTrackList; }
+    virtual const AtomicString& shadowPseudoId() const;
+};
 
 // ----------------------------
 
index 942c0f4..2580502 100644 (file)
@@ -88,6 +88,7 @@ class MediaControls : public HTMLDivElement {
     virtual void changedVolume();
 
     virtual void changedClosedCaptionsVisibility();
+    virtual void toggleClosedCaptionTrackList() { }
 
     virtual void enteredFullscreen();
     virtual void exitedFullscreen();
index 0e539c6..6cc1c7f 100644 (file)
@@ -55,6 +55,8 @@ MediaControlsApple::MediaControlsApple(Document* document)
     , m_timelineContainer(0)
     , m_seekBackButton(0)
     , m_seekForwardButton(0)
+    , m_closedCaptionsTrackList(0)
+    , m_closedCaptionsContainer(0)
     , m_volumeSliderMuteButton(0)
     , m_volumeSliderContainer(0)
     , m_fullScreenMinVolumeButton(0)
@@ -145,11 +147,24 @@ PassRefPtr<MediaControlsApple> MediaControlsApple::createControls(Document* docu
         return 0;
 
     if (document->page()->theme()->supportsClosedCaptioning()) {
-        RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document);
+        RefPtr<MediaControlClosedCaptionsContainerElement> closedCaptionsContainer = MediaControlClosedCaptionsContainerElement::create(document);
+
+        RefPtr<MediaControlClosedCaptionsTrackListElement> closedCaptionsTrackList = MediaControlClosedCaptionsTrackListElement::create(document);
+        controls->m_closedCaptionsTrackList = closedCaptionsTrackList.get();
+        closedCaptionsContainer->appendChild(closedCaptionsTrackList.release(), ec, true);
+        if (ec)
+            return 0;
+
+        RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get());
         controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get();
         panel->appendChild(toggleClosedCaptionsButton.release(), ec, true);
         if (ec)
             return 0;
+
+        controls->m_closedCaptionsContainer = closedCaptionsContainer.get();
+        panel->appendChild(closedCaptionsContainer.release(), ec, true);
+        if (ec)
+            return 0;
     }
 
     // FIXME: Only create when needed <http://webkit.org/b/57163>
@@ -252,18 +267,26 @@ void MediaControlsApple::setMediaController(MediaControllerInterface* controller
         m_fullScreenVolumeSlider->setMediaController(controller);
     if (m_fullScreenMaxVolumeButton)
         m_fullScreenMaxVolumeButton->setMediaController(controller);
+    if (m_closedCaptionsTrackList)
+        m_closedCaptionsTrackList->setMediaController(controller);
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->setMediaController(controller);
 }
 
 void MediaControlsApple::hide()
 {
     MediaControls::hide();
     m_volumeSliderContainer->hide();
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->hide();
 }
 
 void MediaControlsApple::makeTransparent()
 {
     MediaControls::makeTransparent();
     m_volumeSliderContainer->hide();
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->hide();
 }
 
 void MediaControlsApple::reset()
@@ -297,9 +320,11 @@ void MediaControlsApple::reset()
         m_volumeSlider->setVolume(m_mediaController->volume());
 
     if (m_toggleClosedCaptionsButton) {
-        if (m_mediaController->hasClosedCaptions())
+        if (m_mediaController->hasClosedCaptions()) {
             m_toggleClosedCaptionsButton->show();
-        else
+            if (m_closedCaptionsTrackList)
+                m_closedCaptionsTrackList->updateDisplay();
+        } else
             m_toggleClosedCaptionsButton->hide();
     }
 
@@ -370,6 +395,8 @@ void MediaControlsApple::reportedError()
         m_volumeSliderContainer->hide();
     if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
         m_toggleClosedCaptionsButton->hide();
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->hide();
 }
 
 void MediaControlsApple::updateStatusDisplay()
@@ -446,6 +473,19 @@ void MediaControlsApple::showVolumeSlider()
         m_volumeSliderContainer->show();
 }
 
+void MediaControlsApple::toggleClosedCaptionTrackList()
+{
+    if (!m_mediaController->hasClosedCaptions())
+        return;
+
+    if (m_closedCaptionsContainer) {
+        if (m_closedCaptionsContainer->isShowing())
+            m_closedCaptionsContainer->hide();
+        else
+            m_closedCaptionsContainer->show();
+    }
+}
+
 }
 
 #endif
index b8ce75d..dc47306 100644 (file)
@@ -58,6 +58,8 @@ public:
     virtual void updateCurrentTimeDisplay() OVERRIDE;
     virtual void updateStatusDisplay() OVERRIDE;
 
+    void toggleClosedCaptionTrackList();
+
 private:
     MediaControlsApple(Document*);
 
@@ -69,6 +71,8 @@ private:
     MediaControlTimelineContainerElement* m_timelineContainer;
     MediaControlSeekBackButtonElement* m_seekBackButton;
     MediaControlSeekForwardButtonElement* m_seekForwardButton;
+    MediaControlClosedCaptionsTrackListElement* m_closedCaptionsTrackList;
+    MediaControlClosedCaptionsContainerElement* m_closedCaptionsContainer;
     MediaControlVolumeSliderMuteButtonElement* m_volumeSliderMuteButton;
     MediaControlVolumeSliderContainerElement* m_volumeSliderContainer;
     MediaControlFullscreenVolumeMinButtonElement* m_fullScreenMinVolumeButton;
index c4683eb..28b77cf 100644 (file)
@@ -136,7 +136,7 @@ bool MediaControlsChromium::initializeControls(Document* document)
         return false;
 
     if (document->page()->theme()->supportsClosedCaptioning()) {
-        RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document);
+        RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, this);
         m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get();
         panel->appendChild(toggleClosedCaptionsButton.release(), ec, true);
         if (ec)
index dba3a89..e28e76e 100644 (file)
 #include "Language.h"
 
 #include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
 #include <wtf/text/WTFString.h>
 
+#if PLATFORM(MAC)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
 namespace WebCore {
 
 typedef HashMap<void*, LanguageChangeObserverFunction> ObserverMap;
@@ -142,5 +147,14 @@ String preferredLanguageFromList(const Vector<String>& languageList)
 
     return emptyString();
 }
-    
+
+String displayNameForLanguageLocale(const String& localeName)
+{
+#if PLATFORM(MAC)
+    if (!localeName.isNull() && !localeName.isEmpty())
+        return CFLocaleCopyDisplayNameForPropertyValue(CFLocaleCopyCurrent(), kCFLocaleIdentifier, localeName.createCFString().get());
+#endif
+    return localeName;
+}
+
 }
index 411615c..29f1ca8 100644 (file)
@@ -43,6 +43,8 @@ void removeLanguageChangeObserver(void* context);
 
 Vector<String> platformUserPreferredLanguages();
 
+String displayNameForLanguageLocale(const String&);
+
 // Called from platform specific code when the user's preferred language(s) change.
 void languageDidChange();
 }
index cfaed5e..f17647b 100644 (file)
@@ -197,9 +197,11 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
         ASSERT_NOT_REACHED();
     case MediaTextTrackDisplayContainer:
     case MediaTextTrackDisplay:
+    case MediaClosedCaptionsContainer:
+    case MediaClosedCaptionsTrackList:
         ASSERT_NOT_REACHED();
         break;
-}
+    }
 
     return false;
 }
index 38a4e5a..0451fbd 100644 (file)
@@ -383,6 +383,8 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType
     case MediaTextTrackDisplay:
     case MediaFullScreenVolumeSlider:
     case MediaFullScreenVolumeSliderThumb:
+    case MediaClosedCaptionsContainer:
+    case MediaClosedCaptionsTrackList:
         ASSERT_NOT_REACHED();
         break;
     }