--- a/suite/browser/test/mochitest/test_contextmenu.html
+++ b/suite/browser/test/mochitest/test_contextmenu.html
@@ -380,16 +380,21 @@ function runTest(testNum) {
break;
case 9:
// Context menu for a video (with a VALID media source)
checkContextMenu(["popupwindow-reject", true,
"---", null,
"context-media-play", true,
"context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
"context-media-hidecontrols", true,
"context-video-showstats", true,
"context-video-fullscreen", true,
"---", null,
"context-viewvideo", true,
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
@@ -400,32 +405,42 @@ function runTest(testNum) {
break;
case 10:
// Context menu for a video (with an audio-only file)
checkContextMenu(["popupwindow-reject", true,
"---", null,
"context-media-play", true,
"context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
"context-media-showcontrols", true,
"---", null,
"context-copyaudiourl", true,
"---", null,
"context-saveaudio", true,
"context-sendaudio", true]);
closeContextMenu();
openContextMenuFor(video_bad); // Invoke context menu for next test.
break;
case 11:
// Context menu for a video (with an INVALID media source)
checkContextMenu(["popupwindow-reject", true,
"---", null,
"context-media-play", false,
"context-media-mute", false,
+ "context-media-playbackrate", false,
+ ["context-media-playbackrate-050", null,
+ "context-media-playbackrate-100", null,
+ "context-media-playbackrate-150", null,
+ "context-media-playbackrate-200", null], null,
"context-media-hidecontrols", false,
"context-video-showstats", false,
"context-video-fullscreen", false,
"---", null,
"context-viewvideo", true,
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
@@ -436,16 +451,21 @@ function runTest(testNum) {
break;
case 12:
// Context menu for a video (with an INVALID media source)
checkContextMenu(["popupwindow-reject", true,
"---", null,
"context-media-play", false,
"context-media-mute", false,
+ "context-media-playbackrate", false,
+ ["context-media-playbackrate-050", null,
+ "context-media-playbackrate-100", null,
+ "context-media-playbackrate-150", null,
+ "context-media-playbackrate-200", null], null,
"context-media-hidecontrols", false,
"context-video-showstats", false,
"context-video-fullscreen", false,
"---", null,
"context-viewvideo", false,
"context-copyvideourl", false,
"---", null,
"context-savevideo", false,
@@ -492,16 +512,21 @@ function runTest(testNum) {
break;
case 14:
// Context menu for a video in an iframe
checkContextMenu(["popupwindow-reject", true,
"---", null,
"context-media-play", true,
"context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
"context-media-hidecontrols", true,
"context-video-showstats", true,
"context-video-fullscreen", true,
"---", null,
"context-viewvideo", true,
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
--- a/suite/common/nsContextMenu.js
+++ b/suite/common/nsContextMenu.js
@@ -372,35 +372,41 @@ nsContextMenu.prototype = {
var onMedia = (this.onVideo || this.onAudio);
// Several mutually exclusive items... play/pause, mute/unmute, show/hide
this.showItem("context-media-play",
onMedia && (this.target.paused || this.target.ended));
this.showItem("context-media-pause",
onMedia && !this.target.paused && !this.target.ended);
this.showItem("context-media-mute", onMedia && !this.target.muted);
this.showItem("context-media-unmute", onMedia && this.target.muted);
+ this.showItem("context-media-playbackrate", onMedia);
this.showItem("context-media-showcontrols", onMedia && !this.target.controls);
this.showItem("context-media-hidecontrols", onMedia && this.target.controls);
this.showItem("context-video-fullscreen", this.onVideo);
var statsShowing = this.onVideo &&
this.target.wrappedJSObject.mozMediaStatisticsShowing;
this.showItem("context-video-showstats",
this.onVideo && this.target.controls && !statsShowing);
this.showItem("context-video-hidestats",
this.onVideo && this.target.controls && statsShowing);
// Disable them when there isn't a valid media source loaded.
if (onMedia) {
+ this.setItemAttr("context-media-playbackrate-050", "checked", this.target.playbackRate == 0.5);
+ this.setItemAttr("context-media-playbackrate-100", "checked", this.target.playbackRate == 1.0);
+ this.setItemAttr("context-media-playbackrate-150", "checked", this.target.playbackRate == 1.5);
+ this.setItemAttr("context-media-playbackrate-200", "checked", this.target.playbackRate == 2.0);
var hasError = this.target.error != null ||
this.target.networkState == this.target.NETWORK_NO_SOURCE;
this.setItemAttr("context-media-play", "disabled", hasError);
this.setItemAttr("context-media-pause", "disabled", hasError);
this.setItemAttr("context-media-mute", "disabled", hasError);
this.setItemAttr("context-media-unmute", "disabled", hasError);
+ this.setItemAttr("context-media-playbackrate", "disabled", hasError);
this.setItemAttr("context-media-showcontrols", "disabled", hasError);
this.setItemAttr("context-media-hidecontrols", "disabled", hasError);
if (this.onVideo) {
let canSave = this.target.readyState >= this.target.HAVE_CURRENT_DATA;
this.setItemAttr("context-video-saveimage", "disabled", !canSave);
this.setItemAttr("context-video-fullscreen", "disabled", hasError);
this.setItemAttr("context-video-showstats", "disabled", hasError);
this.setItemAttr("context-video-hidestats", "disabled", hasError);
@@ -1367,32 +1373,35 @@ nsContextMenu.prototype = {
if (sibling.getAttribute("hidden") != "true")
return true;
sibling = sibling.previousSibling;
}
}
return false;
},
- mediaCommand: function(aCommand) {
+ mediaCommand: function(aCommand, aData) {
var media = this.target;
switch (aCommand) {
case "play":
media.play();
break;
case "pause":
media.pause();
break;
case "mute":
media.muted = true;
break;
case "unmute":
media.muted = false;
break;
+ case "playbackRate":
+ media.playbackRate = aData;
+ break;
case "hidecontrols":
media.removeAttribute("controls");
break;
case "showcontrols":
media.setAttribute("controls", "true");
break;
case "showstats":
case "hidestats":