зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
71adb3de58
10
.cron.yml
10
.cron.yml
|
@ -31,6 +31,16 @@ jobs:
|
|||
- date
|
||||
when: [] # never (hook only)
|
||||
|
||||
- name: nightly-desktop-win64
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nd-Win64
|
||||
triggered-by: nightly
|
||||
target-tasks-method: nightly_win64
|
||||
run-on-projects:
|
||||
- date
|
||||
when: [] # never (hook only)
|
||||
|
||||
- name: nightly-android
|
||||
job:
|
||||
type: decision-task
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Note: this file is included in aboutDialog.xul if MOZ_UPDATER is defined.
|
||||
// Note: this file is included in aboutDialog.xul and preferences/advanced.xul
|
||||
// if MOZ_UPDATER is defined.
|
||||
|
||||
/* import-globals-from aboutDialog.js */
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ with Files("sync/**"):
|
|||
BUG_COMPONENT = ("Firefox", "Sync")
|
||||
|
||||
with Files("test/alerts/**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notification and Alerts")
|
||||
BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
|
||||
|
||||
with Files("test/appUpdate/**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Application Update")
|
||||
|
|
|
@ -215,15 +215,15 @@ nsContextMenu.prototype = {
|
|||
initNavigationItems: function CM_initNavigationItems() {
|
||||
var shouldShow = !(this.isContentSelected || this.onLink || this.onImage ||
|
||||
this.onCanvas || this.onVideo || this.onAudio ||
|
||||
this.onTextInput || this.onSocial);
|
||||
this.onTextInput) && this.inTabBrowser;
|
||||
this.showItem("context-navigation", shouldShow);
|
||||
this.showItem("context-sep-navigation", shouldShow);
|
||||
|
||||
let stopped = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true";
|
||||
|
||||
let stopReloadItem = "";
|
||||
if (shouldShow || this.onSocial) {
|
||||
stopReloadItem = (stopped || this.onSocial) ? "reload" : "stop";
|
||||
if (shouldShow || !this.inTabBrowser) {
|
||||
stopReloadItem = (stopped || !this.inTabBrowser) ? "reload" : "stop";
|
||||
}
|
||||
|
||||
this.showItem("context-reload", stopReloadItem == "reload");
|
||||
|
@ -290,9 +290,12 @@ nsContextMenu.prototype = {
|
|||
this.onImage || this.onCanvas ||
|
||||
this.onVideo || this.onAudio ||
|
||||
this.onLink || this.onTextInput);
|
||||
var showInspect = !this.onSocial && gPrefService.getBoolPref("devtools.inspector.enabled");
|
||||
var showInspect = this.inTabBrowser && gPrefService.getBoolPref("devtools.inspector.enabled");
|
||||
this.showItem("context-viewsource", shouldShow);
|
||||
this.showItem("context-viewinfo", shouldShow);
|
||||
// The page info is broken for WebExtension popups, as the browser is
|
||||
// destroyed when the popup is closed.
|
||||
this.setItemAttr("context-viewinfo", "disabled", this.webExtBrowserType === "popup");
|
||||
this.showItem("inspect-separator", showInspect);
|
||||
this.showItem("context-inspect", showInspect);
|
||||
|
||||
|
@ -341,6 +344,9 @@ nsContextMenu.prototype = {
|
|||
.disabled = !this.hasBGImage;
|
||||
|
||||
this.showItem("context-viewimageinfo", this.onImage);
|
||||
// The image info popup is broken for WebExtension popups, since the browser
|
||||
// is destroyed when the popup is closed.
|
||||
this.setItemAttr("context-viewimageinfo", "disabled", this.webExtBrowserType === "popup");
|
||||
this.showItem("context-viewimagedesc", this.onImage && this.imageDescURL !== "");
|
||||
},
|
||||
|
||||
|
@ -350,11 +356,12 @@ nsContextMenu.prototype = {
|
|||
this.showItem(bookmarkPage,
|
||||
!(this.isContentSelected || this.onTextInput || this.onLink ||
|
||||
this.onImage || this.onVideo || this.onAudio || this.onSocial ||
|
||||
this.onCanvas));
|
||||
this.onCanvas || this.inWebExtBrowser));
|
||||
bookmarkPage.setAttribute("tooltiptext", bookmarkPage.getAttribute("buttontooltiptext"));
|
||||
|
||||
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
|
||||
!this.onSocial) || this.onPlainTextLink);
|
||||
!this.onSocial && !this.onMozExtLink) ||
|
||||
this.onPlainTextLink);
|
||||
this.showItem("context-keywordfield",
|
||||
this.onTextInput && this.onKeywordField);
|
||||
this.showItem("frame", this.inFrame);
|
||||
|
@ -398,13 +405,14 @@ nsContextMenu.prototype = {
|
|||
let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial;
|
||||
let pageShare = shareEnabled && !(this.isContentSelected ||
|
||||
this.onTextInput || this.onLink || this.onImage ||
|
||||
this.onVideo || this.onAudio || this.onCanvas);
|
||||
this.onVideo || this.onAudio || this.onCanvas ||
|
||||
this.inWebExtBrowser);
|
||||
this.showItem("context-sharepage", pageShare);
|
||||
this.showItem("context-shareselect", shareEnabled && this.isContentSelected);
|
||||
this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink);
|
||||
this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink && !this.onMozExtLink);
|
||||
this.showItem("context-shareimage", shareEnabled && this.onImage);
|
||||
this.showItem("context-sharevideo", shareEnabled && this.onVideo);
|
||||
this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL || this.mediaURL.startsWith("blob:"));
|
||||
this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL || this.mediaURL.startsWith("blob:") || this.mediaURL.startsWith("moz-extension:"));
|
||||
},
|
||||
|
||||
initSpellingItems() {
|
||||
|
@ -677,6 +685,10 @@ nsContextMenu.prototype = {
|
|||
this.onCTPPlugin = false;
|
||||
this.canSpellCheck = false;
|
||||
this.onPassword = false;
|
||||
this.webExtBrowserType = "";
|
||||
this.inWebExtBrowser = false;
|
||||
this.inTabBrowser = true;
|
||||
this.onMozExtLink = false;
|
||||
|
||||
if (this.isRemote) {
|
||||
this.selectionInfo = gContextMenuContentData.selectionInfo;
|
||||
|
@ -713,6 +725,10 @@ nsContextMenu.prototype = {
|
|||
this.frameOuterWindowID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
|
||||
}
|
||||
this.onSocial = !!this.browser.getAttribute("origin");
|
||||
this.webExtBrowserType = this.browser.getAttribute("webextension-view-type");
|
||||
this.inWebExtBrowser = !!this.webExtBrowserType;
|
||||
this.inTabBrowser = this.browser.ownerGlobal.gBrowser ?
|
||||
!!this.browser.ownerGlobal.gBrowser.getTabForBrowser(this.browser) : false;
|
||||
|
||||
// Check if we are in a synthetic document (stand alone image, video, etc.).
|
||||
this.inSyntheticDoc = ownerDoc.mozSyntheticDocument;
|
||||
|
@ -869,6 +885,7 @@ nsContextMenu.prototype = {
|
|||
this.linkTextStr = this.getLinkText();
|
||||
this.linkProtocol = this.getLinkProtocol();
|
||||
this.onMailtoLink = (this.linkProtocol == "mailto");
|
||||
this.onMozExtLink = (this.linkProtocol == "moz-extension");
|
||||
this.onSaveableLink = this.isLinkSaveable( this.link );
|
||||
this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem);
|
||||
try {
|
||||
|
@ -1033,8 +1050,11 @@ nsContextMenu.prototype = {
|
|||
}
|
||||
|
||||
if (!this.isRemote) {
|
||||
params.frameOuterWindowID = WebNavigationFrames.getFrameId(this.target.ownerGlobal);
|
||||
// Propagate the frameOuterWindowID value saved when
|
||||
// the context menu has been opened.
|
||||
params.frameOuterWindowID = this.frameOuterWindowID;
|
||||
}
|
||||
|
||||
// If we want to change userContextId, we must be sure that we don't
|
||||
// propagate the referrer.
|
||||
if ("userContextId" in params &&
|
||||
|
@ -1911,7 +1931,7 @@ nsContextMenu.prototype = {
|
|||
_getTelemetryPageContextInfo() {
|
||||
let rv = [];
|
||||
for (let k of ["isContentSelected", "onLink", "onImage", "onCanvas", "onVideo", "onAudio",
|
||||
"onTextInput", "onSocial"]) {
|
||||
"onTextInput", "onSocial", "inWebExtBrowser", "inTabBrowser"]) {
|
||||
if (this[k]) {
|
||||
rv.push(k.replace(/^(?:is|on)(.)/, (match, firstLetter) => firstLetter.toLowerCase()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/browser-test"
|
||||
]
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
!/browser/base/content/test/general/contextmenu_common.js
|
||||
subtst_contextmenu_webext.html
|
||||
|
||||
[browser_contextmenu_mozextension.js]
|
|
@ -0,0 +1,82 @@
|
|||
"use strict";
|
||||
|
||||
var { SocialService } = Cu.import("resource:///modules/SocialService.jsm", {});
|
||||
|
||||
let contextMenu;
|
||||
let hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled");
|
||||
let hasContainers = Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||
|
||||
// A social share provider
|
||||
let manifest = {
|
||||
name: "provider 1",
|
||||
origin: "https://example.com",
|
||||
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
|
||||
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
|
||||
};
|
||||
|
||||
add_task(function* test_setup() {
|
||||
const example_base = "http://example.com/browser/browser/base/content/test/contextMenu/";
|
||||
const url = example_base + "subtst_contextmenu_webext.html";
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
|
||||
const chrome_base = "chrome://mochitests/content/browser/browser/base/content/test/general/";
|
||||
const contextmenu_common = chrome_base + "contextmenu_common.js";
|
||||
/* import-globals-from ../general/contextmenu_common.js */
|
||||
Services.scriptloader.loadSubScript(contextmenu_common, this);
|
||||
|
||||
// Enable social sharing functions in the browser, so the context menu item is shown.
|
||||
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
|
||||
|
||||
yield new Promise((resolve) => SocialService.addProvider(manifest, resolve));
|
||||
ok(SocialShare.shareButton && !SocialShare.shareButton.disabled, "Sharing is enabled");
|
||||
});
|
||||
|
||||
add_task(function* test_link() {
|
||||
// gets hidden for this case.
|
||||
yield test_contextmenu("#link",
|
||||
["context-openlinkintab", true,
|
||||
...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
|
||||
// We need a blank entry here because the containers submenu is
|
||||
// dynamically generated with no ids.
|
||||
...(hasContainers ? ["", null] : []),
|
||||
"context-openlink", true,
|
||||
"context-openlinkprivate", true,
|
||||
"---", null,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true]);
|
||||
});
|
||||
|
||||
add_task(function* test_video() {
|
||||
yield test_contextmenu("#video",
|
||||
["context-media-play", null,
|
||||
"context-media-mute", null,
|
||||
"context-media-playbackrate", null,
|
||||
["context-media-playbackrate-050x", null,
|
||||
"context-media-playbackrate-100x", null,
|
||||
"context-media-playbackrate-125x", null,
|
||||
"context-media-playbackrate-150x", null,
|
||||
"context-media-playbackrate-200x", null], null,
|
||||
"context-media-loop", null,
|
||||
"context-media-showcontrols", null,
|
||||
"context-video-fullscreen", null,
|
||||
"---", null,
|
||||
"context-viewvideo", null,
|
||||
"context-copyvideourl", null,
|
||||
"---", null,
|
||||
"context-savevideo", null,
|
||||
"context-sharevideo", false,
|
||||
"context-video-saveimage", null,
|
||||
"context-sendvideo", null,
|
||||
"context-castvideo", null,
|
||||
[], null
|
||||
]);
|
||||
});
|
||||
|
||||
add_task(function* test_cleanup() {
|
||||
lastElementSelector = null;
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
yield new Promise((resolve) => {
|
||||
return SocialService.disableProvider(manifest.origin, resolve);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Subtest for browser context menu</title>
|
||||
</head>
|
||||
<body>
|
||||
Browser context menu subtest.
|
||||
<a href="moz-extension://foo-bar/tab.html" id="link">Link to an extension resource</a>
|
||||
<video src="moz-extension://foo-bar/video.ogg" id="video"></video>
|
||||
</body>
|
||||
</html>
|
|
@ -6,3 +6,4 @@ support-files =
|
|||
skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds
|
||||
[browser_selectpopup_colors.js]
|
||||
skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds
|
||||
[browser_selectpopup_searchfocus.js]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
let SELECT =
|
||||
"<html><body><select id='one'>";
|
||||
for (let i = 0; i < 75; i++) {
|
||||
SELECT +=
|
||||
` <option>${i}${i}${i}${i}${i}</option>`;
|
||||
}
|
||||
SELECT +=
|
||||
' <option selected="true">{"end": "true"}</option>' +
|
||||
"</select></body></html>";
|
||||
|
||||
add_task(function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.select_popup_in_parent.enabled", true],
|
||||
["dom.forms.selectSearch", true]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_focus_on_search_shouldnt_close_popup() {
|
||||
const pageUrl = "data:text/html," + escape(SELECT);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
||||
let menulist = document.getElementById("ContentSelectDropdown");
|
||||
let selectPopup = menulist.menupopup;
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
|
||||
yield popupShownPromise;
|
||||
|
||||
let searchInput = selectPopup.querySelector("textbox[type='search']");
|
||||
searchInput.scrollIntoView();
|
||||
let searchFocused = BrowserTestUtils.waitForEvent(searchInput, "focus");
|
||||
yield EventUtils.synthesizeMouseAtCenter(searchInput, {}, window);
|
||||
yield searchFocused;
|
||||
|
||||
is(selectPopup.state, "open", "select popup should still be open after clicking on the search field");
|
||||
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
|
@ -235,8 +235,6 @@ var whitelist = new Set([
|
|||
{file: "resource://gre/modules/Manifest.jsm"},
|
||||
// Bug 1351089
|
||||
{file: "resource://gre/modules/PresentationDeviceInfoManager.jsm"},
|
||||
// Bug 1351091
|
||||
{file: "resource://gre/modules/Profiler.jsm"},
|
||||
// Bug 1351658
|
||||
{file: "resource://gre/modules/PropertyListUtils.jsm", platforms: ["linux", "win"]},
|
||||
// Bug 1351097
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
dummy_page.html
|
||||
test_bug1358314.html
|
||||
|
||||
[browser_abandonment_telemetry.js]
|
||||
[browser_allow_process_switches_despite_related_browser.js]
|
||||
[browser_contextmenu_openlink_after_tabnavigated.js]
|
||||
[browser_tabCloseProbes.js]
|
||||
[browser_tabSpinnerProbe.js]
|
||||
skip-if = !e10s # Tab spinner is e10s only.
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
"use strict";
|
||||
|
||||
const example_base = "http://example.com/browser/browser/base/content/test/tabs/";
|
||||
|
||||
add_task(function* test_contextmenu_openlink_after_tabnavigated() {
|
||||
let url = example_base + "test_bug1358314.html";
|
||||
|
||||
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
|
||||
const contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouse("a", 0, 0, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
}, gBrowser.selectedBrowser);
|
||||
yield awaitPopupShown;
|
||||
info("Popup Shown");
|
||||
|
||||
info("Navigate the tab with the opened context menu");
|
||||
gBrowser.selectedBrowser.loadURI("about:blank");
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
|
||||
let awaitNewTabOpen = BrowserTestUtils.waitForNewTab(gBrowser, "http://example.com/");
|
||||
|
||||
info("Click the 'open link in new tab' menu item");
|
||||
let openLinkMenuItem = contextMenu.querySelector("#context-openlinkintab");
|
||||
openLinkMenuItem.click();
|
||||
|
||||
info("Wait for the new tab to be opened");
|
||||
const newTab = yield awaitNewTabOpen;
|
||||
|
||||
// Close the contextMenu popup if it has not been closed yet.
|
||||
contextMenu.hidePopup();
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
|
||||
const newTabURL = yield ContentTask.spawn(newTab.linkedBrowser, null, function* () {
|
||||
return content.location.href;
|
||||
});
|
||||
is(newTabURL, "http://example.com/", "Got the expected URL loaded in the new tab");
|
||||
|
||||
yield BrowserTestUtils.removeTab(newTab);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<p>Test page</p>
|
||||
<a href="/">Link</a>
|
||||
</body>
|
||||
</html>
|
|
@ -17,6 +17,7 @@ MOCHITEST_CHROME_MANIFESTS += [
|
|||
BROWSER_CHROME_MANIFESTS += [
|
||||
'content/test/alerts/browser.ini',
|
||||
'content/test/captivePortal/browser.ini',
|
||||
'content/test/contextMenu/browser.ini',
|
||||
'content/test/forms/browser.ini',
|
||||
'content/test/general/browser.ini',
|
||||
'content/test/newtab/browser.ini',
|
||||
|
|
|
@ -233,6 +233,7 @@ class BasePopup {
|
|||
browser.setAttribute("class", "webextension-popup-browser");
|
||||
browser.setAttribute("webextension-view-type", "popup");
|
||||
browser.setAttribute("tooltip", "aHTMLTooltip");
|
||||
browser.setAttribute("contextmenu", "contentAreaContextMenu");
|
||||
|
||||
if (this.extension.remote) {
|
||||
browser.setAttribute("remote", "true");
|
||||
|
@ -286,6 +287,9 @@ class BasePopup {
|
|||
setupBrowser(browser);
|
||||
let mm = browser.messageManager;
|
||||
|
||||
// Sets the context information for context menus.
|
||||
mm.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
|
||||
mm.loadFrameScript(
|
||||
"chrome://extensions/content/ext-browser-content.js", false);
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ this.browserAction = class extends ExtensionAPI {
|
|||
|
||||
if (pendingPopup) {
|
||||
if (pendingPopup.window === window && pendingPopup.popupURL === popupURL) {
|
||||
if (!this.blockParser) {
|
||||
if (!blockParser) {
|
||||
pendingPopup.unblockParser();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ support-files =
|
|||
|
||||
[browser_ext_browserAction_area.js]
|
||||
[browser_ext_browserAction_context.js]
|
||||
[browser_ext_browserAction_contextMenu.js]
|
||||
[browser_ext_browserAction_disabled.js]
|
||||
[browser_ext_browserAction_pageAction_icon.js]
|
||||
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
||||
|
@ -73,6 +74,7 @@ skip-if = debug || asan # Bug 1354681
|
|||
[browser_ext_optionsPage_browser_style.js]
|
||||
[browser_ext_optionsPage_privileges.js]
|
||||
[browser_ext_pageAction_context.js]
|
||||
[browser_ext_pageAction_contextMenu.js]
|
||||
[browser_ext_pageAction_popup.js]
|
||||
[browser_ext_pageAction_popup_resize.js]
|
||||
[browser_ext_pageAction_simple.js]
|
||||
|
@ -93,6 +95,7 @@ skip-if = debug || asan # Bug 1354681
|
|||
[browser_ext_sessions_restore.js]
|
||||
[browser_ext_sidebarAction.js]
|
||||
[browser_ext_sidebarAction_context.js]
|
||||
[browser_ext_sidebarAction_contextMenu.js]
|
||||
[browser_ext_sidebarAction_tabs.js]
|
||||
[browser_ext_sidebarAction_windows.js]
|
||||
[browser_ext_simple.js]
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
let extData = {
|
||||
manifest: {
|
||||
"permissions": ["contextMenus"],
|
||||
"browser_action": {
|
||||
"default_popup": "popup.html",
|
||||
},
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
|
||||
files: {
|
||||
"popup.html": `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<span id="text">A Test Popup</span>
|
||||
<img id="testimg" src="data:image/svg+xml,<svg></svg>" height="10" width="10">
|
||||
</body></html>
|
||||
`,
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.contextMenus.create({
|
||||
id: "clickme-page",
|
||||
title: "Click me!",
|
||||
contexts: ["all"],
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
let contextMenuItems = {
|
||||
"context-navigation": "hidden",
|
||||
"context-sep-navigation": "hidden",
|
||||
"context-viewsource": "",
|
||||
"context-viewinfo": "disabled",
|
||||
"inspect-separator": "hidden",
|
||||
"context-inspect": "hidden",
|
||||
"context-bookmarkpage": "hidden",
|
||||
"context-sharepage": "hidden",
|
||||
};
|
||||
|
||||
add_task(function* browseraction_popup_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
|
||||
yield clickBrowserAction(extension, window);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension);
|
||||
let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
|
||||
is(item.length, 1, "contextMenu item for page was found");
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* browseraction_popup_contextmenu_hidden_items() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
|
||||
yield clickBrowserAction(extension);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#text");
|
||||
|
||||
let item, state;
|
||||
for (const itemID in contextMenuItems) {
|
||||
item = contentAreaContextMenu.querySelector(`#${itemID}`);
|
||||
state = contextMenuItems[itemID];
|
||||
|
||||
if (state !== "") {
|
||||
ok(item[state], `${itemID} is ${state}`);
|
||||
|
||||
if (state !== "hidden") {
|
||||
ok(!item.hidden, `Disabled ${itemID} is not hidden`);
|
||||
}
|
||||
} else {
|
||||
ok(!item.hidden, `${itemID} is not hidden`);
|
||||
ok(!item.disabled, `${itemID} is not disabled`);
|
||||
}
|
||||
}
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* browseraction_popup_image_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
|
||||
yield clickBrowserAction(extension);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#testimg");
|
||||
|
||||
let item = contentAreaContextMenu.querySelector("#context-viewimageinfo");
|
||||
ok(!item.hidden);
|
||||
ok(item.disabled);
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
|
@ -0,0 +1,116 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
let extData = {
|
||||
manifest: {
|
||||
"permissions": ["contextMenus"],
|
||||
"page_action": {
|
||||
"default_popup": "popup.html",
|
||||
},
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
|
||||
files: {
|
||||
"popup.html": `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<span id="text">A Test Popup</span>
|
||||
<img id="testimg" src="data:image/svg+xml,<svg></svg>" height="10" width="10">
|
||||
</body></html>
|
||||
`,
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.contextMenus.create({
|
||||
id: "clickme-page",
|
||||
title: "Click me!",
|
||||
contexts: ["all"],
|
||||
});
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
const tabId = tabs[0].id;
|
||||
|
||||
browser.pageAction.show(tabId).then(() => {
|
||||
browser.test.sendMessage("action-shown");
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
let contextMenuItems = {
|
||||
"context-navigation": "hidden",
|
||||
"context-sep-navigation": "hidden",
|
||||
"context-viewsource": "",
|
||||
"context-viewinfo": "disabled",
|
||||
"inspect-separator": "hidden",
|
||||
"context-inspect": "hidden",
|
||||
"context-bookmarkpage": "hidden",
|
||||
"context-sharepage": "hidden",
|
||||
};
|
||||
|
||||
add_task(function* pageaction_popup_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("action-shown");
|
||||
|
||||
yield clickPageAction(extension, window);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension);
|
||||
let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
|
||||
is(item.length, 1, "contextMenu item for page was found");
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* pageaction_popup_contextmenu_hidden_items() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("action-shown");
|
||||
|
||||
yield clickPageAction(extension, window);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#text");
|
||||
|
||||
let item, state;
|
||||
for (const itemID in contextMenuItems) {
|
||||
item = contentAreaContextMenu.querySelector(`#${itemID}`);
|
||||
state = contextMenuItems[itemID];
|
||||
|
||||
if (state !== "") {
|
||||
ok(item[state], `${itemID} is ${state}`);
|
||||
|
||||
if (state !== "hidden") {
|
||||
ok(!item.hidden, `Disabled ${itemID} is not hidden`);
|
||||
}
|
||||
} else {
|
||||
ok(!item.hidden, `${itemID} is not hidden`);
|
||||
ok(!item.disabled, `${itemID} is not disabled`);
|
||||
}
|
||||
}
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* pageaction_popup_image_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("action-shown");
|
||||
|
||||
yield clickPageAction(extension, window);
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#testimg");
|
||||
|
||||
let item = contentAreaContextMenu.querySelector("#context-viewimageinfo");
|
||||
ok(!item.hidden);
|
||||
ok(item.disabled);
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
let extData = {
|
||||
manifest: {
|
||||
"permissions": ["contextMenus"],
|
||||
"sidebar_action": {
|
||||
"default_panel": "sidebar.html",
|
||||
},
|
||||
|
@ -31,12 +30,6 @@ let extData = {
|
|||
},
|
||||
|
||||
background: function() {
|
||||
browser.contextMenus.create({
|
||||
id: "clickme-page",
|
||||
title: "Click me!",
|
||||
contexts: ["all"],
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg === "set-panel") {
|
||||
browser.sidebarAction.setPanel({panel: ""}).then(() => {
|
||||
|
@ -103,20 +96,6 @@ add_task(function* sidebar_empty_panel() {
|
|||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* sidebar_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInSidebar();
|
||||
let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
|
||||
is(item.length, 1, "contextMenu item for page was found");
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// This is set on initial sidebar install.
|
||||
Services.prefs.clearUserPref("extensions.sidebar-button.shown");
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
let extData = {
|
||||
manifest: {
|
||||
"permissions": ["contextMenus"],
|
||||
"sidebar_action": {
|
||||
"default_panel": "sidebar.html",
|
||||
},
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
|
||||
files: {
|
||||
"sidebar.html": `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"/>
|
||||
<script src="sidebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<span id="text">A Test Sidebar</span>
|
||||
<img id="testimg" src="data:image/svg+xml,<svg></svg>" height="10" width="10">
|
||||
</body></html>
|
||||
`,
|
||||
|
||||
"sidebar.js": function() {
|
||||
window.onload = () => {
|
||||
browser.test.sendMessage("sidebar");
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.contextMenus.create({
|
||||
id: "clickme-page",
|
||||
title: "Click me!",
|
||||
contexts: ["all"],
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
let contextMenuItems = {
|
||||
"context-navigation": "hidden",
|
||||
"context-sep-navigation": "hidden",
|
||||
"context-viewsource": "",
|
||||
"context-viewinfo": "",
|
||||
"inspect-separator": "hidden",
|
||||
"context-inspect": "hidden",
|
||||
"context-bookmarkpage": "hidden",
|
||||
"context-sharepage": "hidden",
|
||||
};
|
||||
|
||||
add_task(function* sidebar_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInSidebar();
|
||||
let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
|
||||
is(item.length, 1, "contextMenu item for page was found");
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* sidebar_contextmenu_hidden_items() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInSidebar("#text");
|
||||
|
||||
let item, state;
|
||||
for (const itemID in contextMenuItems) {
|
||||
item = contentAreaContextMenu.querySelector(`#${itemID}`);
|
||||
state = contextMenuItems[itemID];
|
||||
|
||||
if (state !== "") {
|
||||
ok(item[state], `${itemID} is ${state}`);
|
||||
|
||||
if (state !== "hidden") {
|
||||
ok(!item.hidden, `Disabled ${itemID} is not hidden`);
|
||||
}
|
||||
} else {
|
||||
ok(!item.hidden, `${itemID} is not hidden`);
|
||||
ok(!item.disabled, `${itemID} is not disabled`);
|
||||
}
|
||||
}
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* sidebar_image_contextmenu() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
|
||||
let contentAreaContextMenu = yield openContextMenuInSidebar("#testimg");
|
||||
|
||||
let item = contentAreaContextMenu.querySelector("#context-viewimageinfo");
|
||||
ok(!item.hidden);
|
||||
ok(!item.disabled);
|
||||
|
||||
yield closeContextMenu(contentAreaContextMenu);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// This is set on initial sidebar install.
|
||||
Services.prefs.clearUserPref("extensions.sidebar-button.shown");
|
||||
});
|
|
@ -8,7 +8,8 @@
|
|||
* getBrowserActionPopup getPageActionPopup
|
||||
* closeBrowserAction closePageAction
|
||||
* promisePopupShown promisePopupHidden
|
||||
* openContextMenu closeContextMenu openContextMenuInSidebar
|
||||
* openContextMenu closeContextMenu
|
||||
* openContextMenuInSidebar openContextMenuInPopup
|
||||
* openExtensionContextMenu closeExtensionContextMenu
|
||||
* openActionContextMenu openSubmenu closeActionContextMenu
|
||||
* openTabContextMenu closeTabContextMenu
|
||||
|
@ -232,6 +233,16 @@ function closeBrowserAction(extension, win = window) {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async function openContextMenuInPopup(extension, selector = "body") {
|
||||
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let browser = await awaitExtensionPanel(extension);
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "mousedown", button: 2}, browser);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "contextmenu"}, browser);
|
||||
await popupShownPromise;
|
||||
return contentAreaContextMenu;
|
||||
}
|
||||
|
||||
async function openContextMenuInSidebar(selector = "body") {
|
||||
let contentAreaContextMenu = SidebarUI.browser.contentDocument.getElementById("contentAreaContextMenu");
|
||||
let browser = SidebarUI.browser.contentDocument.getElementById("webext-panels-browser");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js
|
||||
../../../../../toolkit/components/extensions/test/mochitest/file_sample.html
|
||||
tags = webextensions
|
||||
|
||||
[test_ext_all_apis.html]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
|
||||
|
||||
// Load DownloadUtils module for convertByteUnits
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
|
@ -20,7 +21,56 @@ var gAdvancedPane = {
|
|||
|
||||
this._inited = true;
|
||||
|
||||
let version = AppConstants.MOZ_APP_VERSION_DISPLAY;
|
||||
|
||||
// Include the build ID if this is an "a#" (nightly) build
|
||||
if (/a\d+$/.test(version)) {
|
||||
let buildID = Services.appinfo.appBuildID;
|
||||
let year = buildID.slice(0, 4);
|
||||
let month = buildID.slice(4, 6);
|
||||
let day = buildID.slice(6, 8);
|
||||
version += ` (${year}-${month}-${day})`;
|
||||
}
|
||||
|
||||
// Append "(32-bit)" or "(64-bit)" build architecture to the version number:
|
||||
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
let archResource = Services.appinfo.is64Bit
|
||||
? "aboutDialog.architecture.sixtyFourBit"
|
||||
: "aboutDialog.architecture.thirtyTwoBit";
|
||||
let arch = bundle.GetStringFromName(archResource);
|
||||
version += ` (${arch})`;
|
||||
|
||||
document.getElementById("version").textContent = version;
|
||||
|
||||
// Show a release notes link if we have a URL.
|
||||
let relNotesLink = document.getElementById("releasenotes");
|
||||
let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL");
|
||||
if (relNotesPrefType != Services.prefs.PREF_INVALID) {
|
||||
let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
|
||||
if (relNotesURL != "about:blank") {
|
||||
relNotesLink.href = relNotesURL;
|
||||
relNotesLink.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
let distroId = Services.prefs.getCharPref("distribution.id", "");
|
||||
if (distroId) {
|
||||
let distroVersion = Services.prefs.getCharPref("distribution.version");
|
||||
|
||||
let distroIdField = document.getElementById("distributionId");
|
||||
distroIdField.value = distroId + " - " + distroVersion;
|
||||
distroIdField.hidden = false;
|
||||
|
||||
let distroAbout = Services.prefs.getStringPref("distribution.about", "");
|
||||
if (distroAbout) {
|
||||
let distroField = document.getElementById("distribution");
|
||||
distroField.value = distroAbout;
|
||||
distroField.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
gAppUpdater = new appUpdater();
|
||||
let onUnload = () => {
|
||||
window.removeEventListener("unload", onUnload);
|
||||
Services.prefs.removeObserver("app.update.", this);
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
<!-- Advanced panel -->
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
<script type="application/javascript" src="chrome://browser/content/aboutDialog-appUpdater.js"/>
|
||||
#endif
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content/advanced.js"/>
|
||||
|
||||
|
@ -52,23 +56,16 @@
|
|||
<!-- Update -->
|
||||
<groupbox id="updateApp" data-category="paneAdvanced" hidden="true">
|
||||
<caption><label>&updateApplication.label;</label></caption>
|
||||
#ifdef MOZ_UPDATER
|
||||
<description>&updateApplication.description;</description>
|
||||
<hbox align="start">
|
||||
<vbox flex="1">
|
||||
<radiogroup id="updateRadioGroup">
|
||||
<radio id="autoDesktop"
|
||||
value="auto"
|
||||
label="&updateAuto2.label;"
|
||||
accesskey="&updateAuto2.accesskey;"/>
|
||||
<radio value="checkOnly"
|
||||
label="&updateCheckChoose2.label;"
|
||||
accesskey="&updateCheckChoose2.accesskey;"/>
|
||||
<radio value="manual"
|
||||
label="&updateManual2.label;"
|
||||
accesskey="&updateManual2.accesskey;"/>
|
||||
</radiogroup>
|
||||
<description>
|
||||
&updateApplication.version.pre;<label id="version"/>&updateApplication.version.post;
|
||||
<label id="releasenotes" class="learnMore text-link" hidden="true">&releaseNotes.link;</label>
|
||||
</description>
|
||||
<description id="distribution" class="text-blurb" hidden="true"/>
|
||||
<description id="distributionId" class="text-blurb" hidden="true"/>
|
||||
</vbox>
|
||||
#ifdef MOZ_UPDATER
|
||||
<spacer flex="1"/>
|
||||
<vbox>
|
||||
<button id="showUpdateHistory"
|
||||
|
@ -77,7 +74,112 @@
|
|||
accesskey="&updateHistory2.accesskey;"
|
||||
preference="app.update.disable_button.showUpdateHistory"/>
|
||||
</vbox>
|
||||
#endif
|
||||
</hbox>
|
||||
#ifdef MOZ_UPDATER
|
||||
<vbox id="updateBox">
|
||||
<deck id="updateDeck" orient="vertical">
|
||||
<hbox id="checkForUpdates" align="center">
|
||||
<spacer flex="1"/>
|
||||
<button id="checkForUpdatesButton"
|
||||
label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="downloadAndInstall" align="center">
|
||||
<spacer flex="1"/>
|
||||
<button id="downloadAndInstallButton"
|
||||
oncommand="gAppUpdater.startDownload();"/>
|
||||
<!-- label and accesskey will be filled by JS -->
|
||||
</hbox>
|
||||
<hbox id="apply" align="center">
|
||||
<spacer flex="1"/>
|
||||
<button id="updateButton"
|
||||
label="&update.updateButton.label3;"
|
||||
accesskey="&update.updateButton.accesskey;"
|
||||
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
|
||||
</hbox>
|
||||
<hbox id="checkingForUpdates" align="center">
|
||||
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="downloading" align="center">
|
||||
<image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
|
||||
</hbox>
|
||||
<hbox id="applying" align="center">
|
||||
<image class="update-throbber"/><label>&update.applying;</label>
|
||||
</hbox>
|
||||
<hbox id="downloadFailed" align="center">
|
||||
<label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="adminDisabled" align="center">
|
||||
<label>&update.adminDisabled;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="noUpdatesFound" align="center">
|
||||
<label>&update.noUpdatesFound;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="otherInstanceHandlingUpdates" align="center">
|
||||
<label>&update.otherInstanceHandlingUpdates;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="manualUpdate" align="center">
|
||||
<label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="unsupportedSystem" align="center">
|
||||
<label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.checkForUpdatesButton.label;"
|
||||
accesskey="&update.checkForUpdatesButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="restarting" align="center">
|
||||
<label>&update.restarting;</label>
|
||||
<spacer flex="1"/>
|
||||
<button label="&update.updateButton.label3;"
|
||||
accesskey="&update.updateButton.accesskey;"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
</deck>
|
||||
</vbox>
|
||||
#endif
|
||||
|
||||
<separator/>
|
||||
#ifdef MOZ_UPDATER
|
||||
<description>&updateApplication.description;</description>
|
||||
<radiogroup id="updateRadioGroup">
|
||||
<radio id="autoDesktop"
|
||||
value="auto"
|
||||
label="&updateAuto2.label;"
|
||||
accesskey="&updateAuto2.accesskey;"/>
|
||||
<radio value="checkOnly"
|
||||
label="&updateCheckChoose2.label;"
|
||||
accesskey="&updateCheckChoose2.accesskey;"/>
|
||||
<radio value="manual"
|
||||
label="&updateManual2.label;"
|
||||
accesskey="&updateManual2.accesskey;"/>
|
||||
</radiogroup>
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
<checkbox id="useService"
|
||||
label="&useService.label;"
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
"chrome://browser/locale/preferences/applications.dtd">
|
||||
<!ENTITY % advancedDTD SYSTEM
|
||||
"chrome://browser/locale/preferences/advanced.dtd">
|
||||
<!ENTITY % aboutDialogDTD SYSTEM "chrome://browser/locale/aboutDialog.dtd" >
|
||||
%aboutDialogDTD;
|
||||
%brandDTD;
|
||||
%globalPreferencesDTD;
|
||||
%preferencesDTD;
|
||||
|
|
|
@ -110,14 +110,19 @@ add_task(function*() {
|
|||
});
|
||||
|
||||
add_task(function*() {
|
||||
mockUpdateManager.register();
|
||||
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", { leaveOpen: true });
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
|
||||
let showBtn = doc.getElementById("showUpdateHistory");
|
||||
let dialogOverlay = doc.getElementById("dialogOverlay");
|
||||
|
||||
// XXX: For unknown reasons, this mock cannot be loaded by
|
||||
// XPCOMUtils.defineLazyServiceGetter() called in aboutDialog-appUpdater.js.
|
||||
// It is registered here so that we could assert update history subdialog
|
||||
// without stopping the preferences advanced pane from loading.
|
||||
// See bug 1361929.
|
||||
mockUpdateManager.register();
|
||||
|
||||
// Test the dialog window opens
|
||||
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
|
||||
showBtn.doCommand();
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
class="showNormal"
|
||||
label="&privatebrowsingpage.openPrivateWindow.label;"
|
||||
accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"/>
|
||||
<div class="showPrivate about-content-container">
|
||||
<div class="showPrivate container">
|
||||
<h1 class="title">
|
||||
<span id="title">&privateBrowsing.title;</span>
|
||||
<span id="titleTracking">&privateBrowsing.title.tracking;</span>
|
||||
|
|
|
@ -46,28 +46,9 @@ const prefObserver = {
|
|||
}
|
||||
};
|
||||
|
||||
const appStartupObserver = {
|
||||
register() {
|
||||
Services.obs.addObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
|
||||
},
|
||||
|
||||
unregister() {
|
||||
Services.obs.removeObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
|
||||
},
|
||||
|
||||
observe() {
|
||||
appStartupDone();
|
||||
this.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
const APP_STARTUP = 1;
|
||||
function startup(data, reason) { // eslint-disable-line no-unused-vars
|
||||
if (reason === APP_STARTUP) {
|
||||
appStartupObserver.register();
|
||||
} else {
|
||||
appStartupDone();
|
||||
}
|
||||
appStartupDone();
|
||||
prefObserver.register();
|
||||
addonResourceURI = data.resourceURI;
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
|
|
|
@ -199,7 +199,7 @@ this.main = (function() {
|
|||
}
|
||||
|
||||
browser.tabs.onUpdated.addListener(catcher.watchFunction((id, info, tab) => {
|
||||
if (info.url && tab.active) {
|
||||
if (info.url) {
|
||||
if (urlEnabled(info.url)) {
|
||||
enableButton(tab.id);
|
||||
} else if (hasSeenOnboarding) {
|
||||
|
@ -208,20 +208,6 @@ this.main = (function() {
|
|||
}
|
||||
}, true));
|
||||
|
||||
browser.tabs.onActivated.addListener(catcher.watchFunction(({tabId, windowId}) => {
|
||||
catcher.watchPromise(browser.tabs.get(tabId).then((tab) => {
|
||||
// onActivated may fire before the url is set
|
||||
if (!tab.url) {
|
||||
return;
|
||||
}
|
||||
if (urlEnabled(tab.url)) {
|
||||
enableButton(tabId);
|
||||
} else if (hasSeenOnboarding) {
|
||||
disableButton(tabId);
|
||||
}
|
||||
}), true);
|
||||
}));
|
||||
|
||||
communication.register("sendEvent", (sender, ...args) => {
|
||||
catcher.watchPromise(sendEvent(...args));
|
||||
// We don't wait for it to complete:
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||
|
||||
<!-- LOCALIZATION NOTE (update.*):
|
||||
# These strings are also used in the update pane of preferences.
|
||||
# See about:preferences#advanced.
|
||||
-->
|
||||
<!-- LOCALIZATION NOTE (update.checkForUpdatesButton.*, update.updateButton.*):
|
||||
# Only one button is present at a time.
|
||||
# The button when displayed is located directly under the Firefox version in
|
||||
|
@ -91,7 +95,7 @@
|
|||
<!ENTITY update.unsupported.linkText "Learn more">
|
||||
<!ENTITY update.unsupported.end "">
|
||||
|
||||
<!-- LOCALIZATION NOTE (update.downloading.start,update.downloading.end): update.downloading.start and
|
||||
<!-- LOCALIZATION NOTE (update.downloading.start,update.downloading.end): update.downloading.start and
|
||||
update.downloading.end all go into one line, with the amount downloaded inserted in between. As this
|
||||
is all in one line, try to make the localized text short (see bug 596813 for screenshots). The — is
|
||||
the "em dash" (long dash).
|
||||
|
|
|
@ -81,7 +81,19 @@
|
|||
|
||||
<!ENTITY updateTab.label "Update">
|
||||
|
||||
<!-- LOCALIZATION NOTE (updateApplication.label):
|
||||
Strings from aboutDialog.dtd are displayed in this section of the preferences.
|
||||
Please check for possible accesskey conflicts.
|
||||
-->
|
||||
<!ENTITY updateApplication.label "&brandShortName; Updates">
|
||||
<!-- LOCALIZATION NOTE (updateApplication.version.*): updateApplication.version.pre
|
||||
# is followed by a version number, keep the trailing space or replace it with a
|
||||
# different character as needed. updateApplication.version.post is displayed
|
||||
# after the version number, and is empty on purpose for English. You can use it
|
||||
# if required by your language.
|
||||
-->
|
||||
<!ENTITY updateApplication.version.pre "Version ">
|
||||
<!ENTITY updateApplication.version.post "">
|
||||
<!ENTITY updateApplication.description "Allow &brandShortName; to">
|
||||
<!ENTITY updateAuto2.label "Automatically install updates (recommended for improved security)">
|
||||
<!ENTITY updateAuto2.accesskey "A">
|
||||
|
|
|
@ -568,6 +568,23 @@ description > html|a {
|
|||
}
|
||||
}
|
||||
|
||||
#updateDeck > hbox > label {
|
||||
margin-inline-end: 5px ! important;
|
||||
}
|
||||
|
||||
.update-throbber {
|
||||
width: 16px;
|
||||
min-height: 16px;
|
||||
margin-inline-end: 3px;
|
||||
list-style-image: url("chrome://global/skin/icons/loading.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.help-button {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
|
|
|
@ -176,7 +176,6 @@
|
|||
skin/classic/browser/places/bookmarks-notification-finish.png (../shared/places/bookmarks-notification-finish.png)
|
||||
skin/classic/browser/places/bookmarks-notification-finish@2x.png (../shared/places/bookmarks-notification-finish@2x.png)
|
||||
skin/classic/browser/privatebrowsing/aboutPrivateBrowsing.css (../shared/privatebrowsing/aboutPrivateBrowsing.css)
|
||||
skin/classic/browser/privatebrowsing/check.svg (../shared/privatebrowsing/check.svg)
|
||||
skin/classic/browser/privatebrowsing/favicon.svg (../shared/privatebrowsing/favicon.svg)
|
||||
skin/classic/browser/privatebrowsing/private-browsing.svg (../shared/privatebrowsing/private-browsing.svg)
|
||||
skin/classic/browser/privatebrowsing/tracking-protection-off.svg (../shared/privatebrowsing/tracking-protection-off.svg)
|
||||
|
|
|
@ -5,52 +5,26 @@
|
|||
@import url("chrome://global/skin/in-content/info-pages.css");
|
||||
|
||||
:root {
|
||||
--color-grey-lightest: #fbfbfb;
|
||||
--color-grey: #b1b1b1;
|
||||
|
||||
--color-blue: #0996f8;
|
||||
--color-blue-dark: #0670cc;
|
||||
--color-blue-darker: #005bab;
|
||||
|
||||
--icon-margin: 64px;
|
||||
}
|
||||
|
||||
html.private {
|
||||
--in-content-page-color: #beb8cc;
|
||||
--in-content-text-color: #beb8cc;
|
||||
--in-content-page-background: #1c023c;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 40px;
|
||||
--in-content-page-color: white;
|
||||
--in-content-text-color: white;
|
||||
--in-content-page-background: #25003e;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: var(--color-blue);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-blue-dark);
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover:active {
|
||||
color: var(--color-blue-darker);
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: var(--color-blue-darker);
|
||||
}
|
||||
|
||||
.about-content-container {
|
||||
max-width: 780px;
|
||||
.container {
|
||||
max-width: 48em;
|
||||
}
|
||||
|
||||
.section-main {
|
||||
margin-bottom: 48px;
|
||||
margin-inline-start: var(--icon-margin);
|
||||
padding-inline-start: 24px;
|
||||
}
|
||||
|
||||
.section-main:last-child {
|
||||
|
@ -67,8 +41,8 @@ p {
|
|||
|
||||
.list-row > ul > li {
|
||||
float: left;
|
||||
width: 220px;
|
||||
line-height: 1.5em;
|
||||
width: 16em;
|
||||
line-height: 2em;
|
||||
margin-inline-start: 1em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -79,17 +53,15 @@ p {
|
|||
|
||||
.title {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing/private-browsing.svg");
|
||||
background-size: 64px;
|
||||
background-position: left, center;
|
||||
font-weight: lighter;
|
||||
line-height: 1.5em;
|
||||
min-height: 64px;
|
||||
margin-inline-start: 0;
|
||||
padding-inline-start: calc(var(--icon-margin) + 24px);
|
||||
background-position: left center;
|
||||
background-size: 2em;
|
||||
line-height: 2em;
|
||||
margin-inline-start: calc(-2em - 10px);
|
||||
padding-inline-start: calc(2em + 10px);
|
||||
}
|
||||
|
||||
.title:dir(rtl) {
|
||||
background-position: right, center;
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.about-subheader {
|
||||
|
@ -97,12 +69,13 @@ p {
|
|||
align-items: center;
|
||||
font-size: 1.5em;
|
||||
font-weight: lighter;
|
||||
min-height: 32px;
|
||||
background-image: url("chrome://browser/skin/privatebrowsing/tracking-protection.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 32px;
|
||||
margin-inline-start: calc(var(--icon-margin) - 32px);
|
||||
padding-inline-start: 56px;
|
||||
background-position: left center;
|
||||
background-size: 1.5em;
|
||||
line-height: 1.5em;
|
||||
margin-inline-start: calc(-1.5em - 10px);
|
||||
padding-inline-start: calc(1.5em + 10px);
|
||||
}
|
||||
|
||||
.about-subheader:dir(rtl) {
|
||||
|
@ -114,23 +87,17 @@ p {
|
|||
}
|
||||
|
||||
.about-info {
|
||||
font-size: .875em;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.tpTitle {
|
||||
margin-inline-end: 12px;
|
||||
}
|
||||
|
||||
.private strong {
|
||||
color: var(--color-grey-lightest);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a.button {
|
||||
padding: 5px 40px;
|
||||
background-color: #381e59;
|
||||
border: 1px solid #43256a;
|
||||
border-radius: 4px;
|
||||
padding: 3px 20px;
|
||||
background-color: #8000d7;
|
||||
border: 1px solid #6000a1;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -155,69 +122,42 @@ a.button {
|
|||
.toggle + .toggle-btn {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
min-width: 60px;
|
||||
height: 24px;
|
||||
border-radius: 12px;
|
||||
min-width: 42px;
|
||||
height: 26px;
|
||||
border-radius: 13px;
|
||||
background-color: var(--color-grey);
|
||||
border: 1px var(--color-grey) solid;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.toggle + .toggle-btn::after,
|
||||
.toggle + .toggle-btn::before {
|
||||
position: relative;
|
||||
display: block;
|
||||
content: "";
|
||||
width: 19px;
|
||||
height: 100%;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.toggle + .toggle-btn::after {
|
||||
position: relative;
|
||||
display: block;
|
||||
content: "";
|
||||
width: 24px;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
box-shadow: 0 0 1px 1px hsla(0, 0%, 0%, .1),
|
||||
0 1px 0 hsla(0, 0%, 0%, .2);
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
transition: left .2s ease;
|
||||
}
|
||||
|
||||
.toggle + .toggle-btn::before {
|
||||
float: left;
|
||||
left: 9px;
|
||||
visibility: hidden;
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-color: transparent;
|
||||
background-image: url("chrome://browser/skin/privatebrowsing/check.svg");
|
||||
}
|
||||
|
||||
.toggle + .toggle-btn:dir(rtl)::after {
|
||||
left: auto;
|
||||
right: 0;
|
||||
transition-property: right;
|
||||
}
|
||||
|
||||
.toggle + .toggle-btn:dir(rtl)::before {
|
||||
float: right;
|
||||
left: auto;
|
||||
right: 9px;
|
||||
}
|
||||
|
||||
.toggle:checked + .toggle-btn {
|
||||
background: #3fc455;
|
||||
border: 1px solid #269939;
|
||||
background: #16da00;
|
||||
}
|
||||
|
||||
.toggle:checked + .toggle-btn::after {
|
||||
left: 35px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
.toggle:checked + .toggle-btn:dir(rtl)::after {
|
||||
right: 35px;
|
||||
}
|
||||
|
||||
.toggle:checked + .toggle-btn::before {
|
||||
visibility: visible;
|
||||
left: auto;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.toggle:-moz-focusring + .toggle-btn {
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<path fill="#fff" d="M30.057,9.752L15.9,23.909h0l-4.044,4.045-4.045-4.045h0l-6.068-6.067,4.045-4.045,6.068,6.067L26.012,5.707Z"/>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 475 B |
|
@ -175,7 +175,8 @@ function waitForSources(dbg, ...sources) {
|
|||
sources.map(url => {
|
||||
function sourceExists(state) {
|
||||
return getSources(state).some(s => {
|
||||
return s.get("url").includes(url);
|
||||
let u = s.get("url");
|
||||
return u && u.includes(url);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -212,8 +213,9 @@ function assertPausedLocation(dbg, source, line) {
|
|||
is(location.get("line"), line);
|
||||
|
||||
// Check the debug line
|
||||
let cm = dbg.win.document.querySelector(".CodeMirror").CodeMirror;
|
||||
ok(
|
||||
dbg.win.cm.lineInfo(line - 1).wrapClass.includes("debug-line"),
|
||||
cm.lineInfo(line - 1).wrapClass.includes("debug-line"),
|
||||
"Line is highlighted as paused"
|
||||
);
|
||||
}
|
||||
|
@ -356,7 +358,10 @@ function findSource(dbg, url) {
|
|||
}
|
||||
|
||||
const sources = dbg.selectors.getSources(dbg.getState());
|
||||
const source = sources.find(s => s.get("url").includes(url));
|
||||
const source = sources.find(s => {
|
||||
let u = s.get("url");
|
||||
return u && u.includes(url);
|
||||
});
|
||||
|
||||
if (!source) {
|
||||
throw new Error("Unable to find source: " + url);
|
||||
|
|
|
@ -23,6 +23,7 @@ support-files =
|
|||
browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
|
||||
browser_toolbox_options_enable_serviceworkers_testing.html
|
||||
serviceworker.js
|
||||
test_browser_toolbox_debugger.js
|
||||
|
||||
[browser_browser_toolbox.js]
|
||||
[browser_browser_toolbox_debugger.js]
|
||||
|
|
|
@ -2,10 +2,19 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This test asserts that the new debugger works from the browser toolbox process
|
||||
// Its pass a big piece of Javascript string to the browser toolbox process via
|
||||
// MOZ_TOOLBOX_TEST_SCRIPT env variable. It does that as test resources fetched from
|
||||
// chrome://mochitests/ package isn't available from browser toolbox process.
|
||||
|
||||
// On debug test runner, it takes about 50s to run the test.
|
||||
requestLongerTimeout(4);
|
||||
|
||||
const { setInterval, clearInterval } = require("sdk/timers");
|
||||
const { fetch } = require("devtools/shared/DevToolsUtils");
|
||||
|
||||
const debuggerHeadURL = CHROME_URL_ROOT + "../../debugger/new/test/mochitest/head.js";
|
||||
const testScriptURL = CHROME_URL_ROOT + "test_browser_toolbox_debugger.js";
|
||||
|
||||
add_task(function* runTest() {
|
||||
yield new Promise(done => {
|
||||
|
@ -41,73 +50,64 @@ add_task(function* runTest() {
|
|||
// which lives in another process. So do not try to use any scope variable!
|
||||
let env = Components.classes["@mozilla.org/process/environment;1"]
|
||||
.getService(Components.interfaces.nsIEnvironment);
|
||||
let testScript = function () {
|
||||
const { Task } = Components.utils.import("resource://gre/modules/Task.jsm", {});
|
||||
dump("Opening the browser toolbox and debugger panel\n");
|
||||
let window, document;
|
||||
let testUrl = "http://mozilla.org/browser-toolbox-test.js";
|
||||
Task.spawn(function* () {
|
||||
dump("Waiting for debugger load\n");
|
||||
let panel = yield toolbox.selectTool("jsdebugger");
|
||||
let window = panel.panelWin;
|
||||
let document = window.document;
|
||||
|
||||
yield window.once(window.EVENTS.SOURCE_SHOWN);
|
||||
|
||||
dump("Loaded, selecting the test script to debug\n");
|
||||
let item = document.querySelector(`.dbg-source-item[tooltiptext="${testUrl}"]`);
|
||||
let onSourceShown = window.once(window.EVENTS.SOURCE_SHOWN);
|
||||
item.click();
|
||||
yield onSourceShown;
|
||||
|
||||
dump("Selected, setting a breakpoint\n");
|
||||
let { Sources, editor } = window.DebuggerView;
|
||||
let onBreak = window.once(window.EVENTS.FETCHED_SCOPES);
|
||||
editor.emit("gutterClick", 1);
|
||||
yield onBreak;
|
||||
|
||||
dump("Paused, asserting breakpoint position\n");
|
||||
let url = Sources.selectedItem.attachment.source.url;
|
||||
if (url != testUrl) {
|
||||
throw new Error("Breaking on unexpected script: " + url);
|
||||
// First inject a very minimal head, with simplest assertion methods
|
||||
// and very common globals
|
||||
let testHead = (function () {
|
||||
const info = msg => dump(msg + "\n");
|
||||
const is = (a, b, description) => {
|
||||
let msg = "'" + JSON.stringify(a) + "' is equal to '" + JSON.stringify(b) + "'";
|
||||
if (description) {
|
||||
msg += " - " + description;
|
||||
}
|
||||
let cursor = editor.getCursor();
|
||||
if (cursor.line != 1) {
|
||||
throw new Error("Breaking on unexpected line: " + cursor.line);
|
||||
if (a !== b) {
|
||||
msg = "FAILURE: " + msg;
|
||||
dump(msg + "\n");
|
||||
throw new Error(msg);
|
||||
} else {
|
||||
msg = "SUCCESS: " + msg;
|
||||
dump(msg + "\n");
|
||||
}
|
||||
|
||||
dump("Now, stepping over\n");
|
||||
let stepOver = window.document.querySelector("#step-over");
|
||||
let onFetchedScopes = window.once(window.EVENTS.FETCHED_SCOPES);
|
||||
stepOver.click();
|
||||
yield onFetchedScopes;
|
||||
|
||||
dump("Stepped, asserting step position\n");
|
||||
url = Sources.selectedItem.attachment.source.url;
|
||||
if (url != testUrl) {
|
||||
throw new Error("Stepping on unexpected script: " + url);
|
||||
};
|
||||
const ok = (a, description) => {
|
||||
let msg = "'" + JSON.stringify(a) + "' is true";
|
||||
if (description) {
|
||||
msg += " - " + description;
|
||||
}
|
||||
cursor = editor.getCursor();
|
||||
if (cursor.line != 2) {
|
||||
throw new Error("Stepping on unexpected line: " + cursor.line);
|
||||
if (!a) {
|
||||
msg = "FAILURE: " + msg;
|
||||
dump(msg + "\n");
|
||||
throw new Error(msg);
|
||||
} else {
|
||||
msg = "SUCCESS: " + msg;
|
||||
dump(msg + "\n");
|
||||
}
|
||||
};
|
||||
const registerCleanupFunction = () => {};
|
||||
|
||||
dump("Resume script execution\n");
|
||||
let resume = window.document.querySelector("#resume");
|
||||
let onResume = toolbox.target.once("thread-resumed");
|
||||
resume.click();
|
||||
yield onResume;
|
||||
const Cu = Components.utils;
|
||||
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
}).toSource().replace(/^\(function \(\) \{|\}\)$/g, "");
|
||||
// Stringify testHead's function and remove `(function {` prefix and `})` suffix
|
||||
// to ensure inner symbols gets exposed to next pieces of code
|
||||
|
||||
dump("Close the browser toolbox\n");
|
||||
toolbox.destroy();
|
||||
// Then inject new debugger head file
|
||||
let { content } = yield fetch(debuggerHeadURL);
|
||||
let debuggerHead = content;
|
||||
// We remove its import of shared-head, which isn't available in browser toolbox process
|
||||
// And isn't needed thanks to testHead's symbols
|
||||
debuggerHead = debuggerHead.replace(/Services.scriptloader.loadSubScript[^\)]*\);/, "");
|
||||
|
||||
}).catch(error => {
|
||||
dump("Error while running code in the browser toolbox process:\n");
|
||||
dump(error + "\n");
|
||||
dump("stack:\n" + error.stack + "\n");
|
||||
});
|
||||
};
|
||||
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
|
||||
// Finally, fetch the debugger test script that is going to be execute in the browser
|
||||
// toolbox process
|
||||
let testScript = (yield fetch(testScriptURL)).content;
|
||||
let source =
|
||||
"try {" + testHead + debuggerHead + testScript + "} catch (e) {" +
|
||||
" dump('Exception: '+ e + ' at ' + e.fileName + ':' + " +
|
||||
" e.lineNumber + '\\nStack: ' + e.stack + '\\n');" +
|
||||
"}";
|
||||
env.set("MOZ_TOOLBOX_TEST_SCRIPT", source);
|
||||
registerCleanupFunction(() => {
|
||||
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
|
||||
});
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* global toolbox */
|
||||
|
||||
info(`START: ${new Error().lineNumber}`);
|
||||
|
||||
let testUrl = "http://mozilla.org/browser-toolbox-test.js";
|
||||
|
||||
Task.spawn(function* () {
|
||||
Services.prefs.clearUserPref("devtools.debugger.tabs")
|
||||
Services.prefs.clearUserPref("devtools.debugger.pending-selected-location")
|
||||
|
||||
info("Waiting for debugger load");
|
||||
yield toolbox.selectTool("jsdebugger");
|
||||
let dbg = createDebuggerContext(toolbox);
|
||||
let window = dbg.win;
|
||||
let document = window.document;
|
||||
|
||||
yield waitForSources(dbg, testUrl);
|
||||
// yield waitForSourceCount(dbg, 6);
|
||||
|
||||
info("Loaded, selecting the test script to debug");
|
||||
// First expand the domain
|
||||
let domain = [...document.querySelectorAll(".tree-node")].find(node => {
|
||||
return node.textContent == "mozilla.org";
|
||||
});
|
||||
let arrow = domain.querySelector(".arrow");
|
||||
arrow.click();
|
||||
let script = [...document.querySelectorAll(".tree-node")].find(node => {
|
||||
return node.textContent.includes("browser-toolbox-test.js");
|
||||
});
|
||||
script = script.querySelector(".node");
|
||||
script.click();
|
||||
|
||||
let onPaused = waitForPaused(dbg);
|
||||
yield addBreakpoint(dbg, "browser-toolbox-test.js", 2);
|
||||
|
||||
yield onPaused;
|
||||
|
||||
assertPausedLocation(dbg, "browser-toolbox-test.js", 2);
|
||||
|
||||
yield stepIn(dbg);
|
||||
|
||||
assertPausedLocation(dbg, "browser-toolbox-test.js", 3);
|
||||
|
||||
yield resume(dbg);
|
||||
|
||||
info("Close the browser toolbox");
|
||||
toolbox.destroy();
|
||||
});
|
|
@ -70,7 +70,7 @@ function setPrefDefaults() {
|
|||
Services.prefs.setBoolPref("devtools.scratchpad.enabled", true);
|
||||
// Bug 1225160 - Using source maps with browser debugging can lead to a crash
|
||||
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
|
||||
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
|
||||
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
|
||||
Services.prefs.setBoolPref("devtools.debugger.client-source-maps-enabled", true);
|
||||
}
|
||||
|
||||
|
@ -157,16 +157,16 @@ function bindToolboxHandlers() {
|
|||
}
|
||||
|
||||
function setupThreadListeners(panel) {
|
||||
updateBadgeText(panel._controller.activeThread.state == "paused");
|
||||
updateBadgeText(panel._selectors().getPause(panel._getState()));
|
||||
|
||||
let onPaused = updateBadgeText.bind(null, true);
|
||||
let onResumed = updateBadgeText.bind(null, false);
|
||||
panel.target.on("thread-paused", onPaused);
|
||||
panel.target.on("thread-resumed", onResumed);
|
||||
gToolbox.target.on("thread-paused", onPaused);
|
||||
gToolbox.target.on("thread-resumed", onResumed);
|
||||
|
||||
panel.once("destroyed", () => {
|
||||
panel.off("thread-paused", onPaused);
|
||||
panel.off("thread-resumed", onResumed);
|
||||
gToolbox.target.off("thread-paused", onPaused);
|
||||
gToolbox.target.off("thread-resumed", onResumed);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
|||
[browser_inspector_highlighter-cancel.js]
|
||||
[browser_inspector_highlighter-comments.js]
|
||||
[browser_inspector_highlighter-cssgrid_01.js]
|
||||
[browser_inspector_highlighter-cssgrid_02.js]
|
||||
[browser_inspector_highlighter-csstransform_01.js]
|
||||
[browser_inspector_highlighter-csstransform_02.js]
|
||||
[browser_inspector_highlighter-embed.js]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that grid layouts without items don't cause grid highlighter errors.
|
||||
|
||||
const TEST_URL = `
|
||||
<style type='text/css'>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 20px 20px;
|
||||
grid-gap: 15px;
|
||||
}
|
||||
</style>
|
||||
<div class="grid"></div>
|
||||
`;
|
||||
|
||||
const HIGHLIGHTER_TYPE = "CssGridHighlighter";
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector, testActor} = yield openInspectorForURL(
|
||||
"data:text/html;charset=utf-8," + encodeURIComponent(TEST_URL));
|
||||
let front = inspector.inspector;
|
||||
let highlighter = yield front.getHighlighterByType(HIGHLIGHTER_TYPE);
|
||||
|
||||
info("Try to show the highlighter on the grid container");
|
||||
let node = yield getNodeFront(".grid", inspector);
|
||||
yield highlighter.show(node);
|
||||
|
||||
let hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"css-grid-canvas", "hidden", highlighter);
|
||||
ok(!hidden, "The highlighter is visible");
|
||||
|
||||
info("Hiding the highlighter");
|
||||
yield highlighter.hide();
|
||||
|
||||
hidden = yield testActor.getHighlighterNodeAttribute(
|
||||
"css-grid-canvas", "hidden", highlighter);
|
||||
ok(hidden, "The highlighter is hidden");
|
||||
|
||||
yield highlighter.finalize();
|
||||
});
|
|
@ -501,7 +501,7 @@ netmonitor.toolbar.cookies=Cookies
|
|||
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||
netmonitor.toolbar.setCookies=Set-Cookies
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.cookies): This is the label displayed
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.scheme): This is the label displayed
|
||||
# in the network table toolbar, above the "scheme" column.
|
||||
netmonitor.toolbar.scheme=Scheme
|
||||
|
||||
|
|
|
@ -116,10 +116,6 @@ function processFlagFilter(type, value) {
|
|||
}
|
||||
}
|
||||
|
||||
function getSizeOrder(size) {
|
||||
return Math.round(Math.log10(size));
|
||||
}
|
||||
|
||||
function isFlagFilterMatch(item, { type, value, negative }) {
|
||||
let match = true;
|
||||
let { responseCookies = { cookies: [] } } = item;
|
||||
|
@ -160,11 +156,11 @@ function isFlagFilterMatch(item, { type, value, negative }) {
|
|||
if (item.fromCache) {
|
||||
match = false;
|
||||
} else {
|
||||
match = getSizeOrder(value) === getSizeOrder(item.transferredSize);
|
||||
match = isSizeMatch(value, item.transferredSize);
|
||||
}
|
||||
break;
|
||||
case "size":
|
||||
match = getSizeOrder(value) === getSizeOrder(item.contentSize);
|
||||
match = isSizeMatch(value, item.contentSize);
|
||||
break;
|
||||
case "larger-than":
|
||||
match = item.contentSize > value;
|
||||
|
@ -216,6 +212,10 @@ function isFlagFilterMatch(item, { type, value, negative }) {
|
|||
return match;
|
||||
}
|
||||
|
||||
function isSizeMatch(value, size) {
|
||||
return value >= (size - size / 10) && value < (size + size / 10);
|
||||
}
|
||||
|
||||
function isTextFilterMatch({ url }, text) {
|
||||
let lowerCaseUrl = url.toLowerCase();
|
||||
let lowerCaseText = text.toLowerCase();
|
||||
|
|
|
@ -695,6 +695,18 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
return this.currentNode.getGridFragments().length > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Is a given grid fragment valid? i.e. does it actually have tracks? In some cases, we
|
||||
* may have a fragment that defines column tracks but doesn't have any rows (or vice
|
||||
* versa). In which case we do not want to draw anything for that fragment.
|
||||
*
|
||||
* @param {Object} fragment
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isValidFragment(fragment) {
|
||||
return fragment.cols.tracks.length && fragment.rows.tracks.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* The AutoRefreshHighlighter's _hasMoved method returns true only if the
|
||||
* element's quads have changed. Override it so it also returns true if the
|
||||
|
@ -740,8 +752,7 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
|
||||
// Start drawing the grid fragments.
|
||||
for (let i = 0; i < this.gridData.length; i++) {
|
||||
let fragment = this.gridData[i];
|
||||
this.renderFragment(fragment);
|
||||
this.renderFragment(this.gridData[i]);
|
||||
}
|
||||
|
||||
// Display the grid area highlights if needed.
|
||||
|
@ -1030,6 +1041,10 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
},
|
||||
|
||||
renderFragment(fragment) {
|
||||
if (!this.isValidFragment(fragment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderLines(fragment.cols, COLUMNS, "left", "top", "height",
|
||||
this.getFirstRowLinePos(fragment),
|
||||
this.getLastRowLinePos(fragment));
|
||||
|
|
|
@ -201,7 +201,7 @@ contextEmptyReply=Command prefix is unset
|
|||
|
||||
# LOCALIZATION NOTE (connectDesc, connectManual, connectPrefixDesc,
|
||||
# connectMethodDesc, connectUrlDesc, connectDupReply): These strings describe
|
||||
# the 'connect' command and all its available parameters. A 'prefix' is an
|
||||
# the 'connect' command and all its available parameters. A 'prefix' is an
|
||||
# alias for the remote server (think of it as a "connection name"), and it
|
||||
# allows to identify a specific server when connected to multiple remote
|
||||
# servers.
|
||||
|
@ -230,20 +230,9 @@ disconnectPrefixDesc=Parent prefix for imported commands
|
|||
# commands removed.
|
||||
disconnectReply=Removed %S commands.
|
||||
|
||||
# LOCALIZATION NOTE (globalDesc, globalWindowDesc, globalOutput): These
|
||||
# strings describe the 'global' command and its parameters
|
||||
globalDesc=Change the JS global
|
||||
globalWindowDesc=The new window/global
|
||||
globalOutput=JS global is now %S
|
||||
|
||||
# LOCALIZATION NOTE: These strings describe the 'clear' command
|
||||
clearDesc=Clear the output area
|
||||
|
||||
# LOCALIZATION NOTE (langDesc, langOutput): These strings describe the 'lang'
|
||||
# command and its parameters
|
||||
langDesc=Enter commands in different languages
|
||||
langOutput=You are now using %S
|
||||
|
||||
# LOCALIZATION NOTE (prefDesc, prefManual, prefListDesc, prefListManual,
|
||||
# prefListSearchDesc, prefListSearchManual, prefShowDesc, prefShowManual,
|
||||
# prefShowSettingDesc, prefShowSettingManual): These strings describe the
|
||||
|
@ -292,12 +281,6 @@ prefOutputFilter=Filter
|
|||
prefOutputName=Name
|
||||
prefOutputValue=Value
|
||||
|
||||
# LOCALIZATION NOTE (introDesc, introManual): These strings describe the
|
||||
# 'intro' command. The localization of 'Got it!' should be the same used in
|
||||
# introTextGo.
|
||||
introDesc=Show the opening message
|
||||
introManual=Redisplay the message that is shown to new users until they click the ‘Got it!’ button
|
||||
|
||||
# LOCALIZATION NOTE (introTextOpening3, introTextCommands, introTextKeys2,
|
||||
# introTextF1Escape, introTextGo): These strings are displayed when the user
|
||||
# first opens the developer toolbar to explain the command line, and is shown
|
||||
|
|
|
@ -21,6 +21,7 @@ interface nsIDocShellTreeItem;
|
|||
interface nsIStructuredCloneContainer;
|
||||
interface nsIBFCacheEntry;
|
||||
interface nsIPrincipal;
|
||||
interface nsISHistory;
|
||||
|
||||
%{C++
|
||||
#include "nsRect.h"
|
||||
|
@ -326,6 +327,11 @@ interface nsISHEntry : nsISupports
|
|||
* if true == "manual", false == "auto".
|
||||
*/
|
||||
attribute boolean scrollRestorationIsManual;
|
||||
|
||||
/**
|
||||
* Set the session history it belongs to. It's only set on root entries.
|
||||
*/
|
||||
[noscript] void setSHistory(in nsISHistory aSHistory);
|
||||
};
|
||||
|
||||
[scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]
|
||||
|
|
|
@ -96,6 +96,16 @@ interface nsISHistoryInternal: nsISupports
|
|||
*/
|
||||
void evictAllContentViewers();
|
||||
|
||||
/**
|
||||
* Add a BFCache entry to expiration tracker so it gets evicted on expiration.
|
||||
*/
|
||||
void addToExpirationTracker(in nsIBFCacheEntry aEntry);
|
||||
|
||||
/**
|
||||
* Remove a BFCache entry from expiration tracker.
|
||||
*/
|
||||
void removeFromExpirationTracker(in nsIBFCacheEntry aEntry);
|
||||
|
||||
/**
|
||||
* Remove dynamic entries found at given index.
|
||||
*
|
||||
|
|
|
@ -5,17 +5,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsSHEntry.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocShellLoadInfo.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsSHEntryShared.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIStructuredCloneContainer.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsIStructuredCloneContainer.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsSHEntryShared.h"
|
||||
#include "nsSHistory.h"
|
||||
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace dom = mozilla::dom;
|
||||
|
||||
|
@ -23,13 +27,13 @@ static uint32_t gEntryID = 0;
|
|||
|
||||
nsSHEntry::nsSHEntry()
|
||||
: mShared(new nsSHEntryShared())
|
||||
, mLoadReplace(false)
|
||||
, mReferrerPolicy(mozilla::net::RP_Unset)
|
||||
, mLoadType(0)
|
||||
, mID(gEntryID++)
|
||||
, mScrollPositionX(0)
|
||||
, mScrollPositionY(0)
|
||||
, mParent(nullptr)
|
||||
, mLoadReplace(false)
|
||||
, mURIWasModified(false)
|
||||
, mIsSrcdocEntry(false)
|
||||
, mScrollRestorationIsManual(false)
|
||||
|
@ -40,7 +44,6 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
|
|||
: mShared(aOther.mShared)
|
||||
, mURI(aOther.mURI)
|
||||
, mOriginalURI(aOther.mOriginalURI)
|
||||
, mLoadReplace(aOther.mLoadReplace)
|
||||
, mReferrerURI(aOther.mReferrerURI)
|
||||
, mReferrerPolicy(aOther.mReferrerPolicy)
|
||||
, mTitle(aOther.mTitle)
|
||||
|
@ -50,12 +53,13 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
|
|||
, mScrollPositionX(0) // XXX why not copy?
|
||||
, mScrollPositionY(0) // XXX why not copy?
|
||||
, mParent(aOther.mParent)
|
||||
, mURIWasModified(aOther.mURIWasModified)
|
||||
, mStateData(aOther.mStateData)
|
||||
, mIsSrcdocEntry(aOther.mIsSrcdocEntry)
|
||||
, mScrollRestorationIsManual(false)
|
||||
, mSrcdocData(aOther.mSrcdocData)
|
||||
, mBaseURI(aOther.mBaseURI)
|
||||
, mLoadReplace(aOther.mLoadReplace)
|
||||
, mURIWasModified(aOther.mURIWasModified)
|
||||
, mIsSrcdocEntry(aOther.mIsSrcdocEntry)
|
||||
, mScrollRestorationIsManual(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -958,3 +962,10 @@ nsSHEntry::SetLastTouched(uint32_t aLastTouched)
|
|||
mShared->mLastTouched = aLastTouched;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHEntry::SetSHistory(nsISHistory* aSHistory)
|
||||
{
|
||||
mShared->mSHistory = do_GetWeakReference(aSHistory);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,13 @@
|
|||
#ifndef nsSHEntry_h
|
||||
#define nsSHEntry_h
|
||||
|
||||
// Helper Classes
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// Interfaces needed
|
||||
#include "nsISHEntry.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISHContainer.h"
|
||||
#include "nsISHEntry.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsSHEntryShared;
|
||||
class nsIInputStream;
|
||||
|
@ -49,7 +47,6 @@ private:
|
|||
// See nsSHEntry.idl for comments on these members.
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
bool mLoadReplace;
|
||||
nsCOMPtr<nsIURI> mReferrerURI;
|
||||
uint32_t mReferrerPolicy;
|
||||
nsString mTitle;
|
||||
|
@ -60,12 +57,13 @@ private:
|
|||
int32_t mScrollPositionY;
|
||||
nsISHEntry* mParent;
|
||||
nsCOMArray<nsISHEntry> mChildren;
|
||||
bool mURIWasModified;
|
||||
nsCOMPtr<nsIStructuredCloneContainer> mStateData;
|
||||
bool mIsSrcdocEntry;
|
||||
bool mScrollRestorationIsManual;
|
||||
nsString mSrcdocData;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
bool mLoadReplace;
|
||||
bool mURIWasModified;
|
||||
bool mIsSrcdocEntry;
|
||||
bool mScrollRestorationIsManual;
|
||||
};
|
||||
|
||||
#endif /* nsSHEntry_h */
|
||||
|
|
|
@ -6,20 +6,21 @@
|
|||
|
||||
#include "nsSHEntryShared.h"
|
||||
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHistoryInternal.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsArray.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHistoryInternal.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsArray.h"
|
||||
|
||||
namespace dom = mozilla::dom;
|
||||
|
||||
|
@ -29,78 +30,27 @@ uint64_t gSHEntrySharedID = 0;
|
|||
|
||||
} // namespace
|
||||
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS "browser.sessionhistory.contentViewerTimeout"
|
||||
// Default this to time out unused content viewers after 30 minutes
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT (30 * 60)
|
||||
|
||||
typedef nsExpirationTracker<nsSHEntryShared, 3> HistoryTrackerBase;
|
||||
class HistoryTracker final : public HistoryTrackerBase
|
||||
{
|
||||
public:
|
||||
explicit HistoryTracker(uint32_t aTimeout)
|
||||
: HistoryTrackerBase(1000 * aTimeout / 2, "HistoryTracker")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void NotifyExpired(nsSHEntryShared* aObj)
|
||||
{
|
||||
RemoveObject(aObj);
|
||||
aObj->Expire();
|
||||
}
|
||||
};
|
||||
|
||||
static HistoryTracker* gHistoryTracker = nullptr;
|
||||
|
||||
void
|
||||
nsSHEntryShared::EnsureHistoryTracker()
|
||||
{
|
||||
if (!gHistoryTracker) {
|
||||
// nsExpirationTracker doesn't allow one to change the timer period,
|
||||
// so just set it once when the history tracker is used for the first time.
|
||||
gHistoryTracker = new HistoryTracker(
|
||||
mozilla::Preferences::GetUint(CONTENT_VIEWER_TIMEOUT_SECONDS,
|
||||
CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::Shutdown()
|
||||
{
|
||||
delete gHistoryTracker;
|
||||
gHistoryTracker = nullptr;
|
||||
}
|
||||
|
||||
nsSHEntryShared::nsSHEntryShared()
|
||||
: mDocShellID({0})
|
||||
, mLastTouched(0)
|
||||
, mID(gSHEntrySharedID++)
|
||||
, mViewerBounds(0, 0, 0, 0)
|
||||
, mIsFrameNavigation(false)
|
||||
, mSaveLayoutState(true)
|
||||
, mSticky(true)
|
||||
, mDynamicallyCreated(false)
|
||||
, mLastTouched(0)
|
||||
, mID(gSHEntrySharedID++)
|
||||
, mExpired(false)
|
||||
, mViewerBounds(0, 0, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
nsSHEntryShared::~nsSHEntryShared()
|
||||
{
|
||||
RemoveFromExpirationTracker();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gHistoryTracker) {
|
||||
// Check that we're not still on track to expire. We shouldn't be, because
|
||||
// we just removed ourselves!
|
||||
nsExpirationTracker<nsSHEntryShared, 3>::Iterator iterator(gHistoryTracker);
|
||||
|
||||
nsSHEntryShared* elem;
|
||||
while ((elem = iterator.Next()) != nullptr) {
|
||||
NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mContentViewer) {
|
||||
RemoveFromBFCacheSync();
|
||||
}
|
||||
|
@ -131,8 +81,9 @@ nsSHEntryShared::Duplicate(nsSHEntryShared* aEntry)
|
|||
void
|
||||
nsSHEntryShared::RemoveFromExpirationTracker()
|
||||
{
|
||||
if (gHistoryTracker && GetExpirationState()->IsTracked()) {
|
||||
gHistoryTracker->RemoveObject(this);
|
||||
nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(mSHistory);
|
||||
if (shistory && GetExpirationState()->IsTracked()) {
|
||||
shistory->RemoveFromExpirationTracker(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,34 +124,6 @@ nsSHEntryShared::DropPresentationState()
|
|||
mEditorData = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::Expire()
|
||||
{
|
||||
// This entry has timed out. If we still have a content viewer, we need to
|
||||
// evict it.
|
||||
if (!mContentViewer) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocShell> container;
|
||||
mContentViewer->GetContainer(getter_AddRefs(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
|
||||
if (!treeItem) {
|
||||
return;
|
||||
}
|
||||
// We need to find the root DocShell since only that object has an
|
||||
// SHistory and we need the SHistory to evict content viewers
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
|
||||
nsCOMPtr<nsISHistory> history;
|
||||
webNav->GetSessionHistory(getter_AddRefs(history));
|
||||
nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
|
||||
if (!historyInt) {
|
||||
return;
|
||||
}
|
||||
historyInt->EvictExpiredContentViewerForEntry(this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSHEntryShared::SetContentViewer(nsIContentViewer* aViewer)
|
||||
{
|
||||
|
@ -214,8 +137,13 @@ nsSHEntryShared::SetContentViewer(nsIContentViewer* aViewer)
|
|||
mContentViewer = aViewer;
|
||||
|
||||
if (mContentViewer) {
|
||||
EnsureHistoryTracker();
|
||||
gHistoryTracker->AddObject(this);
|
||||
// mSHistory is only set for root entries, but in general bfcache only
|
||||
// applies to root entries as well. BFCache for subframe navigation has been
|
||||
// disabled since 2005 in bug 304860.
|
||||
nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(mSHistory);
|
||||
if (shistory) {
|
||||
shistory->AddToExpirationTracker(this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
|
||||
|
|
|
@ -7,14 +7,16 @@
|
|||
#ifndef nsSHEntryShared_h__
|
||||
#define nsSHEntryShared_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsIBFCacheEntry.h"
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWeakPtr.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsSHEntry;
|
||||
|
@ -53,12 +55,9 @@ private:
|
|||
|
||||
friend class nsSHEntry;
|
||||
|
||||
friend class HistoryTracker;
|
||||
|
||||
static already_AddRefed<nsSHEntryShared> Duplicate(nsSHEntryShared* aEntry);
|
||||
|
||||
void RemoveFromExpirationTracker();
|
||||
void Expire();
|
||||
nsresult SyncPresentationState();
|
||||
void DropPresentationState();
|
||||
|
||||
|
@ -73,10 +72,7 @@ private:
|
|||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
|
||||
nsCString mContentType;
|
||||
bool mIsFrameNavigation;
|
||||
bool mSaveLayoutState;
|
||||
bool mSticky;
|
||||
bool mDynamicallyCreated;
|
||||
|
||||
nsCOMPtr<nsISupports> mCacheKey;
|
||||
uint32_t mLastTouched;
|
||||
|
||||
|
@ -86,12 +82,20 @@ private:
|
|||
nsCOMPtr<nsIContentViewer> mContentViewer;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
|
||||
bool mExpired;
|
||||
nsCOMPtr<nsISupports> mWindowState;
|
||||
nsIntRect mViewerBounds;
|
||||
nsCOMPtr<nsIMutableArray> mRefreshURIList;
|
||||
nsExpirationState mExpirationState;
|
||||
nsAutoPtr<nsDocShellEditorData> mEditorData;
|
||||
nsWeakPtr mSHistory;
|
||||
|
||||
bool mIsFrameNavigation;
|
||||
bool mSaveLayoutState;
|
||||
bool mSticky;
|
||||
bool mDynamicallyCreated;
|
||||
|
||||
// This flag is about necko cache, not bfcache.
|
||||
bool mExpired;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#include "nsISHEntry.h"
|
||||
|
||||
nsSHTransaction::nsSHTransaction()
|
||||
: mPersist(true)
|
||||
, mPrev(nullptr)
|
||||
: mPrev(nullptr)
|
||||
, mPersist(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
#ifndef nsSHTransaction_h
|
||||
#define nsSHTransaction_h
|
||||
|
||||
// Helper Classes
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// Needed interfaces
|
||||
#include "nsISHTransaction.h"
|
||||
|
||||
class nsISHEntry;
|
||||
|
@ -27,11 +24,10 @@ protected:
|
|||
virtual ~nsSHTransaction();
|
||||
|
||||
protected:
|
||||
bool mPersist;
|
||||
|
||||
nsISHTransaction* mPrev; // Weak Reference
|
||||
nsCOMPtr<nsISHTransaction> mNext;
|
||||
nsCOMPtr<nsISHEntry> mSHEntry;
|
||||
bool mPersist;
|
||||
};
|
||||
|
||||
#endif /* nsSHTransaction_h */
|
||||
|
|
|
@ -5,41 +5,43 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsSHistory.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Helper Classes
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
// Interfaces Needed
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellLoadInfo.h"
|
||||
#include "nsISHContainer.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsISHContainer.h"
|
||||
#include "nsISHEntry.h"
|
||||
#include "nsISHistoryListener.h"
|
||||
#include "nsISHTransaction.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "prsystem.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsISHEntry.h"
|
||||
#include "nsISHTransaction.h"
|
||||
#include "nsISHistoryListener.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
// For calculating max history entries and max cachable contentviewers
|
||||
#include "prsystem.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
|
||||
#define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS "browser.sessionhistory.contentViewerTimeout"
|
||||
|
||||
// Default this to time out unused content viewers after 30 minutes
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT (30 * 60)
|
||||
|
||||
static const char* kObservedPrefs[] = {
|
||||
PREF_SHISTORY_SIZE,
|
||||
|
@ -233,10 +235,10 @@ nsSHistory::nsSHistory()
|
|||
: mIndex(-1)
|
||||
, mLength(0)
|
||||
, mRequestedIndex(-1)
|
||||
, mIsPartial(false)
|
||||
, mGlobalIndexOffset(0)
|
||||
, mEntriesInFollowingPartialHistories(0)
|
||||
, mRootDocShell(nullptr)
|
||||
, mIsPartial(false)
|
||||
{
|
||||
// Add this new SHistory object to the list
|
||||
gSHistoryList.insertBack(this);
|
||||
|
@ -254,6 +256,7 @@ NS_INTERFACE_MAP_BEGIN(nsSHistory)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISHistory)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISHistoryInternal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// static
|
||||
|
@ -382,6 +385,8 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist)
|
|||
{
|
||||
NS_ENSURE_ARG(aSHEntry);
|
||||
|
||||
aSHEntry->SetSHistory(this);
|
||||
|
||||
// If we have a root docshell, update the docshell id of the root shentry to
|
||||
// match the id of that docshell
|
||||
if (mRootDocShell) {
|
||||
|
@ -1299,6 +1304,30 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aEntry)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aEntry)
|
||||
{
|
||||
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
|
||||
if (!mHistoryTracker || !entry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mHistoryTracker->AddObject(entry);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::RemoveFromExpirationTracker(nsIBFCacheEntry* aEntry)
|
||||
{
|
||||
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
|
||||
if (!mHistoryTracker || !entry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mHistoryTracker->RemoveObject(entry);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Evicts all content viewers in all history objects. This is very
|
||||
// inefficient, because it requires a linear search through all SHistory
|
||||
// objects for each viewer to be evicted. However, this method is called
|
||||
|
@ -1899,6 +1928,23 @@ NS_IMETHODIMP
|
|||
nsSHistory::SetRootDocShell(nsIDocShell* aDocShell)
|
||||
{
|
||||
mRootDocShell = aDocShell;
|
||||
|
||||
// Init mHistoryTracker on setting mRootDocShell so we can bind its event
|
||||
// target to the tabGroup.
|
||||
if (mRootDocShell) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = mRootDocShell->GetWindow();
|
||||
if (!win) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
|
||||
mHistoryTracker = mozilla::MakeUnique<HistoryTracker>(
|
||||
this,
|
||||
mozilla::Preferences::GetUint(CONTENT_VIEWER_TIMEOUT_SECONDS,
|
||||
CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT),
|
||||
tabGroup->EventTargetFor(mozilla::TaskCategory::Other));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,18 @@
|
|||
#define nsSHistory_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsIPartialSHistoryListener.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHistoryInternal.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsSHEntryShared.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsIPartialSHistoryListener.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
class nsIDocShell;
|
||||
class nsSHEnumerator;
|
||||
|
@ -27,9 +30,37 @@ class nsISHTransaction;
|
|||
class nsSHistory final : public mozilla::LinkedListElement<nsSHistory>,
|
||||
public nsISHistory,
|
||||
public nsISHistoryInternal,
|
||||
public nsIWebNavigation
|
||||
public nsIWebNavigation,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
|
||||
// The timer based history tracker is used to evict bfcache on expiration.
|
||||
class HistoryTracker final : public nsExpirationTracker<nsSHEntryShared, 3>
|
||||
{
|
||||
public:
|
||||
explicit HistoryTracker(nsSHistory* aSHistory,
|
||||
uint32_t aTimeout,
|
||||
nsIEventTarget* aEventTarget)
|
||||
: nsExpirationTracker(1000 * aTimeout / 2, "HistoryTracker", aEventTarget)
|
||||
{
|
||||
MOZ_ASSERT(aSHistory);
|
||||
mSHistory = aSHistory;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void NotifyExpired(nsSHEntryShared* aObj)
|
||||
{
|
||||
RemoveObject(aObj);
|
||||
mSHistory->EvictExpiredContentViewerForEntry(aObj);
|
||||
}
|
||||
|
||||
private:
|
||||
// HistoryTracker is owned by nsSHistory; it always outlives HistoryTracker
|
||||
// so it's safe to use raw pointer here.
|
||||
nsSHistory* mSHistory;
|
||||
};
|
||||
|
||||
nsSHistory();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISHISTORY
|
||||
|
@ -85,14 +116,14 @@ private:
|
|||
// otherwise comparison is done to aIndex - 1.
|
||||
bool RemoveDuplicate(int32_t aIndex, bool aKeepNext);
|
||||
|
||||
// Track all bfcache entries and evict on expiration.
|
||||
mozilla::UniquePtr<HistoryTracker> mHistoryTracker;
|
||||
|
||||
nsCOMPtr<nsISHTransaction> mListRoot;
|
||||
int32_t mIndex;
|
||||
int32_t mLength;
|
||||
int32_t mRequestedIndex;
|
||||
|
||||
// Set to true if attached to a grouped session history.
|
||||
bool mIsPartial;
|
||||
|
||||
// The number of entries before this session history object.
|
||||
int32_t mGlobalIndexOffset;
|
||||
|
||||
|
@ -108,6 +139,9 @@ private:
|
|||
// Weak reference. Do not refcount this.
|
||||
nsIDocShell* mRootDocShell;
|
||||
|
||||
// Set to true if attached to a grouped session history.
|
||||
bool mIsPartial;
|
||||
|
||||
// Max viewers allowed total, across all SHistory objects
|
||||
static int32_t sHistoryMaxTotalViewers;
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ support-files =
|
|||
|
||||
[browser_bug1206879.js]
|
||||
[browser_bug1309900_crossProcessHistoryNavigation.js]
|
||||
[browser_bug1347823.js]
|
||||
[browser_bug134911.js]
|
||||
[browser_bug234628-1.js]
|
||||
[browser_bug234628-10.js]
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Test that session history's expiration tracker would remove bfcache on
|
||||
* expiration.
|
||||
*/
|
||||
|
||||
// With bfcache not expired.
|
||||
add_task(async function testValidCache() {
|
||||
// Make an unrealistic large timeout.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.sessionhistory.contentViewerTimeout", 86400]]
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{gBrowser, url: "data:text/html;charset=utf-8,page1"},
|
||||
async function(browser) {
|
||||
// Make a simple modification for bfcache testing.
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.document.body.textContent = "modified";
|
||||
});
|
||||
|
||||
// Load a random page.
|
||||
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,page2");
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// Go back and verify text content.
|
||||
let awaitPageShow = BrowserTestUtils.waitForContentEvent(browser, "pageshow");
|
||||
browser.goBack();
|
||||
await awaitPageShow;
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
is(content.document.body.textContent, "modified");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// With bfcache expired.
|
||||
add_task(async function testExpiredCache() {
|
||||
// Make bfcache timeout in 1 sec.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.sessionhistory.contentViewerTimeout", 1]]
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{gBrowser, url: "data:text/html;charset=utf-8,page1"},
|
||||
async function(browser) {
|
||||
// Make a simple modification for bfcache testing.
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.document.body.textContent = "modified";
|
||||
});
|
||||
|
||||
// Load a random page.
|
||||
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,page2");
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// Wait for 3 times of expiration timeout, hopefully it's evicted...
|
||||
await new Promise(resolve => {
|
||||
setTimeout(resolve, 3000);
|
||||
});
|
||||
|
||||
// Go back and verify text content.
|
||||
let awaitPageShow = BrowserTestUtils.waitForContentEvent(browser, "pageshow");
|
||||
browser.goBack();
|
||||
await awaitPageShow;
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
is(content.document.body.textContent, "page1");
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2690,10 +2690,12 @@ nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
|
|||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = element->GetComposedDoc()->GetShell();
|
||||
RefPtr<nsStyleContext> styleContext = shell
|
||||
? nsComputedDOMStyle::GetStyleContext(element, nullptr, shell)
|
||||
: nullptr;
|
||||
RefPtr<nsStyleContext> styleContext;
|
||||
nsIDocument* doc = element->GetComposedDoc();
|
||||
if (doc && doc->GetShell()) {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContext(element, nullptr, doc->GetShell());
|
||||
}
|
||||
*aResult = v1.ComputeDistance(property, v2, styleContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ CaptureStreamTestHelper.prototype = {
|
|||
*/
|
||||
isOpaquePixelNot: function(px, refColor, threshold) {
|
||||
px[3] = refColor.data[3];
|
||||
return h.isPixelNot(px, refColor, threshold);
|
||||
return this.isPixelNot(px, refColor, threshold);
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
|
@ -45,8 +45,8 @@ GamepadEventChannelParent::GamepadEventChannelParent()
|
|||
RefPtr<GamepadPlatformService> service =
|
||||
GamepadPlatformService::GetParentService();
|
||||
MOZ_ASSERT(service);
|
||||
service->AddChannelParent(this);
|
||||
mBackgroundThread = NS_GetCurrentThread();
|
||||
service->AddChannelParent(this);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
|
|
@ -5249,6 +5249,10 @@ void HTMLMediaElement::DecodeError(const MediaResult& aError)
|
|||
AudioTracks()->EmptyTracks();
|
||||
VideoTracks()->EmptyTracks();
|
||||
if (mIsLoadingFromSourceChildren) {
|
||||
if (mDecoder) {
|
||||
// Shut down the exiting decoder before loading the next source child.
|
||||
ShutdownDecoder();
|
||||
}
|
||||
mErrorSink->ResetError();
|
||||
if (mSourceLoadCandidate) {
|
||||
DispatchAsyncSourceError(mSourceLoadCandidate);
|
||||
|
|
|
@ -2658,20 +2658,14 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
INIT_CANONICAL(mCurrentPosition, TimeUnit::Zero()),
|
||||
INIT_CANONICAL(mPlaybackOffset, 0),
|
||||
INIT_CANONICAL(mIsAudioDataAudible, false)
|
||||
#ifdef XP_WIN
|
||||
, mShouldUseHiResTimers(Preferences::GetBool("media.hi-res-timers.enabled", true))
|
||||
#endif
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
InitVideoQueuePrefs();
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Ensure high precision timers are enabled on Windows, otherwise the state
|
||||
// machine isn't woken up at reliable intervals to set the next frame, and we
|
||||
// drop frames while painting. Note that multiple calls to this function
|
||||
// per-process is OK, provided each call is matched by a corresponding
|
||||
// timeEndPeriod() call.
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef INIT_WATCHABLE
|
||||
|
@ -2684,7 +2678,7 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
|||
MOZ_COUNT_DTOR(MediaDecoderStateMachine);
|
||||
|
||||
#ifdef XP_WIN
|
||||
timeEndPeriod(1);
|
||||
MOZ_ASSERT(!mHiResTimersRequested);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2895,6 +2889,12 @@ MediaDecoderStateMachine::StopPlayback()
|
|||
if (IsPlaying()) {
|
||||
mMediaSink->SetPlaying(false);
|
||||
MOZ_ASSERT(!IsPlaying());
|
||||
#ifdef XP_WIN
|
||||
if (mHiResTimersRequested) {
|
||||
mHiResTimersRequested = false;
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2918,6 +2918,20 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
|
|||
mOnPlaybackEvent.Notify(MediaEventType::PlaybackStarted);
|
||||
StartMediaSink();
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (!mHiResTimersRequested && mShouldUseHiResTimers) {
|
||||
mHiResTimersRequested = true;
|
||||
// Ensure high precision timers are enabled on Windows, otherwise the state
|
||||
// machine isn't woken up at reliable intervals to set the next frame, and we
|
||||
// drop frames while painting. Note that each call must be matched by a
|
||||
// corresponding timeEndPeriod() call. Enabling high precision timers causes
|
||||
// the CPU to wake up more frequently on Windows 7 and earlier, which causes
|
||||
// more CPU load and battery use. So we only enable high precision timers
|
||||
// when we're actually playing.
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!IsPlaying()) {
|
||||
mMediaSink->SetPlaying(true);
|
||||
MOZ_ASSERT(IsPlaying());
|
||||
|
|
|
@ -779,6 +779,17 @@ public:
|
|||
{
|
||||
return &mIsAudioDataAudible;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Whether we've called timeBeginPeriod(1) to request high resolution
|
||||
// timers. We request high resolution timers when playback starts, and
|
||||
// turn them off when playback is paused. Enabling high resolution
|
||||
// timers can cause higher CPU usage and battery drain on Windows 7.
|
||||
bool mHiResTimersRequested = false;
|
||||
// Whether we should enable high resolution timers. This is initialized at
|
||||
// MDSM construction, and mirrors the value of media.hi-res-timers.enabled.
|
||||
const bool mShouldUseHiResTimers;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -242,6 +242,17 @@ public:
|
|||
return bytes.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaByteBuffer> CachedReadAt(int64_t aOffset, uint32_t aCount)
|
||||
{
|
||||
RefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
|
||||
bool ok = bytes->SetLength(aCount, fallible);
|
||||
NS_ENSURE_TRUE(ok, nullptr);
|
||||
char* curr = reinterpret_cast<char*>(bytes->Elements());
|
||||
nsresult rv = ReadFromCache(curr, aOffset, aCount);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return bytes.forget();
|
||||
}
|
||||
|
||||
// Report the current offset in bytes from the start of the stream.
|
||||
// This is used to approximate where we currently are in the playback of a
|
||||
// media.
|
||||
|
|
|
@ -725,7 +725,7 @@ GMPParent::ReadChromiumManifestFile(nsIFile* aFile)
|
|||
}
|
||||
|
||||
// DOM JSON parsing needs to run on the main thread.
|
||||
return InvokeAsync<nsString&&>(
|
||||
return InvokeAsync(
|
||||
mMainThread, this, __func__,
|
||||
&GMPParent::ParseChromiumManifest, NS_ConvertUTF8toUTF16(json));
|
||||
}
|
||||
|
|
|
@ -642,7 +642,7 @@ GeckoMediaPluginServiceParent::AsyncAddPluginDirectory(const nsAString& aDirecto
|
|||
|
||||
nsString dir(aDirectory);
|
||||
RefPtr<GeckoMediaPluginServiceParent> self = this;
|
||||
return InvokeAsync<nsString&&>(
|
||||
return InvokeAsync(
|
||||
thread, this, __func__,
|
||||
&GeckoMediaPluginServiceParent::AddOnGMPThread, dir)
|
||||
->Then(
|
||||
|
|
|
@ -417,7 +417,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
}
|
||||
StartUpdating();
|
||||
|
||||
mTrackBuffersManager->AppendData(data, mCurrentAttributes)
|
||||
mTrackBuffersManager->AppendData(data.forget(), mCurrentAttributes)
|
||||
->Then(mAbstractMainThread, __func__, this,
|
||||
&SourceBuffer::AppendDataCompletedWithSuccess,
|
||||
&SourceBuffer::AppendDataErrored)
|
||||
|
|
|
@ -47,7 +47,7 @@ protected:
|
|||
|
||||
class AppendBufferTask : public SourceBufferTask {
|
||||
public:
|
||||
AppendBufferTask(MediaByteBuffer* aData,
|
||||
AppendBufferTask(already_AddRefed<MediaByteBuffer> aData,
|
||||
const SourceBufferAttributes& aAttributes)
|
||||
: mBuffer(aData)
|
||||
, mAttributes(aAttributes)
|
||||
|
|
|
@ -116,24 +116,24 @@ TrackBuffersManager::~TrackBuffersManager()
|
|||
}
|
||||
|
||||
RefPtr<TrackBuffersManager::AppendPromise>
|
||||
TrackBuffersManager::AppendData(MediaByteBuffer* aData,
|
||||
TrackBuffersManager::AppendData(already_AddRefed<MediaByteBuffer> aData,
|
||||
const SourceBufferAttributes& aAttributes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("Appending %" PRIuSIZE " bytes", aData->Length());
|
||||
RefPtr<MediaByteBuffer> data(aData);
|
||||
MSE_DEBUG("Appending %" PRIuSIZE " bytes", data->Length());
|
||||
|
||||
mEnded = false;
|
||||
|
||||
return InvokeAsync<RefPtr<MediaByteBuffer>, SourceBufferAttributes&&>(
|
||||
GetTaskQueue(), this, __func__,
|
||||
&TrackBuffersManager::DoAppendData, aData, aAttributes);
|
||||
return InvokeAsync(GetTaskQueue(), this, __func__,
|
||||
&TrackBuffersManager::DoAppendData, data.forget(), aAttributes);
|
||||
}
|
||||
|
||||
RefPtr<TrackBuffersManager::AppendPromise>
|
||||
TrackBuffersManager::DoAppendData(MediaByteBuffer* aData,
|
||||
TrackBuffersManager::DoAppendData(already_AddRefed<MediaByteBuffer> aData,
|
||||
const SourceBufferAttributes& aAttributes)
|
||||
{
|
||||
RefPtr<AppendBufferTask> task = new AppendBufferTask(aData, aAttributes);
|
||||
RefPtr<AppendBufferTask> task = new AppendBufferTask(Move(aData), aAttributes);
|
||||
RefPtr<AppendPromise> p = task->mPromise.Ensure(__func__);
|
||||
QueueTask(task);
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
// Buffer Append Algorithm
|
||||
// 3.5.5 Buffer Append Algorithm.
|
||||
// http://w3c.github.io/media-source/index.html#sourcebuffer-buffer-append
|
||||
RefPtr<AppendPromise> AppendData(MediaByteBuffer* aData,
|
||||
RefPtr<AppendPromise> AppendData(already_AddRefed<MediaByteBuffer> aData,
|
||||
const SourceBufferAttributes& aAttributes);
|
||||
|
||||
// Queue a task to abort any pending AppendData.
|
||||
|
@ -174,7 +174,7 @@ private:
|
|||
friend class MediaSourceDemuxer;
|
||||
~TrackBuffersManager();
|
||||
// All following functions run on the taskqueue.
|
||||
RefPtr<AppendPromise> DoAppendData(MediaByteBuffer* aData,
|
||||
RefPtr<AppendPromise> DoAppendData(already_AddRefed<MediaByteBuffer> aData,
|
||||
const SourceBufferAttributes& aAttributes);
|
||||
void ScheduleSegmentParserLoop();
|
||||
void SegmentParserLoop();
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
var htmlAudio = new Audio(URL.createObjectURL(new window.MediaSource()));
|
||||
|
||||
(new window.AudioContext("ringer")).createMediaElementSource(htmlAudio);
|
||||
(new window.AudioContext("alarm")).createMediaElementSource(htmlAudio);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -81,8 +81,6 @@ load 1157994.html
|
|||
load 1158427.html
|
||||
load 1185176.html
|
||||
load 1185192.html
|
||||
load 1223670.html
|
||||
load 1228484.html
|
||||
load 1304948.html
|
||||
load 1319486.html
|
||||
load 1291702.html
|
||||
|
|
|
@ -908,55 +908,94 @@ AudioStreamHelper.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
function VideoStreamHelper() {
|
||||
this._helper = new CaptureStreamTestHelper2D(50,50);
|
||||
this._canvas = this._helper.createAndAppendElement('canvas', 'source_canvas');
|
||||
// Make sure this is initted
|
||||
this._helper.drawColor(this._canvas, this._helper.green);
|
||||
this._stream = this._canvas.captureStream(10);
|
||||
}
|
||||
class VideoFrameEmitter {
|
||||
constructor(color1, color2) {
|
||||
this._helper = new CaptureStreamTestHelper2D(50,50);
|
||||
this._canvas = this._helper.createAndAppendElement('canvas', 'source_canvas');
|
||||
this._color1 = color1 ? color1 : this._helper.green;
|
||||
this._color2 = color2 ? color2 : this._helper.red;
|
||||
// Make sure this is initted
|
||||
this._helper.drawColor(this._canvas, this._color1);
|
||||
this._stream = this._canvas.captureStream();
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
VideoStreamHelper.prototype = {
|
||||
stream: function() {
|
||||
stream() {
|
||||
return this._stream;
|
||||
},
|
||||
}
|
||||
|
||||
startCapturingFrames: function() {
|
||||
var i = 0;
|
||||
var helper = this;
|
||||
return setInterval(function() {
|
||||
start() {
|
||||
if (this._started) {
|
||||
return;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
this._started = true;
|
||||
this._intervalId = setInterval(() => {
|
||||
try {
|
||||
helper._helper.drawColor(helper._canvas,
|
||||
i ? helper._helper.green : helper._helper.red);
|
||||
this._helper.drawColor(this._canvas, i ? this._color1: this._color2);
|
||||
i = 1 - i;
|
||||
helper._stream.requestFrame();
|
||||
} catch (e) {
|
||||
// ignore; stream might have shut down, and we don't bother clearing
|
||||
// the setInterval.
|
||||
}
|
||||
}, 500);
|
||||
},
|
||||
}
|
||||
|
||||
waitForFrames: function(canvas, timeout_value) {
|
||||
var intervalId = this.startCapturingFrames();
|
||||
timeout_value = timeout_value || 8000;
|
||||
stop() {
|
||||
if (this._started) {
|
||||
clearInterval(this._intervalId);
|
||||
this._started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addFinallyToPromise(timeout(
|
||||
Promise.all([
|
||||
this._helper.waitForPixelColor(canvas, this._helper.green, 128,
|
||||
canvas.id + " should become green"),
|
||||
this._helper.waitForPixelColor(canvas, this._helper.red, 128,
|
||||
canvas.id + " should become red")
|
||||
]),
|
||||
timeout_value,
|
||||
"Timed out waiting for frames")).finally(() => clearInterval(intervalId));
|
||||
},
|
||||
class VideoStreamHelper {
|
||||
constructor() {
|
||||
this._helper = new CaptureStreamTestHelper2D(50,50);
|
||||
}
|
||||
|
||||
verifyNoFrames: function(canvas) {
|
||||
return this.waitForFrames(canvas).then(
|
||||
() => ok(false, "Color should not change"),
|
||||
() => ok(true, "Color should not change")
|
||||
);
|
||||
checkHasFrame(video, offsetX, offsetY, threshold) {
|
||||
const h = this._helper;
|
||||
return h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isOpaquePixelNot(px, h.black, threshold);
|
||||
info("Checking that we have a frame, got [" +
|
||||
Array.slice(px) + "]. Ref=[" +
|
||||
Array.slice(h.black.data) + "]. Threshold=" + threshold +
|
||||
". Pass=" + result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
async checkVideoPlaying(video, offsetX, offsetY, threshold) {
|
||||
const h = this._helper;
|
||||
await this.checkHasFrame(video, offsetX, offsetY, threshold);
|
||||
let startPixel = { data: h.getPixel(video, offsetX, offsetY)
|
||||
, name: "startcolor"
|
||||
};
|
||||
return h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isPixelNot(px, startPixel, threshold)
|
||||
info("Checking playing, [" +
|
||||
Array.slice(px) + "] vs [" + Array.slice(startPixel.data) +
|
||||
"]. Threshold=" + threshold + " Pass=" + result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
async checkVideoPaused(video, offsetX, offsetY, threshold, timeout) {
|
||||
const h = this._helper;
|
||||
await this.checkHasFrame(video, offsetX, offsetY, threshold);
|
||||
let startPixel = { data: h.getPixel(video, offsetX, offsetY)
|
||||
, name: "startcolor"
|
||||
};
|
||||
const changed = await h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isOpaquePixelNot(px, startPixel, threshold);
|
||||
info("Checking paused, [" +
|
||||
Array.slice(px) + "] vs [" + Array.slice(startPixel.data) +
|
||||
"]. Threshold=" + threshold + " Pass=" + result);
|
||||
return result;
|
||||
}, timeout);
|
||||
ok(!changed, "Frame shouldn't change within " + timeout / 1000 + " seconds.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1004,13 +1004,13 @@ PeerConnectionWrapper.prototype = {
|
|||
return Promise.all(constraintsList.map(constraints => {
|
||||
return getUserMedia(constraints).then(stream => {
|
||||
if (constraints.audio) {
|
||||
stream.getAudioTracks().map(track => {
|
||||
stream.getAudioTracks().forEach(track => {
|
||||
info(this + " gUM local stream " + stream.id +
|
||||
" with audio track " + track.id);
|
||||
});
|
||||
}
|
||||
if (constraints.video) {
|
||||
stream.getVideoTracks().map(track => {
|
||||
stream.getVideoTracks().forEach(track => {
|
||||
info(this + " gUM local stream " + stream.id +
|
||||
" with video track " + track.id);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
<head>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -24,43 +23,11 @@ const offsetX = 20;
|
|||
const offsetY = 20;
|
||||
const threshold = 16;
|
||||
const pausedTimeout = 1000;
|
||||
const h = new CaptureStreamTestHelper2D(50, 50);
|
||||
|
||||
var checkHasFrame = video => h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isOpaquePixelNot(px, h.black, threshold);
|
||||
info("Checking that we have a frame, got [" +
|
||||
Array.slice(px) + "]. Pass=" + result);
|
||||
return result;
|
||||
});
|
||||
|
||||
var checkVideoPlaying = video => checkHasFrame(video)
|
||||
.then(() => {
|
||||
let startPixel = { data: h.getPixel(video, offsetX, offsetY)
|
||||
, name: "startcolor"
|
||||
};
|
||||
return h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isPixelNot(px, startPixel, threshold)
|
||||
info("Checking playing, [" + Array.slice(px) + "] vs [" +
|
||||
Array.slice(startPixel.data) + "]. Pass=" + result);
|
||||
return result;
|
||||
});
|
||||
});
|
||||
|
||||
var checkVideoPaused = video => checkHasFrame(video)
|
||||
.then(() => {
|
||||
let startPixel = { data: h.getPixel(video, offsetX, offsetY)
|
||||
, name: "startcolor"
|
||||
};
|
||||
return h.waitForPixel(video, offsetX, offsetY, px => {
|
||||
let result = h.isOpaquePixelNot(px, startPixel, threshold);
|
||||
info("Checking paused, [" + Array.slice(px) + "] vs [" +
|
||||
Array.slice(startPixel.data) + "]. Pass=" + result);
|
||||
return result;
|
||||
}, pausedTimeout);
|
||||
}).then(result => ok(!result, "Frame shouldn't change within " + pausedTimeout / 1000 + " seconds."));
|
||||
let h;
|
||||
|
||||
runTest(() => getUserMedia({video: true, fake: true})
|
||||
.then(stream => {
|
||||
h = new VideoStreamHelper();
|
||||
gUMVideoElement =
|
||||
createMediaElement("video", "gUMVideo");
|
||||
gUMVideoElement.srcObject = stream;
|
||||
|
@ -80,43 +47,45 @@ runTest(() => getUserMedia({video: true, fake: true})
|
|||
let osc = createOscillatorStream(new AudioContext(), 1000);
|
||||
captureStreamElement.srcObject.addTrack(osc.getTracks()[0]);
|
||||
|
||||
return checkVideoPlaying(captureStreamElement);
|
||||
return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
|
||||
})
|
||||
.then(() => {
|
||||
info("Video flowing. Pausing.");
|
||||
gUMVideoElement.pause();
|
||||
|
||||
return checkVideoPaused(captureStreamElement);
|
||||
return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout);
|
||||
})
|
||||
.then(() => {
|
||||
info("Video stopped flowing. Playing.");
|
||||
gUMVideoElement.play();
|
||||
|
||||
return checkVideoPlaying(captureStreamElement);
|
||||
return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
|
||||
})
|
||||
.then(() => {
|
||||
info("Video flowing. Removing source.");
|
||||
var stream = gUMVideoElement.srcObject;
|
||||
gUMVideoElement.srcObject = null;
|
||||
|
||||
return checkVideoPaused(captureStreamElement).then(() => stream);
|
||||
return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout)
|
||||
.then(() => stream);
|
||||
})
|
||||
.then(stream => {
|
||||
info("Video stopped flowing. Setting source.");
|
||||
gUMVideoElement.srcObject = stream;
|
||||
return checkVideoPlaying(captureStreamElement);
|
||||
return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
|
||||
})
|
||||
.then(() => {
|
||||
info("Video flowing. Changing source by track manipulation. Remove first.");
|
||||
var track = gUMVideoElement.srcObject.getTracks()[0];
|
||||
gUMVideoElement.srcObject.removeTrack(track);
|
||||
return checkVideoPaused(captureStreamElement).then(() => track);
|
||||
return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout)
|
||||
.then(() => track);
|
||||
})
|
||||
.then(track => {
|
||||
info("Video paused. Changing source by track manipulation. Add first.");
|
||||
gUMVideoElement.srcObject.addTrack(track);
|
||||
gUMVideoElement.play();
|
||||
return checkVideoPlaying(captureStreamElement);
|
||||
return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
|
||||
})
|
||||
.then(() => {
|
||||
gUMVideoElement.srcObject.getTracks().forEach(t => t.stop());
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -11,9 +11,8 @@
|
|||
title: "Renegotiation: add second audio stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
|
@ -21,10 +20,22 @@
|
|||
[{audio: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
// We test both tracks to avoid an ordering problem
|
||||
is(test.pcRemote._pc.getReceivers().length, 2,
|
||||
"pcRemote should have two receivers");
|
||||
return Promise.all(test.pcRemote._pc.getReceivers().map(r => {
|
||||
const analyser = new AudioStreamAnalyser(
|
||||
new AudioContext(), new MediaStream([r.track]));
|
||||
const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
|
||||
}));
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -11,11 +11,9 @@
|
|||
title: "Renegotiation: add second audio stream, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
options = options || { };
|
||||
runNetworkTest(function (options = {}) {
|
||||
options.bundle = false;
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
|
@ -29,6 +27,19 @@
|
|||
function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcRemote.expectIceChecking();
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
// We test both tracks to avoid an ordering problem
|
||||
is(test.pcRemote._pc.getReceivers().length, 2,
|
||||
"pcRemote should have two receivers");
|
||||
return Promise.all(test.pcRemote._pc.getReceivers().map(r => {
|
||||
const analyser = new AudioStreamAnalyser(
|
||||
new AudioContext(), new MediaStream([r.track]));
|
||||
const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
|
||||
}));
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -11,21 +12,30 @@
|
|||
title: "Renegotiation: add second video stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{video: true}, {video: true}],
|
||||
[{video: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
// Use fake:true here since the native fake device on linux doesn't
|
||||
// change color as needed by checkVideoPlaying() below.
|
||||
return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
|
||||
const h = new VideoStreamHelper();
|
||||
is(test.pcRemote.remoteMediaElements.length, 2,
|
||||
"Should have two remote media elements after renegotiation");
|
||||
return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
|
||||
h.checkVideoPlaying(video, 10, 10, 16)));
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.setMediaConstraints([{video: true, fake: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -11,11 +12,9 @@
|
|||
title: "Renegotiation: add second video stream, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
options = options || { };
|
||||
runNetworkTest(function (options = {}) {
|
||||
options.bundle = false;
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
|
@ -24,16 +23,26 @@
|
|||
// Since this is a NoBundle variant, adding a track will cause us to
|
||||
// go back to checking.
|
||||
test.pcLocal.expectIceChecking();
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
// Use fake:true here since the native fake device on linux doesn't
|
||||
// change color as needed by checkVideoPlaying() below.
|
||||
return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
|
||||
},
|
||||
function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcRemote.expectIceChecking();
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
|
||||
const h = new VideoStreamHelper();
|
||||
is(test.pcRemote.remoteMediaElements.length, 2,
|
||||
"Should have two remote media elements after renegotiation");
|
||||
return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
|
||||
h.checkVideoPlaying(video, 10, 10, 16)));
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.setMediaConstraints([{video: true, fake: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -11,20 +11,42 @@
|
|||
title: "Renegotiation: remove audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
let receivedTrack, analyser, freq;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_REMOTE_SETUP_ANALYSER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver before renegotiation");
|
||||
|
||||
receivedTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
is(receivedTrack.readyState, "live",
|
||||
"The received track should be live");
|
||||
|
||||
analyser = new AudioStreamAnalyser(
|
||||
new AudioContext(), new MediaStream([receivedTrack]));
|
||||
freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
|
||||
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
|
||||
},
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
test.setOfferOptions({ offerToReceiveAudio: true });
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_FLOW_STOPPED(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 0,
|
||||
"pcRemote should have no more receivers");
|
||||
is(receivedTrack.readyState, "ended",
|
||||
"The received track should have ended");
|
||||
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] < 50);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
|
||||
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -11,11 +11,16 @@
|
|||
title: "Renegotiation: remove then add audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
let originalTrack;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_REMOTE_FIND_RECEIVER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver");
|
||||
originalTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
},
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
|
@ -26,10 +31,22 @@
|
|||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should still have one receiver");
|
||||
const track = test.pcRemote._pc.getReceivers()[0].track;
|
||||
isnot(originalTrack.id, track.id, "Receiver should have changed");
|
||||
|
||||
const analyser = new AudioStreamAnalyser(
|
||||
new AudioContext(), new MediaStream([track]));
|
||||
const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -11,11 +11,16 @@
|
|||
title: "Renegotiation: remove then add audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
let originalTrack;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_REMOTE_FIND_RECEIVER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver");
|
||||
originalTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
},
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
|
@ -26,13 +31,25 @@
|
|||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should still have one receiver");
|
||||
const track = test.pcRemote._pc.getReceivers()[0].track;
|
||||
isnot(originalTrack.id, track.id, "Receiver should have changed");
|
||||
|
||||
const analyser = new AudioStreamAnalyser(
|
||||
new AudioContext(), new MediaStream([track]));
|
||||
const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
|
||||
return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -11,25 +12,47 @@
|
|||
title: "Renegotiation: remove then add video track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
const helper = new VideoStreamHelper();
|
||||
var originalTrack;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
function PC_REMOTE_FIND_RECEIVER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver");
|
||||
originalTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
},
|
||||
function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
function PC_LOCAL_ADD_VIDEO_TRACK(test) {
|
||||
// Use fake:true here since the native fake device on linux doesn't
|
||||
// change color as needed by checkVideoPlaying() below.
|
||||
return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should still have one receiver");
|
||||
const track = test.pcRemote._pc.getReceivers()[0].track;
|
||||
isnot(originalTrack.id, track.id, "Receiver should have changed");
|
||||
|
||||
const vOriginal = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(originalTrack.id));
|
||||
const vAdded = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(track.id));
|
||||
ok(vOriginal.ended, "Original video element should have ended");
|
||||
return helper.checkVideoPlaying(vAdded, 10, 10, 16);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -11,28 +12,50 @@
|
|||
title: "Renegotiation: remove then add video track, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
const helper = new VideoStreamHelper();
|
||||
var originalTrack;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
function PC_REMOTE_FIND_RECEIVER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver");
|
||||
originalTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
},
|
||||
function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
function PC_LOCAL_ADD_VIDEO_TRACK(test) {
|
||||
// Use fake:true here since the native fake device on linux doesn't
|
||||
// change color as needed by checkVideoPlaying() below.
|
||||
return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should still have one receiver");
|
||||
const track = test.pcRemote._pc.getReceivers()[0].track;
|
||||
isnot(originalTrack.id, track.id, "Receiver should have changed");
|
||||
|
||||
const vOriginal = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(originalTrack.id));
|
||||
const vAdded = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(track.id));
|
||||
ok(vOriginal.ended, "Original video element should have ended");
|
||||
return helper.checkVideoPlaying(vAdded, 10, 10, 16);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -11,21 +11,41 @@
|
|||
title: "Renegotiation: remove video track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
let receivedTrack, element;
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_REMOTE_SETUP_HELPER(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 1,
|
||||
"pcRemote should have one receiver before renegotiation");
|
||||
|
||||
receivedTrack = test.pcRemote._pc.getReceivers()[0].track;
|
||||
is(receivedTrack.readyState, "live",
|
||||
"The received track should be live");
|
||||
|
||||
element = createMediaElement("video", "pcRemoteReceivedVideo");
|
||||
element.srcObject = new MediaStream([receivedTrack]);
|
||||
return haveEvent(element, "loadeddata");
|
||||
},
|
||||
function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
|
||||
test.setOfferOptions({ offerToReceiveVideo: true });
|
||||
test.setMediaConstraints([], [{video: true}]);
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_FLOW_STOPPED(test) {
|
||||
is(test.pcRemote._pc.getReceivers().length, 0,
|
||||
"pcRemote should have no more receivers");
|
||||
is(receivedTrack.readyState, "ended",
|
||||
"The received track should have ended");
|
||||
is(element.ended, true,
|
||||
"Element playing the removed track should have ended");
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
|
||||
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
|
@ -11,33 +12,74 @@
|
|||
title: "Renegotiation: replaceTrack followed by adding a second video stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
const test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{video:true}], [{video:true}]);
|
||||
const helper = new VideoStreamHelper();
|
||||
const emitter1 = new VideoFrameEmitter(CaptureStreamTestHelper.prototype.red,
|
||||
CaptureStreamTestHelper.prototype.green);
|
||||
const emitter2 = new VideoFrameEmitter(CaptureStreamTestHelper.prototype.blue,
|
||||
CaptureStreamTestHelper.prototype.grey);
|
||||
test.chain.replace("PC_LOCAL_GUM", [
|
||||
function PC_LOCAL_ADDTRACK(test) {
|
||||
test.pcLocal.attachLocalStream(emitter1.stream());
|
||||
emitter1.start();
|
||||
},
|
||||
]);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REPLACE_VIDEO_TRACK_THEN_ADD_SECOND_STREAM(test) {
|
||||
var oldstream = test.pcLocal._pc.getLocalStreams()[0];
|
||||
var oldtrack = oldstream.getVideoTracks()[0];
|
||||
var sender = test.pcLocal._pc.getSenders()[0];
|
||||
return navigator.mediaDevices.getUserMedia({video:true})
|
||||
.then(newstream => {
|
||||
var newtrack = newstream.getVideoTracks()[0];
|
||||
return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id);
|
||||
})
|
||||
emitter1.stop();
|
||||
emitter2.start();
|
||||
const newstream = emitter2.stream();
|
||||
const newtrack = newstream.getVideoTracks()[0];
|
||||
return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id)
|
||||
.then(() => {
|
||||
test.setMediaConstraints([{video: true}, {video: true}],
|
||||
[{video: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
// Use fake:true here since the native fake device on linux
|
||||
// doesn't change color as needed by checkVideoPlaying() below.
|
||||
return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
|
||||
});
|
||||
},
|
||||
],
|
||||
[
|
||||
function PC_REMOTE_CHECK_ORIGINAL_TRACK_ENDED(test) {
|
||||
const vremote = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(emitter1.stream().getTracks()[0].id));
|
||||
if (!vremote) {
|
||||
return Promise.reject(new Error("Couldn't find video element"));
|
||||
}
|
||||
ok(vremote.ended, "Original track should have ended after renegotiation");
|
||||
},
|
||||
function PC_REMOTE_CHECK_REPLACED_TRACK_FLOW(test) {
|
||||
const vremote = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(test.pcLocal._pc.getSenders()[0].track.id));
|
||||
if (!vremote) {
|
||||
return Promise.reject(new Error("Couldn't find video element"));
|
||||
}
|
||||
return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
|
||||
.finally(() => emitter2.stop())
|
||||
.then(() => {
|
||||
const px = helper._helper.getPixel(vremote, 10, 10);
|
||||
const isBlue = helper._helper.isPixel(
|
||||
px, CaptureStreamTestHelper.prototype.blue, 5);
|
||||
const isGrey = helper._helper.isPixel(
|
||||
px, CaptureStreamTestHelper.prototype.grey, 5);
|
||||
ok(isBlue || isGrey, "replaced track should be blue or grey");
|
||||
});
|
||||
},
|
||||
function PC_REMOTE_CHECK_ADDED_TRACK_FLOW(test) {
|
||||
const vremote = test.pcRemote.remoteMediaElements.find(
|
||||
elem => elem.id.includes(test.pcLocal._pc.getSenders()[1].track.id));
|
||||
if (!vremote) {
|
||||
return Promise.reject(new Error("Couldn't find video element"));
|
||||
}
|
||||
return helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835):
|
||||
// figure out how to verify if media flows through the new stream
|
||||
// figure out how to verify that media stopped flowing from old stream
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -13,21 +13,20 @@
|
|||
visible: true
|
||||
});
|
||||
|
||||
var test;
|
||||
var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
|
||||
const pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
|
||||
|
||||
function addRIDExtension(pc, extensionId) {
|
||||
var receivers = pc._pc.getReceivers();
|
||||
const receivers = pc._pc.getReceivers();
|
||||
is(receivers.length, 1, "We have exactly one RTP receiver");
|
||||
var receiver = receivers[0];
|
||||
const receiver = receivers[0];
|
||||
|
||||
SpecialPowers.wrap(pc._pc).mozAddRIDExtension(receiver, extensionId);
|
||||
}
|
||||
|
||||
function selectRecvRID(pc, rid) {
|
||||
var receivers = pc._pc.getReceivers();
|
||||
const receivers = pc._pc.getReceivers();
|
||||
is(receivers.length, 1, "We have exactly one RTP receiver");
|
||||
var receiver = receivers[0];
|
||||
const receiver = receivers[0];
|
||||
|
||||
SpecialPowers.wrap(pc._pc).mozAddRIDFilter(receiver, rid);
|
||||
}
|
||||
|
@ -38,23 +37,24 @@
|
|||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]).then(() => {
|
||||
var helper;
|
||||
let emitter, helper;
|
||||
|
||||
test = new PeerConnectionTest({bundle: false});
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
|
||||
test.chain.replace("PC_REMOTE_GUM", [
|
||||
function PC_REMOTE_CANVAS_CAPTURESTREAM(test) {
|
||||
emitter = new VideoFrameEmitter();
|
||||
helper = new VideoStreamHelper();
|
||||
test.pcRemote.attachLocalStream(helper.stream());
|
||||
test.pcRemote.attachLocalStream(emitter.stream());
|
||||
}
|
||||
]);
|
||||
|
||||
test.chain.insertAfter('PC_REMOTE_GET_OFFER', [
|
||||
function PC_REMOTE_SET_RIDS(test) {
|
||||
var senders = test.pcRemote._pc.getSenders();
|
||||
const senders = test.pcRemote._pc.getSenders();
|
||||
is(senders.length, 1, "We have exactly one RTP sender");
|
||||
var sender = senders[0];
|
||||
const sender = senders[0];
|
||||
ok(sender.track, "Sender has a track");
|
||||
|
||||
return sender.setParameters({
|
||||
|
@ -88,7 +88,7 @@
|
|||
// has been created.
|
||||
test.chain.insertAfter('PC_LOCAL_SET_REMOTE_DESCRIPTION',[
|
||||
function PC_LOCAL_SET_RTP_FIRST_RID(test) {
|
||||
var extmap_id = test._local_offer.sdp.match(
|
||||
const extmap_id = test._local_offer.sdp.match(
|
||||
"a=extmap:([0-9+])/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
|
||||
ok(extmap_id, "Local offer has extmap id for simulcast: " + extmap_id[1]);
|
||||
// Cause pcLocal to filter out everything but RID "bar", only
|
||||
|
@ -99,14 +99,16 @@
|
|||
]);
|
||||
|
||||
test.chain.append([
|
||||
function PC_LOCAL_WAIT_FOR_FRAMES() {
|
||||
var vremote = test.pcLocal.remoteMediaElements[0];
|
||||
async function PC_LOCAL_WAIT_FOR_FRAMES() {
|
||||
const vremote = test.pcLocal.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcLocal");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
function PC_LOCAL_CHECK_SIZE_1() {
|
||||
var vlocal = test.pcRemote.localMediaElements[0];
|
||||
var vremote = test.pcLocal.remoteMediaElements[0];
|
||||
const vlocal = test.pcRemote.localMediaElements[0];
|
||||
const vremote = test.pcLocal.remoteMediaElements[0];
|
||||
ok(vlocal, "Should have local video element for pcRemote");
|
||||
ok(vremote, "Should have remote video element for pcLocal");
|
||||
ok(vlocal.videoWidth > 0, "source width is positive");
|
||||
|
@ -122,21 +124,25 @@
|
|||
function PC_LOCAL_WAIT_FOR_SECOND_MEDIA_FLOW(test) {
|
||||
return test.pcLocal.waitForMediaFlow();
|
||||
},
|
||||
function PC_LOCAL_WAIT_FOR_FRAMES_2() {
|
||||
var vremote = test.pcLocal.remoteMediaElements[0];
|
||||
async function PC_LOCAL_WAIT_FOR_FRAMES_2() {
|
||||
const vremote = test.pcLocal.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcLocal");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
// For some reason, even though we're getting a 25x25 stream, sometimes
|
||||
// the resolution isn't updated on the video element on the first frame.
|
||||
function PC_LOCAL_WAIT_FOR_FRAMES_3() {
|
||||
var vremote = test.pcLocal.remoteMediaElements[0];
|
||||
async function PC_LOCAL_WAIT_FOR_FRAMES_3() {
|
||||
const vremote = test.pcLocal.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcLocal");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
function PC_LOCAL_CHECK_SIZE_2() {
|
||||
var vlocal = test.pcRemote.localMediaElements[0];
|
||||
var vremote = test.pcLocal.remoteMediaElements[0];
|
||||
const vlocal = test.pcRemote.localMediaElements[0];
|
||||
const vremote = test.pcLocal.remoteMediaElements[0];
|
||||
ok(vlocal, "Should have local video element for pcRemote");
|
||||
ok(vremote, "Should have remote video element for pcLocal");
|
||||
ok(vlocal.videoWidth > 0, "source width is positive");
|
||||
|
|
|
@ -13,21 +13,20 @@
|
|||
visible: true
|
||||
});
|
||||
|
||||
var test;
|
||||
var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
|
||||
const pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
|
||||
|
||||
function addRIDExtension(pc, extensionId) {
|
||||
var receivers = pc._pc.getReceivers();
|
||||
const receivers = pc._pc.getReceivers();
|
||||
is(receivers.length, 1, "We have exactly one RTP receiver");
|
||||
var receiver = receivers[0];
|
||||
const receiver = receivers[0];
|
||||
|
||||
SpecialPowers.wrap(pc._pc).mozAddRIDExtension(receiver, extensionId);
|
||||
}
|
||||
|
||||
function selectRecvRID(pc, rid) {
|
||||
var receivers = pc._pc.getReceivers();
|
||||
const receivers = pc._pc.getReceivers();
|
||||
is(receivers.length, 1, "We have exactly one RTP receiver");
|
||||
var receiver = receivers[0];
|
||||
const receiver = receivers[0];
|
||||
|
||||
SpecialPowers.wrap(pc._pc).mozAddRIDFilter(receiver, rid);
|
||||
}
|
||||
|
@ -38,23 +37,24 @@
|
|||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]).then(() => {
|
||||
var helper;
|
||||
let emitter, helper;
|
||||
|
||||
test = new PeerConnectionTest({bundle: false});
|
||||
const test = new PeerConnectionTest({bundle: false});
|
||||
test.setMediaConstraints([{video: true}], []);
|
||||
|
||||
test.chain.replace("PC_LOCAL_GUM", [
|
||||
function PC_LOCAL_CANVAS_CAPTURESTREAM(test) {
|
||||
emitter = new VideoFrameEmitter();
|
||||
helper = new VideoStreamHelper();
|
||||
test.pcLocal.attachLocalStream(helper.stream());
|
||||
test.pcLocal.attachLocalStream(emitter.stream());
|
||||
}
|
||||
]);
|
||||
|
||||
test.chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
|
||||
function PC_LOCAL_SET_RIDS(test) {
|
||||
var senders = test.pcLocal._pc.getSenders();
|
||||
const senders = test.pcLocal._pc.getSenders();
|
||||
is(senders.length, 1, "We have exactly one RTP sender");
|
||||
var sender = senders[0];
|
||||
const sender = senders[0];
|
||||
ok(sender.track, "Sender has a track");
|
||||
|
||||
return sender.setParameters({
|
||||
|
@ -80,7 +80,7 @@
|
|||
// has been created.
|
||||
test.chain.insertAfter('PC_REMOTE_SET_LOCAL_DESCRIPTION',[
|
||||
function PC_REMOTE_SET_RTP_FIRST_RID(test) {
|
||||
var extmap_id = test.originalOffer.sdp.match(
|
||||
const extmap_id = test.originalOffer.sdp.match(
|
||||
"a=extmap:([0-9+])/sendonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
|
||||
ok(extmap_id, "Original offer has extmap id for simulcast: " + extmap_id[1]);
|
||||
// Cause pcRemote to filter out everything but RID "foo", only
|
||||
|
@ -91,14 +91,16 @@
|
|||
]);
|
||||
|
||||
test.chain.append([
|
||||
function PC_REMOTE_WAIT_FOR_FRAMES() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
async function PC_REMOTE_WAIT_FOR_FRAMES() {
|
||||
const vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
function PC_REMOTE_CHECK_SIZE_1() {
|
||||
var vlocal = test.pcLocal.localMediaElements[0];
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
const vlocal = test.pcLocal.localMediaElements[0];
|
||||
const vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vlocal, "Should have local video element for pcLocal");
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
ok(vlocal.videoWidth > 0, "source width is positive");
|
||||
|
@ -114,21 +116,25 @@
|
|||
function PC_REMOTE_WAIT_FOR_SECOND_MEDIA_FLOW(test) {
|
||||
return test.pcRemote.waitForMediaFlow();
|
||||
},
|
||||
function PC_REMOTE_WAIT_FOR_FRAMES_2() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
async function PC_REMOTE_WAIT_FOR_FRAMES_2() {
|
||||
const vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
// For some reason, even though we're getting a 25x25 stream, sometimes
|
||||
// the resolution isn't updated on the video element on the first frame.
|
||||
function PC_REMOTE_WAIT_FOR_FRAMES_3() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
async function PC_REMOTE_WAIT_FOR_FRAMES_3() {
|
||||
const vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
await helper.checkVideoPlaying(vremote, 10, 10, 16);
|
||||
emitter.stop();
|
||||
},
|
||||
function PC_REMOTE_CHECK_SIZE_2() {
|
||||
var vlocal = test.pcLocal.localMediaElements[0];
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
const vlocal = test.pcLocal.localMediaElements[0];
|
||||
const vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vlocal, "Should have local video element for pcLocal");
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
ok(vlocal.videoWidth > 0, "source width is positive");
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
var helper;
|
||||
const emitter = new VideoFrameEmitter();
|
||||
const helper = new VideoStreamHelper();
|
||||
|
||||
test = new PeerConnectionTest(options);
|
||||
|
||||
test.chain.replace("PC_LOCAL_GUM", [
|
||||
function PC_LOCAL_CANVAS_CAPTURESTREAM(test) {
|
||||
helper = new VideoStreamHelper();
|
||||
test.pcLocal.attachLocalStream(helper.stream());
|
||||
test.pcLocal.attachLocalStream(emitter.stream());
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -30,7 +30,9 @@
|
|||
function PC_REMOTE_WAIT_FOR_FRAMES() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
|
||||
.finally(() => emitter.stop());
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -47,7 +49,9 @@
|
|||
function PC_REMOTE_ENSURE_NO_FRAMES() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.verifyNoFrames(vremote);
|
||||
emitter.start();
|
||||
return addFinallyToPromise(helper.checkVideoPaused(vremote, 10, 10, 16, 5000))
|
||||
.finally(() => emitter.stop());
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -60,7 +64,9 @@
|
|||
function PC_REMOTE_WAIT_FOR_FRAMES_2() {
|
||||
var vremote = test.pcRemote.remoteMediaElements[0];
|
||||
ok(vremote, "Should have remote video element for pcRemote");
|
||||
return helper.waitForFrames(vremote);
|
||||
emitter.start();
|
||||
return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
|
||||
.finally(() => emitter.stop());
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
|
@ -197,16 +197,6 @@ AudioContext::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
/* static */ already_AddRefed<AudioContext>
|
||||
AudioContext::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return AudioContext::Constructor(aGlobal,
|
||||
AudioChannelService::GetDefaultAudioChannel(),
|
||||
aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<AudioContext>
|
||||
AudioContext::Constructor(const GlobalObject& aGlobal,
|
||||
AudioChannel aChannel,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
|
@ -214,7 +204,9 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<AudioContext> object = new AudioContext(window, false, aChannel);
|
||||
RefPtr<AudioContext> object =
|
||||
new AudioContext(window, false,
|
||||
AudioChannelService::GetDefaultAudioChannel());
|
||||
aRv = object->Init();
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
|
|
@ -154,12 +154,6 @@ public:
|
|||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
// Constructor for regular AudioContext. A default audio channel is needed.
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
AudioChannel aChannel,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Constructor for offline AudioContext
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
|
|
|
@ -449,7 +449,7 @@ void WebMBufferedState::UpdateIndex(const MediaByteRangeSet& aRanges, MediaResou
|
|||
while (length > 0) {
|
||||
static const uint32_t BLOCK_SIZE = 1048576;
|
||||
uint32_t block = std::min(length, BLOCK_SIZE);
|
||||
RefPtr<MediaByteBuffer> bytes = aResource->MediaReadAt(offset, block);
|
||||
RefPtr<MediaByteBuffer> bytes = aResource->CachedReadAt(offset, block);
|
||||
if (!bytes) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
|
||||
#include "nsTArray.h"
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "MediaResource.h"
|
||||
#include "NesteggPacketHolder.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct nestegg nestegg;
|
||||
|
||||
namespace mozilla {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче