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

Reviewed by Eric Carlson.

Attempt three of commit. The first two times caused build failures on Chromium.

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/MediaControlRootElement.cpp:
(WebCore::MediaControlRootElement::MediaControlRootElement):
(WebCore::MediaControlRootElement::create): New track container and list elements created.
(WebCore::MediaControlRootElement::setMediaController): Hook up the new elements to the controller..
(WebCore::MediaControlRootElement::hide):
(WebCore::MediaControlRootElement::makeTransparent):
(WebCore::MediaControlRootElement::reset):
(WebCore::MediaControlRootElement::reportedError):
(WebCore::MediaControlRootElement::toggleClosedCaptionTrackList): Shows or hides the popup with the list of tracks.
(WebCore):
* html/shadow/MediaControlRootElement.h:
(WebCore):
(MediaControlRootElement):
* html/shadow/MediaControlRootElementChromium.cpp:
(WebCore::MediaControlRootElementChromium::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@134154 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/MediaControlRootElement.cpp
Source/WebCore/html/shadow/MediaControlRootElement.h
Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp
Source/WebCore/html/shadow/MediaControls.h
Source/WebCore/platform/Language.cpp
Source/WebCore/platform/Language.h
Source/WebCore/rendering/RenderMediaControls.cpp
Source/WebCore/rendering/RenderMediaControlsChromium.cpp

index e404b98..c55c30f 100644 (file)
@@ -1,3 +1,63 @@
+2012-11-09  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 three of commit. The first two times caused build failures on Chromium.
+
+        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/MediaControlRootElement.cpp:
+        (WebCore::MediaControlRootElement::MediaControlRootElement):
+        (WebCore::MediaControlRootElement::create): New track container and list elements created.
+        (WebCore::MediaControlRootElement::setMediaController): Hook up the new elements to the controller..
+        (WebCore::MediaControlRootElement::hide):
+        (WebCore::MediaControlRootElement::makeTransparent):
+        (WebCore::MediaControlRootElement::reset):
+        (WebCore::MediaControlRootElement::reportedError):
+        (WebCore::MediaControlRootElement::toggleClosedCaptionTrackList): Shows or hides the popup with the list of tracks.
+        (WebCore):
+        * html/shadow/MediaControlRootElement.h:
+        (WebCore):
+        (MediaControlRootElement):
+        * html/shadow/MediaControlRootElementChromium.cpp:
+        (WebCore::MediaControlRootElementChromium::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-09  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r134152.
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 0bbf763..a71b36c 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 "MediaControlRootElement.h"
@@ -62,6 +63,9 @@
 #include "Settings.h"
 #include "StyleResolver.h"
 #include "Text.h"
+#if ENABLE(VIDEO_TRACK)
+#include "TextTrackList.h"
+#endif
 
 namespace WebCore {
 
@@ -114,6 +118,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)
@@ -851,25 +863,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();
     }
@@ -877,17 +920,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 22a018f..6d7c108 100644 (file)
@@ -62,6 +62,8 @@ MediaControlRootElement::MediaControlRootElement(Document* document)
     , m_seekBackButton(0)
     , m_seekForwardButton(0)
     , m_toggleClosedCaptionsButton(0)
+    , m_closedCaptionsTrackList(0)
+    , m_closedCaptionsContainer(0)
     , m_panelMuteButton(0)
     , m_volumeSlider(0)
     , m_volumeSliderMuteButton(0)
@@ -162,11 +164,25 @@ PassRefPtr<MediaControlRootElement> MediaControlRootElement::create(Document* do
         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>
@@ -266,6 +282,10 @@ void MediaControlRootElement::setMediaController(MediaControllerInterface* contr
         m_seekForwardButton->setMediaController(controller);
     if (m_toggleClosedCaptionsButton)
         m_toggleClosedCaptionsButton->setMediaController(controller);
+    if (m_closedCaptionsTrackList)
+        m_closedCaptionsTrackList->setMediaController(controller);
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->setMediaController(controller);
     if (m_panelMuteButton)
         m_panelMuteButton->setMediaController(controller);
     if (m_volumeSlider)
@@ -302,6 +322,7 @@ void MediaControlRootElement::hide()
     m_panel->setIsDisplayed(false);
     m_panel->hide();
     m_volumeSliderContainer->hide();
+    m_closedCaptionsContainer->hide();
 }
 
 void MediaControlRootElement::makeOpaque()
@@ -313,6 +334,7 @@ void MediaControlRootElement::makeTransparent()
 {
     m_panel->makeTransparent();
     m_volumeSliderContainer->hide();
+    m_closedCaptionsContainer->hide();
 }
 
 void MediaControlRootElement::reset()
@@ -346,9 +368,10 @@ void MediaControlRootElement::reset()
         m_volumeSlider->setVolume(m_mediaController->volume());
 
     if (m_toggleClosedCaptionsButton) {
-        if (m_mediaController->hasClosedCaptions())
+        if (m_mediaController->hasClosedCaptions()) {
             m_toggleClosedCaptionsButton->show();
-        else
+            m_closedCaptionsTrackList->updateDisplay();
+        } else
             m_toggleClosedCaptionsButton->hide();
     }
 
@@ -447,6 +470,8 @@ void MediaControlRootElement::reportedError()
         m_volumeSliderContainer->hide();
     if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
         m_toggleClosedCaptionsButton->hide();
+    if (m_closedCaptionsContainer)
+        m_closedCaptionsContainer->hide();
 }
 
 void MediaControlRootElement::updateStatusDisplay()
@@ -542,6 +567,19 @@ void MediaControlRootElement::showVolumeSlider()
         m_volumeSliderContainer->show();
 }
 
