Support text track selection in video controls
Enable the user to select between text tracks with a menu that is displayed when the CC button is clicked. BUG=353105,495851 TEST=run-webkit-tests media* Review URL: https://codereview.chromium.org/1079323002 Cr-Commit-Position: refs/heads/master@{#389201}
This commit is contained in:
content
third_party/WebKit
LayoutTests
media
media-controls.js
track
cue-style-invalidation.htmltext-track-selection-menu-add-track-expected.txttext-track-selection-menu-add-track.htmltext-track-selection-menu-multiple-tracks-expected.txttext-track-selection-menu-multiple-tracks.html
video-controls-captions-expected.txtvideo-controls-captions-load-by-lang-expected.txtvideo-controls-captions-load-by-lang.htmlvideo-controls-captions-on-off-expected.txtvideo-controls-captions-on-off.htmlvideo-controls-captions.htmlvideo-controls-track-selection-menu-expected.txtvideo-controls-track-selection-menu.htmlSource
core
css
html
HTMLMediaElement.cppHTMLMediaElement.h
shadow
MediaControlElementTypes.hMediaControlElements.cppMediaControlElements.hMediaControls.cppMediaControls.h
track
paint
platform
public
@@ -856,6 +856,14 @@ below:
|
|||||||
Please lengthen this text to <ph name="MIN_CHARACTERS">$2<ex>101</ex></ph> characters or more (you are currently using <ph name="CURRENT_LENGTH">$1<ex>100</ex></ph> characters).
|
Please lengthen this text to <ph name="MIN_CHARACTERS">$2<ex>101</ex></ph> characters or more (you are currently using <ph name="CURRENT_LENGTH">$1<ex>100</ex></ph> characters).
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
|
<message name="IDS_MEDIA_TRACKS_NO_LABEL" desc="Menu item label for a text track that has no name specified">
|
||||||
|
Unknown
|
||||||
|
</message>
|
||||||
|
|
||||||
|
<message name="IDS_MEDIA_TRACKS_OFF" desc="Menu item label for a text track that represents disabling closed captions">
|
||||||
|
Off
|
||||||
|
</message>
|
||||||
|
|
||||||
<message name="IDS_PLUGIN_INITIALIZATION_ERROR" desc="A message displayed when a plugin failed to load">
|
<message name="IDS_PLUGIN_INITIALIZATION_ERROR" desc="A message displayed when a plugin failed to load">
|
||||||
Couldn't load plugin.
|
Couldn't load plugin.
|
||||||
</message>
|
</message>
|
||||||
|
@@ -337,6 +337,10 @@ static int ToMessageID(WebLocalizedString::Name name) {
|
|||||||
return IDS_FORM_INPUT_WEEK_TEMPLATE;
|
return IDS_FORM_INPUT_WEEK_TEMPLATE;
|
||||||
case WebLocalizedString::WeekNumberLabel:
|
case WebLocalizedString::WeekNumberLabel:
|
||||||
return IDS_FORM_WEEK_NUMBER_LABEL;
|
return IDS_FORM_WEEK_NUMBER_LABEL;
|
||||||
|
case WebLocalizedString::TextTracksNoLabel:
|
||||||
|
return IDS_MEDIA_TRACKS_NO_LABEL;
|
||||||
|
case WebLocalizedString::TextTracksOff:
|
||||||
|
return IDS_MEDIA_TRACKS_OFF;
|
||||||
// This "default:" line exists to avoid compile warnings about enum
|
// This "default:" line exists to avoid compile warnings about enum
|
||||||
// coverage when we add a new symbol to WebLocalizedString.h in WebKit.
|
// coverage when we add a new symbol to WebLocalizedString.h in WebKit.
|
||||||
// After a planned WebKit patch is landed, we need to add a case statement
|
// After a planned WebKit patch is landed, we need to add a case statement
|
||||||
@@ -673,6 +677,24 @@ const DataResource kDataResources[] = {
|
|||||||
{"mediaplayerOverlayPlayNew",
|
{"mediaplayerOverlayPlayNew",
|
||||||
IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON_NEW,
|
IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON_NEW,
|
||||||
ui::SCALE_FACTOR_100P},
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerTrackSelectionCheckmark",
|
||||||
|
IDR_MEDIAPLAYER_TRACKSELECTION_CHECKMARK,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerTrackSelectionCheckmarkNew",
|
||||||
|
IDR_MEDIAPLAYER_TRACKSELECTION_CHECKMARK_NEW,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerClosedCaptionsIcon",
|
||||||
|
IDR_MEDIAPLAYER_CLOSEDCAPTIONS_ICON,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerClosedCaptionsIconNew",
|
||||||
|
IDR_MEDIAPLAYER_CLOSEDCAPTIONS_ICON_NEW,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerSubtitlesIcon",
|
||||||
|
IDR_MEDIAPLAYER_SUBTITLES_ICON,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
|
{"mediaplayerSubtitlesIconNew",
|
||||||
|
IDR_MEDIAPLAYER_SUBTITLES_ICON_NEW,
|
||||||
|
ui::SCALE_FACTOR_100P},
|
||||||
{"searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P},
|
{"searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P},
|
||||||
{"searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED, ui::SCALE_FACTOR_100P},
|
{"searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED, ui::SCALE_FACTOR_100P},
|
||||||
{"searchMagnifier", IDR_SEARCH_MAGNIFIER, ui::SCALE_FACTOR_100P},
|
{"searchMagnifier", IDR_SEARCH_MAGNIFIER, ui::SCALE_FACTOR_100P},
|
||||||
|
@@ -47,13 +47,18 @@ function mediaControlsButton(element, id)
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function elementCoordinates(element)
|
||||||
|
{
|
||||||
|
var elementBoundingRect = element.getBoundingClientRect();
|
||||||
|
var x = elementBoundingRect.left + elementBoundingRect.width / 2;
|
||||||
|
var y = elementBoundingRect.top + elementBoundingRect.height / 2;
|
||||||
|
return new Array(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
function mediaControlsButtonCoordinates(element, id)
|
function mediaControlsButtonCoordinates(element, id)
|
||||||
{
|
{
|
||||||
var button = mediaControlsButton(element, id);
|
var button = mediaControlsButton(element, id);
|
||||||
var buttonBoundingRect = button.getBoundingClientRect();
|
return elementCoordinates(button);
|
||||||
var x = buttonBoundingRect.left + buttonBoundingRect.width / 2;
|
|
||||||
var y = buttonBoundingRect.top + buttonBoundingRect.height / 2;
|
|
||||||
return new Array(x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mediaControlsButtonDimensions(element, id)
|
function mediaControlsButtonDimensions(element, id)
|
||||||
@@ -119,12 +124,45 @@ function testClosedCaptionsButtonVisibility(expected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clickAtCoordinates(x, y)
|
||||||
|
{
|
||||||
|
eventSender.mouseMoveTo(x, y);
|
||||||
|
eventSender.mouseDown();
|
||||||
|
eventSender.mouseUp();
|
||||||
|
}
|
||||||
|
|
||||||
function clickCCButton()
|
function clickCCButton()
|
||||||
{
|
{
|
||||||
consoleWrite("*** Click the CC button.");
|
consoleWrite("*** Click the CC button.");
|
||||||
eventSender.mouseMoveTo(captionsButtonCoordinates[0], captionsButtonCoordinates[1]);
|
clickAtCoordinates(captionsButtonCoordinates[0], captionsButtonCoordinates[1]);
|
||||||
eventSender.mouseDown();
|
}
|
||||||
eventSender.mouseUp();
|
|
||||||
|
function textTrackListItemAtIndex(video, index)
|
||||||
|
{
|
||||||
|
var textTrackListElementID = "-internal-media-controls-text-track-list";
|
||||||
|
var textTrackListElement = mediaControlsElement(internals.shadowRoot(video).firstChild, textTrackListElementID);
|
||||||
|
if (!textTrackListElement)
|
||||||
|
throw "Failed to find text track list element";
|
||||||
|
|
||||||
|
var trackListItems = textTrackListElement.childNodes;
|
||||||
|
for (var i = 0; i < trackListItems.length; i++) {
|
||||||
|
var trackListItem = trackListItems[i];
|
||||||
|
if (trackListItem.firstChild.getAttribute("data-track-index") == index)
|
||||||
|
return trackListItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTextTrack(video, index)
|
||||||
|
{
|
||||||
|
clickCCButton();
|
||||||
|
var trackListItemElement = textTrackListItemAtIndex(video, index);
|
||||||
|
var trackListItemCoordinates = elementCoordinates(trackListItemElement);
|
||||||
|
clickAtCoordinates(trackListItemCoordinates[0], trackListItemCoordinates[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function turnClosedCaptionsOff(video)
|
||||||
|
{
|
||||||
|
selectTextTrack(video, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function runAfterHideMediaControlsTimerFired(func, mediaElement)
|
function runAfterHideMediaControlsTimerFired(func, mediaElement)
|
||||||
|
@@ -37,7 +37,7 @@ async_test(function(t) {
|
|||||||
ascendant.offsetTop;
|
ascendant.offsetTop;
|
||||||
ascendant.classList.add("cue");
|
ascendant.classList.add("cue");
|
||||||
if (window.internals)
|
if (window.internals)
|
||||||
assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 8);
|
assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 9);
|
||||||
assert_equals(getComputedStyle(cueNode).backgroundColor, green);
|
assert_equals(getComputedStyle(cueNode).backgroundColor, green);
|
||||||
|
|
||||||
assert_equals(getComputedStyle(cNode).backgroundColor, red);
|
assert_equals(getComputedStyle(cNode).backgroundColor, red);
|
||||||
|
22
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-add-track-expected.txt
vendored
Normal file
22
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-add-track-expected.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Test that we can add a track dynamically and it is displayed on the track selection menu
|
||||||
|
EVENT(canplaythrough)
|
||||||
|
|
||||||
|
** Caption button should be visible and enabled.
|
||||||
|
EXPECTED (captionsButtonCoordinates[0] > '0') OK
|
||||||
|
EXPECTED (captionsButtonCoordinates[1] > '0') OK
|
||||||
|
EXPECTED (captionsButtonElement.disabled == 'false') OK
|
||||||
|
|
||||||
|
EXPECTED (video.textTracks.length == '2') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'showing') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'hidden') OK
|
||||||
|
|
||||||
|
Verify the default track is being displayed
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Lorem') OK
|
||||||
|
|
||||||
|
Select the newly added track
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'showing') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Bonjour') OK
|
||||||
|
END OF TEST
|
||||||
|
|
51
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-add-track.html
vendored
Normal file
51
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-add-track.html
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../media-file.js"></script>
|
||||||
|
<!-- TODO(srivats): Convert test to testharness.js. crbug.com/588956
|
||||||
|
(Please avoid writing new tests using video-test.js) -->
|
||||||
|
<script src="../video-test.js"></script>
|
||||||
|
<script src="../media-controls.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var trackCueText = "Bonjour";
|
||||||
|
|
||||||
|
function selectTrackAdded()
|
||||||
|
{
|
||||||
|
findMediaElement();
|
||||||
|
testClosedCaptionsButtonVisibility(true);
|
||||||
|
consoleWrite("");
|
||||||
|
testExpected("video.textTracks.length", 2);
|
||||||
|
testExpected("video.textTracks[0].mode", "showing");
|
||||||
|
testExpected("video.textTracks[1].mode", "hidden");
|
||||||
|
|
||||||
|
consoleWrite("");
|
||||||
|
consoleWrite("Verify the default track is being displayed");
|
||||||
|
testExpected("textTrackDisplayElement(video, 'display').innerText", "Lorem");
|
||||||
|
|
||||||
|
consoleWrite("");
|
||||||
|
consoleWrite("Select the newly added track");
|
||||||
|
selectTextTrack(video, 1);
|
||||||
|
testExpected("video.textTracks[1].mode", "showing");
|
||||||
|
testExpected("video.textTracks[0].mode", "disabled");
|
||||||
|
testExpected("textTrackDisplayElement(video, 'display').innerText", trackCueText);
|
||||||
|
endTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTextTrack()
|
||||||
|
{
|
||||||
|
track = video.addTextTrack("captions", "French", "fr");
|
||||||
|
track.addCue(new VTTCue(0.0, 1.0, trackCueText));
|
||||||
|
selectTrackAdded();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function()
|
||||||
|
{
|
||||||
|
consoleWrite("Test that we can add a track dynamically and it is displayed on the track selection menu");
|
||||||
|
findMediaElement();
|
||||||
|
video.src = findMediaFile("video", "../content/test");
|
||||||
|
waitForEvent("canplaythrough", addTextTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<video controls>
|
||||||
|
<track src="captions-webvtt/captions.vtt" kind="captions" label="English" srclang="en" default>
|
||||||
|
</video>
|
57
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks-expected.txt
vendored
Normal file
57
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks-expected.txt
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
Test that we can add multiple tracks and select between them from the track selection menu
|
||||||
|
EVENT(canplaythrough)
|
||||||
|
|
||||||
|
** Caption button should be visible and enabled.
|
||||||
|
EXPECTED (captionsButtonCoordinates[0] > '0') OK
|
||||||
|
EXPECTED (captionsButtonCoordinates[1] > '0') OK
|
||||||
|
EXPECTED (captionsButtonElement.disabled == 'false') OK
|
||||||
|
|
||||||
|
EXPECTED (video.textTracks.length == '5') OK
|
||||||
|
|
||||||
|
Select track at index 0
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'English') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[2].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[3].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[4].mode == 'disabled') OK
|
||||||
|
|
||||||
|
Select track at index 1
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Russian') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[2].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[3].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[4].mode == 'disabled') OK
|
||||||
|
|
||||||
|
Select track at index 2
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[2].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'French') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[3].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[4].mode == 'disabled') OK
|
||||||
|
|
||||||
|
Select track at index 3
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[3].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Japanese') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[2].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[4].mode == 'disabled') OK
|
||||||
|
|
||||||
|
Select track at index 4
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[4].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'German') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[2].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[3].mode == 'disabled') OK
|
||||||
|
|
||||||
|
END OF TEST
|
||||||
|
|
53
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks.html
vendored
Normal file
53
third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks.html
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../media-file.js"></script>
|
||||||
|
<!-- TODO(srivats): Convert test to testharness.js. crbug.com/588956
|
||||||
|
(Please avoid writing new tests using video-test.js) -->
|
||||||
|
<script src="../video-test.js"></script>
|
||||||
|
<script src="../media-controls.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var trackLanguages = ["en", "ru", "fr", "jp", "de"];
|
||||||
|
var trackCueText = ["English", "Russian", "French", "Japanese", "German"];
|
||||||
|
|
||||||
|
function startTest()
|
||||||
|
{
|
||||||
|
findMediaElement();
|
||||||
|
testClosedCaptionsButtonVisibility(true);
|
||||||
|
consoleWrite("");
|
||||||
|
testExpected("video.textTracks.length", trackLanguages.length);
|
||||||
|
consoleWrite("");
|
||||||
|
|
||||||
|
for (var i = 0; i < trackLanguages.length; i++) {
|
||||||
|
consoleWrite("Select track at index " + i);
|
||||||
|
selectTextTrack(video, i);
|
||||||
|
testExpected("video.textTracks[" + i + "].mode", "showing");
|
||||||
|
testExpected("textTrackDisplayElement(video, 'display').innerText", trackCueText[i]);
|
||||||
|
for (var j = 0; j < trackLanguages.length; j++) {
|
||||||
|
if (j != i)
|
||||||
|
testExpected("video.textTracks[" + j + "].mode", "disabled");
|
||||||
|
}
|
||||||
|
consoleWrite("");
|
||||||
|
}
|
||||||
|
endTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTextTracks()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < trackLanguages.length; i++) {
|
||||||
|
var track = video.addTextTrack("captions", trackCueText[i], trackLanguages[i]);
|
||||||
|
track.addCue(new VTTCue(0.0, 1.0, trackCueText[i]));
|
||||||
|
track.mode = "disabled";
|
||||||
|
}
|
||||||
|
startTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function()
|
||||||
|
{
|
||||||
|
consoleWrite("Test that we can add multiple tracks and select between them from the track selection menu");
|
||||||
|
findMediaElement();
|
||||||
|
video.src = findMediaFile("video", "../content/test");
|
||||||
|
waitForEvent("canplaythrough", addTextTracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<video controls></video>
|
@@ -1,4 +1,4 @@
|
|||||||
Tests that the closed captions button, when toggled, updates the text track display area.
|
Tests that the closed captions button enables track switching
|
||||||
|
|
||||||
EVENT(canplaythrough)
|
EVENT(canplaythrough)
|
||||||
|
|
||||||
@@ -12,11 +12,11 @@ EXPECTED (video.textTracks.length == '1') OK
|
|||||||
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
Failed to find text track container element
|
Failed to find text track container element
|
||||||
|
|
||||||
** Captions track should load and captions should become visible after button is clicked **
|
** Captions track should load and captions should become visible after a track is selected **
|
||||||
*** Click the CC button.
|
*** Click the CC button.
|
||||||
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Lorem') OK
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Lorem') OK
|
||||||
|
|
||||||
** Captions should not be visible after button is clicked again **
|
** Captions should not be visible after Off is clicked **
|
||||||
*** Click the CC button.
|
*** Click the CC button.
|
||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
|
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
Tests that appropriate language track is loaded, according to user preferences.
|
|
||||||
|
|
||||||
EVENT(canplaythrough)
|
|
||||||
|
|
||||||
** Caption button should be visible and enabled.
|
|
||||||
EXPECTED (captionsButtonCoordinates[0] > '0') OK
|
|
||||||
EXPECTED (captionsButtonCoordinates[1] > '0') OK
|
|
||||||
EXPECTED (captionsButtonElement.disabled == 'false') OK
|
|
||||||
|
|
||||||
** The captions track should be listed in textTracks, but disabled. **
|
|
||||||
EXPECTED (video.textTracks.length == '2') OK
|
|
||||||
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
|
||||||
EXPECTED (video.textTracks[1].mode == 'disabled') OK
|
|
||||||
|
|
||||||
** Set the user language preference so that the track will be chosen when the CC button is clicked. **
|
|
||||||
RUN(internals.setUserPreferredLanguages(['ar']))
|
|
||||||
*** Click the CC button.
|
|
||||||
END OF TEST
|
|
||||||
|
|
@@ -1,52 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<title>Test non-default track load according to user language preference.</title>
|
|
||||||
<script src=media-file.js></script>
|
|
||||||
<script src=media-controls.js></script>
|
|
||||||
<!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956
|
|
||||||
(Please avoid writing new tests using video-test.js) -->
|
|
||||||
<script src=video-test.js></script>
|
|
||||||
<script>
|
|
||||||
var track;
|
|
||||||
|
|
||||||
function startTest()
|
|
||||||
{
|
|
||||||
if (!window.eventSender) {
|
|
||||||
consoleWrite("No eventSender found.");
|
|
||||||
failTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
findMediaElement();
|
|
||||||
testClosedCaptionsButtonVisibility(true);
|
|
||||||
|
|
||||||
consoleWrite("");
|
|
||||||
consoleWrite("** The captions track should be listed in textTracks, but disabled. **");
|
|
||||||
testExpected("video.textTracks.length", 2);
|
|
||||||
testExpected("video.textTracks[0].mode", "disabled");
|
|
||||||
testExpected("video.textTracks[1].mode", "disabled");
|
|
||||||
|
|
||||||
consoleWrite("");
|
|
||||||
consoleWrite("** Set the user language preference so that the track will be chosen when the CC button is clicked. **");
|
|
||||||
run("internals.setUserPreferredLanguages(['ar'])");
|
|
||||||
clickCCButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
function loaded()
|
|
||||||
{
|
|
||||||
findMediaElement();
|
|
||||||
waitForEvent('canplaythrough', startTest);
|
|
||||||
|
|
||||||
video.src = findMediaFile('video', 'content/counting');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onload="loaded()">
|
|
||||||
<p>Tests that appropriate language track is loaded, according to user preferences.</p>
|
|
||||||
<video controls>
|
|
||||||
<track src="track/captions-webvtt/captions-fast.vtt" kind="captions">
|
|
||||||
<track src="track/captions-webvtt/captions-fast.vtt" kind="captions" srclang="ar" onload="endTest()">
|
|
||||||
</video>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,4 +1,4 @@
|
|||||||
Tests that multiple toggles of the closed captions button still display captions
|
Tests that tracks can be turned on and off through the track selection menu
|
||||||
|
|
||||||
EVENT(canplaythrough)
|
EVENT(canplaythrough)
|
||||||
|
|
||||||
@@ -14,19 +14,19 @@ No text track cue with display id '-webkit-media-text-track-display' is currentl
|
|||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
|
|
||||||
** Captions track should become visible after button is clicked **
|
** Captions track should become visible after the track is selected **
|
||||||
*** Click the CC button.
|
*** Click the CC button.
|
||||||
EXPECTED (displayElement.innerText == 'First') OK
|
EXPECTED (displayElement.innerText == 'First') OK
|
||||||
EXPECTED (displayElement.innerText == 'Second') OK
|
EXPECTED (displayElement.innerText == 'Second') OK
|
||||||
EXPECTED (displayElement.innerText == 'Third') OK
|
EXPECTED (displayElement.innerText == 'Third') OK
|
||||||
|
|
||||||
** Captions should not be visible after button is clicked again **
|
** Captions should not be visible after they're turned off through the menu **
|
||||||
*** Click the CC button.
|
*** Click the CC button.
|
||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
No text track cue with display id '-webkit-media-text-track-display' is currently visible
|
||||||
|
|
||||||
** Captions should become visible after button is clicked again **
|
** Captions track should become visible after the track is selected again **
|
||||||
*** Click the CC button.
|
*** Click the CC button.
|
||||||
EXPECTED (displayElement.innerText == 'First') OK
|
EXPECTED (displayElement.innerText == 'First') OK
|
||||||
EXPECTED (displayElement.innerText == 'Second') OK
|
EXPECTED (displayElement.innerText == 'Second') OK
|
@@ -2,22 +2,21 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Test closed caption button toggling.</title>
|
<title>Test closed caption track selection on and off.</title>
|
||||||
<script src=media-file.js></script>
|
<script src=media-file.js></script>
|
||||||
<script src=media-controls.js></script>
|
<script src=media-controls.js></script>
|
||||||
<!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956
|
<!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956
|
||||||
(Please avoid writing new tests using video-test.js) -->
|
(Please avoid writing new tests using video-test.js) -->
|
||||||
<script src=video-test.js></script>
|
<script src=video-test.js></script>
|
||||||
<script>
|
<script>
|
||||||
var displayElement;
|
|
||||||
var track;
|
|
||||||
var text = ["First", "Second", "Third"];
|
var text = ["First", "Second", "Third"];
|
||||||
|
var displayElement;
|
||||||
|
|
||||||
function addTextTrack()
|
function addTextTrack()
|
||||||
{
|
{
|
||||||
track = video.addTextTrack('captions');
|
var track = video.addTextTrack('captions');
|
||||||
|
|
||||||
for(var i = 0; i < 3; i++) {
|
for (var i = 0; i < 3; i++) {
|
||||||
var cue = new VTTCue(0, 120, text[i]);
|
var cue = new VTTCue(0, 120, text[i]);
|
||||||
track.addCue(cue);
|
track.addCue(cue);
|
||||||
}
|
}
|
||||||
@@ -27,9 +26,9 @@
|
|||||||
{
|
{
|
||||||
for (var i = 0; i < 3; i++) {
|
for (var i = 0; i < 3; i++) {
|
||||||
try {
|
try {
|
||||||
displayElement = textTrackDisplayElement(video, 'display', i);
|
displayElement = textTrackDisplayElement(video, "display", i);
|
||||||
testExpected("displayElement.innerText", text[i]);
|
testExpected("displayElement.innerText", text[i]);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
consoleWrite(e);
|
consoleWrite(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,18 +53,18 @@
|
|||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
consoleWrite("** Captions track should become visible after button is clicked **");
|
consoleWrite("** Captions track should become visible after the track is selected **");
|
||||||
clickCCButton();
|
selectTextTrack(video, 0);
|
||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
consoleWrite("** Captions should not be visible after button is clicked again **");
|
consoleWrite("** Captions should not be visible after they're turned off through the menu **");
|
||||||
clickCCButton();
|
turnClosedCaptionsOff(video);
|
||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
consoleWrite("** Captions should become visible after button is clicked again **");
|
consoleWrite("** Captions track should become visible after the track is selected again **");
|
||||||
clickCCButton();
|
selectTextTrack(video, 0);
|
||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
@@ -82,7 +81,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="loaded()">
|
<body onload="loaded()">
|
||||||
<p>Tests that multiple toggles of the closed captions button still display captions</p>
|
<p>Tests that tracks can be turned on and off through the track selection menu</p>
|
||||||
<video controls></video>
|
<video controls></video>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Test closed caption button toggling.</title>
|
<title>Test closed caption track selection functionality.</title>
|
||||||
<script src=media-file.js></script>
|
<script src=media-file.js></script>
|
||||||
<script src=media-controls.js></script>
|
<script src=media-controls.js></script>
|
||||||
<!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956
|
<!-- TODO(philipj): Convert test to testharness.js. crbug.com/588956
|
||||||
@@ -70,21 +70,21 @@
|
|||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
consoleWrite("** Captions track should load and captions should become visible after button is clicked **");
|
consoleWrite("** Captions track should load and captions should become visible after a track is selected **");
|
||||||
|
|
||||||
// Note: the test flow continues with "testCCButtonToggling" when the
|
// Note: the test flow continues with "testCCTrackSelectionFunctionality" when the
|
||||||
// "load" event of the single TextTrack fires up. While the test structure
|
// "load" event of the single TextTrack fires up. While the test structure
|
||||||
// might seem weird, this avoids timeouts.
|
// might seem weird, this avoids timeouts.
|
||||||
clickCCButton();
|
selectTextTrack(video, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCCButtonToggling()
|
function testCCTrackSelectionFunctionality()
|
||||||
{
|
{
|
||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
consoleWrite("** Captions should not be visible after button is clicked again **");
|
consoleWrite("** Captions should not be visible after Off is clicked **");
|
||||||
clickCCButton();
|
turnClosedCaptionsOff(video);
|
||||||
checkCaptionsDisplay();
|
checkCaptionsDisplay();
|
||||||
|
|
||||||
removeHTMLTrackElement();
|
removeHTMLTrackElement();
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
testClosedCaptionsButtonVisibility(true);
|
testClosedCaptionsButtonVisibility(true);
|
||||||
|
|
||||||
consoleWrite("");
|
consoleWrite("");
|
||||||
clickCCButton();
|
selectTextTrack(video, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackError()
|
function trackError()
|
||||||
@@ -118,9 +118,9 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="loaded()">
|
<body onload="loaded()">
|
||||||
<p>Tests that the closed captions button, when toggled, updates the text track display area.</p>
|
<p>Tests that the closed captions button enables track switching</p>
|
||||||
<video controls>
|
<video controls>
|
||||||
<track src="track/captions-webvtt/captions-fast.vtt" kind="captions" onload="testCCButtonToggling()">
|
<track src="track/captions-webvtt/captions-fast.vtt" kind="captions" onload="testCCTrackSelectionFunctionality()">
|
||||||
</video>
|
</video>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
26
third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu-expected.txt
vendored
Normal file
26
third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu-expected.txt
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Test that we can display a track list menu and select tracks from the list
|
||||||
|
EVENT(canplaythrough)
|
||||||
|
|
||||||
|
** Caption button should be visible and enabled.
|
||||||
|
EXPECTED (captionsButtonCoordinates[0] > '0') OK
|
||||||
|
EXPECTED (captionsButtonCoordinates[1] > '0') OK
|
||||||
|
EXPECTED (captionsButtonElement.disabled == 'false') OK
|
||||||
|
|
||||||
|
EXPECTED (video.textTracks.length == '2') OK
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'hidden') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'hidden') OK
|
||||||
|
|
||||||
|
Select track 0 and verify it is displayed
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'showing') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'hidden') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'Lorem') OK
|
||||||
|
|
||||||
|
Select track 1 and verify it is displayed
|
||||||
|
*** Click the CC button.
|
||||||
|
EXPECTED (video.textTracks[0].mode == 'disabled') OK
|
||||||
|
EXPECTED (video.textTracks[1].mode == 'showing') OK
|
||||||
|
EXPECTED (textTrackDisplayElement(video, 'display').innerText == 'first caption') OK
|
||||||
|
|
||||||
|
END OF TEST
|
||||||
|
|
49
third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html
vendored
Normal file
49
third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="media-file.js"></script>
|
||||||
|
<!-- TODO(srivats): Convert test to testharness.js. crbug.com/588956
|
||||||
|
(Please avoid writing new tests using video-test.js) -->
|
||||||
|
<script src="video-test.js"></script>
|
||||||
|
<script src="media-controls.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function startTest()
|
||||||
|
{
|
||||||
|
findMediaElement();
|
||||||
|
testClosedCaptionsButtonVisibility(true);
|
||||||
|
consoleWrite("");
|
||||||
|
testExpected("video.textTracks.length", 2);
|
||||||
|
testExpected("video.textTracks[0].mode", "hidden");
|
||||||
|
testExpected("video.textTracks[1].mode", "hidden");
|
||||||
|
|
||||||
|
consoleWrite("");
|
||||||
|
consoleWrite("Select track 0 and verify it is displayed");
|
||||||
|
selectTextTrack(video, 0);
|
||||||
|
testExpected("video.textTracks[0].mode", "showing");
|
||||||
|
testExpected("video.textTracks[1].mode", "hidden");
|
||||||
|
testExpected("textTrackDisplayElement(video, 'display').innerText", "Lorem");
|
||||||
|
|
||||||
|
consoleWrite("");
|
||||||
|
consoleWrite("Select track 1 and verify it is displayed");
|
||||||
|
selectTextTrack(video, 1);
|
||||||
|
testExpected("video.textTracks[0].mode", "disabled");
|
||||||
|
testExpected("video.textTracks[1].mode", "showing");
|
||||||
|
testExpected("textTrackDisplayElement(video, 'display').innerText", "first caption");
|
||||||
|
|
||||||
|
consoleWrite("");
|
||||||
|
endTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function()
|
||||||
|
{
|
||||||
|
consoleWrite("Test that we can display a track list menu and select tracks from the list");
|
||||||
|
findMediaElement();
|
||||||
|
video.src = findMediaFile("video", "content/test");
|
||||||
|
enableAllTextTracks();
|
||||||
|
waitForEvent("canplaythrough", startTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<video controls>
|
||||||
|
<track src="track/captions-webvtt/captions.vtt" kind="captions" label="Track1">
|
||||||
|
<track src="track/captions-webvtt/long-word.vtt" kind="captions" label="Track2">
|
||||||
|
</video>
|
@@ -456,6 +456,15 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e)
|
|||||||
case MediaTimeRemainingPart:
|
case MediaTimeRemainingPart:
|
||||||
m_value.valueID = CSSValueMediaTimeRemainingDisplay;
|
m_value.valueID = CSSValueMediaTimeRemainingDisplay;
|
||||||
break;
|
break;
|
||||||
|
case MediaTrackSelectionCheckmarkPart:
|
||||||
|
m_value.valueID = CSSValueInternalMediaTrackSelectionCheckmark;
|
||||||
|
break;
|
||||||
|
case MediaClosedCaptionsIconPart:
|
||||||
|
m_value.valueID = CSSValueInternalMediaClosedCaptionsIcon;
|
||||||
|
break;
|
||||||
|
case MediaSubtitlesIconPart:
|
||||||
|
m_value.valueID = CSSValueInternalMediaSubtitlesIcon;
|
||||||
|
break;
|
||||||
case MenulistPart:
|
case MenulistPart:
|
||||||
m_value.valueID = CSSValueMenulist;
|
m_value.valueID = CSSValueMenulist;
|
||||||
break;
|
break;
|
||||||
|
@@ -285,6 +285,11 @@ const static NameToPseudoStruct pseudoTypeWithoutArgumentsMap[] = {
|
|||||||
{"-internal-list-box", CSSSelector::PseudoListBox},
|
{"-internal-list-box", CSSSelector::PseudoListBox},
|
||||||
{"-internal-media-controls-cast-button", CSSSelector::PseudoWebKitCustomElement},
|
{"-internal-media-controls-cast-button", CSSSelector::PseudoWebKitCustomElement},
|
||||||
{"-internal-media-controls-overlay-cast-button", CSSSelector::PseudoWebKitCustomElement},
|
{"-internal-media-controls-overlay-cast-button", CSSSelector::PseudoWebKitCustomElement},
|
||||||
|
{"-internal-media-controls-text-track-list", CSSSelector::PseudoWebKitCustomElement},
|
||||||
|
{"-internal-media-controls-text-track-list-item", CSSSelector::PseudoWebKitCustomElement},
|
||||||
|
{"-internal-media-controls-text-track-list-item-input", CSSSelector::PseudoWebKitCustomElement},
|
||||||
|
{"-internal-media-controls-text-track-list-kind-captions", CSSSelector::PseudoWebKitCustomElement},
|
||||||
|
{"-internal-media-controls-text-track-list-kind-subtitles", CSSSelector::PseudoWebKitCustomElement},
|
||||||
{"-internal-spatial-navigation-focus", CSSSelector::PseudoSpatialNavigationFocus},
|
{"-internal-spatial-navigation-focus", CSSSelector::PseudoSpatialNavigationFocus},
|
||||||
{"-webkit-any-link", CSSSelector::PseudoAnyLink},
|
{"-webkit-any-link", CSSSelector::PseudoAnyLink},
|
||||||
{"-webkit-autofill", CSSSelector::PseudoAutofill},
|
{"-webkit-autofill", CSSSelector::PseudoAutofill},
|
||||||
|
@@ -636,6 +636,9 @@ media-current-time-display
|
|||||||
media-time-remaining-display
|
media-time-remaining-display
|
||||||
-internal-media-cast-off-button
|
-internal-media-cast-off-button
|
||||||
-internal-media-overlay-cast-off-button
|
-internal-media-overlay-cast-off-button
|
||||||
|
-internal-media-track-selection-checkmark
|
||||||
|
-internal-media-closed-captions-icon
|
||||||
|
-internal-media-subtitles-icon
|
||||||
menulist
|
menulist
|
||||||
menulist-button
|
menulist-button
|
||||||
menulist-text
|
menulist-text
|
||||||
|
@@ -44,6 +44,7 @@ video::-webkit-media-controls {
|
|||||||
direction: ltr;
|
direction: ltr;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -204,7 +205,6 @@ audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-contr
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -338,6 +338,82 @@ audio::-webkit-media-controls-fullscreen-volume-max-button, video::-webkit-media
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video::-webkit-scrollbar {
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-webkit-scrollbar-track {
|
||||||
|
box-shadow: inset 0 0 6px rgba(20, 20, 20, 0.3);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: rgba(80, 80, 80, 0.8);
|
||||||
|
box-shadow: inset 0 0 6px rgba(20, 20, 20, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 35px;
|
||||||
|
right: 5px;
|
||||||
|
background: rgba(20, 20, 20, 0.8);
|
||||||
|
max-width: 50%;
|
||||||
|
max-height: 250px;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-top: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
padding: 4px 30px 4px 10px;
|
||||||
|
border-bottom: 1px solid #555;
|
||||||
|
text-align: start;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item:hover {
|
||||||
|
background-color: rgba(105, 105, 105, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item-input {
|
||||||
|
-webkit-appearance: -internal-media-track-selection-checkmark;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item-input:checked {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-kind-captions {
|
||||||
|
-webkit-appearance: -internal-media-closed-captions-icon;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
margin-left: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-kind-subtitles {
|
||||||
|
-webkit-appearance: -internal-media-subtitles-icon;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
margin-left: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
video::-webkit-media-text-track-container {
|
video::-webkit-media-text-track-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
|
@@ -44,6 +44,7 @@ video::-webkit-media-controls {
|
|||||||
direction: ltr;
|
direction: ltr;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
font-family: Segoe, "Helvetica Neue", Roboto, Arial, Helvetica, sans-serif;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -80,7 +81,6 @@ audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel {
|
|||||||
/* The duration is also specified in MediaControlElements.cpp and LayoutTests/media/media-controls.js */
|
/* The duration is also specified in MediaControlElements.cpp and LayoutTests/media/media-controls.js */
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
font-family: Segoe, "Helvetica Neue", Roboto, Arial, Helvetica, sans-serif ;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal; /* Make sure that we don't inherit non-defaults. */
|
font-weight: normal; /* Make sure that we don't inherit non-defaults. */
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -359,6 +359,65 @@ audio::-webkit-media-controls-fullscreen-volume-max-button, video::-webkit-media
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 48px;
|
||||||
|
right: 0px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
max-width: 50%;
|
||||||
|
max-height: 250px;
|
||||||
|
min-width: 150px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 8px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item {
|
||||||
|
display: block;
|
||||||
|
color: #424242;
|
||||||
|
text-align: start;
|
||||||
|
line-height: 40px;
|
||||||
|
padding-right: 16px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item-input {
|
||||||
|
-webkit-appearance: -internal-media-track-selection-checkmark;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-item-input:checked {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-kind-captions {
|
||||||
|
-webkit-appearance: -internal-media-closed-captions-icon;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::-internal-media-controls-text-track-list-kind-subtitles {
|
||||||
|
-webkit-appearance: -internal-media-subtitles-icon;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
video::-webkit-media-text-track-container {
|
video::-webkit-media-text-track-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
|
@@ -413,8 +413,9 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
|
|||||||
, m_seeking(false)
|
, m_seeking(false)
|
||||||
, m_sentStalledEvent(false)
|
, m_sentStalledEvent(false)
|
||||||
, m_sentEndEvent(false)
|
, m_sentEndEvent(false)
|
||||||
, m_closedCaptionsVisible(false)
|
|
||||||
, m_ignorePreloadNone(false)
|
, m_ignorePreloadNone(false)
|
||||||
|
, m_textTracksVisible(false)
|
||||||
|
, m_shouldPerformAutomaticTrackSelection(true)
|
||||||
, m_tracksAreReady(true)
|
, m_tracksAreReady(true)
|
||||||
, m_processingPreferenceChange(false)
|
, m_processingPreferenceChange(false)
|
||||||
, m_remoteRoutesAvailable(false)
|
, m_remoteRoutesAvailable(false)
|
||||||
@@ -1231,6 +1232,11 @@ void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
|
|||||||
textTracks()->scheduleChangeEvent();
|
textTracks()->scheduleChangeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLMediaElement::disableAutomaticTextTrackSelection()
|
||||||
|
{
|
||||||
|
m_shouldPerformAutomaticTrackSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidURLAction actionIfInvalid)
|
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidURLAction actionIfInvalid)
|
||||||
{
|
{
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
@@ -2592,10 +2598,13 @@ void HTMLMediaElement::honorUserPreferencesForAutomaticTextTrackSelection()
|
|||||||
if (!m_textTracks || !m_textTracks->length())
|
if (!m_textTracks || !m_textTracks->length())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_shouldPerformAutomaticTrackSelection)
|
||||||
|
return;
|
||||||
|
|
||||||
AutomaticTrackSelection::Configuration configuration;
|
AutomaticTrackSelection::Configuration configuration;
|
||||||
if (m_processingPreferenceChange)
|
if (m_processingPreferenceChange)
|
||||||
configuration.disableCurrentlyEnabledTracks = true;
|
configuration.disableCurrentlyEnabledTracks = true;
|
||||||
if (m_closedCaptionsVisible)
|
if (m_textTracksVisible)
|
||||||
configuration.forceEnableSubtitleOrCaptionTrack = true;
|
configuration.forceEnableSubtitleOrCaptionTrack = true;
|
||||||
|
|
||||||
Settings* settings = document().settings();
|
Settings* settings = document().settings();
|
||||||
@@ -3265,9 +3274,9 @@ bool HTMLMediaElement::hasClosedCaptions() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTMLMediaElement::closedCaptionsVisible() const
|
bool HTMLMediaElement::textTracksVisible() const
|
||||||
{
|
{
|
||||||
return m_closedCaptionsVisible;
|
return m_textTracksVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assertShadowRootChildren(ShadowRoot& shadowRoot)
|
static void assertShadowRootChildren(ShadowRoot& shadowRoot)
|
||||||
@@ -3323,30 +3332,10 @@ void HTMLMediaElement::mediaControlsDidBecomeVisible()
|
|||||||
// When the user agent starts exposing a user interface for a video element,
|
// When the user agent starts exposing a user interface for a video element,
|
||||||
// the user agent should run the rules for updating the text track rendering
|
// the user agent should run the rules for updating the text track rendering
|
||||||
// of each of the text tracks in the video element's list of text tracks ...
|
// of each of the text tracks in the video element's list of text tracks ...
|
||||||
if (isHTMLVideoElement() && closedCaptionsVisible())
|
if (isHTMLVideoElement() && textTracksVisible())
|
||||||
ensureTextTrackContainer().updateDisplay(*this, TextTrackContainer::DidStartExposingControls);
|
ensureTextTrackContainer().updateDisplay(*this, TextTrackContainer::DidStartExposingControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
|
|
||||||
{
|
|
||||||
WTF_LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%p, %s)", this, boolString(closedCaptionVisible));
|
|
||||||
|
|
||||||
if (!hasClosedCaptions())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_closedCaptionsVisible = closedCaptionVisible;
|
|
||||||
|
|
||||||
markCaptionAndSubtitleTracksAsUnconfigured();
|
|
||||||
m_processingPreferenceChange = true;
|
|
||||||
honorUserPreferencesForAutomaticTextTrackSelection();
|
|
||||||
m_processingPreferenceChange = false;
|
|
||||||
|
|
||||||
// As track visibility changed while m_processingPreferenceChange was set,
|
|
||||||
// there was no call to updateTextTrackDisplay(). This call is not in the
|
|
||||||
// spec, see the note in configureTextTrackDisplay().
|
|
||||||
updateTextTrackDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTMLMediaElement::setTextTrackKindUserPreferenceForAllMediaElements(Document* document)
|
void HTMLMediaElement::setTextTrackKindUserPreferenceForAllMediaElements(Document* document)
|
||||||
{
|
{
|
||||||
auto it = documentToElementSetMap().find(document);
|
auto it = documentToElementSetMap().find(document);
|
||||||
@@ -3365,13 +3354,13 @@ void HTMLMediaElement::automaticTrackSelectionForUpdatedUserPreference()
|
|||||||
|
|
||||||
markCaptionAndSubtitleTracksAsUnconfigured();
|
markCaptionAndSubtitleTracksAsUnconfigured();
|
||||||
m_processingPreferenceChange = true;
|
m_processingPreferenceChange = true;
|
||||||
m_closedCaptionsVisible = false;
|
m_textTracksVisible = false;
|
||||||
honorUserPreferencesForAutomaticTextTrackSelection();
|
honorUserPreferencesForAutomaticTextTrackSelection();
|
||||||
m_processingPreferenceChange = false;
|
m_processingPreferenceChange = false;
|
||||||
|
|
||||||
// If a track is set to 'showing' post performing automatic track selection,
|
// If a track is set to 'showing' post performing automatic track selection,
|
||||||
// set closed captions state to visible to update the CC button and display the track.
|
// set text tracks state to visible to update the CC button and display the track.
|
||||||
m_closedCaptionsVisible = m_textTracks->hasShowingTracks();
|
m_textTracksVisible = m_textTracks->hasShowingTracks();
|
||||||
updateTextTrackDisplay();
|
updateTextTrackDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3496,7 +3485,7 @@ void HTMLMediaElement::configureTextTrackDisplay()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool haveVisibleTextTrack = m_textTracks->hasShowingTracks();
|
bool haveVisibleTextTrack = m_textTracks->hasShowingTracks();
|
||||||
m_closedCaptionsVisible = haveVisibleTextTrack;
|
m_textTracksVisible = haveVisibleTextTrack;
|
||||||
|
|
||||||
if (!haveVisibleTextTrack && !mediaControls())
|
if (!haveVisibleTextTrack && !mediaControls())
|
||||||
return;
|
return;
|
||||||
|
@@ -207,6 +207,7 @@ public:
|
|||||||
void textTrackReadyStateChanged(TextTrack*);
|
void textTrackReadyStateChanged(TextTrack*);
|
||||||
|
|
||||||
void textTrackModeChanged(TextTrack*);
|
void textTrackModeChanged(TextTrack*);
|
||||||
|
void disableAutomaticTextTrackSelection();
|
||||||
|
|
||||||
// EventTarget function.
|
// EventTarget function.
|
||||||
// Both Node (via HTMLElement) and ActiveDOMObject define this method, which
|
// Both Node (via HTMLElement) and ActiveDOMObject define this method, which
|
||||||
@@ -223,8 +224,7 @@ public:
|
|||||||
virtual bool usesOverlayFullscreenVideo() const { return false; }
|
virtual bool usesOverlayFullscreenVideo() const { return false; }
|
||||||
|
|
||||||
bool hasClosedCaptions() const;
|
bool hasClosedCaptions() const;
|
||||||
bool closedCaptionsVisible() const;
|
bool textTracksVisible() const;
|
||||||
void setClosedCaptionsVisible(bool);
|
|
||||||
|
|
||||||
static void setTextTrackKindUserPreferenceForAllMediaElements(Document*);
|
static void setTextTrackKindUserPreferenceForAllMediaElements(Document*);
|
||||||
void automaticTrackSelectionForUpdatedUserPreference();
|
void automaticTrackSelectionForUpdatedUserPreference();
|
||||||
@@ -561,9 +561,11 @@ private:
|
|||||||
// time has not changed since sending an "ended" event
|
// time has not changed since sending an "ended" event
|
||||||
bool m_sentEndEvent : 1;
|
bool m_sentEndEvent : 1;
|
||||||
|
|
||||||
bool m_closedCaptionsVisible : 1;
|
|
||||||
|
|
||||||
bool m_ignorePreloadNone : 1;
|
bool m_ignorePreloadNone : 1;
|
||||||
|
|
||||||
|
bool m_textTracksVisible : 1;
|
||||||
|
bool m_shouldPerformAutomaticTrackSelection : 1;
|
||||||
|
|
||||||
bool m_tracksAreReady : 1;
|
bool m_tracksAreReady : 1;
|
||||||
bool m_processingPreferenceChange : 1;
|
bool m_processingPreferenceChange : 1;
|
||||||
bool m_remoteRoutesAvailable : 1;
|
bool m_remoteRoutesAvailable : 1;
|
||||||
|
@@ -48,11 +48,13 @@ enum MediaControlElementType {
|
|||||||
MediaSliderThumb,
|
MediaSliderThumb,
|
||||||
MediaShowClosedCaptionsButton,
|
MediaShowClosedCaptionsButton,
|
||||||
MediaHideClosedCaptionsButton,
|
MediaHideClosedCaptionsButton,
|
||||||
|
MediaTextTrackList,
|
||||||
MediaUnMuteButton,
|
MediaUnMuteButton,
|
||||||
MediaPauseButton,
|
MediaPauseButton,
|
||||||
MediaTimelineContainer,
|
MediaTimelineContainer,
|
||||||
MediaCurrentTimeDisplay,
|
MediaCurrentTimeDisplay,
|
||||||
MediaTimeRemainingDisplay,
|
MediaTimeRemainingDisplay,
|
||||||
|
MediaTrackSelectionCheckmark,
|
||||||
MediaControlsPanel,
|
MediaControlsPanel,
|
||||||
MediaVolumeSliderContainer,
|
MediaVolumeSliderContainer,
|
||||||
MediaVolumeSlider,
|
MediaVolumeSlider,
|
||||||
|
@@ -32,19 +32,25 @@
|
|||||||
#include "bindings/core/v8/ExceptionStatePlaceholder.h"
|
#include "bindings/core/v8/ExceptionStatePlaceholder.h"
|
||||||
#include "core/InputTypeNames.h"
|
#include "core/InputTypeNames.h"
|
||||||
#include "core/dom/ClientRect.h"
|
#include "core/dom/ClientRect.h"
|
||||||
|
#include "core/dom/Text.h"
|
||||||
#include "core/dom/shadow/ShadowRoot.h"
|
#include "core/dom/shadow/ShadowRoot.h"
|
||||||
#include "core/events/MouseEvent.h"
|
#include "core/events/MouseEvent.h"
|
||||||
#include "core/frame/LocalFrame.h"
|
#include "core/frame/LocalFrame.h"
|
||||||
|
#include "core/html/HTMLLabelElement.h"
|
||||||
#include "core/html/HTMLMediaSource.h"
|
#include "core/html/HTMLMediaSource.h"
|
||||||
|
#include "core/html/HTMLSpanElement.h"
|
||||||
#include "core/html/HTMLVideoElement.h"
|
#include "core/html/HTMLVideoElement.h"
|
||||||
#include "core/html/TimeRanges.h"
|
#include "core/html/TimeRanges.h"
|
||||||
#include "core/html/shadow/MediaControls.h"
|
#include "core/html/shadow/MediaControls.h"
|
||||||
|
#include "core/html/track/TextTrackList.h"
|
||||||
#include "core/input/EventHandler.h"
|
#include "core/input/EventHandler.h"
|
||||||
#include "core/layout/LayoutTheme.h"
|
#include "core/layout/LayoutTheme.h"
|
||||||
#include "core/layout/LayoutVideo.h"
|
#include "core/layout/LayoutVideo.h"
|
||||||
#include "core/layout/api/LayoutSliderItem.h"
|
#include "core/layout/api/LayoutSliderItem.h"
|
||||||
|
#include "platform/EventDispatchForbiddenScope.h"
|
||||||
#include "platform/Histogram.h"
|
#include "platform/Histogram.h"
|
||||||
#include "platform/RuntimeEnabledFeatures.h"
|
#include "platform/RuntimeEnabledFeatures.h"
|
||||||
|
#include "platform/text/PlatformLocale.h"
|
||||||
#include "public/platform/Platform.h"
|
#include "public/platform/Platform.h"
|
||||||
#include "public/platform/UserMetricsAction.h"
|
#include "public/platform/UserMetricsAction.h"
|
||||||
|
|
||||||
@@ -57,6 +63,16 @@ namespace {
|
|||||||
// This is the duration from mediaControls.css
|
// This is the duration from mediaControls.css
|
||||||
const double fadeOutDuration = 0.3;
|
const double fadeOutDuration = 0.3;
|
||||||
|
|
||||||
|
const QualifiedName& trackIndexAttrName()
|
||||||
|
{
|
||||||
|
// Save the track index in an attribute to avoid holding a pointer to the text track.
|
||||||
|
DEFINE_STATIC_LOCAL(QualifiedName, trackIndexAttr, (nullAtom, "data-track-index", nullAtom));
|
||||||
|
return trackIndexAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When specified as trackIndex, disable text tracks.
|
||||||
|
const int trackIndexOffValue = -1;
|
||||||
|
|
||||||
bool isUserInteractionEvent(Event* event)
|
bool isUserInteractionEvent(Event* event)
|
||||||
{
|
{
|
||||||
const AtomicString& type = event->type();
|
const AtomicString& type = event->type();
|
||||||
@@ -96,6 +112,21 @@ Element* elementFromCenter(Element& element)
|
|||||||
return element.document().elementFromPoint(centerX , centerY);
|
return element.document().elementFromPoint(centerX , centerY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasDuplicateLabel(TextTrack* currentTrack)
|
||||||
|
{
|
||||||
|
DCHECK(currentTrack);
|
||||||
|
TextTrackList* trackList = currentTrack->trackList();
|
||||||
|
// The runtime of this method is quadratic but since there are usually very few text tracks it won't
|
||||||
|
// affect the performance much.
|
||||||
|
String currentTrackLabel = currentTrack->label();
|
||||||
|
for (unsigned i = 0; i < trackList->length(); i++) {
|
||||||
|
TextTrack* track = trackList->anonymousIndexedGetter(i);
|
||||||
|
if (currentTrack != track && currentTrackLabel == track->label())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
|
MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
|
||||||
@@ -371,20 +402,14 @@ MediaControlToggleClosedCaptionsButtonElement* MediaControlToggleClosedCaptionsB
|
|||||||
|
|
||||||
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
|
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
|
||||||
{
|
{
|
||||||
bool captionsVisible = mediaElement().closedCaptionsVisible();
|
bool captionsVisible = mediaElement().textTracksVisible();
|
||||||
setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
|
setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
|
||||||
setChecked(captionsVisible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
|
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
|
||||||
{
|
{
|
||||||
if (event->type() == EventTypeNames::click) {
|
if (event->type() == EventTypeNames::click) {
|
||||||
if (mediaElement().closedCaptionsVisible())
|
mediaControls().toggleTextTrackList();
|
||||||
Platform::current()->recordAction(UserMetricsAction("Media.Controls.ClosedCaptionHide"));
|
|
||||||
else
|
|
||||||
Platform::current()->recordAction(UserMetricsAction("Media.Controls.ClosedCaptionShow"));
|
|
||||||
mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVisible());
|
|
||||||
setChecked(mediaElement().closedCaptionsVisible());
|
|
||||||
updateDisplayType();
|
updateDisplayType();
|
||||||
event->setDefaultHandled();
|
event->setDefaultHandled();
|
||||||
}
|
}
|
||||||
@@ -394,6 +419,144 @@ void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e
|
|||||||
|
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
|
|
||||||
|
MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls& mediaControls)
|
||||||
|
: MediaControlDivElement(mediaControls, MediaTextTrackList)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaControlTextTrackListElement* MediaControlTextTrackListElement::create(MediaControls& mediaControls)
|
||||||
|
{
|
||||||
|
MediaControlTextTrackListElement* element = new MediaControlTextTrackListElement(mediaControls);
|
||||||
|
element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list"));
|
||||||
|
element->setIsWanted(false);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlTextTrackListElement::defaultEventHandler(Event* event)
|
||||||
|
{
|
||||||
|
if (event->type() == EventTypeNames::change) {
|
||||||
|
// Identify which input element was selected and set track to showing
|
||||||
|
Node* target = event->target()->toNode();
|
||||||
|
if (!target || !target->isElementNode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
disableShowingTextTracks();
|
||||||
|
int trackIndex = toElement(target)->getIntegralAttribute(trackIndexAttrName());
|
||||||
|
if (trackIndex != trackIndexOffValue) {
|
||||||
|
ASSERT(trackIndex >= 0);
|
||||||
|
showTextTrackAtIndex(trackIndex);
|
||||||
|
mediaElement().disableAutomaticTextTrackSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaControls().toggleTextTrackList();
|
||||||
|
event->setDefaultHandled();
|
||||||
|
}
|
||||||
|
MediaControlDivElement::defaultEventHandler(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlTextTrackListElement::setVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (visible) {
|
||||||
|
setIsWanted(true);
|
||||||
|
refreshTextTrackListMenu();
|
||||||
|
} else {
|
||||||
|
setIsWanted(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnable)
|
||||||
|
{
|
||||||
|
TextTrackList* trackList = mediaElement().textTracks();
|
||||||
|
if (indexToEnable >= trackList->length())
|
||||||
|
return;
|
||||||
|
TextTrack* track = trackList->anonymousIndexedGetter(indexToEnable);
|
||||||
|
if (track && track->canBeRendered())
|
||||||
|
track->setMode(TextTrack::showingKeyword());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlTextTrackListElement::disableShowingTextTracks()
|
||||||
|
{
|
||||||
|
TextTrackList* trackList = mediaElement().textTracks();
|
||||||
|
for (unsigned i = 0; i < trackList->length(); ++i) {
|
||||||
|
TextTrack* track = trackList->anonymousIndexedGetter(i);
|
||||||
|
if (track->mode() == TextTrack::showingKeyword())
|
||||||
|
track->setMode(TextTrack::disabledKeyword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track)
|
||||||
|
{
|
||||||
|
if (!track)
|
||||||
|
return mediaElement().locale().queryString(WebLocalizedString::TextTracksOff);
|
||||||
|
|
||||||
|
String trackLabel = track->label();
|
||||||
|
|
||||||
|
if (trackLabel.isEmpty())
|
||||||
|
trackLabel = String(mediaElement().locale().queryString(WebLocalizedString::TextTracksNoLabel));
|
||||||
|
|
||||||
|
return trackLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextTrack parameter when passed in as a nullptr, creates the "Off" list item in the track list.
|
||||||
|
Element* MediaControlTextTrackListElement::createTextTrackListItem(TextTrack* track)
|
||||||
|
{
|
||||||
|
int trackIndex = track ? track->trackIndex() : trackIndexOffValue;
|
||||||
|
HTMLLabelElement* trackItem = HTMLLabelElement::create(document(), nullptr);
|
||||||
|
trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-item"));
|
||||||
|
HTMLInputElement* trackItemInput = HTMLInputElement::create(document(), nullptr, false);
|
||||||
|
trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-item-input"));
|
||||||
|
trackItemInput->setType(InputTypeNames::checkbox);
|
||||||
|
trackItemInput->setIntegralAttribute(trackIndexAttrName(), trackIndex);
|
||||||
|
if (!mediaElement().textTracksVisible()) {
|
||||||
|
if (!track)
|
||||||
|
trackItemInput->setChecked(true);
|
||||||
|
} else {
|
||||||
|
// If there are multiple text tracks set to showing, they must all have
|
||||||
|
// checkmarks displayed.
|
||||||
|
if (track && track->mode() == TextTrack::showingKeyword())
|
||||||
|
trackItemInput->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackItem->appendChild(trackItemInput);
|
||||||
|
String trackLabel = getTextTrackLabel(track);
|
||||||
|
trackItem->appendChild(Text::create(document(), trackLabel));
|
||||||
|
// Add a track kind marker icon if there are multiple tracks with the same label or if the track has no label.
|
||||||
|
if (track && (track->label().isEmpty() || hasDuplicateLabel(track))) {
|
||||||
|
HTMLSpanElement* trackKindMarker = HTMLSpanElement::create(document());
|
||||||
|
if (track->kind() == track->captionsKeyword()) {
|
||||||
|
trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-kind-captions"));
|
||||||
|
} else {
|
||||||
|
ASSERT(track->kind() == track->subtitlesKeyword());
|
||||||
|
trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-controls-text-track-list-kind-subtitles"));
|
||||||
|
}
|
||||||
|
trackItem->appendChild(trackKindMarker);
|
||||||
|
}
|
||||||
|
return trackItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlTextTrackListElement::refreshTextTrackListMenu()
|
||||||
|
{
|
||||||
|
if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreReady())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
|
||||||
|
removeChildren(OmitSubtreeModifiedEvent);
|
||||||
|
|
||||||
|
// Construct a menu for subtitles and captions
|
||||||
|
// Pass in a nullptr to createTextTrackListItem to create the "Off" track item.
|
||||||
|
appendChild(createTextTrackListItem(nullptr));
|
||||||
|
|
||||||
|
TextTrackList* trackList = mediaElement().textTracks();
|
||||||
|
for (unsigned i = 0; i < trackList->length(); i++) {
|
||||||
|
TextTrack* track = trackList->anonymousIndexedGetter(i);
|
||||||
|
if (!track->canBeRendered())
|
||||||
|
continue;
|
||||||
|
appendChild(createTextTrackListItem(track));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
|
MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
|
||||||
: MediaControlInputElement(mediaControls, MediaSlider)
|
: MediaControlInputElement(mediaControls, MediaSlider)
|
||||||
{
|
{
|
||||||
|
@@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
namespace blink {
|
namespace blink {
|
||||||
|
|
||||||
|
class TextTrack;
|
||||||
|
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
|
|
||||||
class MediaControlPanelElement final : public MediaControlDivElement {
|
class MediaControlPanelElement final : public MediaControlDivElement {
|
||||||
@@ -146,6 +148,32 @@ private:
|
|||||||
|
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
|
|
||||||
|
class MediaControlTextTrackListElement final : public MediaControlDivElement {
|
||||||
|
public:
|
||||||
|
static MediaControlTextTrackListElement* create(MediaControls&);
|
||||||
|
|
||||||
|
bool willRespondToMouseClickEvents() override { return true; }
|
||||||
|
|
||||||
|
void setVisible(bool);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit MediaControlTextTrackListElement(MediaControls&);
|
||||||
|
|
||||||
|
void defaultEventHandler(Event*) override;
|
||||||
|
|
||||||
|
void refreshTextTrackListMenu();
|
||||||
|
|
||||||
|
// Returns the label for the track when a valid track is passed in and "Off" when the parameter is null.
|
||||||
|
String getTextTrackLabel(TextTrack*);
|
||||||
|
// Creates the track element in the list when a valid track is passed in and the "Off" item when the parameter is null.
|
||||||
|
Element* createTextTrackListItem(TextTrack*);
|
||||||
|
|
||||||
|
void showTextTrackAtIndex(unsigned);
|
||||||
|
void disableShowingTextTracks();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
class MediaControlTimelineElement final : public MediaControlInputElement {
|
class MediaControlTimelineElement final : public MediaControlInputElement {
|
||||||
public:
|
public:
|
||||||
static MediaControlTimelineElement* create(MediaControls&);
|
static MediaControlTimelineElement* create(MediaControls&);
|
||||||
|
@@ -116,6 +116,7 @@ MediaControls::MediaControls(HTMLMediaElement& mediaElement)
|
|||||||
, m_muteButton(nullptr)
|
, m_muteButton(nullptr)
|
||||||
, m_volumeSlider(nullptr)
|
, m_volumeSlider(nullptr)
|
||||||
, m_toggleClosedCaptionsButton(nullptr)
|
, m_toggleClosedCaptionsButton(nullptr)
|
||||||
|
, m_textTrackList(nullptr)
|
||||||
, m_castButton(nullptr)
|
, m_castButton(nullptr)
|
||||||
, m_fullScreenButton(nullptr)
|
, m_fullScreenButton(nullptr)
|
||||||
, m_hideMediaControlsTimer(this, &MediaControls::hideMediaControlsTimerFired)
|
, m_hideMediaControlsTimer(this, &MediaControls::hideMediaControlsTimerFired)
|
||||||
@@ -157,6 +158,12 @@ MediaControls* MediaControls::create(HTMLMediaElement& mediaElement)
|
|||||||
// +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-toggle-closed-captions-button)
|
// +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-toggle-closed-captions-button)
|
||||||
// +-MediaControlCastButtonElement (-internal-media-controls-cast-button)
|
// +-MediaControlCastButtonElement (-internal-media-controls-cast-button)
|
||||||
// \-MediaControlFullscreenButtonElement (-webkit-media-controls-fullscreen-button)
|
// \-MediaControlFullscreenButtonElement (-webkit-media-controls-fullscreen-button)
|
||||||
|
// +-MediaControlTextTrackListElement (-internal-media-controls-text-track-list)
|
||||||
|
// | {for each renderable text track}
|
||||||
|
// \-MediaControlTextTrackListItem (-internal-media-controls-text-track-list-item)
|
||||||
|
// +-MediaControlTextTrackListItemInput (-internal-media-controls-text-track-list-item-input)
|
||||||
|
// +-MediaControlTextTrackListItemCaptions (-internal-media-controls-text-track-list-kind-captions)
|
||||||
|
// +-MediaControlTextTrackListItemSubtitles (-internal-media-controls-text-track-list-kind-subtitles)
|
||||||
void MediaControls::initializeControls()
|
void MediaControls::initializeControls()
|
||||||
{
|
{
|
||||||
const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled();
|
const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled();
|
||||||
@@ -231,6 +238,10 @@ void MediaControls::initializeControls()
|
|||||||
|
|
||||||
m_enclosure = enclosure;
|
m_enclosure = enclosure;
|
||||||
appendChild(enclosure);
|
appendChild(enclosure);
|
||||||
|
|
||||||
|
MediaControlTextTrackListElement* textTrackList = MediaControlTextTrackListElement::create(*this);
|
||||||
|
m_textTrackList = textTrackList;
|
||||||
|
appendChild(textTrackList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaControls::reset()
|
void MediaControls::reset()
|
||||||
@@ -334,6 +345,9 @@ bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const
|
|||||||
const bool ignoreFocus = behaviorFlags & IgnoreFocus;
|
const bool ignoreFocus = behaviorFlags & IgnoreFocus;
|
||||||
if (!ignoreFocus && (mediaElement().focused() || contains(document().focusedElement())))
|
if (!ignoreFocus && (mediaElement().focused() || contains(document().focusedElement())))
|
||||||
return false;
|
return false;
|
||||||
|
// Don't hide the media controls when the text track list is showing.
|
||||||
|
if (m_textTrackList->isWanted())
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,6 +474,16 @@ void MediaControls::refreshClosedCaptionsButtonVisibility()
|
|||||||
BatchedControlUpdate batch(this);
|
BatchedControlUpdate batch(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaControls::toggleTextTrackList()
|
||||||
|
{
|
||||||
|
if (!mediaElement().hasClosedCaptions()) {
|
||||||
|
m_textTrackList->setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_textTrackList->setVisible(!m_textTrackList->isWanted());
|
||||||
|
}
|
||||||
|
|
||||||
void MediaControls::refreshCastButtonVisibility()
|
void MediaControls::refreshCastButtonVisibility()
|
||||||
{
|
{
|
||||||
refreshCastButtonVisibilityWithoutUpdate();
|
refreshCastButtonVisibilityWithoutUpdate();
|
||||||
@@ -759,6 +783,7 @@ DEFINE_TRACE(MediaControls)
|
|||||||
visitor->trace(m_fullScreenButton);
|
visitor->trace(m_fullScreenButton);
|
||||||
visitor->trace(m_durationDisplay);
|
visitor->trace(m_durationDisplay);
|
||||||
visitor->trace(m_enclosure);
|
visitor->trace(m_enclosure);
|
||||||
|
visitor->trace(m_textTrackList);
|
||||||
visitor->trace(m_castButton);
|
visitor->trace(m_castButton);
|
||||||
visitor->trace(m_overlayCastButton);
|
visitor->trace(m_overlayCastButton);
|
||||||
HTMLDivElement::trace(visitor);
|
HTMLDivElement::trace(visitor);
|
||||||
|
@@ -59,6 +59,7 @@ public:
|
|||||||
|
|
||||||
void changedClosedCaptionsVisibility();
|
void changedClosedCaptionsVisibility();
|
||||||
void refreshClosedCaptionsButtonVisibility();
|
void refreshClosedCaptionsButtonVisibility();
|
||||||
|
void toggleTextTrackList();
|
||||||
|
|
||||||
void enteredFullscreen();
|
void enteredFullscreen();
|
||||||
void exitedFullscreen();
|
void exitedFullscreen();
|
||||||
@@ -141,6 +142,7 @@ private:
|
|||||||
Member<MediaControlMuteButtonElement> m_muteButton;
|
Member<MediaControlMuteButtonElement> m_muteButton;
|
||||||
Member<MediaControlVolumeSliderElement> m_volumeSlider;
|
Member<MediaControlVolumeSliderElement> m_volumeSlider;
|
||||||
Member<MediaControlToggleClosedCaptionsButtonElement> m_toggleClosedCaptionsButton;
|
Member<MediaControlToggleClosedCaptionsButtonElement> m_toggleClosedCaptionsButton;
|
||||||
|
Member<MediaControlTextTrackListElement> m_textTrackList;
|
||||||
Member<MediaControlCastButtonElement> m_castButton;
|
Member<MediaControlCastButtonElement> m_castButton;
|
||||||
Member<MediaControlFullscreenButtonElement> m_fullScreenButton;
|
Member<MediaControlFullscreenButtonElement> m_fullScreenButton;
|
||||||
|
|
||||||
|
@@ -414,7 +414,7 @@ void TextTrack::invalidateTrackIndex()
|
|||||||
m_renderedTrackIndex = invalidTrackIndex;
|
m_renderedTrackIndex = invalidTrackIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextTrack::isRendered()
|
bool TextTrack::isRendered() const
|
||||||
{
|
{
|
||||||
if (kind() != captionsKeyword() && kind() != subtitlesKeyword())
|
if (kind() != captionsKeyword() && kind() != subtitlesKeyword())
|
||||||
return false;
|
return false;
|
||||||
@@ -425,6 +425,18 @@ bool TextTrack::isRendered()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TextTrack::canBeRendered() const
|
||||||
|
{
|
||||||
|
// A track can be displayed when it's of kind captions or subtitles and hasn't failed to load.
|
||||||
|
if (kind() != captionsKeyword() && kind() != subtitlesKeyword())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (getReadinessState() == FailedToLoad)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
TextTrackCueList* TextTrack::ensureTextTrackCueList()
|
TextTrackCueList* TextTrack::ensureTextTrackCueList()
|
||||||
{
|
{
|
||||||
if (!m_cues)
|
if (!m_cues)
|
||||||
|
@@ -102,7 +102,8 @@ public:
|
|||||||
int trackIndex();
|
int trackIndex();
|
||||||
void invalidateTrackIndex();
|
void invalidateTrackIndex();
|
||||||
|
|
||||||
bool isRendered();
|
bool isRendered() const;
|
||||||
|
bool canBeRendered() const;
|
||||||
int trackIndexRelativeToRenderedTracks();
|
int trackIndexRelativeToRenderedTracks();
|
||||||
|
|
||||||
bool hasBeenConfigured() const { return m_hasBeenConfigured; }
|
bool hasBeenConfigured() const { return m_hasBeenConfigured; }
|
||||||
|
@@ -54,7 +54,7 @@ LayoutObject* TextTrackContainer::createLayoutObject(const ComputedStyle&)
|
|||||||
|
|
||||||
void TextTrackContainer::updateDisplay(HTMLMediaElement& mediaElement, ExposingControls exposingControls)
|
void TextTrackContainer::updateDisplay(HTMLMediaElement& mediaElement, ExposingControls exposingControls)
|
||||||
{
|
{
|
||||||
if (!mediaElement.closedCaptionsVisible()) {
|
if (!mediaElement.textTracksVisible()) {
|
||||||
removeChildren();
|
removeChildren();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -504,7 +504,7 @@ bool MediaControlsPainter::paintMediaToggleClosedCaptionsButton(const LayoutObje
|
|||||||
|
|
||||||
bool isEnabled = mediaElement->hasClosedCaptions();
|
bool isEnabled = mediaElement->hasClosedCaptions();
|
||||||
|
|
||||||
if (mediaElement->closedCaptionsVisible())
|
if (mediaElement->textTracksVisible())
|
||||||
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButton, isEnabled);
|
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButton, isEnabled);
|
||||||
|
|
||||||
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButtonDisabled, isEnabled);
|
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButtonDisabled, isEnabled);
|
||||||
@@ -541,6 +541,39 @@ bool MediaControlsPainter::paintMediaCastButton(const LayoutObject& object, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaControlsPainter::paintMediaTrackSelectionCheckmark(const LayoutObject& object, const PaintInfo& paintInfo, const IntRect& rect)
|
||||||
|
{
|
||||||
|
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
|
||||||
|
if (!mediaElement)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static Image* mediaTrackSelectionCheckmark = platformResource("mediaplayerTrackSelectionCheckmark",
|
||||||
|
"mediaplayerTrackSelectionCheckmarkNew");
|
||||||
|
return paintMediaButton(paintInfo.context, rect, mediaTrackSelectionCheckmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaControlsPainter::paintMediaClosedCaptionsIcon(const LayoutObject& object, const PaintInfo& paintInfo, const IntRect& rect)
|
||||||
|
{
|
||||||
|
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
|
||||||
|
if (!mediaElement)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static Image* mediaClosedCaptionsIcon = platformResource("mediaplayerClosedCaptionsIcon",
|
||||||
|
"mediaplayerClosedCaptionsIconNew");
|
||||||
|
return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionsIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaControlsPainter::paintMediaSubtitlesIcon(const LayoutObject& object, const PaintInfo& paintInfo, const IntRect& rect)
|
||||||
|
{
|
||||||
|
const HTMLMediaElement* mediaElement = toParentMediaElement(object);
|
||||||
|
if (!mediaElement)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static Image* mediaSubtitlesIcon = platformResource("mediaplayerSubtitlesIcon",
|
||||||
|
"mediaplayerSubtitlesIconNew");
|
||||||
|
return paintMediaButton(paintInfo.context, rect, mediaSubtitlesIcon);
|
||||||
|
}
|
||||||
|
|
||||||
void MediaControlsPainter::adjustMediaSliderThumbSize(ComputedStyle& style)
|
void MediaControlsPainter::adjustMediaSliderThumbSize(ComputedStyle& style)
|
||||||
{
|
{
|
||||||
static Image* mediaSliderThumb = platformResource("mediaplayerSliderThumb",
|
static Image* mediaSliderThumb = platformResource("mediaplayerSliderThumb",
|
||||||
|
@@ -51,6 +51,9 @@ public:
|
|||||||
static bool paintMediaFullscreenButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
static bool paintMediaFullscreenButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
static bool paintMediaOverlayPlayButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
static bool paintMediaOverlayPlayButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
static bool paintMediaCastButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
static bool paintMediaCastButton(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
|
static bool paintMediaTrackSelectionCheckmark(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
|
static bool paintMediaClosedCaptionsIcon(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
|
static bool paintMediaSubtitlesIcon(const LayoutObject&, const PaintInfo&, const IntRect&);
|
||||||
static void adjustMediaSliderThumbSize(ComputedStyle&);
|
static void adjustMediaSliderThumbSize(ComputedStyle&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -137,6 +137,12 @@ bool ThemePainter::paint(const LayoutObject& o, const PaintInfo& paintInfo, cons
|
|||||||
case MediaCastOffButtonPart:
|
case MediaCastOffButtonPart:
|
||||||
case MediaOverlayCastOffButtonPart:
|
case MediaOverlayCastOffButtonPart:
|
||||||
return MediaControlsPainter::paintMediaCastButton(o, paintInfo, r);
|
return MediaControlsPainter::paintMediaCastButton(o, paintInfo, r);
|
||||||
|
case MediaTrackSelectionCheckmarkPart:
|
||||||
|
return MediaControlsPainter::paintMediaTrackSelectionCheckmark(o, paintInfo, r);
|
||||||
|
case MediaClosedCaptionsIconPart:
|
||||||
|
return MediaControlsPainter::paintMediaClosedCaptionsIcon(o, paintInfo, r);
|
||||||
|
case MediaSubtitlesIconPart:
|
||||||
|
return MediaControlsPainter::paintMediaSubtitlesIcon(o, paintInfo, r);
|
||||||
case MenulistButtonPart:
|
case MenulistButtonPart:
|
||||||
case TextFieldPart:
|
case TextFieldPart:
|
||||||
case TextAreaPart:
|
case TextAreaPart:
|
||||||
|
@@ -50,7 +50,8 @@ enum ControlPart {
|
|||||||
MediaEnterFullscreenButtonPart, MediaExitFullscreenButtonPart, MediaFullScreenVolumeSliderPart, MediaFullScreenVolumeSliderThumbPart, MediaMuteButtonPart, MediaPlayButtonPart,
|
MediaEnterFullscreenButtonPart, MediaExitFullscreenButtonPart, MediaFullScreenVolumeSliderPart, MediaFullScreenVolumeSliderThumbPart, MediaMuteButtonPart, MediaPlayButtonPart,
|
||||||
MediaOverlayPlayButtonPart, MediaToggleClosedCaptionsButtonPart,
|
MediaOverlayPlayButtonPart, MediaToggleClosedCaptionsButtonPart,
|
||||||
MediaSliderPart, MediaSliderThumbPart, MediaVolumeSliderContainerPart, MediaVolumeSliderPart, MediaVolumeSliderThumbPart,
|
MediaSliderPart, MediaSliderThumbPart, MediaVolumeSliderContainerPart, MediaVolumeSliderPart, MediaVolumeSliderThumbPart,
|
||||||
MediaControlsBackgroundPart, MediaControlsFullscreenBackgroundPart, MediaCurrentTimePart, MediaTimeRemainingPart, MediaCastOffButtonPart, MediaOverlayCastOffButtonPart,
|
MediaControlsBackgroundPart, MediaControlsFullscreenBackgroundPart, MediaCurrentTimePart, MediaTimeRemainingPart, MediaCastOffButtonPart,
|
||||||
|
MediaOverlayCastOffButtonPart, MediaTrackSelectionCheckmarkPart, MediaClosedCaptionsIconPart, MediaSubtitlesIconPart,
|
||||||
MenulistPart, MenulistButtonPart, MenulistTextPart, MenulistTextFieldPart, MeterPart, ProgressBarPart, ProgressBarValuePart,
|
MenulistPart, MenulistButtonPart, MenulistTextPart, MenulistTextFieldPart, MeterPart, ProgressBarPart, ProgressBarValuePart,
|
||||||
SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart,
|
SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart,
|
||||||
SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart,
|
SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart,
|
||||||
|
@@ -44,6 +44,12 @@
|
|||||||
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_ON_NEW" file="blink/mediaplayer_overlay_cast_on_new.png" />
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_ON_NEW" file="blink/mediaplayer_overlay_cast_on_new.png" />
|
||||||
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON" file="blink/mediaplayer_overlay_play.png" />
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON" file="blink/mediaplayer_overlay_play.png" />
|
||||||
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON_NEW" file="blink/mediaplayer_overlay_play_new.png" />
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON_NEW" file="blink/mediaplayer_overlay_play_new.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_TRACKSELECTION_CHECKMARK" file="blink/mediaplayer_trackselection_checkmark.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_TRACKSELECTION_CHECKMARK_NEW" file="blink/mediaplayer_trackselection_checkmark_new.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTIONS_ICON" file="blink/mediaplayer_closedcaptions_icon.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_CLOSEDCAPTIONS_ICON_NEW" file="blink/mediaplayer_closedcaptions_icon_new.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SUBTITLES_ICON" file="blink/mediaplayer_subtitles_icon.png" />
|
||||||
|
<structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SUBTITLES_ICON_NEW" file="blink/mediaplayer_subtitles_icon_new.png" />
|
||||||
<structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL" file="blink/search_cancel.png" />
|
<structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL" file="blink/search_cancel.png" />
|
||||||
<structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL_PRESSED" file="blink/search_cancel_pressed.png" />
|
<structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL_PRESSED" file="blink/search_cancel_pressed.png" />
|
||||||
<structure type="chrome_scaled_image" name="IDR_SEARCH_MAGNIFIER" file="blink/search_magnifier.png" />
|
<structure type="chrome_scaled_image" name="IDR_SEARCH_MAGNIFIER" file="blink/search_magnifier.png" />
|
||||||
|
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_closedcaptions_icon.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_closedcaptions_icon.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.9 KiB |
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_closedcaptions_icon_new.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_closedcaptions_icon_new.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.2 KiB |
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_subtitles_icon.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_subtitles_icon.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_subtitles_icon_new.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_subtitles_icon_new.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 896 B |
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_trackselection_checkmark.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_trackselection_checkmark.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.6 KiB |
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_trackselection_checkmark_new.png
vendored
Normal file
BIN
third_party/WebKit/public/default_100_percent/blink/mediaplayer_trackselection_checkmark_new.png
vendored
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.2 KiB |
@@ -138,6 +138,8 @@ struct WebLocalizedString {
|
|||||||
SearchMenuRecentSearchesText, // Deprecated.
|
SearchMenuRecentSearchesText, // Deprecated.
|
||||||
SelectMenuListText,
|
SelectMenuListText,
|
||||||
SubmitButtonDefaultLabel,
|
SubmitButtonDefaultLabel,
|
||||||
|
TextTracksNoLabel,
|
||||||
|
TextTracksOff,
|
||||||
ThisMonthButtonLabel,
|
ThisMonthButtonLabel,
|
||||||
ThisWeekButtonLabel,
|
ThisWeekButtonLabel,
|
||||||
ValidationBadInputForNumber,
|
ValidationBadInputForNumber,
|
||||||
|
Reference in New Issue
Block a user