+void MediaControlRootElement::toggleClosedCaptionTrackList()
+{
+    if (!m_mediaController->hasClosedCaptions())
+        return;
+
+    if (m_closedCaptionsContainer) {
+        if (m_closedCaptionsContainer->isShowing())
+            m_closedCaptionsContainer->hide();
+        else
+            m_closedCaptionsContainer->show();
+    }
+}
+
 bool MediaControlRootElement::shouldHideControls()
 {
     return !m_panel->hovered();
index a0b09d8..06739be 100644 (file)
@@ -42,7 +42,9 @@ class MediaControlPlayButtonElement;
 class MediaControlSeekButtonElement;
 class MediaControlRewindButtonElement;
 class MediaControlReturnToRealtimeButtonElement;
+class MediaControlClosedCaptionsContainerElement;
 class MediaControlToggleClosedCaptionsButtonElement;
+class MediaControlClosedCaptionsTrackListElement;
 class MediaControlCurrentTimeDisplayElement;
 class MediaControlTimelineElement;
 class MediaControlTimeRemainingDisplayElement;
@@ -103,6 +105,8 @@ public:
     void updateTimeDisplay();
     void updateStatusDisplay();
 
+    void toggleClosedCaptionTrackList();
+
 #if ENABLE(VIDEO_TRACK)
     void createTextTrackDisplay();
     void showTextTrackDisplay();
@@ -141,6 +145,8 @@ private:
     MediaControlSeekBackButtonElement* m_seekBackButton;
     MediaControlSeekForwardButtonElement* m_seekForwardButton;
     MediaControlToggleClosedCaptionsButtonElement* m_toggleClosedCaptionsButton;
+    MediaControlClosedCaptionsTrackListElement* m_closedCaptionsTrackList;
+    MediaControlClosedCaptionsContainerElement* m_closedCaptionsContainer;
     MediaControlPanelMuteButtonElement* m_panelMuteButton;
     MediaControlVolumeSliderElement* m_volumeSlider;
     MediaControlVolumeSliderMuteButtonElement* m_volumeSliderMuteButton;
index 82d8f92..c259fdd 100644 (file)
@@ -166,7 +166,7 @@ bool MediaControlRootElementChromium::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 28908a9..6f0fad8 100644 (file)
@@ -70,6 +70,8 @@ class MediaControls : public HTMLDivElement {
     virtual void updateTimeDisplay() = 0;
     virtual void updateStatusDisplay() = 0;
 
+    virtual void toggleClosedCaptionTrackList() { }
+
     virtual bool shouldHideControls() = 0;
 
 #if ENABLE(VIDEO_TRACK)
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;
     }