diff --git a/.hgignore b/.hgignore
index a79e9f56435d..62b64d72e658 100644
--- a/.hgignore
+++ b/.hgignore
@@ -136,6 +136,7 @@ GPATH
^testing/talos/talos/tests/tp5n
^testing/talos/talos/tests/devtools/damp.manifest.develop
^talos-venv
+^py3venv
# Ignore files created when running a reftest.
^lextab.py$
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index c23d9676aa4c..3b33a7e40a99 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2490,8 +2490,6 @@ ContentPermissionPrompt.prototype = {
var DefaultBrowserCheck = {
get OPTIONPOPUP() { return "defaultBrowserNotificationPopup" },
- _setAsDefaultTimer: null,
- _setAsDefaultButtonClickStartTime: 0,
closePrompt(aNode) {
if (this._notification) {
@@ -2514,33 +2512,6 @@ var DefaultBrowserCheck = {
}
try {
ShellService.setDefaultBrowser(claimAllTypes, false);
-
- if (this._setAsDefaultTimer) {
- this._setAsDefaultTimer.cancel();
- }
-
- this._setAsDefaultButtonClickStartTime = Math.floor(Date.now() / 1000);
- this._setAsDefaultTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._setAsDefaultTimer.init(() => {
- let isDefault = false;
- let isDefaultError = false;
- try {
- isDefault = ShellService.isDefaultBrowser(true, false);
- } catch (ex) {
- isDefaultError = true;
- }
-
- let now = Math.floor(Date.now() / 1000);
- let runTime = now - this._setAsDefaultButtonClickStartTime;
- if (isDefault || runTime > 600) {
- this._setAsDefaultTimer.cancel();
- this._setAsDefaultTimer = null;
- Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_TIME_TO_COMPLETION_SECONDS")
- .add(runTime);
- }
- Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
- .add(isDefaultError);
- }, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
} catch (ex) {
setAsDefaultError = true;
Cu.reportError(ex);
diff --git a/browser/components/preferences/in-content-new/preferences.xul b/browser/components/preferences/in-content-new/preferences.xul
index 6b5466597f4e..0748e3688c54 100644
--- a/browser/components/preferences/in-content-new/preferences.xul
+++ b/browser/components/preferences/in-content-new/preferences.xul
@@ -217,23 +217,22 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/components/preferences/in-content-new/subdialogs.js b/browser/components/preferences/in-content-new/subdialogs.js
index dde373310fd4..6655eac3d78e 100644
--- a/browser/components/preferences/in-content-new/subdialogs.js
+++ b/browser/components/preferences/in-content-new/subdialogs.js
@@ -7,11 +7,38 @@
"use strict";
-var gSubDialog = {
+/**
+ * SubDialog constructor creates a new subdialog from a template and appends
+ * it to the parentElement.
+ * @param {DOMNode} template: The template is copied to create a new dialog.
+ * @param {DOMNode} parentElement: New dialog is appended onto parentElement.
+ * @param {String} id: A unique identifier for the dialog.
+ */
+function SubDialog({template, parentElement, id}) {
+ this._id = id;
+
+ this._overlay = template.cloneNode(true);
+ this._frame = this._overlay.querySelector(".dialogFrame");
+ this._box = this._overlay.querySelector(".dialogBox");
+ this._closeButton = this._overlay.querySelector(".dialogClose");
+ this._titleElement = this._overlay.querySelector(".dialogTitle");
+
+ this._overlay.id = `dialogOverlay-${id}`;
+ this._frame.setAttribute("name", `dialogFrame-${id}`);
+ this._frameCreated = new Promise(resolve => {
+ this._frame.addEventListener("load", resolve, {once: true});
+ });
+
+ parentElement.appendChild(this._overlay);
+ this._overlay.hidden = false;
+}
+
+SubDialog.prototype = {
_closingCallback: null,
_closingEvent: null,
_isClosing: false,
_frame: null,
+ _frameCreated: null,
_overlay: null,
_box: null,
_openedURL: null,
@@ -22,18 +49,15 @@ var gSubDialog = {
"chrome://browser/skin/preferences/in-content-new/dialog.css",
],
_resizeObserver: null,
-
- init() {
- this._frame = document.getElementById("dialogFrame");
- this._overlay = document.getElementById("dialogOverlay");
- this._box = document.getElementById("dialogBox");
- this._closeButton = document.getElementById("dialogClose");
- },
+ _template: null,
+ _id: null,
+ _titleElement: null,
+ _closeButton: null,
updateTitle(aEvent) {
- if (aEvent.target != gSubDialog._frame.contentDocument)
+ if (aEvent.target != this._frame.contentDocument)
return;
- document.getElementById("dialogTitle").textContent = gSubDialog._frame.contentDocument.title;
+ this._titleElement.textContent = this._frame.contentDocument.title;
},
injectXMLStylesheet(aStylesheetURL) {
@@ -45,11 +69,9 @@ var gSubDialog = {
this._frame.contentDocument.documentElement);
},
- open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
- // If we're already open/opening on this URL, do nothing.
- if (this._openedURL == aURL && !this._isClosing) {
- return;
- }
+ async open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
+ // Wait until frame is ready to prevent browser crash in tests
+ await this._frameCreated;
// If we're open on some (other) URL or we're closing, open when closing has finished.
if (this._openedURL || this._isClosing) {
if (!this._isClosing) {
@@ -64,7 +86,7 @@ var gSubDialog = {
this._addDialogEventListeners();
let features = (aFeatures ? aFeatures + "," : "") + "resizable,dialog=no,centerscreen";
- let dialog = window.openDialog(aURL, "dialogFrame", features, aParams);
+ let dialog = window.openDialog(aURL, `dialogFrame-${this._id}`, features, aParams);
if (aClosingCallback) {
this._closingCallback = aClosingCallback.bind(dialog);
}
@@ -109,6 +131,11 @@ var gSubDialog = {
this._box.style.removeProperty("min-height");
this._box.style.removeProperty("min-width");
+ this._overlay.dispatchEvent(new CustomEvent("dialogclose", {
+ bubbles: true,
+ detail: { dialog: this },
+ }));
+
setTimeout(() => {
// Unload the dialog after the event listeners run so that the load of about:blank isn't
// cancelled by the ESC .
@@ -185,32 +212,32 @@ var gSubDialog = {
this._frame.contentWindow.addEventListener("dialogclosing", this);
let oldResizeBy = this._frame.contentWindow.resizeBy;
- this._frame.contentWindow.resizeBy = function(resizeByWidth, resizeByHeight) {
+ this._frame.contentWindow.resizeBy = (resizeByWidth, resizeByHeight) => {
// Only handle resizeByHeight currently.
- let frameHeight = gSubDialog._frame.clientHeight;
- let boxMinHeight = parseFloat(getComputedStyle(gSubDialog._box).minHeight, 10);
+ let frameHeight = this._frame.clientHeight;
+ let boxMinHeight = parseFloat(getComputedStyle(this._box).minHeight, 10);
- gSubDialog._frame.style.height = (frameHeight + resizeByHeight) + "px";
- gSubDialog._box.style.minHeight = (boxMinHeight + resizeByHeight) + "px";
+ this._frame.style.height = (frameHeight + resizeByHeight) + "px";
+ this._box.style.minHeight = (boxMinHeight + resizeByHeight) + "px";
- oldResizeBy.call(gSubDialog._frame.contentWindow, resizeByWidth, resizeByHeight);
+ oldResizeBy.call(this._frame.contentWindow, resizeByWidth, resizeByHeight);
};
// Make window.close calls work like dialog closing.
let oldClose = this._frame.contentWindow.close;
- this._frame.contentWindow.close = function() {
- var closingEvent = gSubDialog._closingEvent;
+ this._frame.contentWindow.close = () => {
+ var closingEvent = this._closingEvent;
if (!closingEvent) {
closingEvent = new CustomEvent("dialogclosing", {
bubbles: true,
detail: { button: null },
});
- gSubDialog._frame.contentWindow.dispatchEvent(closingEvent);
+ this._frame.contentWindow.dispatchEvent(closingEvent);
}
- gSubDialog.close(closingEvent);
- oldClose.call(gSubDialog._frame.contentWindow);
+ this.close(closingEvent);
+ oldClose.call(this._frame.contentWindow);
};
// XXX: Hack to make focus during the dialog's load functions work. Make the element visible
@@ -293,6 +320,10 @@ var gSubDialog = {
(boxVerticalBorder + groupBoxTitleHeight + boxVerticalPadding) +
"px + " + frameMinHeight + ")";
+ this._overlay.dispatchEvent(new CustomEvent("dialogopen", {
+ bubbles: true,
+ detail: { dialog: this },
+ }));
this._overlay.style.visibility = "visible";
this._overlay.style.opacity = ""; // XXX: focus hack continued from _onContentLoaded
@@ -305,7 +336,7 @@ var gSubDialog = {
},
_onResize(mutations) {
- let frame = gSubDialog._frame;
+ let frame = this._frame;
// The width and height styles are needed for the initial
// layout of the frame, but afterward they need to be removed
// or their presence will restrict the contents of the
@@ -348,13 +379,13 @@ var gSubDialog = {
let fm = Services.focus;
- function isLastFocusableElement(el) {
+ let isLastFocusableElement = el => {
// XXXgijs unfortunately there is no way to get the last focusable element without asking
// the focus manager to move focus to it.
- let rv = el == fm.moveFocus(gSubDialog._frame.contentWindow, null, fm.MOVEFOCUS_LAST, 0);
+ let rv = el == fm.moveFocus(this._frame.contentWindow, null, fm.MOVEFOCUS_LAST, 0);
fm.setFocus(el, 0);
return rv;
- }
+ };
let forward = !aEvent.shiftKey;
// check if focus is leaving the frame (incl. the close button):
@@ -449,3 +480,104 @@ var gSubDialog = {
.chromeEventHandler;
},
};
+
+var gSubDialog = {
+ /**
+ * New dialogs are stacked on top of the existing ones, and they are pushed
+ * to the end of the _dialogs array.
+ * @type {Array}
+ */
+ _dialogs: [],
+ _dialogStack: null,
+ _dialogTemplate: null,
+ _nextDialogID: 0,
+ _preloadDialog: null,
+ get _topDialog() {
+ return this._dialogs.length > 0 ? this._dialogs[this._dialogs.length - 1] : undefined;
+ },
+
+ init() {
+ this._dialogStack = document.getElementById("dialogStack");
+ this._dialogTemplate = document.getElementById("dialogTemplate");
+ this._preloadDialog = new SubDialog({template: this._dialogTemplate,
+ parentElement: this._dialogStack,
+ id: this._nextDialogID++});
+ },
+
+ open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
+ // If we're already open/opening on this URL, do nothing.
+ if (this._topDialog && this._topDialog._openedURL == aURL) {
+ return;
+ }
+
+ this._preloadDialog.open(aURL, aFeatures, aParams, aClosingCallback);
+ this._dialogs.push(this._preloadDialog);
+ this._preloadDialog = new SubDialog({template: this._dialogTemplate,
+ parentElement: this._dialogStack,
+ id: this._nextDialogID++});
+
+ if (this._dialogs.length == 1) {
+ this._dialogStack.hidden = false;
+ this._ensureStackEventListeners();
+ }
+ },
+
+ close() {
+ this._topDialog.close();
+ },
+
+ handleEvent(aEvent) {
+ switch (aEvent.type) {
+ case "dialogopen": {
+ this._onDialogOpen();
+ break;
+ }
+ case "dialogclose": {
+ this._onDialogClose(aEvent.detail.dialog);
+ break;
+ }
+ }
+ },
+
+ _onDialogOpen() {
+ let lowerDialog = this._dialogs.length > 1 ? this._dialogs[this._dialogs.length - 2] : undefined;
+ if (lowerDialog) {
+ lowerDialog._overlay.removeAttribute("topmost");
+ lowerDialog._removeDialogEventListeners();
+ }
+ },
+
+ _onDialogClose(dialog) {
+ let fm = Services.focus;
+ if (this._topDialog == dialog) {
+ // XXX: When a top-most dialog is closed, we reuse the closed dialog and
+ // remove the preloadDialog. This is a temporary solution before we
+ // rewrite all the test cases in Bug 1359023.
+ this._preloadDialog._overlay.remove();
+ this._preloadDialog = this._dialogs.pop();
+ } else {
+ dialog._overlay.remove();
+ this._dialogs.splice(this._dialogs.indexOf(dialog), 1);
+ }
+
+ if (this._topDialog) {
+ fm.moveFocus(this._topDialog._frame.contentWindow, null, fm.MOVEFOCUS_FIRST, fm.FLAG_BYKEY);
+ this._topDialog._overlay.setAttribute("topmost", true);
+ this._topDialog._addDialogEventListeners();
+ } else {
+ fm.moveFocus(window, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
+ this._dialogStack.hidden = true;
+ this._removeStackEventListeners();
+ }
+ },
+
+ _ensureStackEventListeners() {
+ this._dialogStack.addEventListener("dialogopen", this);
+ this._dialogStack.addEventListener("dialogclose", this);
+ },
+
+ _removeStackEventListeners() {
+ this._dialogStack.removeEventListener("dialogopen", this);
+ this._dialogStack.removeEventListener("dialogclose", this);
+ },
+};
diff --git a/browser/components/preferences/in-content-new/tests/browser_advanced_update.js b/browser/components/preferences/in-content-new/tests/browser_advanced_update.js
index 6afead63ad1a..b396c072824b 100644
--- a/browser/components/preferences/in-content-new/tests/browser_advanced_update.js
+++ b/browser/components/preferences/in-content-new/tests/browser_advanced_update.js
@@ -114,7 +114,7 @@ add_task(async function() {
let doc = gBrowser.selectedBrowser.contentDocument;
let showBtn = doc.getElementById("showUpdateHistory");
- let dialogOverlay = doc.getElementById("dialogOverlay");
+ let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
// XXX: For unknown reasons, this mock cannot be loaded by
// XPCOMUtils.defineLazyServiceGetter() called in aboutDialog-appUpdater.js.
@@ -125,11 +125,12 @@ add_task(async function() {
// Test the dialog window opens
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
+ let promiseSubDialogLoaded = promiseLoadSubDialog("chrome://mozapps/content/update/history.xul");
showBtn.doCommand();
- await promiseLoadSubDialog("chrome://mozapps/content/update/history.xul");
+ await promiseSubDialogLoaded;
is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
- let dialogFrame = doc.getElementById("dialogFrame");
+ let dialogFrame = dialogOverlay.querySelector(".dialogFrame");
let frameDoc = dialogFrame.contentDocument;
let updates = frameDoc.querySelectorAll("update");
@@ -151,7 +152,7 @@ add_task(async function() {
}
// Test the dialog window closes
- let closeBtn = doc.getElementById("dialogClose");
+ let closeBtn = dialogOverlay.querySelector(".dialogClose");
closeBtn.doCommand();
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
diff --git a/browser/components/preferences/in-content-new/tests/browser_basic_rebuild_fonts_test.js b/browser/components/preferences/in-content-new/tests/browser_basic_rebuild_fonts_test.js
index 7479a2e92820..1ddc577f60a8 100644
--- a/browser/components/preferences/in-content-new/tests/browser_basic_rebuild_fonts_test.js
+++ b/browser/components/preferences/in-content-new/tests/browser_basic_rebuild_fonts_test.js
@@ -20,8 +20,9 @@ add_task(async function() {
let fontSizeField = doc.getElementById("defaultFontSize");
is(fontSizeField.value, defaultFontSize, "Font size should be set correctly.");
+ let promiseSubDialogLoaded = promiseLoadSubDialog("chrome://browser/content/preferences/fonts.xul");
doc.getElementById("advancedFonts").click();
- let win = await promiseLoadSubDialog("chrome://browser/content/preferences/fonts.xul");
+ let win = await promiseSubDialogLoaded;
doc = win.document;
// Simulate a dumb font backend.
diff --git a/browser/components/preferences/in-content-new/tests/browser_cookies_exceptions.js b/browser/components/preferences/in-content-new/tests/browser_cookies_exceptions.js
index 4277b2c8bd8a..9b4ad847489d 100644
--- a/browser/components/preferences/in-content-new/tests/browser_cookies_exceptions.js
+++ b/browser/components/preferences/in-content-new/tests/browser_cookies_exceptions.js
@@ -339,10 +339,12 @@ var testRunner = {
let historyMode = doc.getElementById("historyMode");
historyMode.value = "custom";
historyMode.doCommand();
+
+ let promiseSubDialogLoaded =
+ promiseLoadSubDialog("chrome://browser/content/preferences/permissions.xul");
doc.getElementById("cookieExceptions").doCommand();
- let subDialogURL = "chrome://browser/content/preferences/permissions.xul";
- promiseLoadSubDialog(subDialogURL).then(function(win) {
+ promiseSubDialogLoaded.then(function(win) {
helperFunctions.windowLoad(win);
});
});
diff --git a/browser/components/preferences/in-content-new/tests/browser_siteData.js b/browser/components/preferences/in-content-new/tests/browser_siteData.js
index fd9f1c4969f7..99cb6ee9f8c4 100644
--- a/browser/components/preferences/in-content-new/tests/browser_siteData.js
+++ b/browser/components/preferences/in-content-new/tests/browser_siteData.js
@@ -111,8 +111,8 @@ add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
await updatedPromise;
await openSiteDataSettingsDialog();
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogFrame = doc.getElementById("dialogFrame");
+ let dialog = content.gSubDialog._topDialog;
+ let dialogFrame = dialog._frame;
let frameDoc = dialogFrame.contentDocument;
let siteItems = frameDoc.getElementsByTagName("richlistitem");
@@ -280,8 +280,8 @@ add_task(async function() {
await updatePromise;
await openSiteDataSettingsDialog();
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogFrame = doc.getElementById("dialogFrame");
+ let dialog = content.gSubDialog._topDialog;
+ let dialogFrame = dialog._frame;
let frameDoc = dialogFrame.contentDocument;
let hostCol = frameDoc.getElementById("hostCol");
let usageCol = frameDoc.getElementById("usageCol");
@@ -406,7 +406,7 @@ add_task(async function() {
await openSiteDataSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let frameDoc = content.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
diff --git a/browser/components/preferences/in-content-new/tests/browser_siteData2.js b/browser/components/preferences/in-content-new/tests/browser_siteData2.js
index 13770d59f777..c8db58fb7954 100644
--- a/browser/components/preferences/in-content-new/tests/browser_siteData2.js
+++ b/browser/components/preferences/in-content-new/tests/browser_siteData2.js
@@ -6,11 +6,11 @@ const { DownloadUtils } = Cu.import("resource://gre/modules/DownloadUtils.jsm",
function promiseSettingsDialogClose() {
return new Promise(resolve => {
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogOverlay = doc.getElementById("dialogOverlay");
- let win = content.gSubDialog._frame.contentWindow;
- win.addEventListener("unload", function unload() {
- if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
+ let win = gBrowser.selectedBrowser.contentWindow;
+ let dialogOverlay = win.gSubDialog._topDialog._overlay;
+ let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
+ dialogWin.addEventListener("unload", function unload() {
+ if (dialogWin.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
@@ -55,6 +55,7 @@ add_task(async function() {
await updatePromise;
await openSiteDataSettingsDialog();
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
@@ -66,7 +67,7 @@ add_task(async function() {
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -78,7 +79,7 @@ add_task(async function() {
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -92,7 +93,7 @@ add_task(async function() {
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSiteDataManagerSitesUpdated();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -107,7 +108,7 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
@@ -118,7 +119,7 @@ add_task(async function() {
}
function assertAllSitesNotListed() {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
@@ -184,6 +185,7 @@ add_task(async function() {
await updatePromise;
await openSiteDataSettingsDialog();
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
@@ -196,7 +198,7 @@ add_task(async function() {
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -208,7 +210,7 @@ add_task(async function() {
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -221,7 +223,7 @@ add_task(async function() {
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -235,7 +237,7 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(hosts) {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
hosts.forEach(host => {
@@ -288,8 +290,9 @@ add_task(async function() {
await openSiteDataSettingsDialog();
// Search "foo" to only list foo.com sites
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
searchBox.doCommand();
@@ -349,7 +352,8 @@ add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
await updatedPromise;
await openSiteDataSettingsDialog();
- let dialogFrame = gBrowser.selectedBrowser.contentDocument.getElementById("dialogFrame");
+ let win = gBrowser.selectedBrowser.contentWindow;
+ let dialogFrame = win.gSubDialog._topDialog._frame;
let frameDoc = dialogFrame.contentDocument;
let siteItems = frameDoc.getElementsByTagName("richlistitem");
diff --git a/browser/components/preferences/in-content-new/tests/browser_subdialogs.js b/browser/components/preferences/in-content-new/tests/browser_subdialogs.js
index 109ae2853494..2c1802f1c3b2 100644
--- a/browser/components/preferences/in-content-new/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content-new/tests/browser_subdialogs.js
@@ -17,8 +17,8 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
return ContentTask.spawn(browser, {url, domcontentloadedFnStr}, async function(args) {
let rv = { acceptCount: 0 };
let win = content.window;
- let subdialog = win.gSubDialog;
- subdialog.open(args.url, null, rv);
+ content.gSubDialog.open(args.url, null, rv);
+ let subdialog = content.gSubDialog._topDialog;
info("waiting for subdialog DOMFrameContentLoaded");
await ContentTaskUtils.waitForEvent(win, "DOMFrameContentLoaded", true);
@@ -29,7 +29,7 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
}
info("waiting for subdialog load");
- await ContentTaskUtils.waitForEvent(subdialog._frame, "load");
+ await ContentTaskUtils.waitForEvent(subdialog._overlay, "dialogopen");
info("subdialog window is loaded");
let expectedStyleSheetURLs = subdialog._injectedStyleSheets.slice(0);
@@ -52,9 +52,17 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
}
async function close_subdialog_and_test_generic_end_state(browser, closingFn, closingButton, acceptCount, options) {
+ let getDialogsCount = () => {
+ return ContentTask.spawn(browser, null, () =>
+ content.window.gSubDialog._dialogs.length);
+ };
+ let getStackChildrenCount = () => {
+ return ContentTask.spawn(browser, null, () =>
+ content.window.gSubDialog._dialogStack.children.length);
+ };
let dialogclosingPromise = ContentTask.spawn(browser, {closingButton, acceptCount}, async function(expectations) {
let win = content.window;
- let subdialog = win.gSubDialog;
+ let subdialog = win.gSubDialog._topDialog;
let frame = subdialog._frame;
info("waiting for dialogclosing");
let closingEvent =
@@ -76,7 +84,8 @@ async function close_subdialog_and_test_generic_end_state(browser, closingFn, cl
Assert.equal(actualAcceptCount, expectations.acceptCount,
"should be 1 if accepted, 0 if canceled, undefined if closed w/out button");
});
-
+ let initialDialogsCount = await getDialogsCount();
+ let initialStackChildrenCount = await getStackChildrenCount();
if (options && options.runClosingFnOutsideOfContentTask) {
await closingFn();
} else {
@@ -84,6 +93,12 @@ async function close_subdialog_and_test_generic_end_state(browser, closingFn, cl
}
await dialogclosingPromise;
+ let endDialogsCount = await getDialogsCount();
+ let endStackChildrenCount = await getStackChildrenCount();
+ Assert.equal(initialDialogsCount - 1, endDialogsCount,
+ "dialog count should decrease by 1");
+ Assert.equal(initialStackChildrenCount - 1, endStackChildrenCount,
+ "stack children count should decrease by 1");
}
let tab;
@@ -97,27 +112,28 @@ add_task(async function check_titlebar_focus_returnval_titlechanges_accepting()
let domtitlechangedPromise = BrowserTestUtils.waitForEvent(tab.linkedBrowser, "DOMTitleChanged");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let dialog = content.window.gSubDialog._frame.contentWindow;
- let dialogTitleElement = content.document.getElementById("dialogTitle");
+ let dialog = content.window.gSubDialog._topDialog;
+ let dialogWin = dialog._frame.contentWindow;
+ let dialogTitleElement = dialog._titleElement;
Assert.equal(dialogTitleElement.textContent, "Sample sub-dialog",
"Title should be correct initially");
- Assert.equal(dialog.document.activeElement.value, "Default text",
+ Assert.equal(dialogWin.document.activeElement.value, "Default text",
"Textbox with correct text is focused");
- dialog.document.title = "Updated title";
+ dialogWin.document.title = "Updated title";
});
info("waiting for DOMTitleChanged event");
await domtitlechangedPromise;
ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let dialogTitleElement = content.document.getElementById("dialogTitle");
+ let dialogTitleElement = content.window.gSubDialog._topDialog._titleElement;
Assert.equal(dialogTitleElement.textContent, "Updated title",
"subdialog should have updated title");
});
// Accept the dialog
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
@@ -126,7 +142,7 @@ add_task(async function check_canceling_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.cancelDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.cancelDialog(); },
"cancel", 0);
});
@@ -134,20 +150,40 @@ add_task(async function check_reopening_dialog() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
info("opening another dialog which will close the first");
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, "", gDialogURL2);
- info("closing as normal");
+
+ ContentTask.spawn(tab.linkedBrowser, null, async function() {
+ let win = content.window;
+ let dialogs = win.gSubDialog._dialogs;
+ let lowerDialog = dialogs[0];
+ let topDialog = dialogs[1];
+ Assert.equal(dialogs.length, 2, "There should be two visible dialogs");
+ Assert.equal(win.getComputedStyle(topDialog._overlay).visibility, "visible",
+ "The top dialog should be visible");
+ Assert.equal(win.getComputedStyle(lowerDialog._overlay).visibility, "visible",
+ "The lower dialog should be visible");
+ Assert.equal(win.getComputedStyle(topDialog._overlay).backgroundColor, "rgba(0, 0, 0, 0.5)",
+ "The top dialog should have a semi-transparent overlay");
+ Assert.equal(win.getComputedStyle(lowerDialog._overlay).backgroundColor, "rgba(0, 0, 0, 0)",
+ "The lower dialog should not have an overlay");
+ });
+
+ info("closing two dialogs");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ "accept", 1);
+ await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
add_task(async function check_opening_while_closing() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
info("closing");
- content.window.gSubDialog.close();
+ content.window.gSubDialog._topDialog.close();
info("reopening immediately after calling .close()");
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
@@ -157,7 +193,7 @@ add_task(async function window_close_on_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
@@ -166,7 +202,7 @@ add_task(async function click_close_button_on_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { return BrowserTestUtils.synthesizeMouseAtCenter("#dialogClose", {}, tab.linkedBrowser); },
+ function() { return BrowserTestUtils.synthesizeMouseAtCenter(".dialogClose", {}, tab.linkedBrowser); },
null, 0, {runClosingFnOutsideOfContentTask: true});
});
@@ -176,7 +212,7 @@ add_task(async function background_click_should_close_dialog() {
// Clicking on an inactive part of dialog itself should not close the dialog.
// Click the dialog title bar here to make sure nothing happens.
info("clicking the dialog title bar");
- BrowserTestUtils.synthesizeMouseAtCenter("#dialogTitle", {}, tab.linkedBrowser);
+ BrowserTestUtils.synthesizeMouseAtCenter(".dialogTitle", {}, tab.linkedBrowser);
// Close the dialog by clicking on the overlay background. Simulate a click
// at point (2,2) instead of (0,0) so we are sure we're clicking on the
@@ -193,7 +229,7 @@ add_task(async function back_navigation_on_subdialog_should_close_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.goBack(); },
+ function() { content.window.gSubDialog._topDialog._frame.goBack(); },
null, undefined);
});
@@ -219,7 +255,7 @@ add_task(async function correct_width_and_height_should_be_used_for_dialog() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frameStyle = content.window.gSubDialog._frame.style;
+ let frameStyle = content.window.gSubDialog._topDialog._frame.style;
Assert.equal(frameStyle.width, "32em",
"Width should be set on the frame from the dialog");
Assert.equal(frameStyle.height, "5em",
@@ -227,13 +263,13 @@ add_task(async function correct_width_and_height_should_be_used_for_dialog() {
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight() {
let oldHeight = await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
let doc = frame.contentDocument;
let scrollHeight = doc.documentElement.scrollHeight;
doc.documentElement.style.removeProperty("height");
@@ -253,7 +289,7 @@ add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight
});
await ContentTask.spawn(tab.linkedBrowser, oldHeight, async function(contentOldHeight) {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
let docEl = frame.contentDocument.documentElement;
Assert.equal(frame.style.width, "32em",
"Width should be set on the frame from the dialog");
@@ -264,37 +300,37 @@ add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function dialog_too_tall_should_get_reduced_in_height() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
frame.contentDocument.documentElement.style.height = "100000px";
});
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
Assert.equal(frame.style.width, "32em", "Width should be set on the frame from the dialog");
Assert.ok(parseInt(frame.style.height, 10) < content.window.innerHeight,
"Height on the frame should be smaller than window's innerHeight");
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function scrollWidth_and_scrollHeight_from_subdialog_should_size_the_browser() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
frame.contentDocument.documentElement.style.removeProperty("height");
frame.contentDocument.documentElement.style.removeProperty("width");
});
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
Assert.ok(frame.style.width.endsWith("px"),
"Width (" + frame.style.width + ") should be set to a px value of the scrollWidth from the dialog");
Assert.ok(frame.style.height.endsWith("px"),
@@ -302,7 +338,7 @@ add_task(async function scrollWidth_and_scrollHeight_from_subdialog_should_size_
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
diff --git a/browser/components/preferences/in-content-new/tests/head.js b/browser/components/preferences/in-content-new/tests/head.js
index e48f5b7b83f1..cd92fbecd565 100644
--- a/browser/components/preferences/in-content-new/tests/head.js
+++ b/browser/components/preferences/in-content-new/tests/head.js
@@ -45,20 +45,20 @@ function openAndLoadSubDialog(aURL, aFeatures = null, aParams = null, aClosingCa
function promiseLoadSubDialog(aURL) {
return new Promise((resolve, reject) => {
- content.gSubDialog._frame.addEventListener("load", function load(aEvent) {
- if (aEvent.target.contentWindow.location == "about:blank")
+ content.gSubDialog._dialogStack.addEventListener("dialogopen", function dialogopen(aEvent) {
+ if (aEvent.detail.dialog._frame.contentWindow.location == "about:blank")
return;
- content.gSubDialog._frame.removeEventListener("load", load);
+ content.gSubDialog._dialogStack.removeEventListener("dialogopen", dialogopen);
- is(content.gSubDialog._frame.contentWindow.location.toString(), aURL,
+ is(aEvent.detail.dialog._frame.contentWindow.location.toString(), aURL,
"Check the proper URL is loaded");
// Check visibility
- is_element_visible(content.gSubDialog._overlay, "Overlay is visible");
+ is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
// Check that stylesheets were injected
- let expectedStyleSheetURLs = content.gSubDialog._injectedStyleSheets.slice(0);
- for (let styleSheet of content.gSubDialog._frame.contentDocument.styleSheets) {
+ let expectedStyleSheetURLs = aEvent.detail.dialog._injectedStyleSheets.slice(0);
+ for (let styleSheet of aEvent.detail.dialog._frame.contentDocument.styleSheets) {
let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
if (i >= 0) {
info("found " + styleSheet.href);
@@ -67,7 +67,7 @@ function promiseLoadSubDialog(aURL) {
}
is(expectedStyleSheetURLs.length, 0, "All expectedStyleSheetURLs should have been found");
- resolve(content.gSubDialog._frame.contentWindow);
+ resolve(aEvent.detail.dialog._frame.contentWindow);
});
});
}
@@ -193,7 +193,7 @@ function promiseSiteDataManagerSitesUpdated() {
function openSiteDataSettingsDialog() {
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
- let dialogOverlay = doc.getElementById("dialogOverlay");
+ let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
@@ -204,7 +204,7 @@ function openSiteDataSettingsDialog() {
}
function assertSitesListed(doc, hosts) {
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let frameDoc = content.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
diff --git a/browser/components/preferences/in-content/preferences.xul b/browser/components/preferences/in-content/preferences.xul
index 88fa7e72184a..70933e6a9ff8 100644
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -202,23 +202,22 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/components/preferences/in-content/subdialogs.js b/browser/components/preferences/in-content/subdialogs.js
index 59b475d1643f..06d0dee82545 100644
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -7,11 +7,38 @@
"use strict";
-var gSubDialog = {
+/**
+ * SubDialog constructor creates a new subdialog from a template and appends
+ * it to the parentElement.
+ * @param {DOMNode} template: The template is copied to create a new dialog.
+ * @param {DOMNode} parentElement: New dialog is appended onto parentElement.
+ * @param {String} id: A unique identifier for the dialog.
+ */
+function SubDialog({template, parentElement, id}) {
+ this._id = id;
+
+ this._overlay = template.cloneNode(true);
+ this._frame = this._overlay.querySelector(".dialogFrame");
+ this._box = this._overlay.querySelector(".dialogBox");
+ this._closeButton = this._overlay.querySelector(".dialogClose");
+ this._titleElement = this._overlay.querySelector(".dialogTitle");
+
+ this._overlay.id = `dialogOverlay-${id}`;
+ this._frame.setAttribute("name", `dialogFrame-${id}`);
+ this._frameCreated = new Promise(resolve => {
+ this._frame.addEventListener("load", resolve, {once: true});
+ });
+
+ parentElement.appendChild(this._overlay);
+ this._overlay.hidden = false;
+}
+
+SubDialog.prototype = {
_closingCallback: null,
_closingEvent: null,
_isClosing: false,
_frame: null,
+ _frameCreated: null,
_overlay: null,
_box: null,
_openedURL: null,
@@ -22,18 +49,15 @@ var gSubDialog = {
"chrome://browser/skin/preferences/in-content/dialog.css",
],
_resizeObserver: null,
-
- init() {
- this._frame = document.getElementById("dialogFrame");
- this._overlay = document.getElementById("dialogOverlay");
- this._box = document.getElementById("dialogBox");
- this._closeButton = document.getElementById("dialogClose");
- },
+ _template: null,
+ _id: null,
+ _titleElement: null,
+ _closeButton: null,
updateTitle(aEvent) {
- if (aEvent.target != gSubDialog._frame.contentDocument)
+ if (aEvent.target != this._frame.contentDocument)
return;
- document.getElementById("dialogTitle").textContent = gSubDialog._frame.contentDocument.title;
+ this._titleElement.textContent = this._frame.contentDocument.title;
},
injectXMLStylesheet(aStylesheetURL) {
@@ -45,11 +69,9 @@ var gSubDialog = {
this._frame.contentDocument.documentElement);
},
- open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
- // If we're already open/opening on this URL, do nothing.
- if (this._openedURL == aURL && !this._isClosing) {
- return;
- }
+ async open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
+ // Wait until frame is ready to prevent browser crash in tests
+ await this._frameCreated;
// If we're open on some (other) URL or we're closing, open when closing has finished.
if (this._openedURL || this._isClosing) {
if (!this._isClosing) {
@@ -64,7 +86,7 @@ var gSubDialog = {
this._addDialogEventListeners();
let features = (aFeatures ? aFeatures + "," : "") + "resizable,dialog=no,centerscreen";
- let dialog = window.openDialog(aURL, "dialogFrame", features, aParams);
+ let dialog = window.openDialog(aURL, `dialogFrame-${this._id}`, features, aParams);
if (aClosingCallback) {
this._closingCallback = aClosingCallback.bind(dialog);
}
@@ -109,6 +131,11 @@ var gSubDialog = {
this._box.style.removeProperty("min-height");
this._box.style.removeProperty("min-width");
+ this._overlay.dispatchEvent(new CustomEvent("dialogclose", {
+ bubbles: true,
+ detail: { dialog: this },
+ }));
+
setTimeout(() => {
// Unload the dialog after the event listeners run so that the load of about:blank isn't
// cancelled by the ESC .
@@ -185,32 +212,32 @@ var gSubDialog = {
this._frame.contentWindow.addEventListener("dialogclosing", this);
let oldResizeBy = this._frame.contentWindow.resizeBy;
- this._frame.contentWindow.resizeBy = function(resizeByWidth, resizeByHeight) {
+ this._frame.contentWindow.resizeBy = (resizeByWidth, resizeByHeight) => {
// Only handle resizeByHeight currently.
- let frameHeight = gSubDialog._frame.clientHeight;
- let boxMinHeight = parseFloat(getComputedStyle(gSubDialog._box).minHeight, 10);
+ let frameHeight = this._frame.clientHeight;
+ let boxMinHeight = parseFloat(getComputedStyle(this._box).minHeight, 10);
- gSubDialog._frame.style.height = (frameHeight + resizeByHeight) + "px";
- gSubDialog._box.style.minHeight = (boxMinHeight + resizeByHeight) + "px";
+ this._frame.style.height = (frameHeight + resizeByHeight) + "px";
+ this._box.style.minHeight = (boxMinHeight + resizeByHeight) + "px";
- oldResizeBy.call(gSubDialog._frame.contentWindow, resizeByWidth, resizeByHeight);
+ oldResizeBy.call(this._frame.contentWindow, resizeByWidth, resizeByHeight);
};
// Make window.close calls work like dialog closing.
let oldClose = this._frame.contentWindow.close;
- this._frame.contentWindow.close = function() {
- var closingEvent = gSubDialog._closingEvent;
+ this._frame.contentWindow.close = () => {
+ var closingEvent = this._closingEvent;
if (!closingEvent) {
closingEvent = new CustomEvent("dialogclosing", {
bubbles: true,
detail: { button: null },
});
- gSubDialog._frame.contentWindow.dispatchEvent(closingEvent);
+ this._frame.contentWindow.dispatchEvent(closingEvent);
}
- gSubDialog.close(closingEvent);
- oldClose.call(gSubDialog._frame.contentWindow);
+ this.close(closingEvent);
+ oldClose.call(this._frame.contentWindow);
};
// XXX: Hack to make focus during the dialog's load functions work. Make the element visible
@@ -293,6 +320,10 @@ var gSubDialog = {
(boxVerticalBorder + groupBoxTitleHeight + boxVerticalPadding) +
"px + " + frameMinHeight + ")";
+ this._overlay.dispatchEvent(new CustomEvent("dialogopen", {
+ bubbles: true,
+ detail: { dialog: this },
+ }));
this._overlay.style.visibility = "visible";
this._overlay.style.opacity = ""; // XXX: focus hack continued from _onContentLoaded
@@ -305,7 +336,7 @@ var gSubDialog = {
},
_onResize(mutations) {
- let frame = gSubDialog._frame;
+ let frame = this._frame;
// The width and height styles are needed for the initial
// layout of the frame, but afterward they need to be removed
// or their presence will restrict the contents of the
@@ -348,13 +379,13 @@ var gSubDialog = {
let fm = Services.focus;
- function isLastFocusableElement(el) {
+ let isLastFocusableElement = el => {
// XXXgijs unfortunately there is no way to get the last focusable element without asking
// the focus manager to move focus to it.
- let rv = el == fm.moveFocus(gSubDialog._frame.contentWindow, null, fm.MOVEFOCUS_LAST, 0);
+ let rv = el == fm.moveFocus(this._frame.contentWindow, null, fm.MOVEFOCUS_LAST, 0);
fm.setFocus(el, 0);
return rv;
- }
+ };
let forward = !aEvent.shiftKey;
// check if focus is leaving the frame (incl. the close button):
@@ -449,3 +480,104 @@ var gSubDialog = {
.chromeEventHandler;
},
};
+
+var gSubDialog = {
+ /**
+ * New dialogs are stacked on top of the existing ones, and they are pushed
+ * to the end of the _dialogs array.
+ * @type {Array}
+ */
+ _dialogs: [],
+ _dialogStack: null,
+ _dialogTemplate: null,
+ _nextDialogID: 0,
+ _preloadDialog: null,
+ get _topDialog() {
+ return this._dialogs.length > 0 ? this._dialogs[this._dialogs.length - 1] : undefined;
+ },
+
+ init() {
+ this._dialogStack = document.getElementById("dialogStack");
+ this._dialogTemplate = document.getElementById("dialogTemplate");
+ this._preloadDialog = new SubDialog({template: this._dialogTemplate,
+ parentElement: this._dialogStack,
+ id: this._nextDialogID++});
+ },
+
+ open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
+ // If we're already open/opening on this URL, do nothing.
+ if (this._topDialog && this._topDialog._openedURL == aURL) {
+ return;
+ }
+
+ this._preloadDialog.open(aURL, aFeatures, aParams, aClosingCallback);
+ this._dialogs.push(this._preloadDialog);
+ this._preloadDialog = new SubDialog({template: this._dialogTemplate,
+ parentElement: this._dialogStack,
+ id: this._nextDialogID++});
+
+ if (this._dialogs.length == 1) {
+ this._dialogStack.hidden = false;
+ this._ensureStackEventListeners();
+ }
+ },
+
+ close() {
+ this._topDialog.close();
+ },
+
+ handleEvent(aEvent) {
+ switch (aEvent.type) {
+ case "dialogopen": {
+ this._onDialogOpen();
+ break;
+ }
+ case "dialogclose": {
+ this._onDialogClose(aEvent.detail.dialog);
+ break;
+ }
+ }
+ },
+
+ _onDialogOpen() {
+ let lowerDialog = this._dialogs.length > 1 ? this._dialogs[this._dialogs.length - 2] : undefined;
+ if (lowerDialog) {
+ lowerDialog._overlay.removeAttribute("topmost");
+ lowerDialog._removeDialogEventListeners();
+ }
+ },
+
+ _onDialogClose(dialog) {
+ let fm = Services.focus;
+ if (this._topDialog == dialog) {
+ // XXX: When a top-most dialog is closed, we reuse the closed dialog and
+ // remove the preloadDialog. This is a temporary solution before we
+ // rewrite all the test cases in Bug 1359023.
+ this._preloadDialog._overlay.remove();
+ this._preloadDialog = this._dialogs.pop();
+ } else {
+ dialog._overlay.remove();
+ this._dialogs.splice(this._dialogs.indexOf(dialog), 1);
+ }
+
+ if (this._topDialog) {
+ fm.moveFocus(this._topDialog._frame.contentWindow, null, fm.MOVEFOCUS_FIRST, fm.FLAG_BYKEY);
+ this._topDialog._overlay.setAttribute("topmost", true);
+ this._topDialog._addDialogEventListeners();
+ } else {
+ fm.moveFocus(window, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
+ this._dialogStack.hidden = true;
+ this._removeStackEventListeners();
+ }
+ },
+
+ _ensureStackEventListeners() {
+ this._dialogStack.addEventListener("dialogopen", this);
+ this._dialogStack.addEventListener("dialogclose", this);
+ },
+
+ _removeStackEventListeners() {
+ this._dialogStack.removeEventListener("dialogopen", this);
+ this._dialogStack.removeEventListener("dialogclose", this);
+ },
+};
diff --git a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
index 1adabcf490d9..cb4fd47a001a 100644
--- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
@@ -127,9 +127,10 @@ const cacheUsageGetter = {
};
function openSettingsDialog() {
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
- let dialogOverlay = doc.getElementById("dialogOverlay");
+ let dialogOverlay = win.gSubDialog._preloadDialog._overlay;
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
@@ -141,11 +142,11 @@ function openSettingsDialog() {
function promiseSettingsDialogClose() {
return new Promise(resolve => {
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogOverlay = doc.getElementById("dialogOverlay");
- let win = content.gSubDialog._frame.contentWindow;
- win.addEventListener("unload", function unload() {
- if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
+ let win = gBrowser.selectedBrowser.contentWindow;
+ let dialogOverlay = win.gSubDialog._topDialog._overlay;
+ let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
+ dialogWin.addEventListener("unload", function unload() {
+ if (dialogWin.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
@@ -164,7 +165,8 @@ function promiseCookiesCleared() {
}
function assertSitesListed(doc, hosts) {
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let win = gBrowser.selectedBrowser.contentWindow;
+ let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
@@ -221,7 +223,7 @@ add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatedPromise;
await openSettingsDialog();
- let dialogFrame = gBrowser.selectedBrowser.contentDocument.getElementById("dialogFrame");
+ let dialogFrame = content.gSubDialog._topDialog._frame;
let frameDoc = dialogFrame.contentDocument;
let siteItems = frameDoc.getElementsByTagName("richlistitem");
@@ -262,8 +264,7 @@ add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatedPromise;
await openSettingsDialog();
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogFrame = doc.getElementById("dialogFrame");
+ let dialogFrame = content.gSubDialog._topDialog._frame;
let frameDoc = dialogFrame.contentDocument;
let siteItems = frameDoc.getElementsByTagName("richlistitem");
@@ -431,8 +432,9 @@ add_task(async function() {
await updatePromise;
await openSettingsDialog();
- let doc = gBrowser.selectedBrowser.contentDocument;
- let dialogFrame = doc.getElementById("dialogFrame");
+ let win = gBrowser.selectedBrowser.contentWindow;
+ let dialog = win.gSubDialog._topDialog;
+ let dialogFrame = dialog._frame;
let frameDoc = dialogFrame.contentDocument;
let hostCol = frameDoc.getElementById("hostCol");
let usageCol = frameDoc.getElementById("usageCol");
@@ -556,8 +558,9 @@ add_task(async function() {
await updatePromise;
await openSettingsDialog();
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
@@ -613,6 +616,7 @@ add_task(async function() {
await updatePromise;
await openSettingsDialog();
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
@@ -624,7 +628,7 @@ add_task(async function() {
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -636,7 +640,7 @@ add_task(async function() {
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -650,7 +654,7 @@ add_task(async function() {
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSitesUpdated();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
@@ -665,7 +669,7 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
@@ -676,7 +680,7 @@ add_task(async function() {
}
function assertAllSitesNotListed() {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
@@ -742,6 +746,7 @@ add_task(async function() {
await updatePromise;
await openSettingsDialog();
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
@@ -754,7 +759,7 @@ add_task(async function() {
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -766,7 +771,7 @@ add_task(async function() {
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -779,7 +784,7 @@ add_task(async function() {
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
@@ -793,7 +798,7 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(hosts) {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
hosts.forEach(host => {
@@ -846,8 +851,9 @@ add_task(async function() {
await openSettingsDialog();
// Search "foo" to only list foo.com sites
+ let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
- let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
searchBox.doCommand();
diff --git a/browser/components/preferences/in-content/tests/browser_advanced_update.js b/browser/components/preferences/in-content/tests/browser_advanced_update.js
index 3660f4c485a3..4d57dbdd756e 100644
--- a/browser/components/preferences/in-content/tests/browser_advanced_update.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_update.js
@@ -116,15 +116,16 @@ add_task(async function() {
let doc = gBrowser.selectedBrowser.contentDocument;
let showBtn = doc.getElementById("showUpdateHistory");
- let dialogOverlay = doc.getElementById("dialogOverlay");
+ let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
// Test the dialog window opens
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
+ let promiseSubDialogLoaded = promiseLoadSubDialog("chrome://mozapps/content/update/history.xul");
showBtn.doCommand();
- await promiseLoadSubDialog("chrome://mozapps/content/update/history.xul");
+ await promiseSubDialogLoaded;
is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
- let dialogFrame = doc.getElementById("dialogFrame");
+ let dialogFrame = dialogOverlay.querySelector(".dialogFrame");
let frameDoc = dialogFrame.contentDocument;
let updates = frameDoc.querySelectorAll("update");
@@ -146,7 +147,7 @@ add_task(async function() {
}
// Test the dialog window closes
- let closeBtn = doc.getElementById("dialogClose");
+ let closeBtn = dialogOverlay.querySelector(".dialogClose");
closeBtn.doCommand();
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
diff --git a/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js b/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
index 3d3f128249f7..659208a16b0e 100644
--- a/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
+++ b/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
@@ -20,8 +20,9 @@ add_task(async function() {
let fontSizeField = doc.getElementById("defaultFontSize");
is(fontSizeField.value, defaultFontSize, "Font size should be set correctly.");
+ let promiseSubDialogLoaded = promiseLoadSubDialog("chrome://browser/content/preferences/fonts.xul");
doc.getElementById("advancedFonts").click();
- let win = await promiseLoadSubDialog("chrome://browser/content/preferences/fonts.xul");
+ let win = await promiseSubDialogLoaded;
doc = win.document;
// Simulate a dumb font backend.
diff --git a/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js b/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
index 10fd41a0a98f..617d9401cc74 100644
--- a/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
+++ b/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
@@ -339,10 +339,12 @@ var testRunner = {
let historyMode = doc.getElementById("historyMode");
historyMode.value = "custom";
historyMode.doCommand();
+
+ let promiseSubDialogLoaded =
+ promiseLoadSubDialog("chrome://browser/content/preferences/permissions.xul");
doc.getElementById("cookieExceptions").doCommand();
- let subDialogURL = "chrome://browser/content/preferences/permissions.xul";
- promiseLoadSubDialog(subDialogURL).then(function(win) {
+ promiseSubDialogLoaded.then(function(win) {
helperFunctions.windowLoad(win);
});
});
diff --git a/browser/components/preferences/in-content/tests/browser_subdialogs.js b/browser/components/preferences/in-content/tests/browser_subdialogs.js
index 109ae2853494..2c1802f1c3b2 100644
--- a/browser/components/preferences/in-content/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content/tests/browser_subdialogs.js
@@ -17,8 +17,8 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
return ContentTask.spawn(browser, {url, domcontentloadedFnStr}, async function(args) {
let rv = { acceptCount: 0 };
let win = content.window;
- let subdialog = win.gSubDialog;
- subdialog.open(args.url, null, rv);
+ content.gSubDialog.open(args.url, null, rv);
+ let subdialog = content.gSubDialog._topDialog;
info("waiting for subdialog DOMFrameContentLoaded");
await ContentTaskUtils.waitForEvent(win, "DOMFrameContentLoaded", true);
@@ -29,7 +29,7 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
}
info("waiting for subdialog load");
- await ContentTaskUtils.waitForEvent(subdialog._frame, "load");
+ await ContentTaskUtils.waitForEvent(subdialog._overlay, "dialogopen");
info("subdialog window is loaded");
let expectedStyleSheetURLs = subdialog._injectedStyleSheets.slice(0);
@@ -52,9 +52,17 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
}
async function close_subdialog_and_test_generic_end_state(browser, closingFn, closingButton, acceptCount, options) {
+ let getDialogsCount = () => {
+ return ContentTask.spawn(browser, null, () =>
+ content.window.gSubDialog._dialogs.length);
+ };
+ let getStackChildrenCount = () => {
+ return ContentTask.spawn(browser, null, () =>
+ content.window.gSubDialog._dialogStack.children.length);
+ };
let dialogclosingPromise = ContentTask.spawn(browser, {closingButton, acceptCount}, async function(expectations) {
let win = content.window;
- let subdialog = win.gSubDialog;
+ let subdialog = win.gSubDialog._topDialog;
let frame = subdialog._frame;
info("waiting for dialogclosing");
let closingEvent =
@@ -76,7 +84,8 @@ async function close_subdialog_and_test_generic_end_state(browser, closingFn, cl
Assert.equal(actualAcceptCount, expectations.acceptCount,
"should be 1 if accepted, 0 if canceled, undefined if closed w/out button");
});
-
+ let initialDialogsCount = await getDialogsCount();
+ let initialStackChildrenCount = await getStackChildrenCount();
if (options && options.runClosingFnOutsideOfContentTask) {
await closingFn();
} else {
@@ -84,6 +93,12 @@ async function close_subdialog_and_test_generic_end_state(browser, closingFn, cl
}
await dialogclosingPromise;
+ let endDialogsCount = await getDialogsCount();
+ let endStackChildrenCount = await getStackChildrenCount();
+ Assert.equal(initialDialogsCount - 1, endDialogsCount,
+ "dialog count should decrease by 1");
+ Assert.equal(initialStackChildrenCount - 1, endStackChildrenCount,
+ "stack children count should decrease by 1");
}
let tab;
@@ -97,27 +112,28 @@ add_task(async function check_titlebar_focus_returnval_titlechanges_accepting()
let domtitlechangedPromise = BrowserTestUtils.waitForEvent(tab.linkedBrowser, "DOMTitleChanged");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let dialog = content.window.gSubDialog._frame.contentWindow;
- let dialogTitleElement = content.document.getElementById("dialogTitle");
+ let dialog = content.window.gSubDialog._topDialog;
+ let dialogWin = dialog._frame.contentWindow;
+ let dialogTitleElement = dialog._titleElement;
Assert.equal(dialogTitleElement.textContent, "Sample sub-dialog",
"Title should be correct initially");
- Assert.equal(dialog.document.activeElement.value, "Default text",
+ Assert.equal(dialogWin.document.activeElement.value, "Default text",
"Textbox with correct text is focused");
- dialog.document.title = "Updated title";
+ dialogWin.document.title = "Updated title";
});
info("waiting for DOMTitleChanged event");
await domtitlechangedPromise;
ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let dialogTitleElement = content.document.getElementById("dialogTitle");
+ let dialogTitleElement = content.window.gSubDialog._topDialog._titleElement;
Assert.equal(dialogTitleElement.textContent, "Updated title",
"subdialog should have updated title");
});
// Accept the dialog
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
@@ -126,7 +142,7 @@ add_task(async function check_canceling_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.cancelDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.cancelDialog(); },
"cancel", 0);
});
@@ -134,20 +150,40 @@ add_task(async function check_reopening_dialog() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
info("opening another dialog which will close the first");
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, "", gDialogURL2);
- info("closing as normal");
+
+ ContentTask.spawn(tab.linkedBrowser, null, async function() {
+ let win = content.window;
+ let dialogs = win.gSubDialog._dialogs;
+ let lowerDialog = dialogs[0];
+ let topDialog = dialogs[1];
+ Assert.equal(dialogs.length, 2, "There should be two visible dialogs");
+ Assert.equal(win.getComputedStyle(topDialog._overlay).visibility, "visible",
+ "The top dialog should be visible");
+ Assert.equal(win.getComputedStyle(lowerDialog._overlay).visibility, "visible",
+ "The lower dialog should be visible");
+ Assert.equal(win.getComputedStyle(topDialog._overlay).backgroundColor, "rgba(0, 0, 0, 0.5)",
+ "The top dialog should have a semi-transparent overlay");
+ Assert.equal(win.getComputedStyle(lowerDialog._overlay).backgroundColor, "rgba(0, 0, 0, 0)",
+ "The lower dialog should not have an overlay");
+ });
+
+ info("closing two dialogs");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ "accept", 1);
+ await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
add_task(async function check_opening_while_closing() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
info("closing");
- content.window.gSubDialog.close();
+ content.window.gSubDialog._topDialog.close();
info("reopening immediately after calling .close()");
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentDocument.documentElement.acceptDialog(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentDocument.documentElement.acceptDialog(); },
"accept", 1);
});
@@ -157,7 +193,7 @@ add_task(async function window_close_on_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
@@ -166,7 +202,7 @@ add_task(async function click_close_button_on_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { return BrowserTestUtils.synthesizeMouseAtCenter("#dialogClose", {}, tab.linkedBrowser); },
+ function() { return BrowserTestUtils.synthesizeMouseAtCenter(".dialogClose", {}, tab.linkedBrowser); },
null, 0, {runClosingFnOutsideOfContentTask: true});
});
@@ -176,7 +212,7 @@ add_task(async function background_click_should_close_dialog() {
// Clicking on an inactive part of dialog itself should not close the dialog.
// Click the dialog title bar here to make sure nothing happens.
info("clicking the dialog title bar");
- BrowserTestUtils.synthesizeMouseAtCenter("#dialogTitle", {}, tab.linkedBrowser);
+ BrowserTestUtils.synthesizeMouseAtCenter(".dialogTitle", {}, tab.linkedBrowser);
// Close the dialog by clicking on the overlay background. Simulate a click
// at point (2,2) instead of (0,0) so we are sure we're clicking on the
@@ -193,7 +229,7 @@ add_task(async function back_navigation_on_subdialog_should_close_dialog() {
info("canceling the dialog");
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.goBack(); },
+ function() { content.window.gSubDialog._topDialog._frame.goBack(); },
null, undefined);
});
@@ -219,7 +255,7 @@ add_task(async function correct_width_and_height_should_be_used_for_dialog() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser);
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frameStyle = content.window.gSubDialog._frame.style;
+ let frameStyle = content.window.gSubDialog._topDialog._frame.style;
Assert.equal(frameStyle.width, "32em",
"Width should be set on the frame from the dialog");
Assert.equal(frameStyle.height, "5em",
@@ -227,13 +263,13 @@ add_task(async function correct_width_and_height_should_be_used_for_dialog() {
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight() {
let oldHeight = await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
let doc = frame.contentDocument;
let scrollHeight = doc.documentElement.scrollHeight;
doc.documentElement.style.removeProperty("height");
@@ -253,7 +289,7 @@ add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight
});
await ContentTask.spawn(tab.linkedBrowser, oldHeight, async function(contentOldHeight) {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
let docEl = frame.contentDocument.documentElement;
Assert.equal(frame.style.width, "32em",
"Width should be set on the frame from the dialog");
@@ -264,37 +300,37 @@ add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function dialog_too_tall_should_get_reduced_in_height() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
frame.contentDocument.documentElement.style.height = "100000px";
});
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
Assert.equal(frame.style.width, "32em", "Width should be set on the frame from the dialog");
Assert.ok(parseInt(frame.style.height, 10) < content.window.innerHeight,
"Height on the frame should be smaller than window's innerHeight");
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
add_task(async function scrollWidth_and_scrollHeight_from_subdialog_should_size_the_browser() {
await open_subdialog_and_test_generic_start_state(tab.linkedBrowser, function domcontentloadedFn() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
frame.contentDocument.documentElement.style.removeProperty("height");
frame.contentDocument.documentElement.style.removeProperty("width");
});
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
- let frame = content.window.gSubDialog._frame;
+ let frame = content.window.gSubDialog._topDialog._frame;
Assert.ok(frame.style.width.endsWith("px"),
"Width (" + frame.style.width + ") should be set to a px value of the scrollWidth from the dialog");
Assert.ok(frame.style.height.endsWith("px"),
@@ -302,7 +338,7 @@ add_task(async function scrollWidth_and_scrollHeight_from_subdialog_should_size_
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,
- function() { content.window.gSubDialog._frame.contentWindow.window.close(); },
+ function() { content.window.gSubDialog._topDialog._frame.contentWindow.window.close(); },
null, 0);
});
diff --git a/browser/components/preferences/in-content/tests/head.js b/browser/components/preferences/in-content/tests/head.js
index 96bc8f8cf723..d416121855f5 100644
--- a/browser/components/preferences/in-content/tests/head.js
+++ b/browser/components/preferences/in-content/tests/head.js
@@ -54,20 +54,20 @@ function openAndLoadSubDialog(aURL, aFeatures = null, aParams = null, aClosingCa
function promiseLoadSubDialog(aURL) {
return new Promise((resolve, reject) => {
- content.gSubDialog._frame.addEventListener("load", function load(aEvent) {
- if (aEvent.target.contentWindow.location == "about:blank")
+ content.gSubDialog._dialogStack.addEventListener("dialogopen", function dialogopen(aEvent) {
+ if (aEvent.detail.dialog._frame.contentWindow.location == "about:blank")
return;
- content.gSubDialog._frame.removeEventListener("load", load);
+ content.gSubDialog._dialogStack.removeEventListener("dialogopen", dialogopen);
- is(content.gSubDialog._frame.contentWindow.location.toString(), aURL,
+ is(aEvent.detail.dialog._frame.contentWindow.location.toString(), aURL,
"Check the proper URL is loaded");
// Check visibility
- is_element_visible(content.gSubDialog._overlay, "Overlay is visible");
+ is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
// Check that stylesheets were injected
- let expectedStyleSheetURLs = content.gSubDialog._injectedStyleSheets.slice(0);
- for (let styleSheet of content.gSubDialog._frame.contentDocument.styleSheets) {
+ let expectedStyleSheetURLs = aEvent.detail.dialog._injectedStyleSheets.slice(0);
+ for (let styleSheet of aEvent.detail.dialog._frame.contentDocument.styleSheets) {
let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
if (i >= 0) {
info("found " + styleSheet.href);
@@ -76,7 +76,7 @@ function promiseLoadSubDialog(aURL) {
}
is(expectedStyleSheetURLs.length, 0, "All expectedStyleSheetURLs should have been found");
- resolve(content.gSubDialog._frame.contentWindow);
+ resolve(aEvent.detail.dialog._frame.contentWindow);
});
});
}
diff --git a/browser/extensions/formautofill/content/FormAutofillFrameScript.js b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
index e49a0f333d63..6e01aaa5583d 100644
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -41,10 +41,20 @@ var FormAutofillFrameScript = {
switch (evt.type) {
case "focusin": {
let element = evt.target;
+ let doc = element.ownerDocument;
+
if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
return;
}
- FormAutofillContent.identifyAutofillFields(element.ownerDocument);
+
+ let doIdentifyAutofillFields =
+ () => setTimeout(() => FormAutofillContent.identifyAutofillFields(doc));
+
+ if (doc.readyState === "loading") {
+ doc.addEventListener("DOMContentLoaded", doIdentifyAutofillFields, {once: true});
+ } else {
+ doIdentifyAutofillFields();
+ }
break;
}
}
diff --git a/browser/extensions/formautofill/test/mochitest/formautofill_common.js b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
index 45856217289e..6ae85ed02d30 100644
--- a/browser/extensions/formautofill/test/mochitest/formautofill_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -10,6 +10,14 @@ function setInput(selector, value) {
let input = document.querySelector("input" + selector);
input.value = value;
input.focus();
+
+ // "identifyAutofillFields" is invoked asynchronously in "focusin" event. We
+ // should make sure fields are ready for popup before doing tests.
+ //
+ // TODO: "setTimeout" is used here temporarily because there's no event to
+ // notify us of the state of "identifyAutofillFields" for now. We should
+ // figure out a better way after the heuristics land.
+ return new Promise(resolve => setTimeout(resolve));
}
function checkMenuEntries(expectedValues) {
diff --git a/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js b/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
index 56da0f8cf491..7887d5a5d973 100644
--- a/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
@@ -43,7 +43,6 @@ var ParentUtils = {
},
};
-ParentUtils.cleanUpAddress();
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
addMessageListener("FormAutofillTest:AddAddress", (msg) => {
diff --git a/browser/extensions/formautofill/test/mochitest/mochitest.ini b/browser/extensions/formautofill/test/mochitest/mochitest.ini
index 151ce246916e..15c7f760dcb1 100644
--- a/browser/extensions/formautofill/test/mochitest/mochitest.ini
+++ b/browser/extensions/formautofill/test/mochitest/mochitest.ini
@@ -5,5 +5,5 @@ support-files =
formautofill_common.js
formautofill_parent_utils.js
+[test_autofocus_form.html]
[test_basic_autocomplete_form.html]
-
diff --git a/browser/extensions/formautofill/test/mochitest/test_autofocus_form.html b/browser/extensions/formautofill/test/mochitest/test_autofocus_form.html
new file mode 100644
index 000000000000..880fc4fb214e
--- /dev/null
+++ b/browser/extensions/formautofill/test/mochitest/test_autofocus_form.html
@@ -0,0 +1,86 @@
+
+
+
+
+ Test basic autofill
+
+
+
+
+
+
+
+Form autofill test: autocomplete on an autofocus form
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
index ef1618d57bdb..bd923e4c7d8b 100644
--- a/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
+++ b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
@@ -95,7 +95,7 @@ async function setupFormHistory() {
add_task(async function history_only_menu_checking() {
await setupFormHistory();
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(["1-234-567-890"]);
@@ -105,21 +105,21 @@ add_task(async function history_only_menu_checking() {
add_task(async function check_menu_when_both_existed() {
await setupAddressStorage();
- setInput("#organization", "");
+ await setInput("#organization", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
));
- setInput("#street-address", "");
+ await setInput("#street-address", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address["street-address"], secondary: address.organization})
));
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
@@ -129,7 +129,7 @@ add_task(async function check_menu_when_both_existed() {
// Display history search result if no matched data in addresses.
add_task(async function check_fallback_for_mismatched_field() {
- setInput("#email", "");
+ await setInput("#email", "");
doKey("down");
await expectPopup();
checkMenuEntries(["foo@mozilla.com"]);
@@ -137,7 +137,7 @@ add_task(async function check_fallback_for_mismatched_field() {
// Autofill the address from dropdown menu.
add_task(async function check_fields_after_form_autofill() {
- setInput("#organization", "Moz");
+ await setInput("#organization", "Moz");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
@@ -149,7 +149,7 @@ add_task(async function check_fields_after_form_autofill() {
// Fallback to history search after autofill address.
add_task(async function check_fallback_after_form_autofill() {
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(["1-234-567-890"]);
diff --git a/browser/extensions/screenshots/install.rdf b/browser/extensions/screenshots/install.rdf
index a2102bbb870b..d2a3d5c5c709 100644
--- a/browser/extensions/screenshots/install.rdf
+++ b/browser/extensions/screenshots/install.rdf
@@ -12,7 +12,7 @@
2
- 8.1.0
+ 9.0.0
true
https://pageshot.net/
true
diff --git a/browser/extensions/screenshots/moz.build b/browser/extensions/screenshots/moz.build
index 32560b7506dd..a31c5ea01c73 100644
--- a/browser/extensions/screenshots/moz.build
+++ b/browser/extensions/screenshots/moz.build
@@ -28,6 +28,10 @@ FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales
'webextension/_locales/ach/messages.json'
]
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ar"] += [
+ 'webextension/_locales/ar/messages.json'
+]
+
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["az"] += [
'webextension/_locales/az/messages.json'
]
diff --git a/browser/extensions/screenshots/webextension/_locales/ar/messages.json b/browser/extensions/screenshots/webextension/_locales/ar/messages.json
new file mode 100644
index 000000000000..d2fabc28ac7f
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/ar/messages.json
@@ -0,0 +1,123 @@
+{
+ "addonDescription": {
+ "message": "خذ مقاطع و لقطات من الوب و احفظهم مؤقتًا أو دائمًا."
+ },
+ "addonAuthorsList": {
+ "message": "موزيلا "
+ },
+ "contextMenuLabel": {
+ "message": "خذ لقطة شاشة"
+ },
+ "myShotsLink": {
+ "message": "لقطاتي"
+ },
+ "screenshotInstructions": {
+ "message": "اسحب أو انقر في الصفحة لاختيار منطقة. اضغط ESC للإلغاء."
+ },
+ "saveScreenshotSelectedArea": {
+ "message": "احفظ"
+ },
+ "saveScreenshotVisibleArea": {
+ "message": "احفظ الجزء المرئي"
+ },
+ "saveScreenshotFullPage": {
+ "message": "احفظ كل الصفحة"
+ },
+ "cancelScreenshot": {
+ "message": "ألغِ"
+ },
+ "downloadScreenshot": {
+ "message": "نزّل"
+ },
+ "notificationLinkCopiedTitle": {
+ "message": "نُسخ الرابط"
+ },
+ "notificationLinkCopiedDetails": {
+ "message": "نُسِخَ رابط اللقطة إلى الحافظة. اضغط $META_KEY$-V للصقها.",
+ "placeholders": {
+ "meta_key": {
+ "content": "$1"
+ }
+ }
+ },
+ "requestErrorTitle": {
+ "message": "خارج الخدمة."
+ },
+ "requestErrorDetails": {
+ "message": "تعذّر حفظ لقطتك. رجاء أعد المحاولة فيما بعد."
+ },
+ "connectionErrorTitle": {
+ "message": "تعذّر الاتصال بلقطات شاشتك."
+ },
+ "connectionErrorDetails": {
+ "message": "رجاء فحص اتصال الإنترنت. إذا كان باستطاعتك الاتصال بالإنترنت، فربما هناك عطل مؤقت في خدمة «لقطات شاشة فَيَرفُكس»."
+ },
+ "loginErrorDetails": {
+ "message": "تعذّر حفظ لقطتك لعُطل في خدمة «لقطات شاشة فَيَرفُكس». رجاء إعادة المحاولة لاحقًا."
+ },
+ "unshootablePageErrorTitle": {
+ "message": "تعذّر أخذ لقطة شاشة لهذه الصفحة."
+ },
+ "unshootablePageErrorDetails": {
+ "message": "ليست هذه صفحة وِب قياسية، لذا لا يمكنك أخذ لقطة لها."
+ },
+ "selfScreenshotErrorTitle": {
+ "message": "لا يمكننا أخذ لقطة لصفحة من صفحات «لقطات شاشة فَيَرفُكس»!"
+ },
+ "genericErrorTitle": {
+ "message": "هناك عطل في «لقطات شاشة فَيَرفُكس»."
+ },
+ "genericErrorDetails": {
+ "message": "لسنا متأكدين ما المشكلة. أتمانع إعادة المحاولة أو أخذ لقطة لصفحة أخرى؟"
+ },
+ "tourBodyOne": {
+ "message": "خذ لقطات الشاشة و احفظها و شارطها دون مغادرة فَيَرفُكس."
+ },
+ "tourHeaderTwo": {
+ "message": "التقط ما تريده فقط"
+ },
+ "tourBodyTwo": {
+ "message": "انقر و اسحب لالتقاط جزء معين من الصفحة. يمكنك أيضًا التحويم لإبراز التحديد."
+ },
+ "tourHeaderThree": {
+ "message": "كما تريدها"
+ },
+ "tourBodyThree": {
+ "message": "احفظ اللقطات التي أخذتها على الوب لمشاركتها بسهولة، أو نزّلها على حاسوبك. يمكنك أيضًل النقر على زر ”لقطاتي“ للعثور على كل اللقطات التي أخذتها."
+ },
+ "tourHeaderFour": {
+ "message": "التقط النوافذ أو صفحات كاملة"
+ },
+ "tourBodyFour": {
+ "message": "اختر الأزرار في أعلى اليمين لالتقاط المنطقة المرئية في النافذة أو الصفحة كلها."
+ },
+ "tourSkip": {
+ "message": "تخطَّ"
+ },
+ "tourNext": {
+ "message": "الشريحة التالية"
+ },
+ "tourPrevious": {
+ "message": "الشريحة السابقة"
+ },
+ "tourDone": {
+ "message": "تمّ"
+ },
+ "termsAndPrivacyNoticeCloudServices": {
+ "message": "استخدامك لخدمات «لقطات شاشة فَيَرفُكس» يعني موافقتك على $TERMSANDPRIVACYNOTICETERMSLINK$ و $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+ "placeholders": {
+ "termsandprivacynoticetermslink": {
+ "content": "$1"
+ },
+ "termsandprivacynoticeprivacylink": {
+ "content": "$2"
+ }
+ }
+ },
+ "termsAndPrivacyNoticeTermsLink": {
+ "message": "الشروط"
+ },
+ "termsAndPrivacyNoticyPrivacyLink": {
+ "message": "تنويه الخصوصية"
+ }
+}
\ No newline at end of file
diff --git a/browser/extensions/screenshots/webextension/_locales/de/messages.json b/browser/extensions/screenshots/webextension/_locales/de/messages.json
index c71d73fc8443..34c57e3ff5ec 100644
--- a/browser/extensions/screenshots/webextension/_locales/de/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/de/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Sie können kein Bildschirmfoto einer Firefox-Screenshots-Seite machen!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Ihr Auswahlbereich ist zu klein"
+ },
"genericErrorTitle": {
"message": "Firefox Screenshots funktioniert nicht richtig."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/dsb/messages.json b/browser/extensions/screenshots/webextension/_locales/dsb/messages.json
index 151719f29114..ea306cba5fd8 100644
--- a/browser/extensions/screenshots/webextension/_locales/dsb/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/dsb/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Njamóžośo wobrazowku boka Firefox Screenshots fotografěrowaś!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Waš wuběrk jo pśemały"
+ },
"genericErrorTitle": {
"message": "Hopla! Firefox Screenshots njeźěła."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/en_US/messages.json b/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
index 6202f89a9a57..2d233e959980 100644
--- a/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "You can’t take a shot of a Firefox Screenshots page!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Your selection is too small"
+ },
"genericErrorTitle": {
"message": "Whoa! Firefox Screenshots went haywire."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json b/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
index d2a5891f80b3..4cd41ceb4d12 100644
--- a/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "¡No puedes tomar una captura de la página de capturas de pantalla de Firefox!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Tu selección es demasiado pequeña"
+ },
"genericErrorTitle": {
"message": "¡Oye! Las capturas de pantalla de Firefox salieron mal."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/fr/messages.json b/browser/extensions/screenshots/webextension/_locales/fr/messages.json
index 6eef6f70ef7a..44c9fa59bcef 100644
--- a/browser/extensions/screenshots/webextension/_locales/fr/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/fr/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Vous ne pouvez pas effectuer une capture d’écran d’une page Firefox Screenshots."
},
+ "emptySelectionErrorTitle": {
+ "message": "La zone sélectionnée est trop petite"
+ },
"genericErrorTitle": {
"message": "Firefox Screenshots semble avoir un problème."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/hsb/messages.json b/browser/extensions/screenshots/webextension/_locales/hsb/messages.json
index 174a1112c300..79016c62b096 100644
--- a/browser/extensions/screenshots/webextension/_locales/hsb/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/hsb/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Njemóžeće wobrazowku strony Firefox Screenshots fotografować!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Waš wuběr je přemały"
+ },
"genericErrorTitle": {
"message": "Hopla! Firefox Screenshots njefunguje."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/hu/messages.json b/browser/extensions/screenshots/webextension/_locales/hu/messages.json
index 935252a58b0f..dce33ef67168 100644
--- a/browser/extensions/screenshots/webextension/_locales/hu/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/hu/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Nem készíthet képet a Firefox képernyőképek oldalról!"
},
+ "emptySelectionErrorTitle": {
+ "message": "A kijelölés túl kicsi"
+ },
"genericErrorTitle": {
"message": "Húha! A Firefox képernyőképek megkergült."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/it/messages.json b/browser/extensions/screenshots/webextension/_locales/it/messages.json
index 4b7e802add77..72550f8a2afe 100644
--- a/browser/extensions/screenshots/webextension/_locales/it/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/it/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Non è possibile salvare uno screenshot di una pagina di Firefox Screenshots"
},
+ "emptySelectionErrorTitle": {
+ "message": "L’area selezionata è troppo piccola"
+ },
"genericErrorTitle": {
"message": "Wow! Firefox Screenshots è andato in tilt"
},
diff --git a/browser/extensions/screenshots/webextension/_locales/ja/messages.json b/browser/extensions/screenshots/webextension/_locales/ja/messages.json
index ae78e2d6a3f5..b85cbb71eac6 100644
--- a/browser/extensions/screenshots/webextension/_locales/ja/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ja/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Firefox Screenshots ページのショットは撮れません。"
},
+ "emptySelectionErrorTitle": {
+ "message": "選択範囲が小さすぎます"
+ },
"genericErrorTitle": {
"message": "Firefox Screenshots に問題が発生しました。"
},
diff --git a/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json b/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
index 80aaf33596ba..658601915244 100644
--- a/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
@@ -12,7 +12,7 @@
"message": "Minhas capturas"
},
"screenshotInstructions": {
- "message": "Arraste ou clique na página para selecionar uma área. Pressione ESC para cancelar."
+ "message": "Arraste ou clique na página para selecionar uma região. Pressione ESC para cancelar."
},
"saveScreenshotSelectedArea": {
"message": "Salvar"
@@ -41,7 +41,7 @@
}
},
"requestErrorTitle": {
- "message": "Fora de ordem."
+ "message": "Com defeito."
},
"requestErrorDetails": {
"message": "Desculpa! Não pudemos salvar a sua captura de tela. Por favor, tente novamente mais tarde."
diff --git a/browser/extensions/screenshots/webextension/_locales/sk/messages.json b/browser/extensions/screenshots/webextension/_locales/sk/messages.json
index b03d130267da..30406d66cd4a 100644
--- a/browser/extensions/screenshots/webextension/_locales/sk/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sk/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Nemôžete vytvoriť snímku obrazovky stránky Firefox Screenshots!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Váš výber je príliš malý"
+ },
"genericErrorTitle": {
"message": "Ups! Služba Firefox Screenshots prestala pracovať."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/sl/messages.json b/browser/extensions/screenshots/webextension/_locales/sl/messages.json
index cfd27cb32f23..702789796076 100644
--- a/browser/extensions/screenshots/webextension/_locales/sl/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sl/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Posnetka strani Firefox Screenshots ni mogoče zajeti!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Vaš izbor je premajhen"
+ },
"genericErrorTitle": {
"message": "Uf! Firefox Screenshots se je pokvaril."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/sr/messages.json b/browser/extensions/screenshots/webextension/_locales/sr/messages.json
index e09ffbe4147e..ed925c64df93 100644
--- a/browser/extensions/screenshots/webextension/_locales/sr/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sr/messages.json
@@ -6,7 +6,7 @@
"message": "Mozilla "
},
"contextMenuLabel": {
- "message": "Усликајте екран"
+ "message": "Усликај екран"
},
"myShotsLink": {
"message": "Моји снимци"
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Не можете усликати Firefox Screenshots страницу!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Ваша селекција је премала"
+ },
"genericErrorTitle": {
"message": "Ајој! Firefox Screenshots је пошашавио."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json b/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
index b03b54500052..52351812bd71 100644
--- a/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Du kan inte ta en skärmbild av sidan Firefox Screenshots!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Ditt val är för litet"
+ },
"genericErrorTitle": {
"message": "Oj! Firefox Screenshots verkar inte fungera korrekt."
},
diff --git a/browser/extensions/screenshots/webextension/_locales/te/messages.json b/browser/extensions/screenshots/webextension/_locales/te/messages.json
index 662cc763ea99..f04aa187ffbf 100644
--- a/browser/extensions/screenshots/webextension/_locales/te/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/te/messages.json
@@ -11,6 +11,9 @@
"saveScreenshotSelectedArea": {
"message": "భద్రపరచు"
},
+ "saveScreenshotVisibleArea": {
+ "message": "కనిపించే దానిని బద్రపరచండి"
+ },
"saveScreenshotFullPage": {
"message": "పూర్తి పేజీని భద్రపరచు"
},
@@ -23,9 +26,15 @@
"notificationLinkCopiedTitle": {
"message": "లంకె కాపీ అయింది"
},
+ "requestErrorTitle": {
+ "message": "పని చెయుట లేదు."
+ },
"requestErrorDetails": {
"message": "క్షమిచండి! మీ తెరను భద్రపరచలేకపోయాం. దయచేసి కాసేపాగి మళ్ళీ ప్రయత్నించండి."
},
+ "tourHeaderTwo": {
+ "message": ""
+ },
"tourHeaderThree": {
"message": "మీకు నచ్చినట్టుగా"
},
diff --git a/browser/extensions/screenshots/webextension/_locales/uk/messages.json b/browser/extensions/screenshots/webextension/_locales/uk/messages.json
index e8cc5f6a3ff2..4451dfd19105 100644
--- a/browser/extensions/screenshots/webextension/_locales/uk/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/uk/messages.json
@@ -64,6 +64,9 @@
"selfScreenshotErrorTitle": {
"message": "Ви не можете зробити знімок сторінки Firefox Screenshots!"
},
+ "emptySelectionErrorTitle": {
+ "message": "Обрана область є замалою"
+ },
"genericErrorTitle": {
"message": "Оу! З Firefox Screenshots щось негаразд."
},
diff --git a/browser/extensions/screenshots/webextension/background/auth.js b/browser/extensions/screenshots/webextension/background/auth.js
index 168409707c7e..7bdf7d175457 100644
--- a/browser/extensions/screenshots/webextension/background/auth.js
+++ b/browser/extensions/screenshots/webextension/background/auth.js
@@ -12,7 +12,7 @@ this.auth = (function() {
let sentryPublicDSN = null;
let abTests = {};
- catcher.watchPromise(browser.storage.local.get(["registrationInfo", "abTests"]).then((result) => {
+ let registrationInfoFetched = catcher.watchPromise(browser.storage.local.get(["registrationInfo", "abTests"]).then((result) => {
if (result.abTests) {
abTests = result.abTests;
}
@@ -177,33 +177,37 @@ this.auth = (function() {
};
exports.setDeviceInfoFromOldAddon = function(newDeviceInfo) {
- if (!(newDeviceInfo.deviceId && newDeviceInfo.secret)) {
- throw new Error("Bad deviceInfo");
- }
- if (registrationInfo.deviceId === newDeviceInfo.deviceId &&
- registrationInfo.secret === newDeviceInfo.secret) {
- // Probably we already imported the information
- return Promise.resolve(false);
- }
- registrationInfo = {
- deviceId: newDeviceInfo.deviceId,
- secret: newDeviceInfo.secret,
- registered: true
- };
- initialized = false;
- return browser.storage.local.set({registrationInfo}).then(() => {
- return true;
+ return registrationInfoFetched.then(() => {
+ if (!(newDeviceInfo.deviceId && newDeviceInfo.secret)) {
+ throw new Error("Bad deviceInfo");
+ }
+ if (registrationInfo.deviceId === newDeviceInfo.deviceId &&
+ registrationInfo.secret === newDeviceInfo.secret) {
+ // Probably we already imported the information
+ return Promise.resolve(false);
+ }
+ registrationInfo = {
+ deviceId: newDeviceInfo.deviceId,
+ secret: newDeviceInfo.secret,
+ registered: true
+ };
+ initialized = false;
+ return browser.storage.local.set({registrationInfo}).then(() => {
+ return true;
+ });
});
};
communication.register("getAuthInfo", (sender, ownershipCheck) => {
- let info = registrationInfo;
- if (info.registered) {
- return login({ownershipCheck}).then((result) => {
- return {isOwner: result && result.isOwner, deviceId: registrationInfo.deviceId};
- });
- }
- return Promise.resolve(info);
+ return registrationInfoFetched.then(() => {
+ let info = registrationInfo;
+ if (info.registered) {
+ return login({ownershipCheck}).then((result) => {
+ return {isOwner: result && result.isOwner, deviceId: registrationInfo.deviceId};
+ });
+ }
+ return info;
+ });
});
return exports;
diff --git a/browser/extensions/screenshots/webextension/background/senderror.js b/browser/extensions/screenshots/webextension/background/senderror.js
index 192a61607970..0983c1dcbf4d 100644
--- a/browser/extensions/screenshots/webextension/background/senderror.js
+++ b/browser/extensions/screenshots/webextension/background/senderror.js
@@ -37,6 +37,9 @@ this.senderror = (function() {
MY_SHOTS: {
title: browser.i18n.getMessage("selfScreenshotErrorTitle")
},
+ EMPTY_SELECTION: {
+ title: browser.i18n.getMessage("emptySelectionErrorTitle")
+ },
generic: {
title: browser.i18n.getMessage("genericErrorTitle"),
info: browser.i18n.getMessage("genericErrorDetails"),
@@ -89,7 +92,7 @@ this.senderror = (function() {
return;
}
if (!Raven.isSetup()) {
- Raven.config(dsn).install();
+ Raven.config(dsn, {allowSecretKey: true}).install();
}
let exception = new Error(e.message);
exception.stack = e.multilineStack || e.stack || undefined;
@@ -112,7 +115,9 @@ this.senderror = (function() {
if (!errorObj.noPopup) {
exports.showError(errorObj);
}
- exports.reportError(errorObj);
+ if (!errorObj.noReport) {
+ exports.reportError(errorObj);
+ }
});
return exports;
diff --git a/browser/extensions/screenshots/webextension/build/buildSettings.js b/browser/extensions/screenshots/webextension/build/buildSettings.js
index 6dfe230ad1a0..ac5d165fd33e 100644
--- a/browser/extensions/screenshots/webextension/build/buildSettings.js
+++ b/browser/extensions/screenshots/webextension/build/buildSettings.js
@@ -1,6 +1,7 @@
window.buildSettings = {
- defaultSentryDsn: "https://97d8afa496f94764ae255e739b147f4b@sentry.prod.mozaws.net/139",
- logLevel: "" || "warn"
+ defaultSentryDsn: "https://904ccdd4866247c092ae8fc1a4764a63:940d44bdc71d4daea133c19080ccd38d@sentry.prod.mozaws.net/224",
+ logLevel: "" || "warn",
+ captureText: ("" === "true")
};
null;
diff --git a/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js b/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
index fd5088abe8f9..34e78aeed0c8 100644
--- a/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
+++ b/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
@@ -421,6 +421,9 @@ window.inlineSelectionCss = `
position: absolute;
right: 5px;
top: 5px; }
+ html[dir="rtl"] .myshots-all-buttons-container {
+ left: 5px;
+ right: inherit; }
.myshots-all-buttons-container .spacer {
background-color: #c9c9c9;
flex: 0 0 1px;
diff --git a/browser/extensions/screenshots/webextension/build/shot.js b/browser/extensions/screenshots/webextension/build/shot.js
index 7f0e0e5154e9..eee02ed4519b 100644
--- a/browser/extensions/screenshots/webextension/build/shot.js
+++ b/browser/extensions/screenshots/webextension/build/shot.js
@@ -493,6 +493,9 @@ class AbstractShot {
}
delete this._clips[name];
}
+ delAllClips() {
+ this._clips = {};
+ }
biggestClipSortOrder() {
let biggest = 0;
for (let clipId in this._clips) {
diff --git a/browser/extensions/screenshots/webextension/manifest.json b/browser/extensions/screenshots/webextension/manifest.json
index f4ff303f510b..9dae2b5acc59 100644
--- a/browser/extensions/screenshots/webextension/manifest.json
+++ b/browser/extensions/screenshots/webextension/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Firefox Screenshots",
- "version": "8.1.0",
+ "version": "9.0.0",
"description": "__MSG_addonDescription__",
"author": "__MSG_addonAuthorsList__",
"homepage_url": "https://github.com/mozilla-services/screenshots",
@@ -16,7 +16,7 @@
"16": "icons/icon-16.svg",
"32": "icons/icon-32.svg"
},
- "default_title": "__MSG_contextMenuLabel__",
+ "default_title": "Firefox Screenshots",
"browser_style": false
},
"background": {
diff --git a/browser/extensions/screenshots/webextension/onboarding/slides.js b/browser/extensions/screenshots/webextension/onboarding/slides.js
index c1eea7b4a099..f5acbcf4c7ed 100644
--- a/browser/extensions/screenshots/webextension/onboarding/slides.js
+++ b/browser/extensions/screenshots/webextension/onboarding/slides.js
@@ -46,6 +46,8 @@ this.slides = (function() {
doc.documentElement
);
doc.addEventListener("keyup", onKeyUp);
+ doc.documentElement.dir = browser.i18n.getMessage("@@bidi_dir");
+ doc.documentElement.lang = browser.i18n.getMessage("@@ui_locale");
localizeText(doc);
activateSlide(doc);
resolve();
diff --git a/browser/extensions/screenshots/webextension/selector/shooter.js b/browser/extensions/screenshots/webextension/selector/shooter.js
index e3c7e309cf72..cf23709a8341 100644
--- a/browser/extensions/screenshots/webextension/selector/shooter.js
+++ b/browser/extensions/screenshots/webextension/selector/shooter.js
@@ -1,5 +1,5 @@
/* globals global, documentMetadata, util, uicontrol, ui, catcher */
-/* globals domainFromUrl, randomString */
+/* globals buildSettings, domainFromUrl, randomString */
"use strict";
@@ -67,18 +67,31 @@ this.shooter = (function() { // eslint-disable-line no-unused-vars
// isSaving indicates we're aleady in the middle of saving
// we use a timeout so in the case of a failure the button will
// still start working again
+ if (Math.floor(selectedPos.left) == Math.floor(selectedPos.right) ||
+ Math.floor(selectedPos.top) == Math.floor(selectedPos.bottom)) {
+ let exc = new Error("Empty selection");
+ exc.popupMessage = "EMPTY_SELECTION";
+ exc.noReport = true;
+ catcher.unhandled(exc);
+ return;
+ }
const uicontrol = global.uicontrol;
let deactivateAfterFinish = true;
if (isSaving) {
return;
}
isSaving = setTimeout(() => {
+ ui.Box.clearSaveDisabled();
isSaving = null;
}, 1000);
selectedPos = selectedPos.asJson();
- let captureText = util.captureEnclosedText(selectedPos);
+ let captureText = "";
+ if (buildSettings.captureText) {
+ captureText = util.captureEnclosedText(selectedPos);
+ }
let dataUrl = screenshotPage(selectedPos);
if (dataUrl) {
+ shot.delAllClips();
shot.addClip({
createdDate: Date.now(),
image: {
diff --git a/browser/extensions/screenshots/webextension/selector/ui.js b/browser/extensions/screenshots/webextension/selector/ui.js
index d286ebb0fbfa..8a5d3de69b43 100644
--- a/browser/extensions/screenshots/webextension/selector/ui.js
+++ b/browser/extensions/screenshots/webextension/selector/ui.js
@@ -104,6 +104,8 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
if (this.addClassName) {
this.document.body.className = this.addClassName;
}
+ this.document.documentElement.dir = browser.i18n.getMessage("@@bidi_dir");
+ this.document.documentElement.lang = browser.i18n.getMessage("@@ui_locale");
resolve();
});
document.body.appendChild(this.element);
@@ -246,6 +248,8 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
if (this.addClassName) {
this.document.body.className = this.addClassName;
}
+ this.document.documentElement.dir = browser.i18n.getMessage("@@bidi_dir");
+ this.document.documentElement.lang = browser.i18n.getMessage("@@ui_locale");
const overlay = this.document.querySelector(".preview-overlay");
overlay.querySelector(".preview-instructions").textContent = browser.i18n.getMessage("screenshotInstructions");
overlay.querySelector(".myshots-link").textContent = browser.i18n.getMessage("myShotsLink");
@@ -537,6 +541,10 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
return false;
},
+ clearSaveDisabled() {
+ this.save.removeAttribute("disabled");
+ },
+
el: null,
boxTopEl: null,
boxLeftEl: null,
diff --git a/browser/extensions/screenshots/webextension/selector/uicontrol.js b/browser/extensions/screenshots/webextension/selector/uicontrol.js
index c3cd01629658..7b3bb014f6df 100644
--- a/browser/extensions/screenshots/webextension/selector/uicontrol.js
+++ b/browser/extensions/screenshots/webextension/selector/uicontrol.js
@@ -376,7 +376,7 @@ this.uicontrol = (function() {
ui.Box.remove();
const handler = watchFunction(assertIsTrusted(keyupHandler));
document.addEventListener("keyup", handler);
- registeredDocumentHandlers.push({name: "keyup", doc: document, handler});
+ registeredDocumentHandlers.push({name: "keyup", doc: document, handler, useCapture: false});
}));
},
@@ -874,15 +874,21 @@ this.uicontrol = (function() {
window.addEventListener('beforeunload', beforeunloadHandler);
}
+ let mousedownSetOnDocument = false;
+
function installHandlersOnDocument(docObj) {
for (let [eventName, handler] of primedDocumentHandlers) {
let watchHandler = watchFunction(handler);
- docObj.addEventListener(eventName, watchHandler, eventName !== "keyup");
- registeredDocumentHandlers.push({name: eventName, doc: docObj, watchHandler});
+ let useCapture = eventName !== "keyup";
+ docObj.addEventListener(eventName, watchHandler, useCapture);
+ registeredDocumentHandlers.push({name: eventName, doc: docObj, handler: watchHandler, useCapture});
+ }
+ if (!mousedownSetOnDocument) {
+ let mousedownHandler = primedDocumentHandlers.get("mousedown");
+ document.addEventListener("mousedown", mousedownHandler, true);
+ registeredDocumentHandlers.push({name: "mousedown", doc: document, handler: mousedownHandler, useCapture: true});
+ mousedownSetOnDocument = true;
}
- let mousedownHandler = primedDocumentHandlers.get("mousedown");
- document.addEventListener("mousedown", mousedownHandler, true);
- registeredDocumentHandlers.push({name: "mousedown", doc: document, watchHandler: mousedownHandler, useCapture: true});
}
function beforeunloadHandler() {
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index 9ba83a91c875..bd59efb5d0e0 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -483,6 +483,14 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-p
border: none;
}
+/* On Mac, native buttons keep their full opacity when they become disabled
+ * and only the glyph or text on top of them becomes less opaque. */
+#back-button[disabled="true"] > .toolbarbutton-icon {
+ opacity: 1 !important;
+ -moz-context-properties: fill, fill-opacity;
+ fill-opacity: 0.4;
+}
+
/* Inactive elements are faded out on OSX */
.toolbarbutton-1:not(:hover):-moz-window-inactive,
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] {
diff --git a/browser/themes/shared/icons/back.svg b/browser/themes/shared/icons/back.svg
index 82d701a3e203..c4950af8acba 100644
--- a/browser/themes/shared/icons/back.svg
+++ b/browser/themes/shared/icons/back.svg
@@ -2,5 +2,5 @@
- 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/. -->
diff --git a/browser/themes/shared/incontentprefs-old/preferences.inc.css b/browser/themes/shared/incontentprefs-old/preferences.inc.css
index f9e2800a45ad..dedcb7f35c60 100644
--- a/browser/themes/shared/incontentprefs-old/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs-old/preferences.inc.css
@@ -291,12 +291,15 @@ description > html|a {
* Dialog
*/
-#dialogOverlay {
- background-color: rgba(0,0,0,0.5);
+.dialogOverlay {
visibility: hidden;
}
-#dialogBox {
+.dialogOverlay[topmost="true"] {
+ background-color: rgba(0,0,0,0.5);
+}
+
+.dialogBox {
background-color: #fbfbfb;
background-clip: content-box;
color: #424e5a;
@@ -311,20 +314,20 @@ description > html|a {
padding: 0;
}
-#dialogBox[resizable="true"] {
+.dialogBox[resizable="true"] {
resize: both;
overflow: hidden;
min-height: 20em;
min-width: 66ch;
}
-#dialogBox > .groupbox-title {
+.dialogBox > .groupbox-title {
padding: 3.5px 0;
background-color: #F1F1F1;
border-bottom: 1px solid #C1C1C1;
}
-#dialogTitle {
+.dialogTitle {
text-align: center;
-moz-user-select: none;
}
@@ -339,12 +342,12 @@ description > html|a {
min-width: 0;
}
-#dialogBox > .groupbox-body {
+.dialogBox > .groupbox-body {
-moz-appearance: none;
padding: 20px;
}
-#dialogFrame {
+.dialogFrame {
-moz-box-flex: 1;
/* Default dialog dimensions */
width: 66ch;
diff --git a/browser/themes/shared/incontentprefs/preferences.inc.css b/browser/themes/shared/incontentprefs/preferences.inc.css
index 7e5cfa0a3368..435aee3e8ab5 100644
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -294,12 +294,15 @@ description > html|a {
* Dialog
*/
-#dialogOverlay {
- background-color: rgba(0,0,0,0.5);
+.dialogOverlay {
visibility: hidden;
}
-#dialogBox {
+.dialogOverlay[topmost="true"] {
+ background-color: rgba(0,0,0,0.5);
+}
+
+.dialogBox {
background-color: #fbfbfb;
background-clip: content-box;
color: #424e5a;
@@ -314,20 +317,20 @@ description > html|a {
padding: 0;
}
-#dialogBox[resizable="true"] {
+.dialogBox[resizable="true"] {
resize: both;
overflow: hidden;
min-height: 20em;
min-width: 66ch;
}
-#dialogBox > .groupbox-title {
+.dialogBox > .groupbox-title {
padding: 3.5px 0;
background-color: #F1F1F1;
border-bottom: 1px solid #C1C1C1;
}
-#dialogTitle {
+.dialogTitle {
text-align: center;
-moz-user-select: none;
}
@@ -342,12 +345,12 @@ description > html|a {
min-width: 0;
}
-#dialogBox > .groupbox-body {
+.dialogBox > .groupbox-body {
-moz-appearance: none;
padding: 20px;
}
-#dialogFrame {
+.dialogFrame {
-moz-box-flex: 1;
/* Default dialog dimensions */
width: 66ch;
diff --git a/browser/themes/shared/toolbarbuttons.inc.css b/browser/themes/shared/toolbarbuttons.inc.css
index 485724848026..5ce253064a4c 100644
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -294,6 +294,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not
border-color: var(--toolbarbutton-hover-bordercolor);
box-shadow: var(--toolbarbutton-hover-boxshadow);
%endif
+ color: inherit;
}
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
@@ -310,6 +311,7 @@ toolbarbutton.bookmark-item[open="true"],
box-shadow: var(--toolbarbutton-active-boxshadow);
%endif
transition-duration: 10ms;
+ color: inherit;
}
#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
diff --git a/devtools/client/netmonitor/src/har/har-automation.js b/devtools/client/netmonitor/src/har/har-automation.js
index d991c59b195b..63a532d736ab 100644
--- a/devtools/client/netmonitor/src/har/har-automation.js
+++ b/devtools/client/netmonitor/src/har/har-automation.js
@@ -7,7 +7,6 @@
"use strict";
const { Ci } = require("chrome");
-const { Class } = require("sdk/core/heritage");
const Services = require("Services");
loader.lazyRequireGetter(this, "HarCollector", "devtools/client/netmonitor/har/har-collector", true);
@@ -36,7 +35,11 @@ const trace = {
* If the default log directory preference isn't set the following
* directory is used by default: /har/logs
*/
-var HarAutomation = Class({
+function HarAutomation(toolbox) {
+ this.initialize(toolbox);
+}
+
+HarAutomation.prototype = {
// Initialization
initialize: function (toolbox) {
@@ -201,7 +204,7 @@ var HarAutomation = Class({
getString: function (stringGrip) {
return this.webConsoleClient.getString(stringGrip);
},
-});
+};
// Helpers
diff --git a/devtools/client/storage/storage.xul b/devtools/client/storage/storage.xul
index df1c08a9ce38..5e92d2d2ddd2 100644
--- a/devtools/client/storage/storage.xul
+++ b/devtools/client/storage/storage.xul
@@ -43,14 +43,14 @@
+
+
-
-
diff --git a/devtools/client/storage/test/browser.ini b/devtools/client/storage/test/browser.ini
index 93f0ae64afac..761d261a1e29 100644
--- a/devtools/client/storage/test/browser.ini
+++ b/devtools/client/storage/test/browser.ini
@@ -24,7 +24,8 @@ support-files =
!/devtools/client/framework/test/shared-head.js
[browser_storage_basic.js]
-[browser_storage_basic_usercontextid.js]
+[browser_storage_basic_usercontextid_1.js]
+[browser_storage_basic_usercontextid_2.js]
tags = usercontextid
[browser_storage_basic_with_fragment.js]
[browser_storage_cache_delete.js]
diff --git a/devtools/client/storage/test/browser_storage_basic_usercontextid_1.js b/devtools/client/storage/test/browser_storage_basic_usercontextid_1.js
new file mode 100644
index 000000000000..0c24be26bc35
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_basic_usercontextid_1.js
@@ -0,0 +1,118 @@
+/* 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/. */
+
+// A test to check that the storage inspector is working correctly without
+// userContextId.
+
+"use strict";
+
+const testCases = [
+ [
+ ["cookies", "http://test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c3", "test1.example.org", "/"),
+ getCookieId("uc1", ".example.org", "/")
+ ]
+ ],
+ [
+ ["cookies", "https://sectest1.example.org"],
+ [
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ [["localStorage", "http://test1.example.org"],
+ ["ls1", "ls2"]],
+ [["localStorage", "http://sectest1.example.org"],
+ ["iframe-u-ls1"]],
+ [["localStorage", "https://sectest1.example.org"],
+ ["iframe-s-ls1"]],
+ [["sessionStorage", "http://test1.example.org"],
+ ["ss1"]],
+ [["sessionStorage", "http://sectest1.example.org"],
+ ["iframe-u-ss1", "iframe-u-ss2"]],
+ [["sessionStorage", "https://sectest1.example.org"],
+ ["iframe-s-ss1"]],
+ [["indexedDB", "http://test1.example.org"],
+ ["idb1 (default)", "idb2 (default)"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)"],
+ ["obj1", "obj2"]],
+ [["indexedDB", "http://test1.example.org", "idb2 (default)"],
+ ["obj3"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
+ [1, 2, 3]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
+ [1]],
+ [["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
+ []],
+ [["indexedDB", "http://sectest1.example.org"],
+ []],
+ [["indexedDB", "https://sectest1.example.org"],
+ ["idb-s1 (default)", "idb-s2 (default)"]],
+ [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
+ ["obj-s1"]],
+ [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
+ ["obj-s2"]],
+ [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
+ [6, 7]],
+ [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
+ [16]],
+ [["Cache", "http://test1.example.org", "plop"],
+ [MAIN_DOMAIN + "404_cached_file.js",
+ MAIN_DOMAIN + "browser_storage_basic.js"]],
+];
+
+/**
+ * Test that the desired number of tree items are present
+ */
+function testTree(tests) {
+ let doc = gPanelWindow.document;
+ for (let [item] of tests) {
+ ok(doc.querySelector("[data-id='" + JSON.stringify(item) + "']"),
+ "Tree item " + item[0] + " should be present in the storage tree");
+ }
+}
+
+/**
+ * Test that correct table entries are shown for each of the tree item
+ */
+function* testTables(tests) {
+ let doc = gPanelWindow.document;
+ // Expand all nodes so that the synthesized click event actually works
+ gUI.tree.expandAll();
+
+ // First tree item is already selected so no clicking and waiting for update
+ for (let id of tests[0][1]) {
+ ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+ "Table item " + id + " should be present");
+ }
+
+ // Click rest of the tree items and wait for the table to be updated
+ for (let [treeItem, items] of tests.slice(1)) {
+ yield selectTreeItem(treeItem);
+
+ // Check whether correct number of items are present in the table
+ is(doc.querySelectorAll(
+ ".table-widget-wrapper:first-of-type .table-widget-cell"
+ ).length, items.length, "Number of items in table is correct");
+
+ // Check if all the desired items are present in the table
+ for (let id of items) {
+ ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+ "Table item " + id + " should be present");
+ }
+ }
+}
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
+
+ testTree(testCases);
+ yield testTables(testCases);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_basic_usercontextid.js b/devtools/client/storage/test/browser_storage_basic_usercontextid_2.js
similarity index 65%
rename from devtools/client/storage/test/browser_storage_basic_usercontextid.js
rename to devtools/client/storage/test/browser_storage_basic_usercontextid_2.js
index 88e1a24b6012..80a7b937b34e 100644
--- a/devtools/client/storage/test/browser_storage_basic_usercontextid.js
+++ b/devtools/client/storage/test/browser_storage_basic_usercontextid_2.js
@@ -7,65 +7,6 @@
"use strict";
-const testCases = [
- [
- ["cookies", "http://test1.example.org"],
- [
- getCookieId("c1", "test1.example.org", "/browser"),
- getCookieId("cs2", ".example.org", "/"),
- getCookieId("c3", "test1.example.org", "/"),
- getCookieId("uc1", ".example.org", "/")
- ]
- ],
- [
- ["cookies", "https://sectest1.example.org"],
- [
- getCookieId("uc1", ".example.org", "/"),
- getCookieId("cs2", ".example.org", "/"),
- getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
- ]
- ],
- [["localStorage", "http://test1.example.org"],
- ["ls1", "ls2"]],
- [["localStorage", "http://sectest1.example.org"],
- ["iframe-u-ls1"]],
- [["localStorage", "https://sectest1.example.org"],
- ["iframe-s-ls1"]],
- [["sessionStorage", "http://test1.example.org"],
- ["ss1"]],
- [["sessionStorage", "http://sectest1.example.org"],
- ["iframe-u-ss1", "iframe-u-ss2"]],
- [["sessionStorage", "https://sectest1.example.org"],
- ["iframe-s-ss1"]],
- [["indexedDB", "http://test1.example.org"],
- ["idb1 (default)", "idb2 (default)"]],
- [["indexedDB", "http://test1.example.org", "idb1 (default)"],
- ["obj1", "obj2"]],
- [["indexedDB", "http://test1.example.org", "idb2 (default)"],
- ["obj3"]],
- [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
- [1, 2, 3]],
- [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
- [1]],
- [["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
- []],
- [["indexedDB", "http://sectest1.example.org"],
- []],
- [["indexedDB", "https://sectest1.example.org"],
- ["idb-s1 (default)", "idb-s2 (default)"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
- ["obj-s1"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
- ["obj-s2"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
- [6, 7]],
- [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
- [16]],
- [["Cache", "http://test1.example.org", "plop"],
- [MAIN_DOMAIN + "404_cached_file.js",
- MAIN_DOMAIN + "browser_storage_basic.js"]],
-];
-
const testCasesUserContextId = [
[
["cookies", "http://test1.example.org"],
@@ -169,11 +110,6 @@ function* testTables(tests) {
}
add_task(function* () {
- yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
-
- testTree(testCases);
- yield testTables(testCases);
-
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings-usercontextid.html",
{userContextId: 1});
diff --git a/devtools/client/storage/test/head.js b/devtools/client/storage/test/head.js
index bc698e3bf3e8..368c277ca19e 100644
--- a/devtools/client/storage/test/head.js
+++ b/devtools/client/storage/test/head.js
@@ -201,9 +201,10 @@ var openStoragePanel = Task.async(function* (cb) {
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
- let def = promise.defer();
- waitForFocus(def.resolve, toolbox.win);
- return def.promise;
+
+ return new Promise(resolve => {
+ waitForFocus(resolve, toolbox.win);
+ });
}
/**
@@ -274,18 +275,16 @@ function* finishTests() {
// Sends a click event on the passed DOM node in an async manner
function* click(node) {
- let def = promise.defer();
-
node.scrollIntoView();
- // We need setTimeout here to allow any scrolling to complete before clicking
- // the node.
- setTimeout(() => {
- node.click();
- def.resolve();
- }, 200);
-
- return def;
+ return new Promise(resolve => {
+ // We need setTimeout here to allow any scrolling to complete before clicking
+ // the node.
+ setTimeout(() => {
+ node.click();
+ resolve();
+ }, 200);
+ });
}
/**
@@ -306,35 +305,34 @@ function* click(node) {
function variablesViewExpandTo(options) {
let root = options.rootVariable;
let expandTo = options.expandTo.split(".");
- let lastDeferred = promise.defer();
- function getNext(prop) {
- let name = expandTo.shift();
- let newProp = prop.get(name);
+ return new Promise((resolve, reject) => {
+ function getNext(prop) {
+ let name = expandTo.shift();
+ let newProp = prop.get(name);
- if (expandTo.length > 0) {
- ok(newProp, "found property " + name);
- if (newProp && newProp.expand) {
- newProp.expand();
- getNext(newProp);
+ if (expandTo.length > 0) {
+ ok(newProp, "found property " + name);
+ if (newProp && newProp.expand) {
+ newProp.expand();
+ getNext(newProp);
+ } else {
+ reject(prop);
+ }
+ } else if (newProp) {
+ resolve(newProp);
} else {
- lastDeferred.reject(prop);
+ reject(prop);
}
- } else if (newProp) {
- lastDeferred.resolve(newProp);
- } else {
- lastDeferred.reject(prop);
}
- }
- if (root && root.expand) {
- root.expand();
- getNext(root);
- } else {
- lastDeferred.resolve(root);
- }
-
- return lastDeferred.promise;
+ if (root && root.expand) {
+ root.expand();
+ getNext(root);
+ } else {
+ resolve(root);
+ }
+ });
}
/**
@@ -412,33 +410,32 @@ function findVariableViewProperties(ruleArray, parsed) {
}
function processExpandRules(rules) {
- let rule = rules.shift();
- if (!rule) {
- return promise.resolve(null);
- }
+ return new Promise(resolve => {
+ let rule = rules.shift();
+ if (!rule) {
+ resolve(null);
+ }
- let deferred = promise.defer();
- let expandOptions = {
- rootVariable: gUI.view.getScopeAtIndex(parsed ? 1 : 0),
- expandTo: rule.name
- };
+ let expandOptions = {
+ rootVariable: gUI.view.getScopeAtIndex(parsed ? 1 : 0),
+ expandTo: rule.name
+ };
- variablesViewExpandTo(expandOptions).then(function onSuccess(prop) {
- let name = rule.name;
- let lastName = name.split(".").pop();
- rule.name = lastName;
+ variablesViewExpandTo(expandOptions).then(function onSuccess(prop) {
+ let name = rule.name;
+ let lastName = name.split(".").pop();
+ rule.name = lastName;
- let matched = matchVariablesViewProperty(prop, rule);
- return matched.then(onMatch.bind(null, prop, rule)).then(function () {
- rule.name = name;
+ let matched = matchVariablesViewProperty(prop, rule);
+ return matched.then(onMatch.bind(null, prop, rule)).then(function () {
+ rule.name = name;
+ });
+ }, function onFailure() {
+ resolve(null);
+ }).then(processExpandRules.bind(null, rules)).then(function () {
+ resolve(null);
});
- }, function onFailure() {
- return promise.resolve(null);
- }).then(processExpandRules.bind(null, rules)).then(function () {
- deferred.resolve(null);
});
-
- return deferred.promise;
}
function onAllRulesMatched(rules) {
@@ -545,8 +542,10 @@ function* selectTableItem(id) {
showAvailableIds();
}
+ let updated = gUI.once("sidebar-updated");
+
yield click(target);
- yield gUI.once("sidebar-updated");
+ yield updated;
}
/**
@@ -554,29 +553,28 @@ function* selectTableItem(id) {
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
- * @param {Boolean} [useCapture] for addEventListener/removeEventListener
+ * @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
- let deferred = promise.defer();
-
- for (let [add, remove] of [
- ["addEventListener", "removeEventListener"],
- ["addListener", "removeListener"],
- ["on", "off"]
- ]) {
- if ((add in target) && (remove in target)) {
- target[add](eventName, function onEvent(...aArgs) {
- target[remove](eventName, onEvent, useCapture);
- deferred.resolve.apply(deferred, aArgs);
- }, useCapture);
- break;
+ return new Promise(resolve => {
+ for (let [add, remove] of [
+ ["addEventListener", "removeEventListener"],
+ ["addListener", "removeListener"],
+ ["on", "off"]
+ ]) {
+ if ((add in target) && (remove in target)) {
+ target[add](eventName, function onEvent(...aArgs) {
+ info("Got event: '" + eventName + "' on " + target + ".");
+ target[remove](eventName, onEvent, useCapture);
+ resolve(...aArgs);
+ }, useCapture);
+ break;
+ }
}
- }
-
- return deferred.promise;
+ });
}
/**
diff --git a/devtools/server/actors/highlighters/css-grid.js b/devtools/server/actors/highlighters/css-grid.js
index f35f6683dd00..95c65578f958 100644
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -99,6 +99,77 @@ const CANVAS_SIZE = 4096;
// the viewport's edges, therefore the lines won't looks as "infinite").
const CANVAS_INFINITY = CANVAS_SIZE << 8;
+/**
+ * Returns an array containing the four coordinates of a rectangle, given its diagonal
+ * as input; optionally applying a matrix, and a function to each of the coordinates'
+ * value.
+ *
+ * @param {Number} x1
+ * The x-axis coordinate of the rectangle's diagonal start point.
+ * @param {Number} y1
+ * The y-axis coordinate of the rectangle's diagonal start point.
+ * @param {Number} x2
+ * The x-axis coordinate of the rectangle's diagonal end point.
+ * @param {Number} y2
+ * The y-axis coordinate of the rectangle's diagonal end point.
+ * @param {Array} [matrix=identity()]
+ * A transformation matrix to apply.
+ * @return {Array}
+ * The rect four corners' points transformed by the matrix given.
+ */
+function getPointsFromDiagonal(x1, y1, x2, y2, matrix = identity()) {
+ return [
+ [x1, y1],
+ [x2, y1],
+ [x2, y2],
+ [x1, y2]
+ ].map(point => {
+ let transformedPoint = apply(matrix, point);
+
+ return {x: transformedPoint[0], y: transformedPoint[1]};
+ });
+}
+
+/**
+ * Takes an array of four points and returns a DOMRect-like object, represent the
+ * boundaries defined by the points given.
+ *
+ * @param {Array} points
+ * The four points.
+ * @return {Object}
+ * A DOMRect-like object.
+ */
+function getBoundsFromPoints(points) {
+ let bounds = {};
+
+ bounds.left = Math.min(points[0].x, points[1].x, points[2].x, points[3].x);
+ bounds.right = Math.max(points[0].x, points[1].x, points[2].x, points[3].x);
+ bounds.top = Math.min(points[0].y, points[1].y, points[2].y, points[3].y);
+ bounds.bottom = Math.max(points[0].y, points[1].y, points[2].y, points[3].y);
+
+ bounds.x = bounds.left;
+ bounds.y = bounds.top;
+ bounds.width = bounds.right - bounds.left;
+ bounds.height = bounds.bottom - bounds.top;
+
+ return bounds;
+}
+
+/**
+ * Takes an array of four points and returns a string represent a path description.
+ *
+ * @param {Array} points
+ * The four points.
+ * @return {String}
+ * A Path Description that can be used in svg's element.
+ */
+function getPathDescriptionFromPoints(points) {
+ return "M" + points[0].x + "," + points[0].y + " " +
+ "L" + points[1].x + "," + points[1].y + " " +
+ "L" + points[2].x + "," + points[2].y + " " +
+ "L" + points[3].x + "," + points[3].y;
+}
+
/**
* Draws a line to the context given, applying a transformation matrix if passed.
*
@@ -141,18 +212,13 @@ function drawLine(ctx, x1, y1, x2, y2, matrix = identity()) {
* The transformation matrix to apply.
*/
function drawRect(ctx, x1, y1, x2, y2, matrix = identity()) {
- let p = [
- [x1, y1],
- [x2, y1],
- [x2, y2],
- [x1, y2]
- ].map(point => apply(matrix, point).map(Math.round));
+ let p = getPointsFromDiagonal(x1, y1, x2, y2, matrix);
ctx.beginPath();
- ctx.moveTo(p[0][0], p[0][1]);
- ctx.lineTo(p[1][0], p[1][1]);
- ctx.lineTo(p[2][0], p[2][1]);
- ctx.lineTo(p[3][0], p[3][1]);
+ ctx.moveTo(Math.round(p[0].x), Math.round(p[0].y));
+ ctx.lineTo(Math.round(p[1].x), Math.round(p[1].y));
+ ctx.lineTo(Math.round(p[2].x), Math.round(p[2].y));
+ ctx.lineTo(Math.round(p[3].x), Math.round(p[3].y));
ctx.closePath();
}
@@ -808,18 +874,11 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
*
* @param {GridArea} area
* The grid area object.
- * @param {Number} x1
- * The first x-coordinate of the grid area rectangle.
- * @param {Number} x2
- * The second x-coordinate of the grid area rectangle.
- * @param {Number} y1
- * The first y-coordinate of the grid area rectangle.
- * @param {Number} y2
- * The second y-coordinate of the grid area rectangle.
+ * @param {Object} bounds
+ * A DOMRect-like object represent the grid area rectangle.
*/
- _updateGridAreaInfobar(area, x1, x2, y1, y2) {
- let width = x2 - x1;
- let height = y2 - y1;
+ _updateGridAreaInfobar(area, bounds) {
+ let { width, height } = bounds;
let dim = parseFloat(width.toPrecision(6)) +
" \u00D7 " +
parseFloat(height.toPrecision(6));
@@ -828,15 +887,24 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
this.getElement("area-infobar-dimensions").setTextContent(dim);
let container = this.getElement("area-infobar-container");
- this._moveInfobar(container, x1, x2, y1, y2, {
+ moveInfobar(container, bounds, this.win, {
position: "bottom",
hideIfOffscreen: true
});
},
- _updateGridCellInfobar(rowNumber, columnNumber, x1, x2, y1, y2) {
- let width = x2 - x1;
- let height = y2 - y1;
+ /**
+ * Update the grid information displayed in the grid cell info bar.
+ *
+ * @param {Number} rowNumber
+ * The grid cell's row number.
+ * @param {Number} columnNumber
+ * The grid cell's column number.
+ * @param {Object} bounds
+ * A DOMRect-like object represent the grid cell rectangle.
+ */
+ _updateGridCellInfobar(rowNumber, columnNumber, bounds) {
+ let { width, height } = bounds;
let dim = parseFloat(width.toPrecision(6)) +
" \u00D7 " +
parseFloat(height.toPrecision(6));
@@ -847,7 +915,7 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
this.getElement("cell-infobar-dimensions").setTextContent(dim);
let container = this.getElement("cell-infobar-container");
- this._moveInfobar(container, x1, x2, y1, y2, {
+ moveInfobar(container, bounds, this.win, {
position: "top",
hideIfOffscreen: true
});
@@ -870,34 +938,8 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
this.getElement("line-infobar-names").setTextContent(gridLineNames);
let container = this.getElement("line-infobar-container");
- this._moveInfobar(container, x, x, y, y);
- },
-
- /**
- * Move the given grid infobar to the right place in the highlighter.
- *
- * @param {Number} x1
- * The first x-coordinate of the grid rectangle.
- * @param {Number} x2
- * The second x-coordinate of the grid rectangle.
- * @param {Number} y1
- * The first y-coordinate of the grid rectangle.
- * @param {Number} y2
- * The second y-coordinate of the grid rectangle.
- */
- _moveInfobar(container, x1, x2, y1, y2, options) {
- let bounds = {
- bottom: y2,
- height: y2 - y1,
- left: x1,
- right: x2,
- top: y1,
- width: x2 - x1,
- x: x1,
- y: y1,
- };
-
- moveInfobar(container, bounds, this.win, options);
+ moveInfobar(container,
+ getBoundsFromPoints([{x, y}, {x, y}, {x, y}, {x, y}]), this.win);
},
/**
@@ -991,8 +1033,8 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
},
/**
- * Updates the current matrix taking in account the following transformations, in this
- * order:
+ * Updates the current matrices for both canvas drawing and SVG, taking in account the
+ * following transformations, in this order:
* 1. The scale given by the display pixel ratio.
* 2. The translation to the top left corner of the element.
* 3. The scale given by the current zoom.
@@ -1502,11 +1544,11 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
*/
renderGridArea(areaName) {
let paths = [];
- let currentZoom = getCurrentZoom(this.win);
+ let { devicePixelRatio } = this.win;
+ let displayPixelRatio = getDisplayPixelRatio(this.win);
for (let i = 0; i < this.gridData.length; i++) {
let fragment = this.gridData[i];
- let {bounds} = this.currentQuads.content[i];
for (let area of fragment.areas) {
if (areaName && areaName != area.name) {
@@ -1518,23 +1560,33 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
let columnStart = fragment.cols.lines[area.columnStart - 1];
let columnEnd = fragment.cols.lines[area.columnEnd - 1];
- let x1 = columnStart.start + columnStart.breadth +
- (bounds.left / currentZoom);
- let x2 = columnEnd.start + (bounds.left / currentZoom);
- let y1 = rowStart.start + rowStart.breadth +
- (bounds.top / currentZoom);
- let y2 = rowEnd.start + (bounds.top / currentZoom);
+ let x1 = columnStart.start + columnStart.breadth;
+ let y1 = rowStart.start + rowStart.breadth;
+ let x2 = columnEnd.start;
+ let y2 = rowEnd.start;
- let path = "M" + x1 + "," + y1 + " " +
- "L" + x2 + "," + y1 + " " +
- "L" + x2 + "," + y2 + " " +
- "L" + x1 + "," + y2;
- paths.push(path);
+ let points = getPointsFromDiagonal(x1, y1, x2, y2, this.currentMatrix);
+
+ // Scale down by `devicePixelRatio` since SVG element already take them into
+ // account.
+ let svgPoints = points.map(point => ({
+ x: Math.round(point.x / devicePixelRatio),
+ y: Math.round(point.y / devicePixelRatio)
+ }));
+
+ // Scale down by `displayPixelRatio` since infobar's HTML elements already take it
+ // into account; and the zoom scaling is handled by `moveInfobar`.
+ let bounds = getBoundsFromPoints(points.map(point => ({
+ x: Math.round(point.x / displayPixelRatio),
+ y: Math.round(point.y / displayPixelRatio)
+ })));
+
+ paths.push(getPathDescriptionFromPoints(svgPoints));
// Update and show the info bar when only displaying a single grid area.
if (areaName) {
this._showGridAreaInfoBar();
- this._updateGridAreaInfobar(area, x1, x2, y1, y2);
+ this._updateGridAreaInfobar(area, bounds);
}
}
}
@@ -1568,23 +1620,34 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
return;
}
- let currentZoom = getCurrentZoom(this.win);
- let {bounds} = this.currentQuads.content[gridFragmentIndex];
+ let x1 = column.start;
+ let y1 = row.start;
+ let x2 = column.start + column.breadth;
+ let y2 = row.start + row.breadth;
- let x1 = column.start + (bounds.left / currentZoom);
- let x2 = column.start + column.breadth + (bounds.left / currentZoom);
- let y1 = row.start + (bounds.top / currentZoom);
- let y2 = row.start + row.breadth + (bounds.top / currentZoom);
+ let { devicePixelRatio } = this.win;
+ let displayPixelRatio = getDisplayPixelRatio(this.win);
+
+ let points = getPointsFromDiagonal(x1, y1, x2, y2, this.currentMatrix);
+
+ // Scale down by `devicePixelRatio` since SVG element already take them into account.
+ let svgPoints = points.map(point => ({
+ x: Math.round(point.x / devicePixelRatio),
+ y: Math.round(point.y / devicePixelRatio)
+ }));
+
+ // Scale down by `displayPixelRatio` since infobar's HTML elements already take it
+ // into account, and the zoom scaling is handled by `moveInfobar`.
+ let bounds = getBoundsFromPoints(points.map(point => ({
+ x: Math.round(point.x / displayPixelRatio),
+ y: Math.round(point.y / displayPixelRatio)
+ })));
- let path = "M" + x1 + "," + y1 + " " +
- "L" + x2 + "," + y1 + " " +
- "L" + x2 + "," + y2 + " " +
- "L" + x1 + "," + y2;
let cells = this.getElement("cells");
- cells.setAttribute("d", path);
+ cells.setAttribute("d", getPathDescriptionFromPoints(svgPoints));
this._showGridCellInfoBar();
- this._updateGridCellInfobar(rowNumber, columnNumber, x1, x2, y1, y2);
+ this._updateGridCellInfobar(rowNumber, columnNumber, bounds);
},
/**
diff --git a/dom/animation/test/chrome/test_animation_performance_warning.html b/dom/animation/test/chrome/test_animation_performance_warning.html
index c89557a24853..cf38d94dc02f 100644
--- a/dom/animation/test/chrome/test_animation_performance_warning.html
+++ b/dom/animation/test/chrome/test_animation_performance_warning.html
@@ -1180,7 +1180,7 @@ function start() {
}).then(function() {
// viewport depends on test environment.
var expectedWarning = new RegExp(
- "Animation cannot be run on the compositor because the area of the frame size " +
+ "Animation cannot be run on the compositor because the area of the frame " +
"\\(\\d+\\) is too large relative to the viewport " +
"\\(larger than \\d+\\)");
assert_animation_property_state_equals(
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 5117805aa518..6a502b1ecd3a 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10089,17 +10089,12 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
RefPtr sheet = GetStyleSheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
- // XXXheycam Need to make ServoStyleSheet cloning work.
- if (sheet->IsGecko()) {
- RefPtr clonedSheet =
- sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
- NS_WARNING_ASSERTION(clonedSheet,
- "Cloning a stylesheet didn't work!");
- if (clonedSheet) {
- clonedDoc->AddStyleSheet(clonedSheet);
- }
- } else {
- NS_ERROR("stylo: ServoStyleSheet doesn't support cloning");
+ RefPtr clonedSheet =
+ sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
+ NS_WARNING_ASSERTION(clonedSheet,
+ "Cloning a stylesheet didn't work!");
+ if (clonedSheet) {
+ clonedDoc->AddStyleSheet(clonedSheet);
}
}
}
@@ -10109,17 +10104,12 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
for (StyleSheet* sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
if (sheet) {
if (sheet->IsApplicable()) {
- // XXXheycam Need to make ServoStyleSheet cloning work.
- if (sheet->IsGecko()) {
- RefPtr clonedSheet =
- sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
- NS_WARNING_ASSERTION(clonedSheet,
- "Cloning a stylesheet didn't work!");
- if (clonedSheet) {
- clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
- }
- } else {
- NS_ERROR("stylo: ServoStyleSheet doesn't support cloning");
+ RefPtr clonedSheet =
+ sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
+ NS_WARNING_ASSERTION(clonedSheet,
+ "Cloning a stylesheet didn't work!");
+ if (clonedSheet) {
+ clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
}
}
}
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index 98eabb1969df..c646c9c5a885 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -133,6 +133,7 @@
#ifdef USE_SKIA
#include "SurfaceTypes.h"
#include "GLBlitHelper.h"
+#include "ScopedGLHelpers.h"
#endif
using mozilla::gl::GLContext;
@@ -5232,46 +5233,49 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
return;
}
- gl->MakeCurrent();
- GLuint videoTexture = 0;
- gl->fGenTextures(1, &videoTexture);
- // skiaGL expect upload on drawing, and uses texture 0 for texturing,
- // so we must active texture 0 and bind the texture for it.
- gl->fActiveTexture(LOCAL_GL_TEXTURE0);
- gl->fBindTexture(LOCAL_GL_TEXTURE_2D, videoTexture);
+ {
+ gl->MakeCurrent();
+ GLuint videoTexture = 0;
+ gl->fGenTextures(1, &videoTexture);
+ // skiaGL expect upload on drawing, and uses texture 0 for texturing,
+ // so we must active texture 0 and bind the texture for it.
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+ const gl::ScopedBindTexture scopeBindTexture(gl, videoTexture);
- gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, srcImage->GetSize().width, srcImage->GetSize().height, 0, LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5, nullptr);
- gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
- gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
- gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
- gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+ gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, srcImage->GetSize().width, srcImage->GetSize().height, 0, LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5, nullptr);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
- const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
- bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage, srcImage->GetSize(),
- videoTexture, LOCAL_GL_TEXTURE_2D,
- destOrigin);
- if (ok) {
- NativeSurface texSurf;
- texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;
- texSurf.mFormat = SurfaceFormat::R5G6B5_UINT16;
- texSurf.mSize.width = srcImage->GetSize().width;
- texSurf.mSize.height = srcImage->GetSize().height;
- texSurf.mSurface = (void*)((uintptr_t)videoTexture);
+ const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
+ bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage, srcImage->GetSize(),
+ videoTexture, LOCAL_GL_TEXTURE_2D,
+ destOrigin);
+ if (ok) {
+ NativeSurface texSurf;
+ texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;
+ texSurf.mFormat = SurfaceFormat::R5G6B5_UINT16;
+ texSurf.mSize.width = srcImage->GetSize().width;
+ texSurf.mSize.height = srcImage->GetSize().height;
+ texSurf.mSurface = (void*)((uintptr_t)videoTexture);
- srcSurf = mTarget->CreateSourceSurfaceFromNativeSurface(texSurf);
- if (!srcSurf) {
+ srcSurf = mTarget->CreateSourceSurfaceFromNativeSurface(texSurf);
+ if (!srcSurf) {
+ gl->fDeleteTextures(1, &videoTexture);
+ }
+ imgSize.width = srcImage->GetSize().width;
+ imgSize.height = srcImage->GetSize().height;
+
+ int32_t displayWidth = video->VideoWidth();
+ int32_t displayHeight = video->VideoHeight();
+ aSw *= (double)imgSize.width / (double)displayWidth;
+ aSh *= (double)imgSize.height / (double)displayHeight;
+ } else {
gl->fDeleteTextures(1, &videoTexture);
}
- imgSize.width = srcImage->GetSize().width;
- imgSize.height = srcImage->GetSize().height;
-
- int32_t displayWidth = video->VideoWidth();
- int32_t displayHeight = video->VideoHeight();
- aSw *= (double)imgSize.width / (double)displayWidth;
- aSh *= (double)imgSize.height / (double)displayHeight;
- } else {
- gl->fDeleteTextures(1, &videoTexture);
}
+
srcImage = nullptr;
if (mCanvasElement) {
diff --git a/dom/locales/en-US/chrome/layout/layout_errors.properties b/dom/locales/en-US/chrome/layout/layout_errors.properties
index 3ef63f86fceb..2756912c2295 100644
--- a/dom/locales/en-US/chrome/layout/layout_errors.properties
+++ b/dom/locales/en-US/chrome/layout/layout_errors.properties
@@ -12,9 +12,9 @@ TablePartRelPosWarning=Relative positioning of table rows and row groups is now
ScrollLinkedEffectFound2=This site appears to use a scroll-linked positioning effect. This may not work well with asynchronous panning; see https://developer.mozilla.org/docs/Mozilla/Performance/ScrollLinkedEffects for further details and to join the discussion on related tools and features!
## LOCALIZATION NOTE(CompositorAnimationWarningContentTooLargeArea):
-## %1$S is an integer value of the area of the frame size
+## %1$S is an integer value of the area of the frame
## %2$S is an integer value of the area of a limit based on the viewport size
-CompositorAnimationWarningContentTooLargeArea=Animation cannot be run on the compositor because the area of the frame size (%1$S) is too large relative to the viewport (larger than %2$S)
+CompositorAnimationWarningContentTooLargeArea=Animation cannot be run on the compositor because the area of the frame (%1$S) is too large relative to the viewport (larger than %2$S)
## LOCALIZATION NOTE(CompositorAnimationWarningContentTooLarge2):
## (%1$S, %2$S) is a pair of integer values of the frame size
## (%3$S, %4$S) is a pair of integer values of a limit based on the viewport size
diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp
index 3a4864f296aa..055437d9327d 100644
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -22,10 +22,6 @@
#include "AndroidMediaReader.h"
#include "AndroidMediaPluginHost.h"
#endif
-#ifdef MOZ_DIRECTSHOW
-#include "DirectShowDecoder.h"
-#include "DirectShowReader.h"
-#endif
#ifdef MOZ_FMP4
#include "MP4Decoder.h"
#include "MP4Demuxer.h"
@@ -146,9 +142,6 @@ CanHandleCodecsType(const MediaContainerType& aType,
}
MediaCodecs supportedCodecs;
-#ifdef MOZ_DIRECTSHOW
- DirectShowDecoder::GetSupportedCodecs(aType, &supportedCodecs);
-#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled()) {
EnsureAndroidMediaPluginHost()->FindDecoder(aType, &supportedCodecs);
@@ -211,11 +204,6 @@ CanHandleMediaType(const MediaContainerType& aType,
if (FlacDecoder::IsSupportedType(mimeType)) {
return CANPLAY_MAYBE;
}
-#ifdef MOZ_DIRECTSHOW
- if (DirectShowDecoder::GetSupportedCodecs(mimeType, nullptr)) {
- return CANPLAY_MAYBE;
- }
-#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
EnsureAndroidMediaPluginHost()->FindDecoder(mimeType, nullptr)) {
@@ -314,15 +302,6 @@ InstantiateDecoder(const MediaContainerType& aType,
return decoder.forget();
}
-#ifdef MOZ_DIRECTSHOW
- // Note: DirectShow should come before WMF, so that we prefer DirectShow's
- // MP3 support over WMF's.
- if (DirectShowDecoder::GetSupportedCodecs(aType, nullptr)) {
- decoder = new DirectShowDecoder(aOwner);
- return decoder.forget();
- }
-#endif
-
if (IsHttpLiveStreamingType(aType)) {
// We don't have an HLS decoder.
Telemetry::Accumulate(Telemetry::MEDIA_HLS_DECODER_SUCCESS, false);
@@ -387,13 +366,7 @@ DecoderTraits::CreateReader(const MediaContainerType& aType,
if (WebMDecoder::IsSupportedType(aType)) {
decoderReader =
new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()));
- } else
-#ifdef MOZ_DIRECTSHOW
- if (DirectShowDecoder::GetSupportedCodecs(aType, nullptr)) {
- decoderReader = new DirectShowReader(aDecoder);
- } else
-#endif
- if (false) {} // dummy if to take care of the dangling else
+ }
return decoderReader;
}
@@ -426,9 +399,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
MP3Decoder::IsSupportedType(*type) ||
ADTSDecoder::IsSupportedType(*type) ||
FlacDecoder::IsSupportedType(*type) ||
-#ifdef MOZ_DIRECTSHOW
- DirectShowDecoder::GetSupportedCodecs(*type, nullptr) ||
-#endif
false;
}
diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp
index 4a4ec136ecfa..d7c92a089039 100644
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -738,9 +738,7 @@ AudioCallbackDriver::Init()
return true;
}
}
- bool aec;
- Unused << mGraphImpl->AudioTrackPresent(aec);
- SetMicrophoneActive(aec);
+ SetMicrophoneActive(mGraphImpl->mInputWanted);
cubeb_stream_register_device_changed_callback(mAudioStream,
AudioCallbackDriver::DeviceChangedCallback_s);
diff --git a/dom/media/ThreadPoolCOMListener.h b/dom/media/ThreadPoolCOMListener.h
index 881013a78f69..b5d1d147af47 100644
--- a/dom/media/ThreadPoolCOMListener.h
+++ b/dom/media/ThreadPoolCOMListener.h
@@ -13,8 +13,8 @@
namespace mozilla {
// Thread pool listener which ensures that MSCOM is initialized and
-// deinitialized on the thread pool thread. We may call into WMF or
-// DirectShow on this thread, so we need MSCOM working.
+// deinitialized on the thread pool thread. We may call into WMF on this thread,
+// so we need MSCOM working.
class MSCOMInitThreadPoolListener final : public nsIThreadPoolListener {
~MSCOMInitThreadPoolListener() {}
public:
diff --git a/dom/media/directshow/AudioSinkFilter.cpp b/dom/media/directshow/AudioSinkFilter.cpp
deleted file mode 100644
index 9f23c0e00acb..000000000000
--- a/dom/media/directshow/AudioSinkFilter.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "SampleSink.h"
-#include "AudioSinkFilter.h"
-#include "AudioSinkInputPin.h"
-#include "VideoUtils.h"
-#include "mozilla/Logging.h"
-
-
-#include
-#include
-
-#define DELETE_RESET(p) { delete (p) ; (p) = nullptr ;}
-
-DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde,
- 0xf1, 0x33, 0x7b, 0x33);
-
-using namespace mozilla::media;
-
-namespace mozilla {
-
-static LazyLogModule gDirectShowLog("DirectShowDecoder");
-#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult)
- : BaseFilter(aObjectName, CLSID_MozAudioSinkFilter),
- mFilterCritSec("AudioSinkFilter::mFilterCritSec")
-{
- (*aOutResult) = S_OK;
- mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin",
- this,
- &mFilterCritSec,
- aOutResult);
-}
-
-AudioSinkFilter::~AudioSinkFilter()
-{
-}
-
-int
-AudioSinkFilter::GetPinCount()
-{
- return 1;
-}
-
-BasePin*
-AudioSinkFilter::GetPin(int aIndex)
-{
- CriticalSectionAutoEnter lockFilter(mFilterCritSec);
- return (aIndex == 0) ? static_cast(mInputPin) : nullptr;
-}
-
-HRESULT
-AudioSinkFilter::Pause()
-{
- CriticalSectionAutoEnter lockFilter(mFilterCritSec);
- if (mState == State_Stopped) {
- // Change the state, THEN activate the input pin.
- mState = State_Paused;
- if (mInputPin && mInputPin->IsConnected()) {
- mInputPin->Active();
- }
- } else if (mState == State_Running) {
- mState = State_Paused;
- }
- return S_OK;
-}
-
-HRESULT
-AudioSinkFilter::Stop()
-{
- CriticalSectionAutoEnter lockFilter(mFilterCritSec);
- mState = State_Stopped;
- if (mInputPin) {
- mInputPin->Inactive();
- }
-
- GetSampleSink()->Flush();
-
- return S_OK;
-}
-
-HRESULT
-AudioSinkFilter::Run(REFERENCE_TIME tStart)
-{
- LOG("AudioSinkFilter::Run(%lld) [%4.2lf]",
- RefTimeToUsecs(tStart),
- double(RefTimeToUsecs(tStart)) / USECS_PER_S);
- return media::BaseFilter::Run(tStart);
-}
-
-HRESULT
-AudioSinkFilter::GetClassID( OUT CLSID * pCLSID )
-{
- (* pCLSID) = CLSID_MozAudioSinkFilter;
- return S_OK;
-}
-
-HRESULT
-AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface)
-{
- if (aIId == IID_IMediaSeeking) {
- *aInterface = static_cast(this);
- AddRef();
- return S_OK;
- }
- return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface);
-}
-
-ULONG
-AudioSinkFilter::AddRef()
-{
- return ::InterlockedIncrement(&mRefCnt);
-}
-
-ULONG
-AudioSinkFilter::Release()
-{
- unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
- if (!newRefCnt) {
- delete this;
- }
- return newRefCnt;
-}
-
-SampleSink*
-AudioSinkFilter::GetSampleSink()
-{
- return mInputPin->GetSampleSink();
-}
-
-
-// IMediaSeeking implementation.
-//
-// Calls to IMediaSeeking are forwarded to the output pin that the
-// AudioSinkInputPin is connected to, i.e. upstream towards the parser and
-// source filters, which actually implement seeking.
-#define ENSURE_CONNECTED_PIN_SEEKING \
- if (!mInputPin) { \
- return E_NOTIMPL; \
- } \
- RefPtr pinSeeking = mInputPin->GetConnectedPinSeeking(); \
- if (!pinSeeking) { \
- return E_NOTIMPL; \
- }
-
-HRESULT
-AudioSinkFilter::GetCapabilities(DWORD* aCapabilities)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetCapabilities(aCapabilities);
-}
-
-HRESULT
-AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->CheckCapabilities(aCapabilities);
-}
-
-HRESULT
-AudioSinkFilter::IsFormatSupported(const GUID* aFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->IsFormatSupported(aFormat);
-}
-
-HRESULT
-AudioSinkFilter::QueryPreferredFormat(GUID* aFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->QueryPreferredFormat(aFormat);
-}
-
-HRESULT
-AudioSinkFilter::GetTimeFormat(GUID* aFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetTimeFormat(aFormat);
-}
-
-HRESULT
-AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->IsUsingTimeFormat(aFormat);
-}
-
-HRESULT
-AudioSinkFilter::SetTimeFormat(const GUID* aFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->SetTimeFormat(aFormat);
-}
-
-HRESULT
-AudioSinkFilter::GetDuration(LONGLONG* aDuration)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetDuration(aDuration);
-}
-
-HRESULT
-AudioSinkFilter::GetStopPosition(LONGLONG* aStop)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetStopPosition(aStop);
-}
-
-HRESULT
-AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetCurrentPosition(aCurrent);
-}
-
-HRESULT
-AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget,
- const GUID* aTargetFormat,
- LONGLONG aSource,
- const GUID* aSourceFormat)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->ConvertTimeFormat(aTarget,
- aTargetFormat,
- aSource,
- aSourceFormat);
-}
-
-HRESULT
-AudioSinkFilter::SetPositions(LONGLONG* aCurrent,
- DWORD aCurrentFlags,
- LONGLONG* aStop,
- DWORD aStopFlags)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->SetPositions(aCurrent,
- aCurrentFlags,
- aStop,
- aStopFlags);
-}
-
-HRESULT
-AudioSinkFilter::GetPositions(LONGLONG* aCurrent,
- LONGLONG* aStop)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetPositions(aCurrent, aStop);
-}
-
-HRESULT
-AudioSinkFilter::GetAvailable(LONGLONG* aEarliest,
- LONGLONG* aLatest)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetAvailable(aEarliest, aLatest);
-}
-
-HRESULT
-AudioSinkFilter::SetRate(double aRate)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->SetRate(aRate);
-}
-
-HRESULT
-AudioSinkFilter::GetRate(double* aRate)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetRate(aRate);
-}
-
-HRESULT
-AudioSinkFilter::GetPreroll(LONGLONG* aPreroll)
-{
- ENSURE_CONNECTED_PIN_SEEKING
- return pinSeeking->GetPreroll(aPreroll);
-}
-
-} // namespace mozilla
-
diff --git a/dom/media/directshow/AudioSinkFilter.h b/dom/media/directshow/AudioSinkFilter.h
deleted file mode 100644
index 85abdfccf7bc..000000000000
--- a/dom/media/directshow/AudioSinkFilter.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(AudioSinkFilter_h_)
-#define AudioSinkFilter_h_
-
-#include "BaseFilter.h"
-#include "DirectShowUtils.h"
-#include "nsAutoPtr.h"
-#include "mozilla/RefPtr.h"
-
-namespace mozilla {
-
-class AudioSinkInputPin;
-class SampleSink;
-
-// Filter that acts as the end of the graph. Audio samples input into
-// this filter block the calling thread, and the calling thread is
-// unblocked when the decode thread extracts the sample. The samples
-// input into this filter are stored in the SampleSink, where the blocking
-// is implemented. The input pin owns the SampleSink.
-class AudioSinkFilter: public mozilla::media::BaseFilter,
- public IMediaSeeking
-{
-
-public:
- AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult);
- virtual ~AudioSinkFilter();
-
- // Gets the input pin's sample sink.
- SampleSink* GetSampleSink();
-
- // IUnknown implementation.
- STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface);
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
-
- // --------------------------------------------------------------------
- // CBaseFilter methods
- int GetPinCount ();
- mozilla::media::BasePin* GetPin ( IN int Index);
- STDMETHODIMP Pause ();
- STDMETHODIMP Stop ();
- STDMETHODIMP GetClassID ( OUT CLSID * pCLSID);
- STDMETHODIMP Run(REFERENCE_TIME tStart);
- // IMediaSeeking Methods...
-
- // We defer to SourceFilter, but we must expose the interface on
- // the output pins. Seeking commands come upstream from the renderers,
- // but they must be actioned at the source filters.
- STDMETHODIMP GetCapabilities(DWORD* aCapabilities);
- STDMETHODIMP CheckCapabilities(DWORD* aCapabilities);
- STDMETHODIMP IsFormatSupported(const GUID* aFormat);
- STDMETHODIMP QueryPreferredFormat(GUID* aFormat);
- STDMETHODIMP GetTimeFormat(GUID* aFormat);
- STDMETHODIMP IsUsingTimeFormat(const GUID* aFormat);
- STDMETHODIMP SetTimeFormat(const GUID* aFormat);
- STDMETHODIMP GetDuration(LONGLONG* pDuration);
- STDMETHODIMP GetStopPosition(LONGLONG* pStop);
- STDMETHODIMP GetCurrentPosition(LONGLONG* aCurrent);
- STDMETHODIMP ConvertTimeFormat(LONGLONG* aTarget,
- const GUID* aTargetFormat,
- LONGLONG aSource,
- const GUID* aSourceFormat);
- STDMETHODIMP SetPositions(LONGLONG* aCurrent,
- DWORD aCurrentFlags,
- LONGLONG* aStop,
- DWORD aStopFlags);
- STDMETHODIMP GetPositions(LONGLONG* aCurrent,
- LONGLONG* aStop);
- STDMETHODIMP GetAvailable(LONGLONG* aEarliest,
- LONGLONG* aLatest);
- STDMETHODIMP SetRate(double aRate);
- STDMETHODIMP GetRate(double* aRate);
- STDMETHODIMP GetPreroll(LONGLONG* aPreroll);
-
- // --------------------------------------------------------------------
- // class factory calls this
- static IUnknown * CreateInstance (IN LPUNKNOWN punk, OUT HRESULT * phr);
-
-private:
- CriticalSection mFilterCritSec;
-
- // Note: The input pin defers its refcounting to the sink filter, so when
- // the input pin is addrefed, what actually happens is the sink filter is
- // addrefed.
- nsAutoPtr mInputPin;
-};
-
-} // namespace mozilla
-
-#endif // AudioSinkFilter_h_
diff --git a/dom/media/directshow/AudioSinkInputPin.cpp b/dom/media/directshow/AudioSinkInputPin.cpp
deleted file mode 100644
index 85a6e3da3e68..000000000000
--- a/dom/media/directshow/AudioSinkInputPin.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "AudioSinkInputPin.h"
-#include "AudioSinkFilter.h"
-#include "SampleSink.h"
-#include "mozilla/Logging.h"
-
-#include
-
-using namespace mozilla::media;
-
-namespace mozilla {
-
-static LazyLogModule gDirectShowLog("DirectShowDecoder");
-#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName,
- AudioSinkFilter* aFilter,
- mozilla::CriticalSection* aLock,
- HRESULT* aOutResult)
- : BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName),
- mSegmentStartTime(0)
-{
- MOZ_COUNT_CTOR(AudioSinkInputPin);
- mSampleSink = new SampleSink();
-}
-
-AudioSinkInputPin::~AudioSinkInputPin()
-{
- MOZ_COUNT_DTOR(AudioSinkInputPin);
-}
-
-HRESULT
-AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType)
-{
- NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG);
- NS_ENSURE_TRUE(aOutMediaType, E_POINTER);
-
- if (aPosition > 0) {
- return S_FALSE;
- }
-
- // Note: We set output as PCM, as IEEE_FLOAT only works when using the
- // MP3 decoder as an MFT, and we can't do that while using DirectShow.
- aOutMediaType->SetType(&MEDIATYPE_Audio);
- aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM);
- aOutMediaType->SetType(&FORMAT_WaveFormatEx);
- aOutMediaType->SetTemporalCompression(FALSE);
-
- return S_OK;
-}
-
-HRESULT
-AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType)
-{
- if (!aMediaType) {
- return E_INVALIDARG;
- }
-
- GUID majorType = *aMediaType->Type();
- if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) {
- return E_INVALIDARG;
- }
-
- if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) {
- return E_INVALIDARG;
- }
-
- if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) {
- return E_INVALIDARG;
- }
-
- // We accept the media type, stash its layout format!
- WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat);
- GetSampleSink()->SetAudioFormat(wfx);
-
- return S_OK;
-}
-
-AudioSinkFilter*
-AudioSinkInputPin::GetAudioSinkFilter()
-{
- return reinterpret_cast(mFilter);
-}
-
-SampleSink*
-AudioSinkInputPin::GetSampleSink()
-{
- return mSampleSink;
-}
-
-HRESULT
-AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample)
-{
- HRESULT hr;
- REFERENCE_TIME start = 0, end = 0;
- hr = aSample->GetTime(&start, &end);
- NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
- {
- CriticalSectionAutoEnter lock(*mLock);
- start += mSegmentStartTime;
- end += mSegmentStartTime;
- }
- hr = aSample->SetMediaTime(&start, &end);
- NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
- return S_OK;
-}
-
-HRESULT
-AudioSinkInputPin::Receive(IMediaSample* aSample )
-{
- HRESULT hr;
- NS_ENSURE_TRUE(aSample, E_POINTER);
-
- hr = BaseInputPin::Receive(aSample);
- if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing
- // Set the timestamp of the sample after being adjusted for
- // seeking/segments in the "media time" attribute. When we seek,
- // DirectShow starts a new "segment", and starts labeling samples
- // from time=0 again, so we need to correct for this to get the
- // actual timestamps after seeking.
- hr = SetAbsoluteMediaTime(aSample);
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
- hr = GetSampleSink()->Receive(aSample);
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
- }
- return S_OK;
-}
-
-already_AddRefed
-AudioSinkInputPin::GetConnectedPinSeeking()
-{
- RefPtr peer = GetConnected();
- if (!peer)
- return nullptr;
- RefPtr seeking;
- peer->QueryInterface(static_cast(getter_AddRefs(seeking)));
- return seeking.forget();
-}
-
-HRESULT
-AudioSinkInputPin::BeginFlush()
-{
- HRESULT hr = media::BaseInputPin::BeginFlush();
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- GetSampleSink()->Flush();
-
- return S_OK;
-}
-
-HRESULT
-AudioSinkInputPin::EndFlush()
-{
- HRESULT hr = media::BaseInputPin::EndFlush();
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- // Reset the EOS flag, so that if we're called after a seek we still work.
- GetSampleSink()->Reset();
-
- return S_OK;
-}
-
-HRESULT
-AudioSinkInputPin::EndOfStream(void)
-{
- HRESULT hr = media::BaseInputPin::EndOfStream();
- if (FAILED(hr) || hr == S_FALSE) {
- // Pin is stil flushing.
- return hr;
- }
- GetSampleSink()->SetEOS();
-
- return S_OK;
-}
-
-
-HRESULT
-AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart,
- REFERENCE_TIME tStop,
- double dRate)
-{
- CriticalSectionAutoEnter lock(*mLock);
- // Record the start time of the new segment, so that we can store the
- // correct absolute timestamp in the "media time" each incoming sample.
- mSegmentStartTime = tStart;
- return S_OK;
-}
-
-} // namespace mozilla
-
diff --git a/dom/media/directshow/AudioSinkInputPin.h b/dom/media/directshow/AudioSinkInputPin.h
deleted file mode 100644
index 80503c641ee3..000000000000
--- a/dom/media/directshow/AudioSinkInputPin.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(AudioSinkInputPin_h_)
-#define AudioSinkInputPin_h_
-
-#include "BaseInputPin.h"
-#include "DirectShowUtils.h"
-#include "mozilla/RefPtr.h"
-#include "nsAutoPtr.h"
-
-namespace mozilla {
-
-namespace media {
- class MediaType;
-}
-
-class AudioSinkFilter;
-class SampleSink;
-
-
-// Input pin for capturing audio output of a DirectShow filter graph.
-// This is the input pin for the AudioSinkFilter.
-class AudioSinkInputPin: public mozilla::media::BaseInputPin
-{
-public:
- AudioSinkInputPin(wchar_t* aObjectName,
- AudioSinkFilter* aFilter,
- mozilla::CriticalSection* aLock,
- HRESULT* aOutResult);
- virtual ~AudioSinkInputPin();
-
- HRESULT GetMediaType (IN int iPos, OUT mozilla::media::MediaType * pmt);
- HRESULT CheckMediaType (IN const mozilla::media::MediaType * pmt);
- STDMETHODIMP Receive (IN IMediaSample *);
- STDMETHODIMP BeginFlush() override;
- STDMETHODIMP EndFlush() override;
-
- // Called when we start decoding a new segment, that happens directly after
- // a seek. This captures the segment's start time. Samples decoded by the
- // MP3 decoder have their timestamps offset from the segment start time.
- // Storing the segment start time enables us to set each sample's MediaTime
- // as an offset in the stream relative to the start of the stream, rather
- // than the start of the segment, i.e. its absolute time in the stream.
- STDMETHODIMP NewSegment(REFERENCE_TIME tStart,
- REFERENCE_TIME tStop,
- double dRate) override;
-
- STDMETHODIMP EndOfStream() override;
-
- // Returns the IMediaSeeking interface of the connected output pin.
- // We forward seeking requests upstream from the sink to the source
- // filters.
- already_AddRefed GetConnectedPinSeeking();
-
- SampleSink* GetSampleSink();
-
-private:
- AudioSinkFilter* GetAudioSinkFilter();
-
- // Sets the media time on the media sample, relative to the segment
- // start time.
- HRESULT SetAbsoluteMediaTime(IMediaSample* aSample);
-
- nsAutoPtr mSampleSink;
-
- // Synchronized by the filter lock; BaseInputPin::mLock.
- REFERENCE_TIME mSegmentStartTime;
-};
-
-} // namespace mozilla
-
-#endif // AudioSinkInputPin_h_
diff --git a/dom/media/directshow/DirectShowDecoder.cpp b/dom/media/directshow/DirectShowDecoder.cpp
deleted file mode 100644
index c9e1ff416f96..000000000000
--- a/dom/media/directshow/DirectShowDecoder.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "DirectShowDecoder.h"
-#include "DirectShowReader.h"
-#include "DirectShowUtils.h"
-#include "MediaContainerType.h"
-#include "MediaDecoderStateMachine.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/WindowsVersion.h"
-
-namespace mozilla {
-
-MediaDecoderStateMachine* DirectShowDecoder::CreateStateMachine()
-{
- return new MediaDecoderStateMachine(this, new DirectShowReader(this));
-}
-
-/* static */
-bool
-DirectShowDecoder::GetSupportedCodecs(const MediaContainerType& aType,
- MediaCodecs* aOutCodecs)
-{
- if (!IsEnabled()) {
- return false;
- }
-
- if (aType.Type() == MEDIAMIMETYPE("audio/mpeg")
- || aType.Type() == MEDIAMIMETYPE("audio/mp3")) {
- if (aOutCodecs) {
- *aOutCodecs = MediaCodecs("mp3");
- }
- return true;
- }
-
- return false;
-}
-
-/* static */
-bool
-DirectShowDecoder::IsEnabled()
-{
- return CanDecodeMP3UsingDirectShow() &&
- Preferences::GetBool("media.directshow.enabled");
-}
-
-DirectShowDecoder::DirectShowDecoder(MediaDecoderOwner* aOwner)
- : MediaDecoder(aOwner)
-{
-}
-
-DirectShowDecoder::~DirectShowDecoder() = default;
-
-} // namespace mozilla
-
diff --git a/dom/media/directshow/DirectShowDecoder.h b/dom/media/directshow/DirectShowDecoder.h
deleted file mode 100644
index 2d67870b6816..000000000000
--- a/dom/media/directshow/DirectShowDecoder.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(DirectShowDecoder_h_)
-#define DirectShowDecoder_h_
-
-#include "MediaDecoder.h"
-
-namespace mozilla {
-
-class MediaCodecs;
-class MediaContainerType;
-
-// Decoder that uses DirectShow to playback MP3 files only.
-class DirectShowDecoder : public MediaDecoder
-{
-public:
-
- explicit DirectShowDecoder(MediaDecoderOwner* aOwner);
- virtual ~DirectShowDecoder();
-
- MediaDecoder* Clone(MediaDecoderOwner* aOwner) override {
- if (!IsEnabled()) {
- return nullptr;
- }
- return new DirectShowDecoder(aOwner);
- }
-
- MediaDecoderStateMachine* CreateStateMachine() override;
-
- // Returns true if aType is a MIME type that we render with the
- // DirectShow backend. If aCodecList is non null,
- // it is filled with a (static const) null-terminated list of strings
- // denoting the codecs we'll playback. Note that playback is strictly
- // limited to MP3 only.
- static bool GetSupportedCodecs(const MediaContainerType& aType,
- MediaCodecs* aOutCodecs);
-
- // Returns true if the DirectShow backend is preffed on.
- static bool IsEnabled();
-};
-
-} // namespace mozilla
-
-#endif
diff --git a/dom/media/directshow/DirectShowReader.cpp b/dom/media/directshow/DirectShowReader.cpp
deleted file mode 100644
index 853fb08dc3a0..000000000000
--- a/dom/media/directshow/DirectShowReader.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "DirectShowReader.h"
-#include "MediaDecoderReader.h"
-#include "mozilla/RefPtr.h"
-#include "DirectShowUtils.h"
-#include "AudioSinkFilter.h"
-#include "SourceFilter.h"
-#include "SampleSink.h"
-#include "VideoUtils.h"
-
-using namespace mozilla::media;
-
-namespace mozilla {
-
-// Windows XP's MP3 decoder filter. This is available on XP only, on Vista
-// and later we can use the DMO Wrapper filter and MP3 decoder DMO.
-const GUID DirectShowReader::CLSID_MPEG_LAYER_3_DECODER_FILTER =
-{ 0x38BE3000, 0xDBF4, 0x11D0, {0x86, 0x0E, 0x00, 0xA0, 0x24, 0xCF, 0xEF, 0x6D} };
-
-
-static LazyLogModule gDirectShowLog("DirectShowDecoder");
-#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder)
- : MediaDecoderReader(aDecoder),
- mMP3FrameParser(aDecoder->GetResource()->GetLength()),
-#ifdef DIRECTSHOW_REGISTER_GRAPH
- mRotRegister(0),
-#endif
- mNumChannels(0),
- mAudioRate(0),
- mBytesPerSample(0)
-{
- MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
- MOZ_COUNT_CTOR(DirectShowReader);
-}
-
-DirectShowReader::~DirectShowReader()
-{
- MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
- MOZ_COUNT_DTOR(DirectShowReader);
-#ifdef DIRECTSHOW_REGISTER_GRAPH
- if (mRotRegister) {
- RemoveGraphFromRunningObjectTable(mRotRegister);
- }
-#endif
-}
-
-// Try to parse the MP3 stream to make sure this is indeed an MP3, get the
-// estimated duration of the stream, and find the offset of the actual MP3
-// frames in the stream, as DirectShow doesn't like large ID3 sections.
-static nsresult
-ParseMP3Headers(MP3FrameParser *aParser, MediaResource *aResource)
-{
- const uint32_t MAX_READ_SIZE = 4096;
-
- uint64_t offset = 0;
- while (aParser->NeedsData() && !aParser->ParsedHeaders()) {
- uint32_t bytesRead;
- char buffer[MAX_READ_SIZE];
- nsresult rv = aResource->ReadAt(offset, buffer,
- MAX_READ_SIZE, &bytesRead);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!bytesRead) {
- // End of stream.
- return NS_ERROR_FAILURE;
- }
-
- aParser->Parse(reinterpret_cast(buffer), bytesRead, offset);
- offset += bytesRead;
- }
-
- return aParser->IsMP3() ? NS_OK : NS_ERROR_FAILURE;
-}
-
-nsresult
-DirectShowReader::ReadMetadata(MediaInfo* aInfo,
- MetadataTags** aTags)
-{
- MOZ_ASSERT(OnTaskQueue());
- HRESULT hr;
- nsresult rv;
-
- // Create the filter graph, reference it by the GraphBuilder interface,
- // to make graph building more convenient.
- hr = CoCreateInstance(CLSID_FilterGraph,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder,
- reinterpret_cast(static_cast(getter_AddRefs(mGraph))));
- NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE);
-
- rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource());
- NS_ENSURE_SUCCESS(rv, rv);
-
- #ifdef DIRECTSHOW_REGISTER_GRAPH
- hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
- #endif
-
- // Extract the interface pointers we'll need from the filter graph.
- hr = mGraph->QueryInterface(static_cast(getter_AddRefs(mControl)));
- NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE);
-
- hr = mGraph->QueryInterface(static_cast(getter_AddRefs(mMediaSeeking)));
- NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE);
-
- // Build the graph. Create the filters we need, and connect them. We
- // build the entire graph ourselves to prevent other decoders installed
- // on the system being created and used.
-
- // Our source filters, wraps the MediaResource.
- mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio);
- NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE);
-
- rv = mSourceFilter->Init(mDecoder->GetResource(), mMP3FrameParser.GetMP3Offset());
- NS_ENSURE_SUCCESS(rv, rv);
-
- hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource");
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- // The MPEG demuxer.
- RefPtr demuxer;
- hr = CreateAndAddFilter(mGraph,
- CLSID_MPEG1Splitter,
- L"MPEG1Splitter",
- getter_AddRefs(demuxer));
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- // Platform MP3 decoder.
- RefPtr decoder;
- // Firstly try to create the MP3 decoder filter that ships with WinXP
- // directly. This filter doesn't normally exist on later versions of
- // Windows.
- hr = CreateAndAddFilter(mGraph,
- CLSID_MPEG_LAYER_3_DECODER_FILTER,
- L"MPEG Layer 3 Decoder",
- getter_AddRefs(decoder));
- if (FAILED(hr)) {
- // Failed to create MP3 decoder filter. Try to instantiate
- // the MP3 decoder DMO.
- hr = AddMP3DMOWrapperFilter(mGraph, getter_AddRefs(decoder));
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
- }
-
- // Sink, captures audio samples and inserts them into our pipeline.
- static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter";
- mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr);
- NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE);
- hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- // Join the filters.
- hr = ConnectFilters(mGraph, mSourceFilter, demuxer);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- hr = ConnectFilters(mGraph, demuxer, decoder);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- WAVEFORMATEX format;
- mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format);
- NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE);
-
- mInfo.mAudio.mChannels = mNumChannels = format.nChannels;
- mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec;
- mInfo.mAudio.mBitDepth = format.wBitsPerSample;
- mBytesPerSample = format.wBitsPerSample / 8;
-
- // Begin decoding!
- hr = mControl->Run();
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- DWORD seekCaps = 0;
- hr = mMediaSeeking->GetCapabilities(&seekCaps);
- mInfo.mMediaSeekable = SUCCEEDED(hr) && (AM_SEEKING_CanSeekAbsolute & seekCaps);
-
- int64_t duration = mMP3FrameParser.GetDuration();
- if (SUCCEEDED(hr)) {
- mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
- }
-
- LOG("Successfully initialized DirectShow MP3 decoder.");
- LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d",
- mInfo.mAudio.mChannels,
- mInfo.mAudio.mRate,
- RefTimeToUsecs(duration),
- mBytesPerSample);
-
- *aInfo = mInfo;
- // Note: The SourceFilter strips ID3v2 tags out of the stream.
- *aTags = nullptr;
-
- return NS_OK;
-}
-
-inline float
-UnsignedByteToAudioSample(uint8_t aValue)
-{
- return aValue * (2.0f / UINT8_MAX) - 1.0f;
-}
-
-bool
-DirectShowReader::Finish(HRESULT aStatus)
-{
- MOZ_ASSERT(OnTaskQueue());
-
- LOG("DirectShowReader::Finish(0x%x)", aStatus);
- // Notify the filter graph of end of stream.
- RefPtr eventSink;
- HRESULT hr = mGraph->QueryInterface(static_cast(getter_AddRefs(eventSink)));
- if (SUCCEEDED(hr) && eventSink) {
- eventSink->Notify(EC_COMPLETE, aStatus, 0);
- }
- return false;
-}
-
-class DirectShowCopy
-{
-public:
- DirectShowCopy(uint8_t *aSource, uint32_t aBytesPerSample,
- uint32_t aSamples, uint32_t aChannels)
- : mSource(aSource)
- , mBytesPerSample(aBytesPerSample)
- , mSamples(aSamples)
- , mChannels(aChannels)
- , mNextSample(0)
- { }
-
- uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples)
- {
- uint32_t maxSamples = std::min(aSamples, mSamples - mNextSample);
- uint32_t frames = maxSamples / mChannels;
- size_t byteOffset = mNextSample * mBytesPerSample;
- if (mBytesPerSample == 1) {
- for (uint32_t i = 0; i < maxSamples; ++i) {
- uint8_t *sample = mSource + byteOffset;
- aBuffer[i] = UnsignedByteToAudioSample(*sample);
- byteOffset += mBytesPerSample;
- }
- } else if (mBytesPerSample == 2) {
- for (uint32_t i = 0; i < maxSamples; ++i) {
- int16_t *sample = reinterpret_cast(mSource + byteOffset);
- aBuffer[i] = AudioSampleToFloat(*sample);
- byteOffset += mBytesPerSample;
- }
- }
- mNextSample += maxSamples;
- return frames;
- }
-
-private:
- uint8_t * const mSource;
- const uint32_t mBytesPerSample;
- const uint32_t mSamples;
- const uint32_t mChannels;
- uint32_t mNextSample;
-};
-
-bool
-DirectShowReader::DecodeAudioData()
-{
- MOZ_ASSERT(OnTaskQueue());
- HRESULT hr;
-
- SampleSink* sink = mAudioSinkFilter->GetSampleSink();
- if (sink->AtEOS()) {
- // End of stream.
- return Finish(S_OK);
- }
-
- // Get the next chunk of audio samples. This blocks until the sample
- // arrives, or an error occurs (like the stream is shutdown).
- RefPtr sample;
- hr = sink->Extract(sample);
- if (FAILED(hr) || hr == S_FALSE) {
- return Finish(hr);
- }
-
- int64_t start = 0, end = 0;
- sample->GetMediaTime(&start, &end);
- LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]",
- RefTimeToSeconds(start),
- RefTimeToSeconds(end));
-
- LONG length = sample->GetActualDataLength();
- LONG numSamples = length / mBytesPerSample;
- LONG numFrames = length / mBytesPerSample / mNumChannels;
-
- BYTE* data = nullptr;
- hr = sample->GetPointer(&data);
- NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr));
-
- mAudioCompactor.Push(mDecoder->GetResource()->Tell(),
- RefTimeToUsecs(start),
- mInfo.mAudio.mRate,
- numFrames,
- mNumChannels,
- DirectShowCopy(reinterpret_cast(data),
- mBytesPerSample,
- numSamples,
- mNumChannels));
- return true;
-}
-
-bool
-DirectShowReader::DecodeVideoFrame(bool& aKeyframeSkip,
- const media::TimeUnit& aTimeThreshold)
-{
- MOZ_ASSERT(OnTaskQueue());
- return false;
-}
-
-RefPtr
-DirectShowReader::Seek(const SeekTarget& aTarget)
-{
- nsresult res = SeekInternal(aTarget.GetTime().ToMicroseconds());
- if (NS_FAILED(res)) {
- return SeekPromise::CreateAndReject(res, __func__);
- } else {
- return SeekPromise::CreateAndResolve(aTarget.GetTime(), __func__);
- }
-}
-
-nsresult
-DirectShowReader::SeekInternal(int64_t aTargetUs)
-{
- HRESULT hr;
- MOZ_ASSERT(OnTaskQueue());
-
- LOG("DirectShowReader::Seek() target=%lld", aTargetUs);
-
- hr = mControl->Pause();
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- nsresult rv = ResetDecode();
- NS_ENSURE_SUCCESS(rv, rv);
-
- LONGLONG seekPosition = UsecsToRefTime(aTargetUs);
- hr = mMediaSeeking->SetPositions(&seekPosition,
- AM_SEEKING_AbsolutePositioning,
- nullptr,
- AM_SEEKING_NoPositioning);
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- hr = mControl->Run();
- NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
-
- return NS_OK;
-}
-
-} // namespace mozilla
diff --git a/dom/media/directshow/DirectShowReader.h b/dom/media/directshow/DirectShowReader.h
deleted file mode 100644
index 9559fa4b05bf..000000000000
--- a/dom/media/directshow/DirectShowReader.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(DirectShowReader_h_)
-#define DirectShowReader_h_
-
-#include "windows.h" // HRESULT, DWORD
-#include "MediaDecoderReader.h"
-#include "MediaResource.h"
-#include "mozilla/RefPtr.h"
-#include "MP3FrameParser.h"
-
-// Add the graph to the Running Object Table so that we can connect
-// to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must
-// also regsvr32 proppage.dll from the Windows SDK.
-// See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx
-// #define DIRECTSHOW_REGISTER_GRAPH
-
-struct IGraphBuilder;
-struct IMediaControl;
-struct IMediaSeeking;
-
-namespace mozilla {
-
-class AudioSinkFilter;
-class SourceFilter;
-
-// Decoder backend for decoding MP3 using DirectShow. DirectShow operates as
-// a filter graph. The basic design of the DirectShowReader is that we have
-// a SourceFilter that wraps the MediaResource that connects to the
-// MP3 decoder filter. The MP3 decoder filter "pulls" data as it requires it
-// downstream on its own thread. When the MP3 decoder has produced a block of
-// decoded samples, its thread calls downstream into our AudioSinkFilter,
-// passing the decoded buffer in. The AudioSinkFilter inserts the samples into
-// a SampleSink object. The SampleSink blocks the MP3 decoder's thread until
-// the decode thread calls DecodeAudioData(), whereupon the SampleSink
-// releases the decoded samples to the decode thread, and unblocks the MP3
-// decoder's thread. The MP3 decoder can then request more data from the
-// SourceFilter, and decode more data. If the decode thread calls
-// DecodeAudioData() and there's no decoded samples waiting to be extracted
-// in the SampleSink, the SampleSink blocks the decode thread until the MP3
-// decoder produces a decoded sample.
-class DirectShowReader : public MediaDecoderReader
-{
-public:
- explicit DirectShowReader(AbstractMediaDecoder* aDecoder);
-
- virtual ~DirectShowReader();
-
- bool DecodeAudioData() override;
- bool DecodeVideoFrame(bool& aKeyframeSkip,
- const media::TimeUnit& aTimeThreshold) override;
-
- nsresult ReadMetadata(MediaInfo* aInfo,
- MetadataTags** aTags) override;
-
- RefPtr Seek(const SeekTarget& aTarget) override;
-
- static const GUID CLSID_MPEG_LAYER_3_DECODER_FILTER;
-
-private:
- // Notifies the filter graph that playback is complete. aStatus is
- // the code to send to the filter graph. Always returns false, so
- // that we can just "return Finish()" from DecodeAudioData().
- bool Finish(HRESULT aStatus);
-
- nsresult SeekInternal(int64_t aTime);
-
- // DirectShow filter graph, and associated playback and seeking
- // control interfaces.
- RefPtr mGraph;
- RefPtr mControl;
- RefPtr mMediaSeeking;
-
- // Wraps the MediaResource, and feeds undecoded data into the filter graph.
- RefPtr mSourceFilter;
-
- // Sits at the end of the graph, removing decoded samples from the graph.
- // The graph will block while this is blocked, i.e. it will pause decoding.
- RefPtr mAudioSinkFilter;
-
- // Some MP3s are variable bitrate, so DirectShow's duration estimation
- // can make its duration estimation based on the wrong bitrate. So we parse
- // the MP3 frames to get a more accuate estimate of the duration.
- MP3FrameParser mMP3FrameParser;
-
-#ifdef DIRECTSHOW_REGISTER_GRAPH
- // Used to add/remove the filter graph to the Running Object Table. You can
- // connect GraphEdit/GraphStudio to the graph to observe and/or debug its
- // topology and state.
- DWORD mRotRegister;
-#endif
-
- // Number of channels in the audio stream.
- uint32_t mNumChannels;
-
- // Samples per second in the audio stream.
- uint32_t mAudioRate;
-
- // Number of bytes per sample. Can be either 1 or 2.
- uint32_t mBytesPerSample;
-};
-
-} // namespace mozilla
-
-#endif
diff --git a/dom/media/directshow/DirectShowUtils.cpp b/dom/media/directshow/DirectShowUtils.cpp
deleted file mode 100644
index b2afa7528c98..000000000000
--- a/dom/media/directshow/DirectShowUtils.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "DirectShowUtils.h"
-#include "dmodshow.h"
-#include "wmcodecdsp.h"
-#include "dmoreg.h"
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/RefPtr.h"
-#include "nsPrintfCString.h"
-
-#define WARN(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
-
-namespace mozilla {
-
-// Create a table which maps GUIDs to a string representation of the GUID.
-// This is useful for debugging purposes, for logging the GUIDs of media types.
-// This is only available when logging is enabled, i.e. not in release builds.
-struct GuidToName {
- const char* name;
- const GUID guid;
-};
-
-#pragma push_macro("OUR_GUID_ENTRY")
-#undef OUR_GUID_ENTRY
-#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
- { #name, {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} },
-
-static const GuidToName GuidToNameTable[] = {
-#include
-};
-
-#pragma pop_macro("OUR_GUID_ENTRY")
-
-const char*
-GetDirectShowGuidName(const GUID& aGuid)
-{
- const size_t len = ArrayLength(GuidToNameTable);
- for (unsigned i = 0; i < len; i++) {
- if (IsEqualGUID(aGuid, GuidToNameTable[i].guid)) {
- return GuidToNameTable[i].name;
- }
- }
- return "Unknown";
-}
-
-void
-RemoveGraphFromRunningObjectTable(DWORD aRotRegister)
-{
- RefPtr runningObjectTable;
- if (SUCCEEDED(GetRunningObjectTable(0, getter_AddRefs(runningObjectTable)))) {
- runningObjectTable->Revoke(aRotRegister);
- }
-}
-
-HRESULT
-AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister)
-{
- HRESULT hr;
-
- RefPtr moniker;
- RefPtr runningObjectTable;
-
- hr = GetRunningObjectTable(0, getter_AddRefs(runningObjectTable));
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- const size_t STRING_LENGTH = 256;
- WCHAR wsz[STRING_LENGTH];
-
- StringCchPrintfW(wsz,
- STRING_LENGTH,
- L"FilterGraph %08x pid %08x",
- (DWORD_PTR)aUnkGraph,
- GetCurrentProcessId());
-
- hr = CreateItemMoniker(L"!", wsz, getter_AddRefs(moniker));
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- hr = runningObjectTable->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE,
- aUnkGraph,
- moniker,
- aOutRotRegister);
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- return S_OK;
-}
-
-const char*
-GetGraphNotifyString(long evCode)
-{
-#define CASE(x) case x: return #x
- switch(evCode) {
- CASE(EC_ACTIVATE); // A video window is being activated or deactivated.
- CASE(EC_BANDWIDTHCHANGE); // Not supported.
- CASE(EC_BUFFERING_DATA); // The graph is buffering data, or has stopped buffering data.
- CASE(EC_BUILT); // Send by the Video Control when a graph has been built. Not forwarded to applications.
- CASE(EC_CLOCK_CHANGED); // The reference clock has changed.
- CASE(EC_CLOCK_UNSET); // The clock provider was disconnected.
- CASE(EC_CODECAPI_EVENT); // Sent by an encoder to signal an encoding event.
- CASE(EC_COMPLETE); // All data from a particular stream has been rendered.
- CASE(EC_CONTENTPROPERTY_CHANGED); // Not supported.
- CASE(EC_DEVICE_LOST); // A Plug and Play device was removed or has become available again.
- CASE(EC_DISPLAY_CHANGED); // The display mode has changed.
- CASE(EC_END_OF_SEGMENT); // The end of a segment has been reached.
- CASE(EC_EOS_SOON); // Not supported.
- CASE(EC_ERROR_STILLPLAYING); // An asynchronous command to run the graph has failed.
- CASE(EC_ERRORABORT); // An operation was aborted because of an error.
- CASE(EC_ERRORABORTEX); // An operation was aborted because of an error.
- CASE(EC_EXTDEVICE_MODE_CHANGE); // Not supported.
- CASE(EC_FILE_CLOSED); // The source file was closed because of an unexpected event.
- CASE(EC_FULLSCREEN_LOST); // The video renderer is switching out of full-screen mode.
- CASE(EC_GRAPH_CHANGED); // The filter graph has changed.
- CASE(EC_LENGTH_CHANGED); // The length of a source has changed.
- CASE(EC_LOADSTATUS); // Notifies the application of progress when opening a network file.
- CASE(EC_MARKER_HIT); // Not supported.
- CASE(EC_NEED_RESTART); // A filter is requesting that the graph be restarted.
- CASE(EC_NEW_PIN); // Not supported.
- CASE(EC_NOTIFY_WINDOW); // Notifies a filter of the video renderer's window.
- CASE(EC_OLE_EVENT); // A filter is passing a text string to the application.
- CASE(EC_OPENING_FILE); // The graph is opening a file, or has finished opening a file.
- CASE(EC_PALETTE_CHANGED); // The video palette has changed.
- CASE(EC_PAUSED); // A pause request has completed.
- CASE(EC_PLEASE_REOPEN); // The source file has changed.
- CASE(EC_PREPROCESS_COMPLETE); // Sent by the WM ASF Writer filter when it completes the pre-processing for multipass encoding.
- CASE(EC_PROCESSING_LATENCY); // Indicates the amount of time that a component is taking to process each sample.
- CASE(EC_QUALITY_CHANGE); // The graph is dropping samples, for quality control.
- //CASE(EC_RENDER_FINISHED); // Not supported.
- CASE(EC_REPAINT); // A video renderer requires a repaint.
- CASE(EC_SAMPLE_LATENCY); // Specifies how far behind schedule a component is for processing samples.
- //CASE(EC_SAMPLE_NEEDED); // Requests a new input sample from the Enhanced Video Renderer (EVR) filter.
- CASE(EC_SCRUB_TIME); // Specifies the time stamp for the most recent frame step.
- CASE(EC_SEGMENT_STARTED); // A new segment has started.
- CASE(EC_SHUTTING_DOWN); // The filter graph is shutting down, prior to being destroyed.
- CASE(EC_SNDDEV_IN_ERROR); // A device error has occurred in an audio capture filter.
- CASE(EC_SNDDEV_OUT_ERROR); // A device error has occurred in an audio renderer filter.
- CASE(EC_STARVATION); // A filter is not receiving enough data.
- CASE(EC_STATE_CHANGE); // The filter graph has changed state.
- CASE(EC_STATUS); // Contains two arbitrary status strings.
- CASE(EC_STEP_COMPLETE); // A filter performing frame stepping has stepped the specified number of frames.
- CASE(EC_STREAM_CONTROL_STARTED); // A stream-control start command has taken effect.
- CASE(EC_STREAM_CONTROL_STOPPED); // A stream-control stop command has taken effect.
- CASE(EC_STREAM_ERROR_STILLPLAYING); // An error has occurred in a stream. The stream is still playing.
- CASE(EC_STREAM_ERROR_STOPPED); // A stream has stopped because of an error.
- CASE(EC_TIMECODE_AVAILABLE); // Not supported.
- CASE(EC_UNBUILT); // Send by the Video Control when a graph has been torn down. Not forwarded to applications.
- CASE(EC_USERABORT); // The user has terminated playback.
- CASE(EC_VIDEO_SIZE_CHANGED); // The native video size has changed.
- CASE(EC_VIDEOFRAMEREADY); // A video frame is ready for display.
- CASE(EC_VMR_RECONNECTION_FAILED); // Sent by the VMR-7 and the VMR-9 when it was unable to accept a dynamic format change request from the upstream decoder.
- CASE(EC_VMR_RENDERDEVICE_SET); // Sent when the VMR has selected its rendering mechanism.
- CASE(EC_VMR_SURFACE_FLIPPED); // Sent when the VMR-7's allocator presenter has called the DirectDraw Flip method on the surface being presented.
- CASE(EC_WINDOW_DESTROYED); // The video renderer was destroyed or removed from the graph.
- CASE(EC_WMT_EVENT); // Sent by the WM ASF Reader filter when it reads ASF files protected by digital rights management (DRM).
- CASE(EC_WMT_INDEX_EVENT); // Sent when an application uses the WM ASF Writer to index Windows Media Video files.
- CASE(S_OK); // Success.
- CASE(VFW_S_AUDIO_NOT_RENDERED); // Partial success; the audio was not rendered.
- CASE(VFW_S_DUPLICATE_NAME); // Success; the Filter Graph Manager modified a filter name to avoid duplication.
- CASE(VFW_S_PARTIAL_RENDER); // Partial success; some of the streams in this movie are in an unsupported format.
- CASE(VFW_S_VIDEO_NOT_RENDERED); // Partial success; the video was not rendered.
- CASE(E_ABORT); // Operation aborted.
- CASE(E_OUTOFMEMORY); // Insufficient memory.
- CASE(E_POINTER); // Null pointer argument.
- CASE(VFW_E_CANNOT_CONNECT); // No combination of intermediate filters could be found to make the connection.
- CASE(VFW_E_CANNOT_RENDER); // No combination of filters could be found to render the stream.
- CASE(VFW_E_NO_ACCEPTABLE_TYPES); // There is no common media type between these pins.
- CASE(VFW_E_NOT_IN_GRAPH);
-
- default:
- return "Unknown Code";
- };
-#undef CASE
-}
-
-HRESULT
-CreateAndAddFilter(IGraphBuilder* aGraph,
- REFGUID aFilterClsId,
- LPCWSTR aFilterName,
- IBaseFilter **aOutFilter)
-{
- NS_ENSURE_TRUE(aGraph, E_POINTER);
- NS_ENSURE_TRUE(aOutFilter, E_POINTER);
- HRESULT hr;
-
- RefPtr filter;
- hr = CoCreateInstance(aFilterClsId,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- getter_AddRefs(filter));
- if (FAILED(hr)) {
- // Object probably not available on this system.
- WARN("CoCreateInstance failed, hr=%x", hr);
- return hr;
- }
-
- hr = aGraph->AddFilter(filter, aFilterName);
- if (FAILED(hr)) {
- WARN("AddFilter failed, hr=%x", hr);
- return hr;
- }
-
- filter.forget(aOutFilter);
-
- return S_OK;
-}
-
-HRESULT
-CreateMP3DMOWrapperFilter(IBaseFilter **aOutFilter)
-{
- NS_ENSURE_TRUE(aOutFilter, E_POINTER);
- HRESULT hr;
-
- // Create the wrapper filter.
- RefPtr filter;
- hr = CoCreateInstance(CLSID_DMOWrapperFilter,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- getter_AddRefs(filter));
- if (FAILED(hr)) {
- WARN("CoCreateInstance failed, hr=%x", hr);
- return hr;
- }
-
- // Query for IDMOWrapperFilter.
- RefPtr dmoWrapper;
- hr = filter->QueryInterface(IID_IDMOWrapperFilter,
- getter_AddRefs(dmoWrapper));
- if (FAILED(hr)) {
- WARN("QueryInterface failed, hr=%x", hr);
- return hr;
- }
-
- hr = dmoWrapper->Init(CLSID_CMP3DecMediaObject, DMOCATEGORY_AUDIO_DECODER);
- if (FAILED(hr)) {
- // Can't instantiate MP3 DMO. It doesn't exist on Windows XP, we're
- // probably hitting that. Don't log warning to console, this is an
- // expected error.
- WARN("dmoWrapper Init failed, hr=%x", hr);
- return hr;
- }
-
- filter.forget(aOutFilter);
-
- return S_OK;
-}
-
-HRESULT
-AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
- IBaseFilter **aOutFilter)
-{
- NS_ENSURE_TRUE(aGraph, E_POINTER);
- NS_ENSURE_TRUE(aOutFilter, E_POINTER);
- HRESULT hr;
-
- // Create the wrapper filter.
- RefPtr filter;
- hr = CreateMP3DMOWrapperFilter(getter_AddRefs(filter));
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- // Add the wrapper filter to graph.
- hr = aGraph->AddFilter(filter, L"MP3 Decoder DMO");
- if (FAILED(hr)) {
- WARN("AddFilter failed, hr=%x", hr);
- return hr;
- }
-
- filter.forget(aOutFilter);
-
- return S_OK;
-}
-
-bool
-CanDecodeMP3UsingDirectShow()
-{
- RefPtr filter;
-
- // Can we create the MP3 demuxer filter?
- if (FAILED(CoCreateInstance(CLSID_MPEG1Splitter,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- getter_AddRefs(filter)))) {
- return false;
- }
-
- // Can we create either the WinXP MP3 decoder filter or the MP3 DMO decoder?
- if (FAILED(CoCreateInstance(DirectShowReader::CLSID_MPEG_LAYER_3_DECODER_FILTER,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- getter_AddRefs(filter))) &&
- FAILED(CreateMP3DMOWrapperFilter(getter_AddRefs(filter)))) {
- return false;
- }
-
- // Else, we can create all of the components we need. Assume
- // DirectShow is going to work...
- return true;
-}
-
-// Match a pin by pin direction and connection state.
-HRESULT
-MatchUnconnectedPin(IPin* aPin,
- PIN_DIRECTION aPinDir,
- bool *aOutMatches)
-{
- NS_ENSURE_TRUE(aPin, E_POINTER);
- NS_ENSURE_TRUE(aOutMatches, E_POINTER);
-
- // Ensure the pin is unconnected.
- RefPtr peer;
- HRESULT hr = aPin->ConnectedTo(getter_AddRefs(peer));
- if (hr != VFW_E_NOT_CONNECTED) {
- *aOutMatches = false;
- return hr;
- }
-
- // Ensure the pin is of the specified direction.
- PIN_DIRECTION pinDir;
- hr = aPin->QueryDirection(&pinDir);
- NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
- *aOutMatches = (pinDir == aPinDir);
- return S_OK;
-}
-
-// Return the first unconnected input pin or output pin.
-already_AddRefed
-GetUnconnectedPin(IBaseFilter* aFilter, PIN_DIRECTION aPinDir)
-{
- RefPtr enumPins;
-
- HRESULT hr = aFilter->EnumPins(getter_AddRefs(enumPins));
- NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
-
- // Test each pin to see if it matches the direction we're looking for.
- RefPtr pin;
- while (S_OK == enumPins->Next(1, getter_AddRefs(pin), nullptr)) {
- bool matches = FALSE;
- if (SUCCEEDED(MatchUnconnectedPin(pin, aPinDir, &matches)) &&
- matches) {
- return pin.forget();
- }
- }
-
- return nullptr;
-}
-
-HRESULT
-ConnectFilters(IGraphBuilder* aGraph,
- IBaseFilter* aOutputFilter,
- IBaseFilter* aInputFilter)
-{
- RefPtr output = GetUnconnectedPin(aOutputFilter, PINDIR_OUTPUT);
- NS_ENSURE_TRUE(output, E_FAIL);
-
- RefPtr input = GetUnconnectedPin(aInputFilter, PINDIR_INPUT);
- NS_ENSURE_TRUE(output, E_FAIL);
-
- return aGraph->Connect(output, input);
-}
-
-} // namespace mozilla
-
-// avoid redefined macro in unified build
-#undef WARN
diff --git a/dom/media/directshow/DirectShowUtils.h b/dom/media/directshow/DirectShowUtils.h
deleted file mode 100644
index dc0432817046..000000000000
--- a/dom/media/directshow/DirectShowUtils.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#ifndef _DirectShowUtils_h_
-#define _DirectShowUtils_h_
-
-#include
-#include "dshow.h"
-
-// XXXbz windowsx.h defines GetFirstChild, GetNextSibling,
-// GetPrevSibling are macros, apparently... Eeevil. We have functions
-// called that on some classes, so undef them.
-#undef GetFirstChild
-#undef GetNextSibling
-#undef GetPrevSibling
-
-#include "DShowTools.h"
-#include "mozilla/Logging.h"
-
-namespace mozilla {
-
-// Win32 "Event" wrapper. Must be paired with a CriticalSection to create a
-// Java-style "monitor".
-class Signal {
-public:
-
- explicit Signal(CriticalSection* aLock)
- : mLock(aLock)
- {
- CriticalSectionAutoEnter lock(*mLock);
- mEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
- }
-
- ~Signal() {
- CriticalSectionAutoEnter lock(*mLock);
- CloseHandle(mEvent);
- }
-
- // Lock must be held.
- void Notify() {
- SetEvent(mEvent);
- }
-
- // Lock must be held. Check the wait condition before waiting!
- HRESULT Wait() {
- mLock->Leave();
- DWORD result = WaitForSingleObject(mEvent, INFINITE);
- mLock->Enter();
- return result == WAIT_OBJECT_0 ? S_OK : E_FAIL;
- }
-
-private:
- CriticalSection* mLock;
- HANDLE mEvent;
-};
-
-HRESULT
-AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister);
-
-void
-RemoveGraphFromRunningObjectTable(DWORD aRotRegister);
-
-const char*
-GetGraphNotifyString(long evCode);
-
-// Creates a filter and adds it to a graph.
-HRESULT
-CreateAndAddFilter(IGraphBuilder* aGraph,
- REFGUID aFilterClsId,
- LPCWSTR aFilterName,
- IBaseFilter **aOutFilter);
-
-HRESULT
-AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
- IBaseFilter **aOutFilter);
-
-// Connects the output pin on aOutputFilter to an input pin on
-// aInputFilter, in aGraph.
-HRESULT
-ConnectFilters(IGraphBuilder* aGraph,
- IBaseFilter* aOutputFilter,
- IBaseFilter* aInputFilter);
-
-HRESULT
-MatchUnconnectedPin(IPin* aPin,
- PIN_DIRECTION aPinDir,
- bool *aOutMatches);
-
-// Converts from microseconds to DirectShow "Reference Time"
-// (hundreds of nanoseconds).
-inline int64_t
-UsecsToRefTime(const int64_t aUsecs)
-{
- return aUsecs * 10;
-}
-
-// Converts from DirectShow "Reference Time" (hundreds of nanoseconds)
-// to microseconds.
-inline int64_t
-RefTimeToUsecs(const int64_t hRefTime)
-{
- return hRefTime / 10;
-}
-
-// Converts from DirectShow "Reference Time" (hundreds of nanoseconds)
-// to seconds.
-inline double
-RefTimeToSeconds(const REFERENCE_TIME aRefTime)
-{
- return double(aRefTime) / 10000000;
-}
-
-const char*
-GetDirectShowGuidName(const GUID& aGuid);
-
-// Returns true if we can instantiate an MP3 demuxer and decoder filters.
-// Use this to detect whether MP3 support is installed.
-bool
-CanDecodeMP3UsingDirectShow();
-
-} // namespace mozilla
-
-#endif
diff --git a/dom/media/directshow/SampleSink.cpp b/dom/media/directshow/SampleSink.cpp
deleted file mode 100644
index fa5dc8d19c23..000000000000
--- a/dom/media/directshow/SampleSink.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "SampleSink.h"
-#include "AudioSinkFilter.h"
-#include "AudioSinkInputPin.h"
-#include "VideoUtils.h"
-#include "mozilla/Logging.h"
-
-using namespace mozilla::media;
-
-namespace mozilla {
-
-static LazyLogModule gDirectShowLog("DirectShowDecoder");
-#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-SampleSink::SampleSink()
- : mMonitor("SampleSink"),
- mIsFlushing(false),
- mAtEOS(false)
-{
- MOZ_COUNT_CTOR(SampleSink);
-}
-
-SampleSink::~SampleSink()
-{
- MOZ_COUNT_DTOR(SampleSink);
-}
-
-void
-SampleSink::SetAudioFormat(const WAVEFORMATEX* aInFormat)
-{
- NS_ENSURE_TRUE(aInFormat, );
- ReentrantMonitorAutoEnter mon(mMonitor);
- memcpy(&mAudioFormat, aInFormat, sizeof(WAVEFORMATEX));
-}
-
-void
-SampleSink::GetAudioFormat(WAVEFORMATEX* aOutFormat)
-{
- MOZ_ASSERT(aOutFormat);
- ReentrantMonitorAutoEnter mon(mMonitor);
- memcpy(aOutFormat, &mAudioFormat, sizeof(WAVEFORMATEX));
-}
-
-HRESULT
-SampleSink::Receive(IMediaSample* aSample)
-{
- ReentrantMonitorAutoEnter mon(mMonitor);
-
- while (true) {
- if (mIsFlushing) {
- return S_FALSE;
- }
- if (!mSample) {
- break;
- }
- if (mAtEOS) {
- return E_UNEXPECTED;
- }
- // Wait until the consumer thread consumes the sample.
- mon.Wait();
- }
-
- if (MOZ_LOG_TEST(gDirectShowLog, LogLevel::Debug)) {
- REFERENCE_TIME start = 0, end = 0;
- HRESULT hr = aSample->GetMediaTime(&start, &end);
- LOG("SampleSink::Receive() [%4.2lf-%4.2lf]",
- (double)RefTimeToUsecs(start) / USECS_PER_S,
- (double)RefTimeToUsecs(end) / USECS_PER_S);
- }
-
- mSample = aSample;
- // Notify the signal, to awaken the consumer thread in WaitForSample()
- // if necessary.
- mon.NotifyAll();
- return S_OK;
-}
-
-HRESULT
-SampleSink::Extract(RefPtr& aOutSample)
-{
- ReentrantMonitorAutoEnter mon(mMonitor);
- // Loop until we have a sample, or we should abort.
- while (true) {
- if (mIsFlushing) {
- return S_FALSE;
- }
- if (mSample) {
- break;
- }
- if (mAtEOS) {
- // Order is important here, if we have a sample, we should return it
- // before reporting EOS.
- return E_UNEXPECTED;
- }
- // Wait until the producer thread gives us a sample.
- mon.Wait();
- }
- aOutSample = mSample;
-
- if (MOZ_LOG_TEST(gDirectShowLog, LogLevel::Debug)) {
- int64_t start = 0, end = 0;
- mSample->GetMediaTime(&start, &end);
- LOG("SampleSink::Extract() [%4.2lf-%4.2lf]",
- (double)RefTimeToUsecs(start) / USECS_PER_S,
- (double)RefTimeToUsecs(end) / USECS_PER_S);
- }
-
- mSample = nullptr;
- // Notify the signal, to awaken the producer thread in Receive()
- // if necessary.
- mon.NotifyAll();
- return S_OK;
-}
-
-void
-SampleSink::Flush()
-{
- LOG("SampleSink::Flush()");
- ReentrantMonitorAutoEnter mon(mMonitor);
- mIsFlushing = true;
- mSample = nullptr;
- mon.NotifyAll();
-}
-
-void
-SampleSink::Reset()
-{
- LOG("SampleSink::Reset()");
- ReentrantMonitorAutoEnter mon(mMonitor);
- mIsFlushing = false;
- mAtEOS = false;
-}
-
-void
-SampleSink::SetEOS()
-{
- LOG("SampleSink::SetEOS()");
- ReentrantMonitorAutoEnter mon(mMonitor);
- mAtEOS = true;
- // Notify to unblock any threads waiting for samples in
- // Extract() or Receive(). Now that we're at EOS, no more samples
- // will come!
- mon.NotifyAll();
-}
-
-bool
-SampleSink::AtEOS()
-{
- ReentrantMonitorAutoEnter mon(mMonitor);
- return mAtEOS && !mSample;
-}
-
-} // namespace mozilla
-
diff --git a/dom/media/directshow/SampleSink.h b/dom/media/directshow/SampleSink.h
deleted file mode 100644
index 6a1af9fee475..000000000000
--- a/dom/media/directshow/SampleSink.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(SampleSink_h_)
-#define SampleSink_h_
-
-#include "BaseFilter.h"
-#include "DirectShowUtils.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/ReentrantMonitor.h"
-
-namespace mozilla {
-
-class SampleSink {
-public:
- SampleSink();
- virtual ~SampleSink();
-
- // Sets the audio format of the incoming samples. The upstream filter
- // calls this. This makes a copy.
- void SetAudioFormat(const WAVEFORMATEX* aInFormat);
-
- // Copies the format of incoming audio samples into into *aOutFormat.
- void GetAudioFormat(WAVEFORMATEX* aOutFormat);
-
- // Called when a sample is delivered by the DirectShow graph to the sink.
- // The decode thread retrieves the sample by calling WaitForSample().
- // Blocks if there's already a sample waiting to be consumed by the decode
- // thread.
- HRESULT Receive(IMediaSample* aSample);
-
- // Retrieves a sample from the sample queue, blocking until one becomes
- // available, or until an error occurs. Returns S_FALSE on EOS.
- HRESULT Extract(RefPtr& aOutSample);
-
- // Unblocks any threads waiting in GetSample().
- // Clears mSample, which unblocks upstream stream.
- void Flush();
-
- // Opens up the sink to receive more samples in PutSample().
- // Clears EOS flag.
- void Reset();
-
- // Marks that we've reacehd the end of stream.
- void SetEOS();
-
- // Returns whether we're at end of stream.
- bool AtEOS();
-
-private:
- // All data in this class is syncronized by mMonitor.
- ReentrantMonitor mMonitor;
- RefPtr mSample;
-
- // Format of the audio stream we're receiving.
- WAVEFORMATEX mAudioFormat;
-
- bool mIsFlushing;
- bool mAtEOS;
-};
-
-} // namespace mozilla
-
-#endif // SampleSink_h_
diff --git a/dom/media/directshow/SourceFilter.cpp b/dom/media/directshow/SourceFilter.cpp
deleted file mode 100644
index 4c5a0882c3e1..000000000000
--- a/dom/media/directshow/SourceFilter.cpp
+++ /dev/null
@@ -1,683 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#include "SourceFilter.h"
-#include "MediaResource.h"
-#include "mozilla/RefPtr.h"
-#include "DirectShowUtils.h"
-#include "MP3FrameParser.h"
-#include "mozilla/Logging.h"
-#include
-
-using namespace mozilla::media;
-
-namespace mozilla {
-
-// Define to trace what's on...
-//#define DEBUG_SOURCE_TRACE 1
-
-#if defined (DEBUG_SOURCE_TRACE)
-static LazyLogModule gDirectShowLog("DirectShowDecoder");
-#define DIRECTSHOW_LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#else
-#define DIRECTSHOW_LOG(...)
-#endif
-
-static HRESULT
-DoGetInterface(IUnknown* aUnknown, void** aInterface)
-{
- if (!aInterface)
- return E_POINTER;
- *aInterface = aUnknown;
- aUnknown->AddRef();
- return S_OK;
-}
-
-// Stores details of IAsyncReader::Request().
-class ReadRequest {
-public:
-
- ReadRequest(IMediaSample* aSample,
- DWORD_PTR aDwUser,
- uint32_t aOffset,
- uint32_t aCount)
- : mSample(aSample),
- mDwUser(aDwUser),
- mOffset(aOffset),
- mCount(aCount)
- {
- MOZ_COUNT_CTOR(ReadRequest);
- }
-
- ~ReadRequest() {
- MOZ_COUNT_DTOR(ReadRequest);
- }
-
- RefPtr mSample;
- DWORD_PTR mDwUser;
- uint32_t mOffset;
- uint32_t mCount;
-};
-
-// A wrapper around media resource that presents only a partition of the
-// underlying resource to the caller to use. The partition returned is from
-// an offset to the end of stream, and this object deals with ensuring
-// the offsets and lengths etc are translated from the reduced partition
-// exposed to the caller, to the absolute offsets of the underlying stream.
-class MediaResourcePartition {
-public:
- MediaResourcePartition(MediaResource* aResource,
- int64_t aDataStart)
- : mResource(aResource),
- mDataOffset(aDataStart)
- {}
-
- int64_t GetLength() {
- int64_t len = mResource.GetLength();
- if (len == -1) {
- return len;
- }
- return std::max(0, len - mDataOffset);
- }
- nsresult ReadAt(int64_t aOffset, char* aBuffer,
- uint32_t aCount, uint32_t* aBytes)
- {
- return mResource.ReadAt(aOffset + mDataOffset,
- aBuffer,
- aCount,
- aBytes);
- }
- int64_t GetCachedDataEnd() {
- int64_t tell = mResource.GetResource()->Tell();
- int64_t dataEnd =
- mResource.GetResource()->GetCachedDataEnd(tell) - mDataOffset;
- return dataEnd;
- }
-private:
- // MediaResource from which we read data.
- MediaResourceIndex mResource;
- int64_t mDataOffset;
-};
-
-
-// Output pin for SourceFilter, which implements IAsyncReader, to
-// allow downstream filters to pull/read data from it. Downstream pins
-// register to read data using Request(), and asynchronously wait for the
-// reads to complete using WaitForNext(). They may also synchronously read
-// using SyncRead(). This class is a delegate (tear off) of
-// SourceFilter.
-//
-// We can expose only a segment of the MediaResource to the filter graph.
-// This is used to strip off the ID3v2 tags from the stream, as DirectShow
-// has trouble parsing some headers.
-//
-// Implements:
-// * IAsyncReader
-// * IPin
-// * IQualityControl
-// * IUnknown
-//
-class DECLSPEC_UUID("18e5cfb2-1015-440c-a65c-e63853235894")
-OutputPin : public IAsyncReader,
- public BasePin
-{
-public:
-
- OutputPin(MediaResource* aMediaResource,
- SourceFilter* aParent,
- CriticalSection& aFilterLock,
- int64_t aMP3DataStart);
- virtual ~OutputPin();
-
- // IUnknown
- // Defer to ref counting to BasePin, which defers to owning nsBaseFilter.
- STDMETHODIMP_(ULONG) AddRef() override { return BasePin::AddRef(); }
- STDMETHODIMP_(ULONG) Release() override { return BasePin::Release(); }
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
-
- // BasePin Overrides.
- // Determines if the pin accepts a specific media type.
- HRESULT CheckMediaType(const MediaType* aMediaType) override;
-
- // Retrieves a preferred media type, by index value.
- HRESULT GetMediaType(int aPosition, MediaType* aMediaType) override;
-
- // Releases the pin from a connection.
- HRESULT BreakConnect(void) override;
-
- // Determines whether a pin connection is suitable.
- HRESULT CheckConnect(IPin* aPin) override;
-
-
- // IAsyncReader overrides
-
- // The RequestAllocator method requests an allocator during the
- // pin connection.
- STDMETHODIMP RequestAllocator(IMemAllocator* aPreferred,
- ALLOCATOR_PROPERTIES* aProps,
- IMemAllocator** aActual) override;
-
- // The Request method queues an asynchronous request for data. Downstream
- // will call WaitForNext() when they want to retrieve the result.
- STDMETHODIMP Request(IMediaSample* aSample, DWORD_PTR aUserData) override;
-
- // The WaitForNext method waits for the next pending read request
- // to complete. This method fails if the graph is flushing.
- // Defers to SyncRead/5.
- STDMETHODIMP WaitForNext(DWORD aTimeout,
- IMediaSample** aSamples,
- DWORD_PTR* aUserData) override;
-
- // The SyncReadAligned method performs a synchronous read. The method
- // blocks until the request is completed. Defers to SyncRead/5. This
- // method does not fail if the graph is flushing.
- STDMETHODIMP SyncReadAligned(IMediaSample* aSample) override;
-
- // The SyncRead method performs a synchronous read. The method blocks
- // until the request is completed. Defers to SyncRead/5. This
- // method does not fail if the graph is flushing.
- STDMETHODIMP SyncRead(LONGLONG aPosition, LONG aLength, BYTE* aBuffer) override;
-
- // The Length method retrieves the total length of the stream.
- STDMETHODIMP Length(LONGLONG* aTotal, LONGLONG* aAvailable) override;
-
- // IPin Overrides
- STDMETHODIMP BeginFlush(void) override;
- STDMETHODIMP EndFlush(void) override;
-
- uint32_t GetAndResetBytesConsumedCount();
-
-private:
-
- // Protects thread-shared data/structures (mFlushCount, mPendingReads).
- // WaitForNext() also waits on this monitor
- CriticalSection& mPinLock;
-
- // Signal used with mPinLock to implement WaitForNext().
- Signal mSignal;
-
- // The filter that owns us. Weak reference, as we're a delegate (tear off).
- SourceFilter* mParentSource;
-
- MediaResourcePartition mResource;
-
- // Counter, inc'd in BeginFlush(), dec'd in EndFlush(). Calls to this can
- // come from multiple threads and can interleave, hence the counter.
- int32_t mFlushCount;
-
- // Number of bytes that have been read from the output pin since the last
- // time GetAndResetBytesConsumedCount() was called.
- uint32_t mBytesConsumed;
-
- // Deque of ReadRequest* for reads that are yet to be serviced.
- // nsReadRequest's are stored on the heap, popper must delete them.
- nsDeque mPendingReads;
-
- // Flags if the downstream pin has QI'd for IAsyncReader. We refuse
- // connection if they don't query, as it means they're assuming that we're
- // a push filter, and we're not.
- bool mQueriedForAsyncReader;
-
-};
-
-// For mingw __uuidof support
-#ifdef __CRT_UUID_DECL
-}
-__CRT_UUID_DECL(mozilla::OutputPin, 0x18e5cfb2,0x1015,0x440c,0xa6,0x5c,0xe6,0x38,0x53,0x23,0x58,0x94);
-namespace mozilla {
-#endif
-
-OutputPin::OutputPin(MediaResource* aResource,
- SourceFilter* aParent,
- CriticalSection& aFilterLock,
- int64_t aMP3DataStart)
- : BasePin(static_cast(aParent),
- &aFilterLock,
- L"MozillaOutputPin",
- PINDIR_OUTPUT),
- mPinLock(aFilterLock),
- mSignal(&mPinLock),
- mParentSource(aParent),
- mResource(aResource, aMP3DataStart),
- mFlushCount(0),
- mBytesConsumed(0),
- mQueriedForAsyncReader(false)
-{
- MOZ_COUNT_CTOR(OutputPin);
- DIRECTSHOW_LOG("OutputPin::OutputPin()");
-}
-
-OutputPin::~OutputPin()
-{
- MOZ_COUNT_DTOR(OutputPin);
- DIRECTSHOW_LOG("OutputPin::~OutputPin()");
-}
-
-HRESULT
-OutputPin::BreakConnect()
-{
- mQueriedForAsyncReader = false;
- return BasePin::BreakConnect();
-}
-
-STDMETHODIMP
-OutputPin::QueryInterface(REFIID aIId, void** aInterface)
-{
- if (aIId == IID_IAsyncReader) {
- mQueriedForAsyncReader = true;
- return DoGetInterface(static_cast(this), aInterface);
- }
-
- if (aIId == __uuidof(OutputPin)) {
- AddRef();
- *aInterface = this;
- return S_OK;
- }
-
- return BasePin::QueryInterface(aIId, aInterface);
-}
-
-HRESULT
-OutputPin::CheckConnect(IPin* aPin)
-{
- // Our connection is only suitable if the downstream pin knows
- // that we're asynchronous (i.e. it queried for IAsyncReader).
- return mQueriedForAsyncReader ? S_OK : S_FALSE;
-}
-
-HRESULT
-OutputPin::CheckMediaType(const MediaType* aMediaType)
-{
- const MediaType *myMediaType = mParentSource->GetMediaType();
-
- if (IsEqualGUID(aMediaType->majortype, myMediaType->majortype) &&
- IsEqualGUID(aMediaType->subtype, myMediaType->subtype) &&
- IsEqualGUID(aMediaType->formattype, myMediaType->formattype))
- {
- DIRECTSHOW_LOG("OutputPin::CheckMediaType() Match: major=%s minor=%s TC=%d FSS=%d SS=%u",
- GetDirectShowGuidName(aMediaType->majortype),
- GetDirectShowGuidName(aMediaType->subtype),
- aMediaType->TemporalCompression(),
- aMediaType->bFixedSizeSamples,
- aMediaType->SampleSize());
- return S_OK;
- }
-
- DIRECTSHOW_LOG("OutputPin::CheckMediaType() Failed to match: major=%s minor=%s TC=%d FSS=%d SS=%u",
- GetDirectShowGuidName(aMediaType->majortype),
- GetDirectShowGuidName(aMediaType->subtype),
- aMediaType->TemporalCompression(),
- aMediaType->bFixedSizeSamples,
- aMediaType->SampleSize());
- return S_FALSE;
-}
-
-HRESULT
-OutputPin::GetMediaType(int aPosition, MediaType* aMediaType)
-{
- if (!aMediaType)
- return E_POINTER;
-
- if (aPosition == 0) {
- aMediaType->Assign(mParentSource->GetMediaType());
- return S_OK;
- }
- return VFW_S_NO_MORE_ITEMS;
-}
-
-static inline bool
-IsPowerOf2(int32_t x) {
- return ((-x & x) != x);
-}
-
-STDMETHODIMP
-OutputPin::RequestAllocator(IMemAllocator* aPreferred,
- ALLOCATOR_PROPERTIES* aProps,
- IMemAllocator** aActual)
-{
- // Require the downstream pin to suggest what they want...
- if (!aPreferred) return E_POINTER;
- if (!aProps) return E_POINTER;
- if (!aActual) return E_POINTER;
-
- // We only care about alignment - our allocator will reject anything
- // which isn't power-of-2 aligned, so so try a 4-byte aligned allocator.
- ALLOCATOR_PROPERTIES props;
- memcpy(&props, aProps, sizeof(ALLOCATOR_PROPERTIES));
- if (aProps->cbAlign == 0 || IsPowerOf2(aProps->cbAlign)) {
- props.cbAlign = 4;
- }
-
- // Limit allocator's number of buffers. We know that the media will most
- // likely be bound by network speed, not by decoding speed. We also
- // store the incoming data in a Gecko stream, if we don't limit buffers
- // here we'll end up duplicating a lot of storage. We must have enough
- // space for audio key frames to fit in the first batch of buffers however,
- // else pausing may fail for some downstream decoders.
- if (props.cBuffers > BaseFilter::sMaxNumBuffers) {
- props.cBuffers = BaseFilter::sMaxNumBuffers;
- }
-
- // The allocator properties that are actually used. We don't store
- // this, we need it for SetProperties() below to succeed.
- ALLOCATOR_PROPERTIES actualProps;
- HRESULT hr;
-
- if (aPreferred) {
- // Play nice and prefer the downstream pin's preferred allocator.
- hr = aPreferred->SetProperties(&props, &actualProps);
- if (SUCCEEDED(hr)) {
- aPreferred->AddRef();
- *aActual = aPreferred;
- return S_OK;
- }
- }
-
- // Else downstream hasn't requested a specific allocator, so create one...
-
- // Just create a default allocator. It's highly unlikely that we'll use
- // this anyway, as most parsers insist on using their own allocators.
- RefPtr allocator;
- hr = CoCreateInstance(CLSID_MemoryAllocator,
- 0,
- CLSCTX_INPROC_SERVER,
- IID_IMemAllocator,
- getter_AddRefs(allocator));
- if(FAILED(hr) || (allocator == nullptr)) {
- NS_WARNING("Can't create our own DirectShow allocator.");
- return hr;
- }
-
- // See if we can make it suitable
- hr = allocator->SetProperties(&props, &actualProps);
- if (SUCCEEDED(hr)) {
- // We need to release our refcount on pAlloc, and addref
- // it to pass a refcount to the caller - this is a net nothing.
- allocator.forget(aActual);
- return S_OK;
- }
-
- NS_WARNING("Failed to pick an allocator");
- return hr;
-}
-
-STDMETHODIMP
-OutputPin::Request(IMediaSample* aSample, DWORD_PTR aDwUser)
-{
- if (!aSample) return E_FAIL;
-
- CriticalSectionAutoEnter lock(*mLock);
- NS_ASSERTION(!mFlushCount, "Request() while flushing");
-
- if (mFlushCount)
- return VFW_E_WRONG_STATE;
-
- REFERENCE_TIME refStart = 0, refEnd = 0;
- if (FAILED(aSample->GetTime(&refStart, &refEnd))) {
- NS_WARNING("Sample incorrectly timestamped");
- return VFW_E_SAMPLE_TIME_NOT_SET;
- }
-
- // Convert reference time to bytes.
- uint32_t start = (uint32_t)(refStart / 10000000);
- uint32_t end = (uint32_t)(refEnd / 10000000);
-
- uint32_t numBytes = end - start;
-
- ReadRequest* request = new ReadRequest(aSample,
- aDwUser,
- start,
- numBytes);
- // Memory for |request| is free when it's popped from the completed
- // reads list.
-
- // Push this onto the queue of reads to be serviced.
- mPendingReads.Push(request);
-
- // Notify any threads blocked in WaitForNext() which are waiting for mPendingReads
- // to become non-empty.
- mSignal.Notify();
-
- return S_OK;
-}
-
-STDMETHODIMP
-OutputPin::WaitForNext(DWORD aTimeout,
- IMediaSample** aOutSample,
- DWORD_PTR* aOutDwUser)
-{
- NS_ASSERTION(aTimeout == 0 || aTimeout == INFINITE,
- "Oops, we don't handle this!");
-
- *aOutSample = nullptr;
- *aOutDwUser = 0;
-
- LONGLONG offset = 0;
- LONG count = 0;
- BYTE* buf = nullptr;
-
- {
- CriticalSectionAutoEnter lock(*mLock);
-
- // Wait until there's a pending read to service.
- while (aTimeout && mPendingReads.GetSize() == 0 && !mFlushCount) {
- // Note: No need to guard against shutdown-during-wait here, as
- // typically the thread doing the pull will have already called
- // Request(), so we won't Wait() here anyway. SyncRead() will fail
- // on shutdown.
- mSignal.Wait();
- }
-
- nsAutoPtr request(reinterpret_cast(mPendingReads.PopFront()));
- if (!request)
- return VFW_E_WRONG_STATE;
-
- *aOutSample = request->mSample;
- *aOutDwUser = request->mDwUser;
-
- offset = request->mOffset;
- count = request->mCount;
- buf = nullptr;
- request->mSample->GetPointer(&buf);
- NS_ASSERTION(buf != nullptr, "Invalid buffer!");
-
- if (mFlushCount) {
- return VFW_E_TIMEOUT;
- }
- }
-
- return SyncRead(offset, count, buf);
-}
-
-STDMETHODIMP
-OutputPin::SyncReadAligned(IMediaSample* aSample)
-{
- {
- // Ignore reads while flushing.
- CriticalSectionAutoEnter lock(*mLock);
- if (mFlushCount) {
- return S_FALSE;
- }
- }
-
- if (!aSample)
- return E_FAIL;
-
- REFERENCE_TIME lStart = 0, lEnd = 0;
- if (FAILED(aSample->GetTime(&lStart, &lEnd))) {
- NS_WARNING("Sample incorrectly timestamped");
- return VFW_E_SAMPLE_TIME_NOT_SET;
- }
-
- // Convert reference time to bytes.
- int32_t start = (int32_t)(lStart / 10000000);
- int32_t end = (int32_t)(lEnd / 10000000);
-
- int32_t numBytes = end - start;
-
- // If the range extends off the end of stream, truncate to the end of stream
- // as per IAsyncReader specificiation.
- int64_t streamLength = mResource.GetLength();
- if (streamLength != -1) {
- // We know the exact length of the stream, fail if the requested offset
- // is beyond it.
- if (start > streamLength) {
- return VFW_E_BADALIGN;
- }
-
- // If the end of the chunk to read is off the end of the stream,
- // truncate it to the end of the stream.
- if ((start + numBytes) > streamLength) {
- numBytes = (uint32_t)(streamLength - start);
- }
- }
-
- BYTE* buf=0;
- aSample->GetPointer(&buf);
-
- return SyncRead(start, numBytes, buf);
-}
-
-STDMETHODIMP
-OutputPin::SyncRead(LONGLONG aPosition,
- LONG aLength,
- BYTE* aBuffer)
-{
- MOZ_ASSERT(!NS_IsMainThread());
- NS_ENSURE_TRUE(aPosition >= 0, E_FAIL);
- NS_ENSURE_TRUE(aLength > 0, E_FAIL);
- NS_ENSURE_TRUE(aBuffer, E_POINTER);
-
- DIRECTSHOW_LOG("OutputPin::SyncRead(%lld, %d)", aPosition, aLength);
- {
- // Ignore reads while flushing.
- CriticalSectionAutoEnter lock(*mLock);
- if (mFlushCount) {
- return S_FALSE;
- }
- }
-
- uint32_t totalBytesRead = 0;
- nsresult rv = mResource.ReadAt(aPosition,
- reinterpret_cast(aBuffer),
- aLength,
- &totalBytesRead);
- if (NS_FAILED(rv)) {
- return E_FAIL;
- }
- if (totalBytesRead > 0) {
- CriticalSectionAutoEnter lock(*mLock);
- mBytesConsumed += totalBytesRead;
- }
- return (totalBytesRead == aLength) ? S_OK : S_FALSE;
-}
-
-STDMETHODIMP
-OutputPin::Length(LONGLONG* aTotal, LONGLONG* aAvailable)
-{
- HRESULT hr = S_OK;
- int64_t length = mResource.GetLength();
- if (length == -1) {
- hr = VFW_S_ESTIMATED;
- // Don't have a length. Just lie, it seems to work...
- *aTotal = INT32_MAX;
- } else {
- *aTotal = length;
- }
- if (aAvailable) {
- *aAvailable = mResource.GetCachedDataEnd();
- }
-
- DIRECTSHOW_LOG("OutputPin::Length() len=%lld avail=%lld", *aTotal, *aAvailable);
-
- return hr;
-}
-
-STDMETHODIMP
-OutputPin::BeginFlush()
-{
- CriticalSectionAutoEnter lock(*mLock);
- mFlushCount++;
- mSignal.Notify();
- return S_OK;
-}
-
-STDMETHODIMP
-OutputPin::EndFlush(void)
-{
- CriticalSectionAutoEnter lock(*mLock);
- mFlushCount--;
- return S_OK;
-}
-
-uint32_t
-OutputPin::GetAndResetBytesConsumedCount()
-{
- CriticalSectionAutoEnter lock(*mLock);
- uint32_t bytesConsumed = mBytesConsumed;
- mBytesConsumed = 0;
- return bytesConsumed;
-}
-
-SourceFilter::SourceFilter(const GUID& aMajorType,
- const GUID& aSubType)
- : BaseFilter(L"MozillaDirectShowSource", __uuidof(SourceFilter))
-{
- MOZ_COUNT_CTOR(SourceFilter);
- mMediaType.majortype = aMajorType;
- mMediaType.subtype = aSubType;
-
- DIRECTSHOW_LOG("SourceFilter Constructor(%s, %s)",
- GetDirectShowGuidName(aMajorType),
- GetDirectShowGuidName(aSubType));
-}
-
-SourceFilter::~SourceFilter()
-{
- MOZ_COUNT_DTOR(SourceFilter);
- DIRECTSHOW_LOG("SourceFilter Destructor()");
-}
-
-BasePin*
-SourceFilter::GetPin(int n)
-{
- if (n == 0) {
- NS_ASSERTION(mOutputPin != 0, "GetPin with no pin!");
- return static_cast(mOutputPin);
- } else {
- return nullptr;
- }
-}
-
-// Get's the media type we're supplying.
-const MediaType*
-SourceFilter::GetMediaType() const
-{
- return &mMediaType;
-}
-
-nsresult
-SourceFilter::Init(MediaResource* aResource, int64_t aMP3Offset)
-{
- DIRECTSHOW_LOG("SourceFilter::Init()");
-
- mOutputPin = new OutputPin(aResource,
- this,
- mLock,
- aMP3Offset);
- NS_ENSURE_TRUE(mOutputPin != nullptr, NS_ERROR_FAILURE);
-
- return NS_OK;
-}
-
-uint32_t
-SourceFilter::GetAndResetBytesConsumedCount()
-{
- return mOutputPin->GetAndResetBytesConsumedCount();
-}
-
-
-} // namespace mozilla
diff --git a/dom/media/directshow/SourceFilter.h b/dom/media/directshow/SourceFilter.h
deleted file mode 100644
index d5ce2770e9a6..000000000000
--- a/dom/media/directshow/SourceFilter.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#if !defined(nsDirectShowSource_h___)
-#define nsDirectShowSource_h___
-
-#include "BaseFilter.h"
-#include "BasePin.h"
-#include "MediaType.h"
-
-#include "nsDeque.h"
-#include "nsAutoPtr.h"
-#include "DirectShowUtils.h"
-#include "mozilla/RefPtr.h"
-
-namespace mozilla {
-
-class MediaResource;
-class OutputPin;
-
-
-// SourceFilter is an asynchronous DirectShow source filter which
-// reads from an MediaResource, and supplies data via a pull model downstream
-// using OutputPin. It us used to supply a generic byte stream into
-// DirectShow.
-//
-// Implements:
-// * IBaseFilter
-// * IMediaFilter
-// * IPersist
-// * IUnknown
-//
-class DECLSPEC_UUID("5c2a7ad0-ba82-4659-9178-c4719a2765d6")
-SourceFilter : public media::BaseFilter
-{
-public:
-
- // Constructs source filter to deliver given media type.
- SourceFilter(const GUID& aMajorType, const GUID& aSubType);
- ~SourceFilter();
-
- nsresult Init(MediaResource *aResource, int64_t aMP3Offset);
-
- // BaseFilter overrides.
- // Only one output - the byte stream.
- int GetPinCount() override { return 1; }
-
- media::BasePin* GetPin(int n) override;
-
- // Get's the media type we're supplying.
- const media::MediaType* GetMediaType() const;
-
- uint32_t GetAndResetBytesConsumedCount();
-
-protected:
-
- // Our async pull output pin.
- nsAutoPtr mOutputPin;
-
- // Type of byte stream we output.
- media::MediaType mMediaType;
-
-};
-
-} // namespace mozilla
-
-// For mingw __uuidof support
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(mozilla::SourceFilter, 0x5c2a7ad0,0xba82,0x4659,0x91,0x78,0xc4,0x71,0x9a,0x27,0x65,0xd6);
-#endif
-
-#endif
diff --git a/dom/media/directshow/moz.build b/dom/media/directshow/moz.build
deleted file mode 100644
index 8a9b76200011..000000000000
--- a/dom/media/directshow/moz.build
+++ /dev/null
@@ -1,41 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
- 'AudioSinkFilter.h',
- 'AudioSinkInputPin.h',
- 'DirectShowDecoder.h',
- 'DirectShowReader.h',
- 'DirectShowUtils.h',
-]
-
-UNIFIED_SOURCES += [
- 'DirectShowDecoder.cpp',
- 'DirectShowUtils.cpp',
- 'SourceFilter.cpp',
-]
-
-SOURCES += [
- 'AudioSinkFilter.cpp',
- 'AudioSinkInputPin.cpp',
- 'DirectShowReader.cpp',
- 'SampleSink.cpp',
-]
-
-# If WebRTC isn't being built, we need to compile the DirectShow base classes so that
-# they're available at link time.
-if not CONFIG['MOZ_WEBRTC']:
- SOURCES += [
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseFilter.cpp',
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseInputPin.cpp',
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BasePin.cpp',
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows/MediaType.cpp',
- ]
-
-FINAL_LIBRARY = 'xul'
-LOCAL_INCLUDES += [
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows',
-]
diff --git a/dom/media/moz.build b/dom/media/moz.build
index aa13d3138498..bfee1c11029c 100644
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -50,9 +50,6 @@ DIRS += [
'webvtt',
]
-if CONFIG['MOZ_DIRECTSHOW']:
- DIRS += ['directshow']
-
if CONFIG['MOZ_ANDROID_OMX']:
DIRS += ['android']
@@ -297,11 +294,6 @@ LOCAL_INCLUDES += [
'/netwerk/base',
]
-if CONFIG['MOZ_DIRECTSHOW']:
- LOCAL_INCLUDES += [
- '/media/webrtc/trunk/webrtc/modules/video_capture/windows',
- ]
-
if CONFIG['MOZ_WEBRTC']:
LOCAL_INCLUDES += [
'/media/webrtc/signaling/src/common',
diff --git a/dom/media/platforms/wrappers/H264Converter.cpp b/dom/media/platforms/wrappers/H264Converter.cpp
index 5f0663ca86f1..948794856804 100644
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -132,14 +132,47 @@ RefPtr
H264Converter::Flush()
{
mDecodePromiseRequest.DisconnectIfExists();
- mFlushRequest.DisconnectIfExists();
- mShutdownRequest.DisconnectIfExists();
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mNeedKeyframe = true;
+
+ /*
+ When we detect a change of content in the H264 stream, we first flush the
+ current decoder (1), then shut it down (2).
+ It is possible possible for H264Converter::Flush to be called during any of
+ those time.
+ If during (1):
+ - mFlushRequest and mFlushPromise will not be empty.
+ - The old decoder can still be used, with the current extradata as stored
+ in mCurrentConfig.mExtraData.
+
+ If during (2):
+ - mShutdownRequest and mShutdownPromise won't be empty.
+ - mDecoder is empty.
+ - The old decoder is no longer referenced by the H264Converter.
+ */
+ if (mFlushPromise) {
+ // Flush in progress, hijack that one.
+ mFlushRequest.Disconnect();
+ return mFlushPromise.forget();
+ }
if (mDecoder) {
return mDecoder->Flush();
}
- return FlushPromise::CreateAndResolve(true, __func__);
+ if (!mShutdownPromise) {
+ return FlushPromise::CreateAndResolve(true, __func__);
+ }
+
+ mShutdownRequest.Disconnect();
+ // Let's continue when the the current shutdown completes.
+ RefPtr shutdownPromise = mShutdownPromise.forget();
+ return shutdownPromise->Then(
+ AbstractThread::GetCurrent()->AsTaskQueue(),
+ __func__,
+ [](bool) { return FlushPromise::CreateAndResolve(true, __func__); },
+ [](bool) {
+ MOZ_ASSERT_UNREACHABLE("Shutdown promises are always resolved");
+ return FlushPromise::CreateAndResolve(true, __func__);
+ });
}
RefPtr
@@ -158,8 +191,11 @@ H264Converter::Shutdown()
mInitPromiseRequest.DisconnectIfExists();
mDecodePromiseRequest.DisconnectIfExists();
mFlushRequest.DisconnectIfExists();
+ mFlushPromise = nullptr;
mShutdownRequest.DisconnectIfExists();
mPendingSample = nullptr;
+ mNeedAVCC.reset();
+
if (mShutdownPromise) {
// We have a shutdown in progress, return that promise instead as we can't
// shutdown a decoder twice.
@@ -347,6 +383,8 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
}
// This sample doesn't contain inband SPS/PPS
// We now check if the out of band one has changed.
+ // This scenario can only occur on Android with devices that can recycle a
+ // decoder.
if (mp4_demuxer::AnnexB::HasSPS(aSample->mExtraData) &&
!mp4_demuxer::AnnexB::CompareExtraData(aSample->mExtraData,
mOriginalExtraData)) {
@@ -373,7 +411,8 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
// The SPS has changed, signal to flush the current decoder and create a
// new one.
RefPtr self = this;
- mDecoder->Flush()
+ mFlushPromise = mDecoder->Flush();
+ mFlushPromise
->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
__func__,
[self, sample, this]() {
@@ -385,7 +424,6 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
[self, sample, this]() {
mShutdownRequest.Complete();
mShutdownPromise = nullptr;
- mNeedAVCC.reset();
nsresult rv = CreateDecoderAndInit(sample);
if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
// All good so far, will continue later.
@@ -400,6 +438,7 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
},
[self, this](const MediaResult& aError) {
mFlushRequest.Complete();
+ mFlushPromise = nullptr;
mDecodePromise.Reject(aError, __func__);
})
->Track(mFlushRequest);
diff --git a/dom/media/platforms/wrappers/H264Converter.h b/dom/media/platforms/wrappers/H264Converter.h
index f2fa1846c6bf..918843139c02 100644
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -92,6 +92,7 @@ private:
MozPromiseRequestHolder mDecodePromiseRequest;
MozPromiseHolder mDecodePromise;
MozPromiseRequestHolder mFlushRequest;
+ RefPtr mFlushPromise;
MozPromiseRequestHolder mShutdownRequest;
RefPtr mShutdownPromise;
diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js
index e5ce50b9312b..c6b06640387b 100644
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -263,10 +263,10 @@ var gPlayTests = [
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
// owl.mp3 as above, but with something funny going on in the ID3v2 tag
- // that causes DirectShow to fail.
+ // that caused DirectShow to fail.
{ name:"owl-funny-id3.mp3", type:"audio/mpeg", duration:3.343 },
// owl.mp3 as above, but with something even funnier going on in the ID3v2 tag
- // that causes DirectShow to fail.
+ // that caused DirectShow to fail.
{ name:"owl-funnier-id3.mp3", type:"audio/mpeg", duration:3.343 },
// One second of silence with ~140KB of ID3 tags. Usually when the first MP3
// frame is at such a high offset into the file, MP3FrameParser will give up
diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html
index 744d2237d397..933272327c55 100644
--- a/dom/media/test/test_can_play_type_mpeg.html
+++ b/dom/media/test/test_can_play_type_mpeg.html
@@ -162,8 +162,7 @@ var haveMp4 = getPref("media.wmf.enabled") ||
check_mp4(document.getElementById('v'), haveMp4);
-var haveMp3 = getPref("media.directshow.enabled") ||
- getPref("media.wmf.enabled") ||
+var haveMp3 = getPref("media.wmf.enabled") ||
(IsLinux() && getPref("media.ffmpeg.enabled")) ||
(IsSupportedAndroid() &&
((IsJellyBeanOrLater() && getPref("media.android-media-codec.enabled")) ||
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index d0a1085bf537..5307f9269f18 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1939,7 +1939,7 @@ WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
return SetPrincipalOnMainThread(principal, loadGroup);
}
-#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool
WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
{
@@ -2027,7 +2027,7 @@ WorkerLoadInfo::PrincipalURIMatchesScriptURL()
return equal;
}
-#endif // defined(DEBUG) || !defined(RELEASE_OR_BETA)
+#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
@@ -3922,7 +3922,7 @@ WorkerPrivateParent::SetPrincipalFromChannel(nsIChannel* aChannel)
return mLoadInfo.SetPrincipalFromChannel(aChannel);
}
-#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
template
bool
WorkerPrivateParent::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
@@ -4071,7 +4071,7 @@ WorkerPrivateParent::AssertInnerWindowIsCorrect() const
#endif
-#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
template
bool
WorkerPrivateParent::PrincipalIsValid() const
diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp
index d7088b081cad..c8692c0e1924 100644
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -2967,12 +2967,7 @@ HTMLEditor::EnableStyleSheet(const nsAString& aURL,
nsCOMPtr doc = do_QueryReferent(mDocWeak);
sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument);
- if (sheet->IsServo()) {
- // XXXheycam ServoStyleSheets don't support being enabled/disabled yet.
- NS_ERROR("stylo: ServoStyleSheets can't be disabled yet");
- return NS_ERROR_FAILURE;
- }
- return sheet->AsGecko()->SetDisabled(!aEnable);
+ return sheet->SetDisabled(!aEnable);
}
bool
diff --git a/gfx/2d/ScaledFontMac.cpp b/gfx/2d/ScaledFontMac.cpp
index 1345dcb14a29..5244a9cae751 100644
--- a/gfx/2d/ScaledFontMac.cpp
+++ b/gfx/2d/ScaledFontMac.cpp
@@ -207,7 +207,7 @@ struct writeBuf
this->offset = 0;
}
~writeBuf() {
- delete this->data;
+ delete[] this->data;
}
template
diff --git a/gfx/cairo/cairo/src/moz.build b/gfx/cairo/cairo/src/moz.build
index 8a4288cdc6bf..da8c9ec1f037 100644
--- a/gfx/cairo/cairo/src/moz.build
+++ b/gfx/cairo/cairo/src/moz.build
@@ -235,6 +235,26 @@ if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
'-Wno-error=uninitialized',
]
+if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']:
+ CFLAGS += [
+ '-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition
+ '-wd4018', # '>' : signed/unsigned mismatch
+ '-wd4047', # different levels of indirection
+ '-wd4101', # unreferenced local variable
+ '-wd4133', # 'function' : incompatible types
+ '-wd4146', # unary minus operator applied to unsigned type
+ '-wd4311', # 'variable' : pointer truncation from 'type' to 'type'
+ '-wd4477', # format string '%s' requires an argument of type 'type'
+ '-wd4996', # The compiler encountered a deprecated declaration.
+ ]
+ CXXFLAGS += [
+ '-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition
+ '-wd4018', # '>' : signed/unsigned mismatch
+ '-wd4146', # unary minus operator applied to unsigned type
+ '-wd4828', # illegal in the current source character set
+ '-wd4838', # requires a narrowing conversion
+ ]
+
# See bug 386897.
if CONFIG['GNU_CC'] and CONFIG['OS_TARGET'] == 'Android' and CONFIG['MOZ_OPTIMIZE']:
CFLAGS += ['-O2']
diff --git a/gfx/cairo/libpixman/src/moz.build b/gfx/cairo/libpixman/src/moz.build
index 3ffeddf661b3..09d2f6857be7 100644
--- a/gfx/cairo/libpixman/src/moz.build
+++ b/gfx/cairo/libpixman/src/moz.build
@@ -154,6 +154,14 @@ if CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-unused-variable',
]
+if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']:
+ CFLAGS += [
+ '-wd4047', # different levels of indirection
+ '-wd4101', # unreferenced local variable
+ '-wd4133', # 'function' : incompatible types
+ '-wd4146', # unary minus operator applied to unsigned type
+ '-wd4311', # 'variable' : pointer truncation from 'type' to 'type'
+ ]
# See bug 386897.
if CONFIG['OS_TARGET'] == 'Android' and CONFIG['MOZ_OPTIMIZE']:
diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp
index aab6f151dc24..8edb8fbc00b5 100644
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -751,6 +751,17 @@ ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
PostRestyleEvent(aElement, restyleHint, changeHint);
}
+static inline bool
+AttributeInfluencesOtherPseudoClassState(Element* aElement, nsIAtom* aAttribute)
+{
+ // We must record some state for :-moz-browser-frame and
+ // :-moz-table-border-nonzero.
+ return (aAttribute == nsGkAtoms::mozbrowser &&
+ aElement->IsAnyOfHTMLElements(nsGkAtoms::iframe, nsGkAtoms::frame)) ||
+ (aAttribute == nsGkAtoms::border &&
+ aElement->IsHTMLElement(nsGkAtoms::table));
+}
+
void
ServoRestyleManager::AttributeWillChange(Element* aElement,
int32_t aNameSpaceID,
@@ -766,6 +777,10 @@ ServoRestyleManager::AttributeWillChange(Element* aElement,
ServoElementSnapshot& snapshot = SnapshotFor(aElement);
snapshot.AddAttrs(aElement);
+ if (AttributeInfluencesOtherPseudoClassState(aElement, aAttribute)) {
+ snapshot.AddOtherPseudoClassState(aElement);
+ }
+
if (Element* parent = aElement->GetFlattenedTreeParentElementForStyle()) {
parent->NoteDirtyDescendantsForServo();
}
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 35c145abb498..e46ed972732f 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -153,7 +153,6 @@ using namespace mozilla::gfx;
#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
#define GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME "layout.css.grid-template-subgrid-value.enabled"
#define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit"
-#define DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME "layout.css.display-flow-root.enabled"
#define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled"
#define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled"
@@ -320,36 +319,6 @@ WebkitPrefixEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
}
}
-// When the pref "layout.css.display-flow-root.enabled" changes, this function is
-// invoked to let us update kDisplayKTable, to selectively disable or restore
-// the entries for "flow-root" in that table.
-static void
-DisplayFlowRootEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
-{
- NS_ASSERTION(strcmp(aPrefName, DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME) == 0,
- "Did you misspell " DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME " ?");
-
- static bool sIsDisplayFlowRootKeywordIndexInitialized;
- static int32_t sIndexOfFlowRootInDisplayTable;
- bool isDisplayFlowRootEnabled =
- Preferences::GetBool(DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME, false);
-
- if (!sIsDisplayFlowRootKeywordIndexInitialized) {
- // First run: find the position of "flow-root" in kDisplayKTable.
- sIndexOfFlowRootInDisplayTable =
- nsCSSProps::FindIndexOfKeyword(eCSSKeyword_flow_root,
- nsCSSProps::kDisplayKTable);
- sIsDisplayFlowRootKeywordIndexInitialized = true;
- }
-
- // OK -- now, stomp on or restore the "flow-root" entry in kDisplayKTable,
- // depending on whether the pref is enabled vs. disabled.
- if (sIndexOfFlowRootInDisplayTable >= 0) {
- nsCSSProps::kDisplayKTable[sIndexOfFlowRootInDisplayTable].mKeyword =
- isDisplayFlowRootEnabled ? eCSSKeyword_flow_root : eCSSKeyword_UNKNOWN;
- }
-}
-
// When the pref "layout.css.text-align-unsafe-value.enabled" changes, this
// function is called to let us update kTextAlignKTable & kTextAlignLastKTable,
// to selectively disable or restore the entries for "unsafe" in those tables.
@@ -7780,8 +7749,6 @@ static const PrefCallbacks kPrefCallbacks[] = {
WebkitPrefixEnabledPrefChangeCallback },
{ TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
TextAlignUnsafeEnabledPrefChangeCallback },
- { DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME,
- DisplayFlowRootEnabledPrefChangeCallback },
{ FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
FloatLogicalValuesEnabledPrefChangeCallback },
};
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index 477491f351c6..e50d66994420 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -800,7 +800,7 @@ nsImageFrame::EnsureIntrinsicSizeAndRatio()
// image request is null or image size not known, probably an
// invalid image specified
if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) {
- bool imageBroken = false;
+ bool imageInvalid = false;
// check for broken images. valid null images (eg. img src="") are
// not considered broken because they have no image requests
nsCOMPtr imageLoader = do_QueryInterface(mContent);
@@ -808,14 +808,21 @@ nsImageFrame::EnsureIntrinsicSizeAndRatio()
nsCOMPtr currentRequest;
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(currentRequest));
- uint32_t imageStatus;
- imageBroken =
- currentRequest &&
- NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus)) &&
- (imageStatus & imgIRequest::STATUS_ERROR);
+ if (currentRequest) {
+ uint32_t imageStatus;
+ imageInvalid =
+ NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus)) &&
+ (imageStatus & imgIRequest::STATUS_ERROR);
+ } else {
+ // check if images are user-disabled (or blocked for other
+ // reasons)
+ int16_t imageBlockingStatus;
+ imageLoader->GetImageBlockingStatus(&imageBlockingStatus);
+ imageInvalid = imageBlockingStatus != nsIContentPolicy::ACCEPT;
+ }
}
// invalid image specified. make the image big enough for the "broken" icon
- if (imageBroken) {
+ if (imageInvalid) {
nscoord edgeLengthToUse =
nsPresContext::CSSPixelsToAppUnits(
ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH)));
diff --git a/layout/reftests/bugs/1365159-1-ref.html b/layout/reftests/bugs/1365159-1-ref.html
new file mode 100644
index 000000000000..2e57a292c306
--- /dev/null
+++ b/layout/reftests/bugs/1365159-1-ref.html
@@ -0,0 +1,5 @@
+
+
+ There should be |
+ no borders visible |
+
diff --git a/layout/reftests/bugs/1365159-1.html b/layout/reftests/bugs/1365159-1.html
new file mode 100644
index 000000000000..b7583ffeb3ae
--- /dev/null
+++ b/layout/reftests/bugs/1365159-1.html
@@ -0,0 +1,8 @@
+
+
+ There should be |
+ no borders visible |
+
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index 2328082cdeaa..7d34ae5c94e3 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -2008,3 +2008,4 @@ fails-if(styloVsGecko) == 1322512-1.html 1322512-1-ref.html
== 1369584-1a.html 1369584-1-ref.html
== 1369584-1b.html 1369584-1-ref.html
== 1367592-1.html 1367592-1-ref.html
+== 1365159-1.html 1365159-1-ref.html
diff --git a/layout/reftests/css-display/display-flow-root-disabled-001-ref.html b/layout/reftests/css-display/display-flow-root-disabled-001-ref.html
deleted file mode 100644
index 15f99ceb0c6b..000000000000
--- a/layout/reftests/css-display/display-flow-root-disabled-001-ref.html
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
- Reference: display:flow-root (disabled)
-
-
-
-
-
-
-
-
-
-
-
-
- x
-
-
-
-
-
-
-
-
-
diff --git a/layout/reftests/css-display/reftest.list b/layout/reftests/css-display/reftest.list
index 60e97d3d9ca4..d09842c55eff 100644
--- a/layout/reftests/css-display/reftest.list
+++ b/layout/reftests/css-display/reftest.list
@@ -28,5 +28,4 @@ asserts(1) asserts-if(styloVsGecko,2) == display-contents-xbl-5.xul display-cont
== display-contents-writing-mode-1.html display-contents-writing-mode-1-ref.html
== display-contents-writing-mode-2.html display-contents-writing-mode-2-ref.html
needs-focus == display-contents-state-change.html display-contents-state-change-ref.html
-pref(layout.css.display-flow-root.enabled,true) == display-flow-root-001.html display-flow-root-001-ref.html
-pref(layout.css.display-flow-root.enabled,false) fails-if(styloVsGecko||stylo) == display-flow-root-001.html display-flow-root-disabled-001-ref.html
+== display-flow-root-001.html display-flow-root-001-ref.html
\ No newline at end of file
diff --git a/layout/reftests/svg/smil/container/reftest.list b/layout/reftests/svg/smil/container/reftest.list
index 0fe56d6c52b3..d58a3e839695 100644
--- a/layout/reftests/svg/smil/container/reftest.list
+++ b/layout/reftests/svg/smil/container/reftest.list
@@ -5,8 +5,8 @@
random == enveloped-tree-1.xhtml enveloped-tree-1-ref.xhtml # bug 470868
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) fuzzy-if(skiaContent,1,810) == promoted-tree-1.xhtml promoted-tree-1-ref.xhtml
random == moved-tree-1.xhtml moved-tree-1-ref.xhtml # bug 470868
-random-if(cocoaWidget||d2d) fails-if(styloVsGecko||stylo) == deferred-anim-1.xhtml deferred-anim-1-ref.xhtml # bug 470868, bug 585484
-random-if(cocoaWidget&&layersGPUAccelerated) fails-if(styloVsGecko||stylo) == deferred-tree-1.xhtml deferred-tree-1-ref.xhtml # bug 470868
+random-if(cocoaWidget||d2d) == deferred-anim-1.xhtml deferred-anim-1-ref.xhtml # bug 470868, bug 585484
+random-if(cocoaWidget&&layersGPUAccelerated) == deferred-tree-1.xhtml deferred-tree-1-ref.xhtml # bug 470868
random-if(cocoaWidget&&layersGPUAccelerated) fuzzy-if(skiaContent,1,530) == deferred-tree-2a.xhtml deferred-tree-2-ref.xhtml # bug 470868
random-if(cocoaWidget&&layersGPUAccelerated) fuzzy-if(skiaContent,1,530) == deferred-tree-2b.xhtml deferred-tree-2-ref.xhtml # bug 470868
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,16) fuzzy-if(skiaContent,1,410) == deferred-tree-3a.xhtml deferred-tree-3-ref.xhtml
diff --git a/layout/reftests/svg/smil/event/reftest.list b/layout/reftests/svg/smil/event/reftest.list
index 84463e19703d..02b845b076c6 100644
--- a/layout/reftests/svg/smil/event/reftest.list
+++ b/layout/reftests/svg/smil/event/reftest.list
@@ -1,32 +1,32 @@
# Tests related to SVG Animation (using SMIL) that use event timing.
-fails-if(styloVsGecko||stylo) == event-begin-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-begin-offset-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-begin-offset-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-begin-timeevent-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-begin-timeevent-2.svg green-box-ref.svg
-random-if(Android) fails-if(styloVsGecko||stylo) == event-begin-timeevent-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-begin-load-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-bubble-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-custom-1.svg green-box-ref.svg
+== event-begin-1.svg green-box-ref.svg
+== event-begin-offset-1.svg green-box-ref.svg
+== event-begin-offset-2.svg green-box-ref.svg
+== event-begin-timeevent-1.svg green-box-ref.svg
+== event-begin-timeevent-2.svg green-box-ref.svg
+random-if(Android) == event-begin-timeevent-3.svg green-box-ref.svg
+== event-begin-load-1.svg green-box-ref.svg
+== event-bubble-1.svg green-box-ref.svg
+== event-custom-1.svg green-box-ref.svg
== event-end-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-end-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-end-open-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-end-trimmed-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-preventDefault-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-seek-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-default-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-default-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-id-change-1.svg green-box-ref.svg
+== event-end-2.svg green-box-ref.svg
+== event-end-open-1.svg green-box-ref.svg
+== event-end-trimmed-1.svg green-box-ref.svg
+== event-preventDefault-1.svg green-box-ref.svg
+== event-seek-1.svg green-box-ref.svg
+== event-target-default-1.svg green-box-ref.svg
+== event-target-default-2.svg green-box-ref.svg
+== event-target-id-change-1.svg green-box-ref.svg
== event-target-id-change-2.svg green-box-ref.svg
== event-target-id-change-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-xlink-change-1.svg green-box-ref.svg
+== event-target-xlink-change-1.svg green-box-ref.svg
== event-target-xlink-change-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-xlink-change-3.svg green-box-ref.svg
+== event-target-xlink-change-3.svg green-box-ref.svg
== event-target-xlink-change-4.svg green-box-ref.svg
== event-target-surgery-1.svg green-box-ref.svg
== event-target-surgery-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-surgery-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == event-target-non-svg-1.xhtml green-box-ref.xhtml
-fails-if(styloVsGecko||stylo) == accesskey-entity-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == accesskey-entity-2.svg green-box-ref.svg
+== event-target-surgery-3.svg green-box-ref.svg
+== event-target-non-svg-1.xhtml green-box-ref.xhtml
+== accesskey-entity-1.svg green-box-ref.svg
+== accesskey-entity-2.svg green-box-ref.svg
diff --git a/layout/reftests/svg/smil/reftest.list b/layout/reftests/svg/smil/reftest.list
index 42f644e8c2a0..e3d4316ae0aa 100644
--- a/layout/reftests/svg/smil/reftest.list
+++ b/layout/reftests/svg/smil/reftest.list
@@ -168,8 +168,8 @@ fails-if(styloVsGecko||stylo) == anim-paintserver-1.svg anim-paintserver-1-ref.s
== anim-text-attr-01.svg anim-text-attr-01-ref.svg
# animate where the base value is non-interpolatable but will be replaced anyway
-fails-if(styloVsGecko||stylo) == anim-fill-overpaintserver-1.svg lime.svg
-fails-if(styloVsGecko||stylo) == anim-fill-overpaintserver-2.svg lime.svg
+== anim-fill-overpaintserver-1.svg lime.svg
+== anim-fill-overpaintserver-2.svg lime.svg
# animate where we fallback from 'additive' animation to non-additive
fails-if(styloVsGecko||stylo) == anim-additive-fallback-1.svg anim-standard-ref.svg
@@ -183,7 +183,7 @@ fails-if(styloVsGecko||stylo) == anim-additive-fallback-1.svg anim-standard-ref.
== anim-remove-7.svg anim-standard-ref.svg
== anim-remove-8css.svg anim-standard-ref.svg
== anim-remove-8xml.svg anim-standard-ref.svg
-fails-if(styloVsGecko||stylo) == anim-remove-9.svg anim-standard-ref.svg
+== anim-remove-9.svg anim-standard-ref.svg
== anim-retarget-1.svg anim-standard-ref.svg
== anim-retarget-2.svg anim-standard-ref.svg
== anim-retarget-3.svg anim-standard-ref.svg
@@ -248,18 +248,18 @@ fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,2) == anim-gradient-attr-presence-0
== freeze-applied-late-4.svg anim-standard-ref.svg
== frozen-to-anim-1.svg lime.svg
-fails-if(styloVsGecko||stylo) == inactivate-with-active-unchanged-1.svg anim-standard-ref.svg
-fails-if(styloVsGecko||stylo) == inactivate-with-active-unchanged-2.svg anim-standard-ref.svg
+== inactivate-with-active-unchanged-1.svg anim-standard-ref.svg
+== inactivate-with-active-unchanged-2.svg anim-standard-ref.svg
-fails-if(styloVsGecko||stylo) == mapped-attr-long-url-1.svg lime.svg
-fails-if(styloVsGecko||stylo) == mapped-attr-long-url-2.svg lime.svg
+== mapped-attr-long-url-1.svg lime.svg
+== mapped-attr-long-url-2.svg lime.svg
== min-1.svg lime.svg
-fails-if(styloVsGecko||stylo) == smil-transitions-interaction-1a.svg lime.svg
-fails-if(styloVsGecko||stylo) == smil-transitions-interaction-1b.svg lime.svg
-fails-if(styloVsGecko||stylo) == smil-transitions-interaction-2a.svg lime.svg
-fails-if(styloVsGecko||stylo) == smil-transitions-interaction-2b.svg lime.svg
+== smil-transitions-interaction-1a.svg lime.svg
+== smil-transitions-interaction-1b.svg lime.svg
+== smil-transitions-interaction-2a.svg lime.svg
+== smil-transitions-interaction-2b.svg lime.svg
== smil-transitions-interaction-3a.svg lime.svg
== smil-transitions-interaction-3b.svg lime.svg
== smil-transitions-interaction-4a.svg lime.svg
@@ -271,7 +271,7 @@ fails-if(styloVsGecko||stylo) == smil-transitions-interaction-2b.svg lime.svg
# Test animation using defs element
fails-if(styloVsGecko||stylo) == anim-defs-gradient-property.svg lime.svg
== anim-defs-gradient-attribute.svg lime.svg
-fails-if(styloVsGecko||stylo) == anim-defs-fill.svg lime.svg
+== anim-defs-fill.svg lime.svg
== anim-defs-width.svg lime.svg
# Test animation that changes 'display' attribute
diff --git a/layout/reftests/svg/smil/repeat/reftest.list b/layout/reftests/svg/smil/repeat/reftest.list
index a54b7d22aec4..9249500c7c45 100644
--- a/layout/reftests/svg/smil/repeat/reftest.list
+++ b/layout/reftests/svg/smil/repeat/reftest.list
@@ -1,3 +1,3 @@
# Tests for repeat behaviour
-fails-if(styloVsGecko||stylo) == indefinite-repeat-1.svg green-box-ref.svg
+== indefinite-repeat-1.svg green-box-ref.svg
== init-repeat-1.svg init-repeat-1-ref.svg
diff --git a/layout/reftests/svg/smil/restart/reftest.list b/layout/reftests/svg/smil/restart/reftest.list
index 77e913a2e977..98ed6d4b13bf 100644
--- a/layout/reftests/svg/smil/restart/reftest.list
+++ b/layout/reftests/svg/smil/restart/reftest.list
@@ -1,8 +1,8 @@
# Tests for restart behaviour
== reset-1.svg reset-1-ref.svg
== reset-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == reset-3.svg green-box-ref.svg
+== reset-3.svg green-box-ref.svg
== reset-4.svg green-box-ref.svg
# reset-5.svg is no longer valid and has been removed
-fails-if(styloVsGecko||stylo) == reset-6.svg green-box-ref.svg
+== reset-6.svg green-box-ref.svg
== reset-7.svg green-box-ref.svg
diff --git a/layout/reftests/svg/smil/style/reftest.list b/layout/reftests/svg/smil/style/reftest.list
index d96c309c0dff..363022b843de 100644
--- a/layout/reftests/svg/smil/style/reftest.list
+++ b/layout/reftests/svg/smil/style/reftest.list
@@ -22,28 +22,28 @@ fuzzy-if(skiaContent,1,580) == anim-css-color-3-from-by-rgb-ident.svg anim-cs
# 'fill' property, from/to/by with named colors & hex values
fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-by-ident-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-by-hex-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-by-ident-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-to-hex-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-to-ident-ident.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-to-ident-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-to-ident-ident.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-by-hex-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-by-ident-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-to-hex-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-to-ident-ident.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-to-ident-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-to-ident-ident.svg anim-css-fill-1-ref.svg
# 'fill' property, from/to/by, with 'currentColor' keyword
fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-by-ident-curcol.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-by-curcol-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-by-hex-curcol.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-to-curcol-hex.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-from-to-hex-curcol.svg anim-css-fill-1-ref.svg
-fuzzy-if(skiaContent,1,550) fails-if(styloVsGecko||stylo) == anim-css-fill-1-to-ident-curcol.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-by-curcol-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-by-hex-curcol.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-to-curcol-hex.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-from-to-hex-curcol.svg anim-css-fill-1-ref.svg
+fuzzy-if(skiaContent,1,550) == anim-css-fill-1-to-ident-curcol.svg anim-css-fill-1-ref.svg
# 'fill' property, paced calcMode
fails-if(styloVsGecko||stylo) == anim-css-fill-2-paced-rgb.svg anim-css-fill-2-ref.svg
# 'fill' property, animating *by* a named color
fuzzy-if(skiaContent,1,580) fails-if(styloVsGecko||stylo) == anim-css-fill-3-by-ident-ident.svg anim-css-fill-3-ref.svg
-fuzzy-if(skiaContent,1,580) fails-if(styloVsGecko||stylo) == anim-css-fill-3-from-by-ident-ident.svg anim-css-fill-3-ref.svg
-fuzzy-if(skiaContent,1,580) fails-if(styloVsGecko||stylo) == anim-css-fill-3-from-by-rgb-ident.svg anim-css-fill-3-ref.svg
+fuzzy-if(skiaContent,1,580) == anim-css-fill-3-from-by-ident-ident.svg anim-css-fill-3-ref.svg
+fuzzy-if(skiaContent,1,580) == anim-css-fill-3-from-by-rgb-ident.svg anim-css-fill-3-ref.svg
# check handling of overflowing color values
# NOTE: The second test fails because we compute "from + by" as the animation
@@ -52,7 +52,7 @@ fuzzy-if(skiaContent,1,580) fails-if(styloVsGecko||stylo) == anim-css-fill-3-fro
# us to clamp -- we're only supposed to clamp *final presentation values*.
# (Reference: SVG 1.1 Appendix F.4)
fails-if(styloVsGecko||stylo) == anim-css-fill-overflow-1-by.svg anim-css-fill-overflow-1-ref.svg
-fails == anim-css-fill-overflow-1-from-by.svg anim-css-fill-overflow-1-ref.svg
+fails-if(!stylo) == anim-css-fill-overflow-1-from-by.svg anim-css-fill-overflow-1-ref.svg
# 'fill-opacity' property
fuzzy-if(skiaContent,1,885) fails-if(styloVsGecko||stylo) == anim-css-fillopacity-1-by.svg anim-css-fillopacity-1-ref.svg
diff --git a/layout/reftests/svg/smil/syncbase/reftest.list b/layout/reftests/svg/smil/syncbase/reftest.list
index d08c82b2432d..52728b2a538c 100644
--- a/layout/reftests/svg/smil/syncbase/reftest.list
+++ b/layout/reftests/svg/smil/syncbase/reftest.list
@@ -1,48 +1,48 @@
# Tests related to SVG Animation (using SMIL) that use syncbase timing.
# New intervals
-fails-if(styloVsGecko||stylo) == new-interval-simple-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-simple-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-negative-offset-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-negative-offset-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-negative-offset-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-negative-offset-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-negative-syncbase-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-restart-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-restart-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-restart-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-early-end-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-early-end-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-early-end-3.svg green-box-ref.svg
+== new-interval-simple-1.svg green-box-ref.svg
+== new-interval-simple-2.svg green-box-ref.svg
+== new-interval-negative-offset-1.svg green-box-ref.svg
+== new-interval-negative-offset-2.svg green-box-ref.svg
+== new-interval-negative-offset-3.svg green-box-ref.svg
+== new-interval-negative-offset-4.svg green-box-ref.svg
+== new-interval-negative-syncbase-1.svg green-box-ref.svg
+== new-interval-restart-1.svg green-box-ref.svg
+== new-interval-restart-2.svg green-box-ref.svg
+== new-interval-restart-3.svg green-box-ref.svg
+== new-interval-early-end-1.svg green-box-ref.svg
+== new-interval-early-end-2.svg green-box-ref.svg
+== new-interval-early-end-3.svg green-box-ref.svg
== new-interval-early-end-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-early-end-5.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-early-end-6.svg green-box-ref.svg
+== new-interval-early-end-5.svg green-box-ref.svg
+== new-interval-early-end-6.svg green-box-ref.svg
== new-interval-early-end-7.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-doubly-dependent-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-doubly-dependent-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-doubly-dependent-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-triply-dependent-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-triply-dependent-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-end-negative-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-end-negative-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-end-dep-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-chain-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-chain-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-sample-order-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == new-interval-freeze-begin-1.svg green-box-ref.svg
+== new-interval-doubly-dependent-1.svg green-box-ref.svg
+== new-interval-doubly-dependent-2.svg green-box-ref.svg
+== new-interval-doubly-dependent-3.svg green-box-ref.svg
+== new-interval-triply-dependent-1.svg green-box-ref.svg
+== new-interval-triply-dependent-2.svg green-box-ref.svg
+== new-interval-end-negative-1.svg green-box-ref.svg
+== new-interval-end-negative-2.svg green-box-ref.svg
+== new-interval-end-dep-1.svg green-box-ref.svg
+== new-interval-chain-1.svg green-box-ref.svg
+== new-interval-chain-2.svg green-box-ref.svg
+== new-interval-sample-order-1.svg green-box-ref.svg
+== new-interval-freeze-begin-1.svg green-box-ref.svg
# Changing intervals
-fails-if(styloVsGecko||stylo) == changed-interval-simple-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-simple-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-simple-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-simple-4.svg green-box-ref.svg
+== changed-interval-simple-1.svg green-box-ref.svg
+== changed-interval-simple-2.svg green-box-ref.svg
+== changed-interval-simple-3.svg green-box-ref.svg
+== changed-interval-simple-4.svg green-box-ref.svg
== changed-interval-simple-5.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-resolved-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-resolved-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-sort-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-change-spec-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-change-spec-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == changed-interval-change-spec-3.svg green-box-ref.svg
+== changed-interval-resolved-1.svg green-box-ref.svg
+== changed-interval-resolved-2.svg green-box-ref.svg
+== changed-interval-sort-1.svg green-box-ref.svg
+== changed-interval-change-spec-1.svg green-box-ref.svg
+== changed-interval-change-spec-2.svg green-box-ref.svg
+== changed-interval-change-spec-3.svg green-box-ref.svg
== changed-interval-change-spec-4.svg green-box-ref.svg
# Deleted intervals
@@ -53,47 +53,47 @@ fails-if(styloVsGecko||stylo) == changed-interval-change-spec-3.svg green-box-re
== deleted-interval-simple-5.svg green-box-ref.svg
# Trimmed intervals
-fails-if(styloVsGecko||stylo) == trimmed-interval-1.svg green-box-ref.svg
+== trimmed-interval-1.svg green-box-ref.svg
# Cyclic dependencies
-fails-if(styloVsGecko||stylo) == cycle-ok-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-ok-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-ok-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-ok-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-ok-5.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-self-ref-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-self-ref-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-self-ref-3.svg green-box-ref.svg
+== cycle-ok-1.svg green-box-ref.svg
+== cycle-ok-2.svg green-box-ref.svg
+== cycle-ok-3.svg green-box-ref.svg
+== cycle-ok-4.svg green-box-ref.svg
+== cycle-ok-5.svg green-box-ref.svg
+== cycle-self-ref-1.svg green-box-ref.svg
+== cycle-self-ref-2.svg green-box-ref.svg
+== cycle-self-ref-3.svg green-box-ref.svg
== cycle-self-ref-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-self-ref-5.svg green-box-ref.svg
+== cycle-self-ref-5.svg green-box-ref.svg
== cycle-invalid-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-invalid-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-invalid-3.svg green-box-ref.svg
+== cycle-invalid-2.svg green-box-ref.svg
+== cycle-invalid-3.svg green-box-ref.svg
== cycle-invalid-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-change-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-change-2.svg green-box-ref.svg
+== cycle-change-1.svg green-box-ref.svg
+== cycle-change-2.svg green-box-ref.svg
== cycle-delete-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == cycle-recursion-1.svg green-box-ref.svg
+== cycle-recursion-1.svg green-box-ref.svg
== cycle-recursion-2.svg green-box-ref.svg
# Animation sandwich priority
-fails-if(styloVsGecko||stylo) == sandwich-priority-1.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-2.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-3.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-4.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-5.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-6.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-7.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-8.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-9.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-10.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-11.svg green-box-ref.svg
-fails-if(styloVsGecko||stylo) == sandwich-priority-12.svg green-box-ref.svg
+== sandwich-priority-1.svg green-box-ref.svg
+== sandwich-priority-2.svg green-box-ref.svg
+== sandwich-priority-3.svg green-box-ref.svg
+== sandwich-priority-4.svg green-box-ref.svg
+== sandwich-priority-5.svg green-box-ref.svg
+== sandwich-priority-6.svg green-box-ref.svg
+== sandwich-priority-7.svg green-box-ref.svg
+== sandwich-priority-8.svg green-box-ref.svg
+== sandwich-priority-9.svg green-box-ref.svg
+== sandwich-priority-10.svg green-box-ref.svg
+== sandwich-priority-11.svg green-box-ref.svg
+== sandwich-priority-12.svg green-box-ref.svg
# Cross-time container dependencies
-fails-if(styloVsGecko||stylo) == cross-container-1.xhtml green-box-ref.xhtml
+== cross-container-1.xhtml green-box-ref.xhtml
== cross-container-2.xhtml green-box-ref.xhtml
-fails-if(styloVsGecko||stylo) == cross-container-3.xhtml green-box-ref.xhtml
+== cross-container-3.xhtml green-box-ref.xhtml
# Filtering
-fails-if(styloVsGecko||stylo) == filtered-interval-1.svg green-box-ref.svg
+== filtered-interval-1.svg green-box-ref.svg
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 0da5ef549f2a..62755fddaa2a 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1412,10 +1412,10 @@ Loader::InsertChildSheet(StyleSheet* aSheet,
MOZ_ASSERT(aParentSheet, "Need a parent to insert into");
MOZ_ASSERT_IF(aSheet->IsGecko(), aGeckoParentRule && !aServoChildSheet);
MOZ_ASSERT_IF(aSheet->IsServo(), aServoChildSheet && !aGeckoParentRule);
+ // child sheets should always start out enabled, even if they got
+ // cloned off of top-level sheets which were disabled
+ aSheet->SetEnabled(true);
if (aSheet->IsGecko()) {
- // child sheets should always start out enabled, even if they got
- // cloned off of top-level sheets which were disabled
- aSheet->AsGecko()->SetEnabled(true);
aGeckoParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
} else {
if (!aSheet->AsServo()->RawSheet()) {
@@ -1900,8 +1900,7 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
// If mSheetAlreadyComplete, then the sheet could well be modified between
// when we posted the async call to SheetComplete and now, since the sheet
// was page-accessible during that whole time.
- MOZ_ASSERT(!(data->mSheet->IsGecko() &&
- data->mSheet->AsGecko()->IsModified()),
+ MOZ_ASSERT(!data->mSheet->IsModified(),
"should not get marked modified during parsing");
data->mSheet->SetComplete();
data->ScheduleLoadEventIfNeeded(aStatus);
diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml
index 6370cf0862ec..baad9246d7c0 100644
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -281,7 +281,7 @@ opaque-types = [
"nsTObserverArray", # <- Inherits from nsAutoTObserverArray
"nsTHashtable", # <- Inheriting from inner typedefs that clang
# doesn't expose properly.
- "nsRefPtrHashtable", "nsDataHashtable", "nsClassHashtable", # <- Ditto
+ "nsBaseHashtable", "nsRefPtrHashtable", "nsDataHashtable", "nsClassHashtable", # <- Ditto
"nsInterfaceHashtable", # <- Ditto
"nsIDocument_SelectorCache", # <- Inherits from nsExpirationTracker<.., 4>
"nsIPresShell_ScrollAxis", # <- For some reason the alignment of this is 4
diff --git a/layout/style/ServoElementSnapshot.cpp b/layout/style/ServoElementSnapshot.cpp
index bb1987388aca..b404caa98e6b 100644
--- a/layout/style/ServoElementSnapshot.cpp
+++ b/layout/style/ServoElementSnapshot.cpp
@@ -14,6 +14,8 @@ namespace mozilla {
ServoElementSnapshot::ServoElementSnapshot(const Element* aElement)
: mState(0)
, mContains(Flags(0))
+ , mIsTableBorderNonzero(false)
+ , mIsMozBrowserFrame(false)
{
MOZ_COUNT_CTOR(ServoElementSnapshot);
mIsHTMLElementInHTMLDocument =
@@ -53,4 +55,23 @@ ServoElementSnapshot::AddAttrs(Element* aElement)
}
}
+void
+ServoElementSnapshot::AddOtherPseudoClassState(Element* aElement)
+{
+ MOZ_ASSERT(aElement);
+
+ if (HasOtherPseudoClassState()) {
+ return;
+ }
+
+ mIsTableBorderNonzero =
+ *nsCSSPseudoClasses::MatchesElement(CSSPseudoClassType::mozTableBorderNonzero,
+ aElement);
+ mIsMozBrowserFrame =
+ *nsCSSPseudoClasses::MatchesElement(CSSPseudoClassType::mozBrowserFrame,
+ aElement);
+
+ mContains |= Flags::OtherPseudoClassState;
+}
+
} // namespace mozilla
diff --git a/layout/style/ServoElementSnapshot.h b/layout/style/ServoElementSnapshot.h
index bee003fab7d6..ebcc14dd7b7b 100644
--- a/layout/style/ServoElementSnapshot.h
+++ b/layout/style/ServoElementSnapshot.h
@@ -48,6 +48,7 @@ enum class ServoElementSnapshotFlags : uint8_t
Attributes = 1 << 1,
Id = 1 << 2,
MaybeClass = 1 << 3,
+ OtherPseudoClassState = 1 << 4,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoElementSnapshotFlags)
@@ -75,6 +76,11 @@ public:
bool HasState() const { return HasAny(Flags::State); }
+ bool HasOtherPseudoClassState() const
+ {
+ return HasAny(Flags::OtherPseudoClassState);
+ }
+
/**
* Captures the given state (if not previously captured).
*/
@@ -91,6 +97,12 @@ public:
*/
void AddAttrs(Element* aElement);
+ /**
+ * Captures some other pseudo-class matching state not included in
+ * EventStates.
+ */
+ void AddOtherPseudoClassState(Element* aElement);
+
/**
* Needed methods for attribute matching.
*/
@@ -140,6 +152,18 @@ public:
bool HasAny(Flags aFlags) const { return bool(mContains & aFlags); }
+ bool IsTableBorderNonzero() const
+ {
+ MOZ_ASSERT(HasOtherPseudoClassState());
+ return mIsTableBorderNonzero;
+ }
+
+ bool IsMozBrowserFrame() const
+ {
+ MOZ_ASSERT(HasOtherPseudoClassState());
+ return mIsMozBrowserFrame;
+ }
+
private:
// TODO: Profile, a 1 or 2 element AutoTArray could be worth it, given we know
// we're dealing with attribute changes when we take snapshots of attributes,
@@ -148,8 +172,10 @@ private:
nsTArray mAttrs;
ServoStateType mState;
Flags mContains;
- bool mIsHTMLElementInHTMLDocument;
- bool mIsInChromeDocument;
+ bool mIsHTMLElementInHTMLDocument : 1;
+ bool mIsInChromeDocument : 1;
+ bool mIsTableBorderNonzero : 1;
+ bool mIsMozBrowserFrame : 1;
};
} // namespace mozilla
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index 74ac7114e847..17a169ea750c 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -6695,6 +6695,33 @@ GetEnumColorValue(nsCSSKeyword aKeyword, bool aIsChrome)
return Some(value);
}
+/// Returns the number of digits in a positive number
+/// assuming it has <= 6 digits
+static uint32_t
+CountNumbersForHashlessColor(uint32_t number) {
+ /// Just use a simple match instead of calculating a log
+ /// or dividing in a loop to be more efficient.
+ if (number < 10) {
+ return 1;
+ } else if (number < 100) {
+ return 2;
+ } else if (number < 1000) {
+ return 3;
+ } else if (number < 10000) {
+ return 4;
+ } else if (number < 100000) {
+ return 5;
+ } else if (number < 1000000) {
+ return 6;
+ } else {
+ // we don't care about numbers with more than 6 digits other
+ // than the fact that they have more than 6 digits, so just return something
+ // larger than 6 here. This is incorrect in the general case.
+ return 100;
+ }
+}
+
+
CSSParseResult
CSSParserImpl::ParseColor(nsCSSValue& aValue)
{
@@ -6804,16 +6831,20 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
// try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
if (mHashlessColorQuirk) {
+ // https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
+ //
// - If the string starts with 'a-f', the nsCSSScanner builds the
// token as a eCSSToken_Ident and we can parse the string as a
// 'xxyyzz' RGB color.
- // - If it only contains '0-9' digits, the token is a
+ // - If it only contains up to six '0-9' digits, the token is a
// eCSSToken_Number and it must be converted back to a 6
- // characters string to be parsed as a RGB color.
+ // characters string to be parsed as a RGB color. The number cannot
+ // be specified as more than six digits.
// - If it starts with '0-9' and contains any 'a-f', the token is a
// eCSSToken_Dimension, the mNumber part must be converted back to
// a string and the mIdent part must be appended to that string so
- // that the resulting string has 6 characters.
+ // that the resulting string has 6 characters. The combined
+ // dimension cannot be longer than 6 characters.
// Note: This is a hack for Nav compatibility. Do not attempt to
// simplify it by hacking into the ncCSSScanner. This would be very
// bad.
@@ -6825,15 +6856,17 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
break;
case eCSSToken_Number:
- if (tk->mIntegerValid) {
+ if (tk->mIntegerValid && tk->mInteger < 1000000 && tk->mInteger >= 0) {
SprintfLiteral(buffer, "%06d", tk->mInteger);
str.AssignWithConversion(buffer);
}
break;
case eCSSToken_Dimension:
- if (tk->mIdent.Length() <= 6) {
- SprintfLiteral(buffer, "%06.0f", tk->mNumber);
+ if (tk->mIntegerValid &&
+ tk->mIdent.Length() + CountNumbersForHashlessColor(tk->mInteger) <= 6 &&
+ tk->mInteger >= 0) {
+ SprintfLiteral(buffer, "%06d", tk->mInteger);
nsAutoString temp;
temp.AssignWithConversion(buffer);
temp.Right(str, 6 - tk->mIdent.Length());
diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp
index 2079b118a163..b92a14833931 100644
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1294,7 +1294,6 @@ KTableEntry nsCSSProps::kDisplayKTable[] = {
{ eCSSKeyword__webkit_flex, StyleDisplay::Flex },
{ eCSSKeyword__webkit_inline_flex, StyleDisplay::InlineFlex },
{ eCSSKeyword_contents, StyleDisplay::Contents },
- // The next entry is controlled by the layout.css.display-flow-root.enabled pref.
{ eCSSKeyword_flow_root, StyleDisplay::FlowRoot },
{ eCSSKeyword_UNKNOWN, -1 }
};
diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp
index 2e4a45eb45a9..275e6fc61d29 100644
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -256,10 +256,10 @@ nsLayoutStylesheetCache::Shutdown()
{
gCSSLoader_Gecko = nullptr;
gCSSLoader_Servo = nullptr;
- MOZ_ASSERT(!gStyleCache_Gecko || !gUserContentSheetURL_Gecko,
- "Got the URL but never used by Gecko?");
- MOZ_ASSERT(!gStyleCache_Servo || !gUserContentSheetURL_Servo,
- "Got the URL but never used by Servo?");
+ NS_WARNING_ASSERTION(!gStyleCache_Gecko || !gUserContentSheetURL_Gecko,
+ "Got the URL but never used by Gecko?");
+ NS_WARNING_ASSERTION(!gStyleCache_Servo || !gUserContentSheetURL_Servo,
+ "Got the URL but never used by Servo?");
gStyleCache_Gecko = nullptr;
gStyleCache_Servo = nullptr;
gUserContentSheetURL_Gecko = nullptr;
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 8559616344b7..6632e9a8139b 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7852,9 +7852,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.float-logical-values.enabled")) {
gCSSProperties["clear"].invalid_values.push("inline-end");
}
-if (IsCSSPropertyPrefEnabled("layout.css.display-flow-root.enabled")) {
- gCSSProperties["display"].other_values.push("flow-root");
-}
+gCSSProperties["display"].other_values.push("flow-root");
// Copy aliased properties' fields from their alias targets.
for (var prop in gCSSProperties) {
diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md
index 1a8b032645dc..dcf34b062403 100644
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -113,7 +113,7 @@ to mochitest command.
* getComputedStyle style doesn't contain custom properties bug 1336891
* test_variable_serialization_computed.html [35]
* test_variables.html `custom property name` [2]
-* test_css_supports.html: issues around @supports syntax servo/servo#15482 [7]
+* test_css_supports.html: issues around @supports syntax servo/servo#15482 [2]
* test_author_specified_style.html: support serializing color as author specified bug 1348165 [27]
* browser_newtab_share_rule_processors.js: agent style sheet sharing [1]
* :visited support (bug 1328509)
diff --git a/mfbt/Assertions.h b/mfbt/Assertions.h
index bf1a0e534d21..2910d10cb9b5 100644
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -315,7 +315,11 @@ MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...);
#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
do { \
static_assert( \
- MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \
+ MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
+ "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \
+ "Or maybe you want MOZ_CRASH instead?"); \
+ static_assert( \
+ MOZ_ARG_COUNT(__VA_ARGS__) <= sPrintfMaxArgs, \
"Only up to 4 additional arguments are allowed!"); \
static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
"The supplied format string is too long!"); \
@@ -446,14 +450,14 @@ struct AssertionConditionType
# define MOZ_ASSERT(...) do { } while (0)
#endif /* DEBUG */
-#ifdef RELEASE_OR_BETA
+#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION)
+# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
+# define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
+#else
# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
# ifdef DEBUG
# define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
# endif
-#else
-# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
-# define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
#endif
/*
diff --git a/mfbt/MacroArgs.h b/mfbt/MacroArgs.h
index 1f77dd0c43ad..7f55cc7f0326 100644
--- a/mfbt/MacroArgs.h
+++ b/mfbt/MacroArgs.h
@@ -16,44 +16,35 @@
#define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y)
/*
- * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
- * arguments and prefixes it with |aPrefix|. For example:
+ * MOZ_ARG_COUNT(...) counts the number of variadic arguments.
+ * You must pass in between 0 and 50 (inclusive) variadic arguments.
+ * For example:
*
- * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
- * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
- * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0
- * MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there
- * aren't enough arguments given.
- *
- * You must pass in between 0 and 50 (inclusive) variadic arguments, past
- * |aPrefix|.
+ * MOZ_ARG_COUNT() expands to 0
+ * MOZ_ARG_COUNT(a) expands to 1
+ * MOZ_ARG_COUNT(a, b) expands to 2
*
+ * Implementation notes:
* The `##__VA_ARGS__` form is a GCC extension that removes the comma if
* __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##,
* and its default behavior is already to strip the comma when __VA_ARGS__
* is empty.
*
- * So MOZ_MACROARGS_ARG_COUNT_HELPER(prefix) expands to
- * (_, prefix50, prefix49, ...)
- * MOZ_MACROARGS_ARG_COUNT_HELPER(prefix, a) expands to
- * (_, a, prefix50, prefix49, ...)
+ * So MOZ_MACROARGS_ARG_COUNT_HELPER() expands to
+ * (_, 50, 49, ...)
+ * MOZ_MACROARGS_ARG_COUNT_HELPER(a) expands to
+ * (_, a, 50, 49, ...)
* etc.
*/
-#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
- MOZ_MACROARGS_ARG_COUNT_HELPER2( \
- MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ##__VA_ARGS__))
+#define MOZ_ARG_COUNT(...) \
+ MOZ_MACROARGS_ARG_COUNT_HELPER2(MOZ_MACROARGS_ARG_COUNT_HELPER(__VA_ARGS__))
-#define MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ...) (_, ##__VA_ARGS__, \
- aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \
- aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \
- aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \
- aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \
- aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \
- aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \
- aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \
- aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \
- aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \
- aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0)
+#define MOZ_MACROARGS_ARG_COUNT_HELPER(...) (_, ##__VA_ARGS__, \
+ 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \
+ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \
+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
+ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \
MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs
@@ -66,6 +57,24 @@
a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
a51, ...) a51
+/*
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
+ * arguments and prefixes it with |aPrefix|. For example:
+ *
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there
+ * aren't enough arguments given.
+ *
+ * You must pass in between 0 and 50 (inclusive) variadic arguments, past
+ * |aPrefix|.
+ */
+#define MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(a, b) a b
+#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
+ MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE( \
+ MOZ_CONCAT, (aPrefix, MOZ_ARG_COUNT(__VA_ARGS__)))
+
/*
* MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
* arguments. For example:
diff --git a/mfbt/Variant.h b/mfbt/Variant.h
index cf8d1046f905..71ed4722c908 100644
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -234,7 +234,7 @@ struct VariantImplementation
if (aRhs.template is()) {
::new (KnownNotNull, aLhs) T(aRhs.template extract());
} else {
- Next::moveConstruct(aLhs, aRhs);
+ Next::moveConstruct(aLhs, Move(aRhs));
}
}
diff --git a/mfbt/tests/TestMacroArgs.cpp b/mfbt/tests/TestMacroArgs.cpp
index 235170d27f0c..f9d1a0fd9062 100644
--- a/mfbt/tests/TestMacroArgs.cpp
+++ b/mfbt/tests/TestMacroArgs.cpp
@@ -6,6 +6,11 @@
#include "mozilla/MacroArgs.h"
+static_assert(MOZ_ARG_COUNT() == 0, "");
+static_assert(MOZ_ARG_COUNT(a) == 1, "");
+static_assert(MOZ_ARG_COUNT(a, b) == 2, "");
+static_assert(MOZ_ARG_COUNT(a, b, c) == 3, "");
+
static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100) == 1000, "");
static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a) == 1001, "");
static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b) == 1002, "");
diff --git a/mfbt/tests/TestMacroForEach.cpp b/mfbt/tests/TestMacroForEach.cpp
index 2379add7f712..c9c8b88bbe00 100644
--- a/mfbt/tests/TestMacroForEach.cpp
+++ b/mfbt/tests/TestMacroForEach.cpp
@@ -16,6 +16,9 @@ static_assert(MOZ_FOR_EACH_SEPARATED(HELPER_IDENTITY, (+),
static_assert(MOZ_FOR_EACH_SEPARATED(HELPER_IDENTITY, (+),
(), (1, 1, 1)) == 3, "");
+#define HELPER_ONE_PLUS(x) HELPER_IDENTITY_PLUS(1)
+static_assert(MOZ_FOR_EACH(HELPER_ONE_PLUS, (), ()) 0 == 0, "");
+
#define HELPER_DEFINE_VAR(x) const int test1_##x = x;
MOZ_FOR_EACH(HELPER_DEFINE_VAR, (), (10, 20))
static_assert(test1_10 == 10 && test1_20 == 20, "");
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 2db1be804dc6..27c2617cad32 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -354,9 +354,6 @@ pref("media.play-stand-alone", true);
pref("media.hardware-video-decoding.enabled", true);
pref("media.hardware-video-decoding.force-enabled", false);
-#ifdef MOZ_DIRECTSHOW
-pref("media.directshow.enabled", true);
-#endif
#ifdef MOZ_FMP4
pref("media.mp4.enabled", true);
// Specifies whether the PDMFactory can create a test decoder that
@@ -2889,9 +2886,6 @@ pref("layout.css.grid-template-subgrid-value.enabled", false);
// Is support for CSS contain enabled?
pref("layout.css.contain.enabled", false);
-// Is support for CSS display:flow-root enabled?
-pref("layout.css.display-flow-root.enabled", true);
-
// Is support for CSS box-decoration-break enabled?
pref("layout.css.box-decoration-break.enabled", true);
diff --git a/old-configure.in b/old-configure.in
index 7f29bb483ea0..db7ac3c90e2f 100644
--- a/old-configure.in
+++ b/old-configure.in
@@ -2185,7 +2185,6 @@ MOZ_VORBIS=
MOZ_TREMOR=
MOZ_SAMPLE_TYPE_FLOAT32=
MOZ_SAMPLE_TYPE_S16=
-MOZ_DIRECTSHOW=
MOZ_WEBRTC=1
MOZ_PEERCONNECTION=
MOZ_SRTP=
@@ -2793,23 +2792,6 @@ if test -n "$MOZ_APPLEMEDIA"; then
fi
fi # COMPILE_ENVIRONMENT
-dnl ========================================================
-dnl = DirectShow support
-dnl ========================================================
-if test "$OS_ARCH" = "WINNT"; then
- dnl Enable DirectShow support by default.
- MOZ_DIRECTSHOW=1
-fi
-
-MOZ_ARG_DISABLE_BOOL(directshow,
-[ --disable-directshow Disable support for DirectShow],
- MOZ_DIRECTSHOW=,
- MOZ_DIRECTSHOW=1)
-
-if test -n "$MOZ_DIRECTSHOW"; then
- AC_DEFINE(MOZ_DIRECTSHOW)
-fi;
-
dnl ========================================================
dnl = Built-in fragmented MP4 support.
dnl ========================================================
@@ -5335,7 +5317,6 @@ AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)
AC_SUBST(MOZ_FFVPX)
AC_SUBST_LIST(FFVPX_ASFLAGS)
-AC_SUBST(MOZ_DIRECTSHOW)
AC_SUBST(MOZ_ANDROID_OMX)
AC_SUBST(MOZ_OMX_PLUGIN)
AC_SUBST(VPX_USE_YASM)
diff --git a/services/common/blocklist-clients.js b/services/common/blocklist-clients.js
index a2e1188d92be..84600f93c45f 100644
--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -27,6 +27,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAdapter",
"resource://services-common/kinto-storage-adapter.js");
XPCOMUtils.defineLazyModuleGetter(this, "CanonicalJSON",
"resource://gre/modules/CanonicalJSON.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "UptakeTelemetry",
+ "resource://services-common/uptake-telemetry.js");
const KEY_APPDIR = "XCurProcD";
const PREF_SETTINGS_SERVER = "services.settings.server";
@@ -203,6 +205,7 @@ class BlocklistClient {
}
let sqliteHandle;
+ let reportStatus = null;
try {
// Synchronize remote data into a local Sqlite DB.
sqliteHandle = await FirefoxAdapter.openConnection({path: KINTO_STORAGE_PATH});
@@ -233,6 +236,7 @@ class BlocklistClient {
// to record the fact that a check happened.
if (lastModified <= collectionLastModified) {
this.updateLastCheck(serverTime);
+ reportStatus = UptakeTelemetry.STATUS.UP_TO_DATE;
return;
}
@@ -240,16 +244,25 @@ class BlocklistClient {
try {
const {ok} = await collection.sync({remote});
if (!ok) {
+ // Some synchronization conflicts occured.
+ reportStatus = UptakeTelemetry.STATUS.CONFLICT_ERROR;
throw new Error("Sync failed");
}
} catch (e) {
if (e.message == INVALID_SIGNATURE) {
+ // Signature verification failed during synchronzation.
+ reportStatus = UptakeTelemetry.STATUS.SIGNATURE_ERROR;
// if sync fails with a signature error, it's likely that our
// local data has been modified in some way.
// We will attempt to fix this by retrieving the whole
// remote collection.
const payload = await fetchRemoteCollection(remote, collection);
- await this.validateCollectionSignature(remote, payload, collection, {ignoreLocal: true});
+ try {
+ await this.validateCollectionSignature(remote, payload, collection, {ignoreLocal: true});
+ } catch (e) {
+ reportStatus = UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR;
+ throw e;
+ }
// if the signature is good (we haven't thrown), and the remote
// last_modified is newer than the local last_modified, replace the
// local data
@@ -259,18 +272,46 @@ class BlocklistClient {
await collection.loadDump(payload.data);
}
} else {
+ // The sync has thrown, it can be a network or a general error.
+ if (/NetworkError/.test(e.message)) {
+ reportStatus = UptakeTelemetry.STATUS.NETWORK_ERROR;
+ } else if (/Backoff/.test(e.message)) {
+ reportStatus = UptakeTelemetry.STATUS.BACKOFF;
+ } else {
+ reportStatus = UptakeTelemetry.STATUS.SYNC_ERROR;
+ }
throw e;
}
}
// Read local collection of records.
const {data} = await collection.list();
- await this.processCallback(data);
+ // Handle the obtained records (ie. apply locally).
+ try {
+ await this.processCallback(data);
+ } catch (e) {
+ reportStatus = UptakeTelemetry.STATUS.APPLY_ERROR;
+ throw e;
+ }
// Track last update.
this.updateLastCheck(serverTime);
+ } catch (e) {
+ // No specific error was tracked, mark it as unknown.
+ if (reportStatus === null) {
+ reportStatus = UptakeTelemetry.STATUS.UNKNOWN_ERROR;
+ }
+ throw e;
} finally {
- await sqliteHandle.close();
+ if (sqliteHandle) {
+ await sqliteHandle.close();
+ }
+ // No error was reported, this is a success!
+ if (reportStatus === null) {
+ reportStatus = UptakeTelemetry.STATUS.SUCCESS;
+ }
+ // Report success/error status to Telemetry.
+ UptakeTelemetry.report(this.identifier, reportStatus);
}
}
diff --git a/services/common/blocklist-updater.js b/services/common/blocklist-updater.js
index 78c72d777433..8dbb89870382 100644
--- a/services/common/blocklist-updater.js
+++ b/services/common/blocklist-updater.js
@@ -9,6 +9,8 @@ const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.importGlobalProperties(["fetch"]);
+XPCOMUtils.defineLazyModuleGetter(this, "UptakeTelemetry",
+ "resource://services-common/uptake-telemetry.js");
const PREF_SETTINGS_SERVER = "services.settings.server";
const PREF_SETTINGS_SERVER_BACKOFF = "services.settings.server.backoff";
@@ -17,6 +19,9 @@ const PREF_BLOCKLIST_LAST_UPDATE = "services.blocklist.last_update_second
const PREF_BLOCKLIST_LAST_ETAG = "services.blocklist.last_etag";
const PREF_BLOCKLIST_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
+// Telemetry update source identifier.
+const TELEMETRY_HISTOGRAM_KEY = "settings-changes-monitoring";
+
XPCOMUtils.defineLazyGetter(this, "gBlocklistClients", function() {
const BlocklistClients = Cu.import("resource://services-common/blocklist-clients.js", {});
@@ -33,6 +38,56 @@ XPCOMUtils.defineLazyGetter(this, "gBlocklistClients", function() {
this.addTestBlocklistClient = (name, client) => { gBlocklistClients[name] = client; }
+async function pollChanges(url, lastEtag) {
+ //
+ // Fetch a versionInfo object from the server that looks like:
+ // {"data":[
+ // {
+ // "host":"kinto-ota.dev.mozaws.net",
+ // "last_modified":1450717104423,
+ // "bucket":"blocklists",
+ // "collection":"certificates"
+ // }]}
+
+ // Use ETag to obtain a `304 Not modified` when no change occurred.
+ const headers = {};
+ if (lastEtag) {
+ headers["If-None-Match"] = lastEtag;
+ }
+ const response = await fetch(url, {headers});
+
+ let versionInfo = [];
+ // If no changes since last time, go on with empty list of changes.
+ if (response.status != 304) {
+ let payload;
+ try {
+ payload = await response.json();
+ } catch (e) {}
+ if (!payload.hasOwnProperty("data")) {
+ // If the server is failing, the JSON response might not contain the
+ // expected data (e.g. error response - Bug 1259145)
+ throw new Error(`Server error response ${JSON.stringify(payload)}`);
+ }
+ versionInfo = payload.data;
+ }
+ // The server should always return ETag. But we've had situations where the CDN
+ // was interfering.
+ const currentEtag = response.headers.has("ETag") ? response.headers.get("ETag") : undefined;
+ const serverTimeMillis = Date.parse(response.headers.get("Date"));
+
+ // Check if the server asked the clients to back off.
+ let backoffSeconds;
+ if (response.headers.has("Backoff")) {
+ const value = parseInt(response.headers.get("Backoff"), 10);
+ if (!isNaN(value)) {
+ backoffSeconds = value;
+ }
+ }
+
+ return {versionInfo, currentEtag, serverTimeMillis, backoffSeconds};
+}
+
+
// This is called by the ping mechanism.
// returns a promise that rejects if something goes wrong
this.checkVersions = async function() {
@@ -41,69 +96,66 @@ this.checkVersions = async function() {
const backoffReleaseTime = Services.prefs.getCharPref(PREF_SETTINGS_SERVER_BACKOFF);
const remainingMilliseconds = parseInt(backoffReleaseTime, 10) - Date.now();
if (remainingMilliseconds > 0) {
+ // Backoff time has not elapsed yet.
+ UptakeTelemetry.report(TELEMETRY_HISTOGRAM_KEY,
+ UptakeTelemetry.STATUS.BACKOFF);
throw new Error(`Server is asking clients to back off; retry in ${Math.ceil(remainingMilliseconds / 1000)}s.`);
} else {
Services.prefs.clearUserPref(PREF_SETTINGS_SERVER_BACKOFF);
}
}
- // Fetch a versionInfo object that looks like:
- // {"data":[
- // {
- // "host":"kinto-ota.dev.mozaws.net",
- // "last_modified":1450717104423,
- // "bucket":"blocklists",
- // "collection":"certificates"
- // }]}
// Right now, we only use the collection name and the last modified info
const kintoBase = Services.prefs.getCharPref(PREF_SETTINGS_SERVER);
const changesEndpoint = kintoBase + Services.prefs.getCharPref(PREF_BLOCKLIST_CHANGES_PATH);
- // Use ETag to obtain a `304 Not modified` when no change occurred.
- const headers = {};
+ let lastEtag;
if (Services.prefs.prefHasUserValue(PREF_BLOCKLIST_LAST_ETAG)) {
- const lastEtag = Services.prefs.getCharPref(PREF_BLOCKLIST_LAST_ETAG);
- if (lastEtag) {
- headers["If-None-Match"] = lastEtag;
+ lastEtag = Services.prefs.getCharPref(PREF_BLOCKLIST_LAST_ETAG);
+ }
+
+ let pollResult;
+ try {
+ pollResult = await pollChanges(changesEndpoint, lastEtag);
+ } catch (e) {
+ // Report polling error to Uptake Telemetry.
+ let report;
+ if (/Server/.test(e.message)) {
+ report = UptakeTelemetry.STATUS.SERVER_ERROR;
+ } else if (/NetworkError/.test(e.message)) {
+ report = UptakeTelemetry.STATUS.NETWORK_ERROR;
+ } else {
+ report = UptakeTelemetry.STATUS.UNKNOWN_ERROR;
}
+ UptakeTelemetry.report(TELEMETRY_HISTOGRAM_KEY, report);
+ // No need to go further.
+ throw new Error(`Polling for changes failed: ${e.message}.`);
}
- const response = await fetch(changesEndpoint, {headers});
+ const {serverTimeMillis, versionInfo, currentEtag, backoffSeconds} = pollResult;
- // Check if the server asked the clients to back off.
- if (response.headers.has("Backoff")) {
- const backoffSeconds = parseInt(response.headers.get("Backoff"), 10);
- if (!isNaN(backoffSeconds)) {
- const backoffReleaseTime = Date.now() + backoffSeconds * 1000;
- Services.prefs.setCharPref(PREF_SETTINGS_SERVER_BACKOFF, backoffReleaseTime);
- }
+ // Report polling success to Uptake Telemetry.
+ const report = versionInfo.length == 0 ? UptakeTelemetry.STATUS.UP_TO_DATE
+ : UptakeTelemetry.STATUS.SUCCESS;
+ UptakeTelemetry.report(TELEMETRY_HISTOGRAM_KEY, report);
+
+ // Check if the server asked the clients to back off (for next poll).
+ if (backoffSeconds) {
+ const backoffReleaseTime = Date.now() + backoffSeconds * 1000;
+ Services.prefs.setCharPref(PREF_SETTINGS_SERVER_BACKOFF, backoffReleaseTime);
}
- let versionInfo;
- // No changes since last time. Go on with empty list of changes.
- if (response.status == 304) {
- versionInfo = {data: []};
- } else {
- versionInfo = await response.json();
- }
-
- // If the server is failing, the JSON response might not contain the
- // expected data (e.g. error response - Bug 1259145)
- if (!versionInfo.hasOwnProperty("data")) {
- throw new Error("Polling for changes failed.");
- }
-
- // Record new update time and the difference between local and server time
- const serverTimeMillis = Date.parse(response.headers.get("Date"));
-
- // negative clockDifference means local time is behind server time
+ // Record new update time and the difference between local and server time.
+ // Negative clockDifference means local time is behind server time
// by the absolute of that value in seconds (positive means it's ahead)
const clockDifference = Math.floor((Date.now() - serverTimeMillis) / 1000);
Services.prefs.setIntPref(PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, clockDifference);
Services.prefs.setIntPref(PREF_BLOCKLIST_LAST_UPDATE, serverTimeMillis / 1000);
+ // Iterate through the collections version info and initiate a synchronization
+ // on the related blocklist client.
let firstError;
- for (let collectionInfo of versionInfo.data) {
+ for (const collectionInfo of versionInfo) {
const {bucket, collection, last_modified: lastModified} = collectionInfo;
const client = gBlocklistClients[collection];
if (client && client.bucketName == bucket) {
@@ -122,8 +174,7 @@ this.checkVersions = async function() {
}
// Save current Etag for next poll.
- if (response.headers.has("ETag")) {
- const currentEtag = response.headers.get("ETag");
+ if (currentEtag) {
Services.prefs.setCharPref(PREF_BLOCKLIST_LAST_ETAG, currentEtag);
}
};
diff --git a/services/common/moz.build b/services/common/moz.build
index d543cc9ac4f9..3f5e43cd8fc7 100644
--- a/services/common/moz.build
+++ b/services/common/moz.build
@@ -23,6 +23,7 @@ EXTRA_JS_MODULES['services-common'] += [
'logmanager.js',
'observers.js',
'rest.js',
+ 'uptake-telemetry.js',
'utils.js',
]
diff --git a/services/common/tests/unit/head_helpers.js b/services/common/tests/unit/head_helpers.js
index 98adde009183..69bee9c38e23 100644
--- a/services/common/tests/unit/head_helpers.js
+++ b/services/common/tests/unit/head_helpers.js
@@ -159,3 +159,22 @@ function uninstallFakePAC() {
_("Uninstalling fake PAC.");
MockRegistrar.unregister(fakePACCID);
}
+
+
+function getUptakeTelemetrySnapshot(key) {
+ Cu.import("resource://gre/modules/Services.jsm");
+ const TELEMETRY_HISTOGRAM_ID = "UPTAKE_REMOTE_CONTENT_RESULT_1";
+ return Services.telemetry
+ .getKeyedHistogramById(TELEMETRY_HISTOGRAM_ID)
+ .snapshot(key);
+}
+
+function checkUptakeTelemetry(snapshot1, snapshot2, expectedIncrements) {
+ const LABELS = ["up_to_date", "success", "backoff", "pref_disabled", "parse_error", "content_error", "sign_error", "sign_retry_error", "conflict_error", "sync_error", "apply_error", "server_error", "certificate_error", "download_error", "timeout_error", "network_error", "offline_error", "cleanup_error", "unknown_error", "custom_1_error", "custom_2_error", "custom_3_error", "custom_4_error", "custom_5_error"];
+ for (const label of LABELS) {
+ const key = LABELS.indexOf(label);
+ const expected = expectedIncrements[label] || 0;
+ const actual = snapshot2.counts[key] - snapshot1.counts[key];
+ equal(expected, actual, `check histogram count for ${label}`);
+ }
+}
diff --git a/services/common/tests/unit/test_blocklist_clients.js b/services/common/tests/unit/test_blocklist_clients.js
index 1ea00dcb927c..0c99e8b49f81 100644
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -9,6 +9,7 @@ const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js", {});
const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js", {});
const BlocklistClients = Cu.import("resource://services-common/blocklist-clients.js", {});
+const { UptakeTelemetry } = Cu.import("resource://services-common/uptake-telemetry.js", {});
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream", "setInputStream");
@@ -190,13 +191,14 @@ add_task(function* test_sends_reload_message_when_blocklist_has_changes() {
});
add_task(clear_state);
-add_task(function* test_do_nothing_when_blocklist_is_up_to_date() {
+add_task(function* test_telemetry_reports_up_to_date() {
for (let {client} of gBlocklistClients) {
yield client.maybeSync(2000, Date.now() - 1000, {loadDump: false});
const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename);
const profFile = new FileUtils.File(filePath);
const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000;
const serverTime = Date.now();
+ const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
yield client.maybeSync(3000, serverTime);
@@ -205,11 +207,86 @@ add_task(function* test_do_nothing_when_blocklist_is_up_to_date() {
// Server time was updated.
const after = Services.prefs.getIntPref(client.lastCheckTimePref);
equal(after, Math.round(serverTime / 1000));
+ // No Telemetry was sent.
+ const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const expectedIncrements = {[UptakeTelemetry.STATUS.UP_TO_DATE]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
}
});
add_task(clear_state);
+add_task(function* test_telemetry_if_sync_succeeds() {
+ // We test each client because Telemetry requires preleminary declarations.
+ for (let {client} of gBlocklistClients) {
+ const serverTime = Date.now();
+ const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ yield client.maybeSync(2000, serverTime, {loadDump: false});
+
+ const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const expectedIncrements = {[UptakeTelemetry.STATUS.SUCCESS]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+ }
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_reports_if_application_fails() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+ const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const backup = client.processCallback;
+ client.processCallback = () => { throw new Error("boom"); };
+
+ try {
+ yield client.maybeSync(2000, serverTime, {loadDump: false});
+ } catch (e) {}
+
+ client.processCallback = backup;
+
+ const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const expectedIncrements = {[UptakeTelemetry.STATUS.APPLY_ERROR]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_reports_if_sync_fails() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+
+ const sqliteHandle = yield FirefoxAdapter.openConnection({path: kintoFilename});
+ const collection = kintoCollection(client.collectionName, sqliteHandle);
+ yield collection.db.saveLastModified(9999);
+ yield sqliteHandle.close();
+
+ const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
+
+ try {
+ yield client.maybeSync(10000, serverTime);
+ } catch (e) {}
+
+ const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const expectedIncrements = {[UptakeTelemetry.STATUS.SYNC_ERROR]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_reports_unknown_errors() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+ const backup = FirefoxAdapter.openConnection;
+ FirefoxAdapter.openConnection = () => { throw new Error("Internal"); };
+ const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
+
+ try {
+ yield client.maybeSync(2000, serverTime);
+ } catch (e) {}
+
+ FirefoxAdapter.openConnection = backup;
+ const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
+ const expectedIncrements = {[UptakeTelemetry.STATUS.UNKNOWN_ERROR]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
// get a response for a given request from sample data
function getSampleResponse(req, port) {
@@ -406,6 +483,20 @@ function getSampleResponse(req, port) {
"os": "Darwin 11",
"featureStatus": "BLOCKED_DEVICE"
}]})
+ },
+ "GET:/v1/buckets/blocklists/collections/addons/records?_sort=-last_modified&_since=9999": {
+ "sampleHeaders": [
+ "Access-Control-Allow-Origin: *",
+ "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
+ "Content-Type: application/json; charset=UTF-8",
+ "Server: waitress",
+ ],
+ "status": {status: 503, statusText: "Service Unavailable"},
+ "responseBody": JSON.stringify({
+ code: 503,
+ errno: 999,
+ error: "Service Unavailable",
+ })
}
};
return responses[`${req.method}:${req.path}?${req.queryString}`] ||
diff --git a/services/common/tests/unit/test_blocklist_signatures.js b/services/common/tests/unit/test_blocklist_signatures.js
index 43528b8c5242..9289f3c66c98 100644
--- a/services/common/tests/unit/test_blocklist_signatures.js
+++ b/services/common/tests/unit/test_blocklist_signatures.js
@@ -7,6 +7,7 @@ const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js"
const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js", {});
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { OneCRLBlocklistClient } = Cu.import("resource://services-common/blocklist-clients.js", {});
+const { UptakeTelemetry } = Cu.import("resource://services-common/uptake-telemetry.js", {});
let server;
@@ -16,6 +17,9 @@ const PREF_BLOCKLIST_ONECRL_COLLECTION = "services.blocklist.onecrl.collection";
const PREF_SETTINGS_SERVER = "services.settings.server";
const PREF_SIGNATURE_ROOT = "security.content.signature.root_hash";
+// Telemetry reports.
+const TELEMETRY_HISTOGRAM_KEY = OneCRLBlocklistClient.identifier;
+
const kintoFilename = "kinto.sqlite";
const CERT_DIR = "test_blocklist_signatures/";
@@ -301,11 +305,19 @@ add_task(function* test_check_signatures() {
// .. and use this map to register handlers for each path
registerHandlers(emptyCollectionResponses);
+ let startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+
// With all of this set up, we attempt a sync. This will resolve if all is
// well and throw if something goes wrong.
// We don't want to load initial json dumps in this test suite.
yield OneCRLBlocklistClient.maybeSync(1000, startTime, {loadDump: false});
+ let endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+
+ // ensure that a success histogram is tracked when a succesful sync occurs.
+ let expectedIncrements = {[UptakeTelemetry.STATUS.SUCCESS]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+
// Check that some additions (2 records) to the collection have a valid
// signature.
@@ -442,8 +454,19 @@ add_task(function* test_check_signatures() {
};
registerHandlers(badSigGoodSigResponses);
+
+ startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+
yield OneCRLBlocklistClient.maybeSync(5000, startTime);
+ endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+
+ // ensure that the failure count is incremented for a succesful sync with an
+ // (initial) bad signature - only SERVICES_SETTINGS_SYNC_SIG_FAIL should
+ // increment.
+ expectedIncrements = {[UptakeTelemetry.STATUS.SIGNATURE_ERROR]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+
const badSigGoodOldResponses = {
// In this test, we deliberately serve a bad signature initially. The
// subsequent sitnature returned is a valid one for the three item
@@ -483,6 +506,7 @@ add_task(function* test_check_signatures() {
[RESPONSE_COMPLETE_INITIAL_SORTED_BY_ID]
};
+ startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
registerHandlers(allBadSigResponses);
try {
yield OneCRLBlocklistClient.maybeSync(6000, startTime);
@@ -490,6 +514,11 @@ add_task(function* test_check_signatures() {
} catch (e) {
yield checkRecordCount(2);
}
+
+ // Ensure that the failure is reflected in the accumulated telemetry:
+ endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+ expectedIncrements = {[UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR]: 1};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
function run_test() {
diff --git a/services/common/tests/unit/test_blocklist_updater.js b/services/common/tests/unit/test_blocklist_updater.js
index 888f465f96d5..aa4791d1d2f9 100644
--- a/services/common/tests/unit/test_blocklist_updater.js
+++ b/services/common/tests/unit/test_blocklist_updater.js
@@ -1,4 +1,5 @@
Cu.import("resource://testing-common/httpd.js");
+const { UptakeTelemetry } = Cu.import("resource://services-common/uptake-telemetry.js", {});
var server;
@@ -8,6 +9,9 @@ const PREF_LAST_UPDATE = "services.blocklist.last_update_seconds";
const PREF_LAST_ETAG = "services.blocklist.last_etag";
const PREF_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
+// Telemetry report result.
+const TELEMETRY_HISTOGRAM_KEY = "settings-changes-monitoring";
+
// Check to ensure maybeSync is called with correct values when a changes
// document contains information on when a collection was last modified
add_task(function* test_check_maybeSync() {
@@ -64,6 +68,9 @@ add_task(function* test_check_maybeSync() {
do_check_eq(serverTime, 2000);
}
});
+
+ const startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+
yield updater.checkVersions();
// check the last_update is updated
@@ -102,6 +109,7 @@ add_task(function* test_check_maybeSync() {
response.setStatusLine(null, 503, "Service Unavailable");
}
server.registerPathHandler(changesPath, simulateErrorResponse);
+
// checkVersions() fails with adequate error.
let error;
try {
@@ -109,7 +117,7 @@ add_task(function* test_check_maybeSync() {
} catch (e) {
error = e;
}
- do_check_eq(error.message, "Polling for changes failed.");
+ do_check_true(/Polling for changes failed/.test(error.message));
// When an error occurs, last update was not overwritten (see Date header above).
do_check_eq(Services.prefs.getIntPref(PREF_LAST_UPDATE), 2);
@@ -150,6 +158,25 @@ add_task(function* test_check_maybeSync() {
yield updater.checkVersions();
// Backoff tracking preference was cleared.
do_check_false(Services.prefs.prefHasUserValue(PREF_SETTINGS_SERVER_BACKOFF));
+
+
+ // Simulate a network error (to check telemetry report).
+ Services.prefs.setCharPref(PREF_SETTINGS_SERVER, "http://localhost:42/v1");
+ try {
+ yield updater.checkVersions();
+ } catch (e) {}
+
+ const endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
+ // ensure that we've accumulated the correct telemetry
+ const expectedIncrements = {
+ [UptakeTelemetry.STATUS.UP_TO_DATE]: 4,
+ [UptakeTelemetry.STATUS.SUCCESS]: 1,
+ [UptakeTelemetry.STATUS.BACKOFF]: 1,
+ [UptakeTelemetry.STATUS.SERVER_ERROR]: 1,
+ [UptakeTelemetry.STATUS.NETWORK_ERROR]: 1,
+ [UptakeTelemetry.STATUS.UNKNOWN_ERROR]: 0,
+ };
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
function run_test() {
diff --git a/services/common/tests/unit/test_uptake_telemetry.js b/services/common/tests/unit/test_uptake_telemetry.js
new file mode 100644
index 000000000000..3111b92e94ea
--- /dev/null
+++ b/services/common/tests/unit/test_uptake_telemetry.js
@@ -0,0 +1,32 @@
+const { UptakeTelemetry } = Cu.import("resource://services-common/uptake-telemetry.js", {});
+
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* test_unknown_status_is_not_reported() {
+ const source = "update-source";
+ const startHistogram = getUptakeTelemetrySnapshot(source);
+
+ UptakeTelemetry.report(source, "unknown-status");
+
+ const endHistogram = getUptakeTelemetrySnapshot(source);
+ const expectedIncrements = {};
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+});
+
+add_task(function* test_each_status_can_be_caught_in_snapshot() {
+ const source = "some-source";
+ const startHistogram = getUptakeTelemetrySnapshot(source);
+
+ const expectedIncrements = {};
+ for (const label of Object.keys(UptakeTelemetry.STATUS)) {
+ const status = UptakeTelemetry.STATUS[label];
+ UptakeTelemetry.report(source, status);
+ expectedIncrements[status] = 1;
+ }
+
+ const endHistogram = getUptakeTelemetrySnapshot(source);
+ checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
+});
diff --git a/services/common/tests/unit/xpcshell.ini b/services/common/tests/unit/xpcshell.ini
index 0fce5fedae86..af7fef13b596 100644
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -60,3 +60,5 @@ skip-if = os == "android"
[test_storage_server.js]
skip-if = os == "android"
+
+[test_uptake_telemetry.js]
diff --git a/services/common/uptake-telemetry.js b/services/common/uptake-telemetry.js
new file mode 100644
index 000000000000..cac7051f3c65
--- /dev/null
+++ b/services/common/uptake-telemetry.js
@@ -0,0 +1,94 @@
+/* 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";
+
+
+this.EXPORTED_SYMBOLS = ["UptakeTelemetry"];
+
+const { utils: Cu } = Components;
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+
+
+// Telemetry report results.
+const TELEMETRY_HISTOGRAM_ID = "UPTAKE_REMOTE_CONTENT_RESULT_1";
+
+/**
+ * A Telemetry helper to report uptake of remote content.
+ */
+class UptakeTelemetry {
+
+ /**
+ * Supported uptake statuses:
+ *
+ * - `UP_TO_DATE`: Local content was already up-to-date with remote content.
+ * - `SUCCESS`: Local content was updated successfully.
+ * - `BACKOFF`: Remote server asked clients to backoff.
+ * - `PARSE_ERROR`: Parsing server response has failed.
+ * - `CONTENT_ERROR`: Server response has unexpected content.
+ * - `PREF_DISABLED`: Update is disabled in user preferences.
+ * - `SIGNATURE_ERROR`: Signature verification after diff-based sync has failed.
+ * - `SIGNATURE_RETRY_ERROR`: Signature verification after full fetch has failed.
+ * - `CONFLICT_ERROR`: Some remote changes are in conflict with local changes.
+ * - `SYNC_ERROR`: Synchronization of remote changes has failed.
+ * - `APPLY_ERROR`: Application of changes locally has failed.
+ * - `SERVER_ERROR`: Server failed to respond.
+ * - `CERTIFICATE_ERROR`: Server certificate verification has failed.
+ * - `DOWNLOAD_ERROR`: Data could not be fully retrieved.
+ * - `TIMEOUT_ERROR`: Server response has timed out.
+ * - `NETWORK_ERROR`: Communication with server has failed.
+ * - `NETWORK_OFFLINE_ERROR`: Network not available.
+ * - `UNKNOWN_ERROR`: Uncategorized error.
+ * - `CLEANUP_ERROR`: Clean-up of temporary files has failed.
+ * - `CUSTOM_1_ERROR`: Update source specific error #1.
+ * - `CUSTOM_2_ERROR`: Update source specific error #2.
+ * - `CUSTOM_3_ERROR`: Update source specific error #3.
+ * - `CUSTOM_4_ERROR`: Update source specific error #4.
+ * - `CUSTOM_5_ERROR`: Update source specific error #5.
+ *
+ * @type {Object}
+ */
+ static get STATUS() {
+ return {
+ UP_TO_DATE: "up_to_date",
+ SUCCESS: "success",
+ BACKOFF: "backoff",
+ PREF_DISABLED: "pref_disabled",
+ PARSE_ERROR: "parse_error",
+ CONTENT_ERROR: "content_error",
+ SIGNATURE_ERROR: "sign_error",
+ SIGNATURE_RETRY_ERROR: "sign_retry_error",
+ CONFLICT_ERROR: "conflict_error",
+ SYNC_ERROR: "sync_error",
+ APPLY_ERROR: "apply_error",
+ SERVER_ERROR: "server_error",
+ CERTIFICATE_ERROR: "certificate_error",
+ DOWNLOAD_ERROR: "download_error",
+ TIMEOUT_ERROR: "timeout_error",
+ NETWORK_ERROR: "network_error",
+ NETWORK_OFFLINE_ERROR: "offline_error",
+ CLEANUP_ERROR: "cleanup_error",
+ UNKNOWN_ERROR: "unknown_error",
+ CUSTOM_1_ERROR: "custom_1_error",
+ CUSTOM_2_ERROR: "custom_2_error",
+ CUSTOM_3_ERROR: "custom_3_error",
+ CUSTOM_4_ERROR: "custom_4_error",
+ CUSTOM_5_ERROR: "custom_5_error",
+ };
+ }
+
+ /**
+ * Reports the uptake status for the specified source.
+ *
+ * @param {string} source the identifier of the update source.
+ * @param {string} status the uptake status.
+ */
+ static report(source, status) {
+ Services.telemetry
+ .getKeyedHistogramById(TELEMETRY_HISTOGRAM_ID)
+ .add(source, status);
+ }
+}
+
+this.UptakeTelemetry = UptakeTelemetry;
diff --git a/servo/Cargo.lock b/servo/Cargo.lock
index b5981a9cf6bf..4f18fb7386d5 100644
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1456,9 +1456,7 @@ dependencies = [
name = "layout_tests"
version = "0.0.1"
dependencies = [
- "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"layout 0.0.1",
- "script_layout_interface 0.0.1",
"size_of_test 0.0.1",
]
diff --git a/servo/components/selectors/matching.rs b/servo/components/selectors/matching.rs
index 3a2ddfd998ad..3c269427421d 100644
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -519,17 +519,6 @@ fn matches_simple_selector(
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
- macro_rules! relation_if {
- ($ex:expr, $flag:ident) => {
- if $ex {
- context.relations |= $flag;
- true
- } else {
- false
- }
- }
- }
-
match *selector {
Component::Combinator(_) => unreachable!(),
Component::PseudoElement(ref pseudo) => {
diff --git a/servo/components/style/gecko/generated/atom_macro.rs b/servo/components/style/gecko/generated/atom_macro.rs
index fc228e585f9e..6dcc03e4ffbb 100644
--- a/servo/components/style/gecko/generated/atom_macro.rs
+++ b/servo/components/style/gecko/generated/atom_macro.rs
@@ -786,6 +786,8 @@ cfg_if! {
pub static nsGkAtoms_field: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms8fieldsetE"]
pub static nsGkAtoms_fieldset: *mut nsIAtom;
+ #[link_name = "_ZN9nsGkAtoms4fileE"]
+ pub static nsGkAtoms_file: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms10figcaptionE"]
pub static nsGkAtoms_figcaption: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms6figureE"]
@@ -3938,6 +3940,14 @@ cfg_if! {
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms33mozinputrangeignorepreventdefaultE"]
pub static nsGkAtoms_mozinputrangeignorepreventdefault: *mut nsIAtom;
+ #[link_name = "_ZN9nsGkAtoms13moz_extensionE"]
+ pub static nsGkAtoms_moz_extension: *mut nsIAtom;
+ #[link_name = "_ZN9nsGkAtoms18all_urlsPermissionE"]
+ pub static nsGkAtoms_all_urlsPermission: *mut nsIAtom;
+ #[link_name = "_ZN9nsGkAtoms4httpE"]
+ pub static nsGkAtoms_http: *mut nsIAtom;
+ #[link_name = "_ZN9nsGkAtoms5httpsE"]
+ pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms12cdataTagNameE"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms14commentTagNameE"]
@@ -5809,6 +5819,8 @@ cfg_if! {
pub static nsGkAtoms_field: *mut nsIAtom;
#[link_name = "?fieldset@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_fieldset: *mut nsIAtom;
+ #[link_name = "?file@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+ pub static nsGkAtoms_file: *mut nsIAtom;
#[link_name = "?figcaption@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_figcaption: *mut nsIAtom;
#[link_name = "?figure@nsGkAtoms@@2PEAVnsIAtom@@EA"]
@@ -8961,6 +8973,14 @@ cfg_if! {
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "?mozinputrangeignorepreventdefault@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_mozinputrangeignorepreventdefault: *mut nsIAtom;
+ #[link_name = "?moz_extension@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+ pub static nsGkAtoms_moz_extension: *mut nsIAtom;
+ #[link_name = "?all_urlsPermission@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+ pub static nsGkAtoms_all_urlsPermission: *mut nsIAtom;
+ #[link_name = "?http@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+ pub static nsGkAtoms_http: *mut nsIAtom;
+ #[link_name = "?https@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+ pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "?cdataTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "?commentTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
@@ -10832,6 +10852,8 @@ cfg_if! {
pub static nsGkAtoms_field: *mut nsIAtom;
#[link_name = "\x01?fieldset@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_fieldset: *mut nsIAtom;
+ #[link_name = "\x01?file@nsGkAtoms@@2PAVnsIAtom@@A"]
+ pub static nsGkAtoms_file: *mut nsIAtom;
#[link_name = "\x01?figcaption@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_figcaption: *mut nsIAtom;
#[link_name = "\x01?figure@nsGkAtoms@@2PAVnsIAtom@@A"]
@@ -13984,6 +14006,14 @@ cfg_if! {
pub static nsGkAtoms_ondevicechange: *mut nsIAtom;
#[link_name = "\x01?mozinputrangeignorepreventdefault@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_mozinputrangeignorepreventdefault: *mut nsIAtom;
+ #[link_name = "\x01?moz_extension@nsGkAtoms@@2PAVnsIAtom@@A"]
+ pub static nsGkAtoms_moz_extension: *mut nsIAtom;
+ #[link_name = "\x01?all_urlsPermission@nsGkAtoms@@2PAVnsIAtom@@A"]
+ pub static nsGkAtoms_all_urlsPermission: *mut nsIAtom;
+ #[link_name = "\x01?http@nsGkAtoms@@2PAVnsIAtom@@A"]
+ pub static nsGkAtoms_http: *mut nsIAtom;
+ #[link_name = "\x01?https@nsGkAtoms@@2PAVnsIAtom@@A"]
+ pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "\x01?cdataTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "\x01?commentTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
@@ -15858,6 +15888,8 @@ macro_rules! atom {
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_field as *mut _) } };
("fieldset") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_fieldset as *mut _) } };
+("file") =>
+ { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_file as *mut _) } };
("figcaption") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_figcaption as *mut _) } };
("figure") =>
@@ -19010,6 +19042,14 @@ macro_rules! atom {
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_ondevicechange as *mut _) } };
("mozinputrangeignorepreventdefault") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_mozinputrangeignorepreventdefault as *mut _) } };
+("moz-extension") =>
+ { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_moz_extension as *mut _) } };
+("") =>
+ { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_all_urlsPermission as *mut _) } };
+("http") =>
+ { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_http as *mut _) } };
+("https") =>
+ { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_https as *mut _) } };
("#cdata-section") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_cdataTagName as *mut _) } };
("#comment") =>
diff --git a/servo/components/style/gecko/generated/structs_debug.rs b/servo/components/style/gecko/generated/structs_debug.rs
index 6ce08212a1d1..1709aa24417c 100644
--- a/servo/components/style/gecko/generated/structs_debug.rs
+++ b/servo/components/style/gecko/generated/structs_debug.rs
@@ -975,7 +975,6 @@ pub mod root {
pub const NS_STYLE_DISPLAY_MODE_BROWSER: ::std::os::raw::c_uint = 0;
pub const NS_STYLE_DISPLAY_MODE_MINIMAL_UI: ::std::os::raw::c_uint = 1;
pub const NS_STYLE_DISPLAY_MODE_STANDALONE: ::std::os::raw::c_uint = 2;
- pub const NS_STYLE_DISPLAY_MODE_FULLSCREEN: ::std::os::raw::c_uint = 3;
pub const CSS_PSEUDO_ELEMENT_IS_CSS2: ::std::os::raw::c_uint = 1;
pub const CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS: ::std::os::raw::c_uint =
2;
@@ -1046,19 +1045,6 @@ pub mod root {
}
pub type pair_first_type<_T1> = _T1;
pub type pair_second_type<_T2> = _T2;
- pub type pair__EnableB = u8;
- #[repr(C)]
- #[derive(Debug, Copy, Clone)]
- pub struct pair__CheckArgs {
- pub _address: u8,
- }
- pub type pair__CheckArgsDep = u8;
- #[repr(C)]
- #[derive(Debug, Copy, Clone)]
- pub struct pair__CheckTupleLikeConstructor {
- pub _address: u8,
- }
- pub type pair__CheckTLC = u8;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct input_iterator_tag {
@@ -1078,101 +1064,54 @@ pub mod root {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
- #[derive(Debug, Copy)]
- pub struct forward_iterator_tag {
+ #[derive(Debug, Copy, Clone)]
+ pub struct iterator {
pub _address: u8,
}
- #[test]
- fn bindgen_test_layout_forward_iterator_tag() {
- assert_eq!(::std::mem::size_of::() , 1usize
- , concat ! (
- "Size of: " , stringify ! ( forward_iterator_tag ) ));
- assert_eq! (::std::mem::align_of::() ,
- 1usize , concat ! (
- "Alignment of " , stringify ! ( forward_iterator_tag )
- ));
- }
- impl Clone for forward_iterator_tag {
- fn clone(&self) -> Self { *self }
- }
+ pub type iterator_iterator_category<_Category> = _Category;
+ pub type iterator_value_type<_Tp> = _Tp;
+ pub type iterator_difference_type<_Distance> = _Distance;
+ pub type iterator_pointer<_Pointer> = _Pointer;
+ pub type iterator_reference<_Reference> = _Reference;
#[repr(C)]
- #[derive(Debug, Copy)]
- pub struct bidirectional_iterator_tag {
+ #[derive(Debug, Copy, Clone)]
+ pub struct __iterator_traits {
pub _address: u8,
}
- #[test]
- fn bindgen_test_layout_bidirectional_iterator_tag() {
- assert_eq!(::std::mem::size_of::() ,
- 1usize , concat ! (
- "Size of: " , stringify ! ( bidirectional_iterator_tag
- ) ));
- assert_eq! (::std::mem::align_of::() ,
- 1usize , concat ! (
- "Alignment of " , stringify ! (
- bidirectional_iterator_tag ) ));
- }
- impl Clone for bidirectional_iterator_tag {
- fn clone(&self) -> Self { *self }
- }
- #[repr(C)]
- #[derive(Debug, Copy)]
- pub struct random_access_iterator_tag {
- pub _address: u8,
- }
- #[test]
- fn bindgen_test_layout_random_access_iterator_tag() {
- assert_eq!(::std::mem::size_of::() ,
- 1usize , concat ! (
- "Size of: " , stringify ! ( random_access_iterator_tag
- ) ));
- assert_eq! (::std::mem::align_of::() ,
- 1usize , concat ! (
- "Alignment of " , stringify ! (
- random_access_iterator_tag ) ));
- }
- impl Clone for random_access_iterator_tag {
- fn clone(&self) -> Self { *self }
- }
#[repr(C)]
+ #[derive(Debug, Copy, Clone)]
pub struct iterator_traits {
pub _address: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
- pub struct iterator {
- pub _address: u8,
+ pub struct reverse_iterator<_Iterator> {
+ pub current: _Iterator,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iterator>>,
}
- pub type iterator_value_type<_Tp> = _Tp;
- pub type iterator_difference_type<_Distance> = _Distance;
- pub type iterator_pointer<_Pointer> = _Pointer;
- pub type iterator_reference<_Reference> = _Reference;
- pub type iterator_iterator_category<_Category> = _Category;
- #[repr(C)]
- pub struct reverse_iterator<_Iter> {
- pub __t: _Iter,
- pub current: _Iter,
- pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iter>>,
- }
- pub type reverse_iterator_iterator_type<_Iter> = _Iter;
+ pub type reverse_iterator___traits_type = root::std::iterator_traits;
+ pub type reverse_iterator_iterator_type<_Iterator> = _Iterator;
pub type reverse_iterator_difference_type =
- root::std::iterator_traits;
- pub type reverse_iterator_reference = root::std::iterator_traits;
- pub type reverse_iterator_pointer = root::std::iterator_traits;
+ root::std::reverse_iterator___traits_type;
+ pub type reverse_iterator_pointer =
+ root::std::reverse_iterator___traits_type;
+ pub type reverse_iterator_reference =
+ root::std::reverse_iterator___traits_type;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct atomic {
}
- pub type atomic___base = u8;
- #[repr(C)]
- pub struct __bit_const_reference {
- pub __seg_: root::std::__bit_const_reference___storage_pointer,
- pub __mask_: root::std::__bit_const_reference___storage_type,
+ pub mod chrono {
+ #[allow(unused_imports)]
+ use self::super::super::super::root;
}
- pub type __bit_const_reference___storage_type = [u8; 0usize];
- pub type __bit_const_reference___storage_pointer = [u8; 0usize];
}
- pub type __int64_t = ::std::os::raw::c_longlong;
- pub type __darwin_off_t = root::__int64_t;
+ pub mod __gnu_cxx {
+ #[allow(unused_imports)]
+ use self::super::super::root;
+ }
+ pub type __off_t = ::std::os::raw::c_long;
+ pub type __off64_t = ::std::os::raw::c_long;
pub mod mozilla {
#[allow(unused_imports)]
use self::super::super::root;
@@ -1215,9 +1154,8 @@ pub mod root {
root::nsSubstringTuple;
pub type nsStringRepr_string_type = ::nsstring::nsStringRepr;
pub type nsStringRepr_const_iterator =
- root::nsReadingIterator;
- pub type nsStringRepr_iterator =
- root::nsWritingIterator;
+ root::nsReadingIterator;
+ pub type nsStringRepr_iterator = root::nsWritingIterator;
pub type nsStringRepr_comparator_type = root::nsStringComparator;
pub type nsStringRepr_char_iterator =
*mut root::mozilla::detail::nsStringRepr_char_type;
@@ -1307,9 +1245,9 @@ pub mod root {
root::nsCSubstringTuple;
pub type nsCStringRepr_string_type = root::nsCString;
pub type nsCStringRepr_const_iterator =
- root::nsReadingIterator;
+ root::nsReadingIterator<::std::os::raw::c_char>;
pub type nsCStringRepr_iterator =
- root::nsWritingIterator;
+ root::nsWritingIterator<::std::os::raw::c_char>;
pub type nsCStringRepr_comparator_type =
root::nsCStringComparator;
pub type nsCStringRepr_char_iterator =
@@ -1457,7 +1395,7 @@ pub mod root {
#[repr(C)]
#[derive(Debug)]
pub struct MutexImpl {
- pub platformData_: [*mut ::std::os::raw::c_void; 8usize],
+ pub platformData_: [*mut ::std::os::raw::c_void; 5usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -1466,7 +1404,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_MutexImpl() {
- assert_eq!(::std::mem::size_of::() , 64usize ,
+ assert_eq!(::std::mem::size_of::() , 40usize ,
concat ! ( "Size of: " , stringify ! ( MutexImpl )
));
assert_eq! (::std::mem::align_of::() , 8usize ,
@@ -2296,7 +2234,7 @@ pub mod root {
}
}
#[repr(C)]
- #[derive(Debug, Copy)]
+ #[derive(Debug)]
pub struct ThreadSafeAutoRefCnt {
pub mValue: u64,
}
@@ -2317,9 +2255,6 @@ pub mod root {
ThreadSafeAutoRefCnt ) , "::" , stringify ! ( mValue )
));
}
- impl Clone for ThreadSafeAutoRefCnt {
- fn clone(&self) -> Self { *self }
- }
#[repr(C)]
#[derive(Debug)]
pub struct OwningNonNull {
@@ -8304,7 +8239,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_OffTheBooksMutex() {
- assert_eq!(::std::mem::size_of::() , 96usize ,
+ assert_eq!(::std::mem::size_of::() , 72usize ,
concat ! (
"Size of: " , stringify ! ( OffTheBooksMutex ) ));
assert_eq! (::std::mem::align_of::() , 8usize ,
@@ -8312,7 +8247,7 @@ pub mod root {
"Alignment of " , stringify ! ( OffTheBooksMutex ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const OffTheBooksMutex ) ) .
- mOwningThread as * const _ as usize } , 88usize ,
+ mOwningThread as * const _ as usize } , 64usize ,
concat ! (
"Alignment of field: " , stringify ! (
OffTheBooksMutex ) , "::" , stringify ! (
@@ -8330,7 +8265,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_Mutex() {
- assert_eq!(::std::mem::size_of::() , 96usize , concat ! (
+ assert_eq!(::std::mem::size_of::() , 72usize , concat ! (
"Size of: " , stringify ! ( Mutex ) ));
assert_eq! (::std::mem::align_of::() , 8usize , concat ! (
"Alignment of " , stringify ! ( Mutex ) ));
@@ -9149,8 +9084,8 @@ pub mod root {
pub mAttrs: root::nsTArray,
pub mState: root::mozilla::ServoElementSnapshot_ServoStateType,
pub mContains: root::mozilla::ServoElementSnapshot_Flags,
- pub mIsHTMLElementInHTMLDocument: bool,
- pub mIsInChromeDocument: bool,
+ pub _bitfield_1: u8,
+ pub __bindgen_padding_0: [u16; 3usize],
}
pub type ServoElementSnapshot_BorrowedAttrInfo =
root::mozilla::dom::BorrowedAttrInfo;
@@ -9187,20 +9122,105 @@ pub mod root {
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! (
mContains ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const ServoElementSnapshot ) ) .
- mIsHTMLElementInHTMLDocument as * const _ as usize } ,
- 17usize , concat ! (
- "Alignment of field: " , stringify ! (
- ServoElementSnapshot ) , "::" , stringify ! (
- mIsHTMLElementInHTMLDocument ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const ServoElementSnapshot ) ) .
- mIsInChromeDocument as * const _ as usize } , 18usize
- , concat ! (
- "Alignment of field: " , stringify ! (
- ServoElementSnapshot ) , "::" , stringify ! (
- mIsInChromeDocument ) ));
+ }
+ impl ServoElementSnapshot {
+ #[inline]
+ pub fn mIsHTMLElementInHTMLDocument(&self) -> bool {
+ let mask = 1usize as u8;
+ let unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ let val = (unit_field_val & mask) >> 0usize;
+ unsafe { ::std::mem::transmute(val as u8) }
+ }
+ #[inline]
+ pub fn set_mIsHTMLElementInHTMLDocument(&mut self, val: bool) {
+ let mask = 1usize as u8;
+ let val = val as u8 as u8;
+ let mut unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ unit_field_val &= !mask;
+ unit_field_val |= (val << 0usize) & mask;
+ self._bitfield_1 =
+ unsafe { ::std::mem::transmute(unit_field_val) };
+ }
+ #[inline]
+ pub fn mIsInChromeDocument(&self) -> bool {
+ let mask = 2usize as u8;
+ let unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ let val = (unit_field_val & mask) >> 1usize;
+ unsafe { ::std::mem::transmute(val as u8) }
+ }
+ #[inline]
+ pub fn set_mIsInChromeDocument(&mut self, val: bool) {
+ let mask = 2usize as u8;
+ let val = val as u8 as u8;
+ let mut unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ unit_field_val &= !mask;
+ unit_field_val |= (val << 1usize) & mask;
+ self._bitfield_1 =
+ unsafe { ::std::mem::transmute(unit_field_val) };
+ }
+ #[inline]
+ pub fn mIsTableBorderNonzero(&self) -> bool {
+ let mask = 4usize as u8;
+ let unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ let val = (unit_field_val & mask) >> 2usize;
+ unsafe { ::std::mem::transmute(val as u8) }
+ }
+ #[inline]
+ pub fn set_mIsTableBorderNonzero(&mut self, val: bool) {
+ let mask = 4usize as u8;
+ let val = val as u8 as u8;
+ let mut unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ unit_field_val &= !mask;
+ unit_field_val |= (val << 2usize) & mask;
+ self._bitfield_1 =
+ unsafe { ::std::mem::transmute(unit_field_val) };
+ }
+ #[inline]
+ pub fn mIsMozBrowserFrame(&self) -> bool {
+ let mask = 8usize as u8;
+ let unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ let val = (unit_field_val & mask) >> 3usize;
+ unsafe { ::std::mem::transmute(val as u8) }
+ }
+ #[inline]
+ pub fn set_mIsMozBrowserFrame(&mut self, val: bool) {
+ let mask = 8usize as u8;
+ let val = val as u8 as u8;
+ let mut unit_field_val: u8 =
+ unsafe { ::std::mem::transmute(self._bitfield_1) };
+ unit_field_val &= !mask;
+ unit_field_val |= (val << 3usize) & mask;
+ self._bitfield_1 =
+ unsafe { ::std::mem::transmute(unit_field_val) };
+ }
+ #[inline]
+ pub fn new_bitfield_1(mIsHTMLElementInHTMLDocument: bool,
+ mIsInChromeDocument: bool,
+ mIsTableBorderNonzero: bool,
+ mIsMozBrowserFrame: bool) -> u8 {
+ ({
+ ({
+ ({
+ ({ 0 } |
+ ((mIsHTMLElementInHTMLDocument as u8 as
+ u8) << 0usize) & (1usize as u8))
+ } |
+ ((mIsInChromeDocument as u8 as u8) << 1usize) &
+ (2usize as u8))
+ } |
+ ((mIsTableBorderNonzero as u8 as u8) << 2usize) &
+ (4usize as u8))
+ } |
+ ((mIsMozBrowserFrame as u8 as u8) << 3usize) &
+ (8usize as u8))
+ }
}
#[repr(C)]
#[derive(Debug)]
@@ -9454,8 +9474,6 @@ pub mod root {
PropertyStyleAnimationValuePair ) , "::" , stringify !
( mValue ) ));
}
- pub type ComputedKeyframeValues =
- root::nsTArray;
#[test]
fn __bindgen_test_layout_DefaultDelete_instantiation_3() {
assert_eq!(::std::mem::size_of::() ,
@@ -9992,6 +10010,7 @@ pub mod root {
Attributes = 2,
Id = 4,
MaybeClass = 8,
+ OtherPseudoClassState = 16,
}
#[repr(C)]
#[derive(Debug, Copy)]
@@ -10652,194 +10671,196 @@ pub mod root {
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>,
}
}
- pub type va_list = root::__builtin_va_list;
- pub type fpos_t = root::__darwin_off_t;
#[repr(C)]
#[derive(Debug, Copy)]
- pub struct __sbuf {
- pub _base: *mut ::std::os::raw::c_uchar,
- pub _size: ::std::os::raw::c_int,
+ pub struct _IO_FILE {
+ pub _flags: ::std::os::raw::c_int,
+ pub _IO_read_ptr: *mut ::std::os::raw::c_char,
+ pub _IO_read_end: *mut ::std::os::raw::c_char,
+ pub _IO_read_base: *mut ::std::os::raw::c_char,
+ pub _IO_write_base: *mut ::std::os::raw::c_char,
+ pub _IO_write_ptr: *mut ::std::os::raw::c_char,
+ pub _IO_write_end: *mut ::std::os::raw::c_char,
+ pub _IO_buf_base: *mut ::std::os::raw::c_char,
+ pub _IO_buf_end: *mut ::std::os::raw::c_char,
+ pub _IO_save_base: *mut ::std::os::raw::c_char,
+ pub _IO_backup_base: *mut ::std::os::raw::c_char,
+ pub _IO_save_end: *mut ::std::os::raw::c_char,
+ pub _markers: *mut root::_IO_marker,
+ pub _chain: *mut root::_IO_FILE,
+ pub _fileno: ::std::os::raw::c_int,
+ pub _flags2: ::std::os::raw::c_int,
+ pub _old_offset: root::__off_t,
+ pub _cur_column: ::std::os::raw::c_ushort,
+ pub _vtable_offset: ::std::os::raw::c_schar,
+ pub _shortbuf: [::std::os::raw::c_char; 1usize],
+ pub _lock: *mut root::_IO_lock_t,
+ pub _offset: root::__off64_t,
+ pub __pad1: *mut ::std::os::raw::c_void,
+ pub __pad2: *mut ::std::os::raw::c_void,
+ pub __pad3: *mut ::std::os::raw::c_void,
+ pub __pad4: *mut ::std::os::raw::c_void,
+ pub __pad5: usize,
+ pub _mode: ::std::os::raw::c_int,
+ pub _unused2: [::std::os::raw::c_char; 20usize],
}
#[test]
- fn bindgen_test_layout___sbuf() {
- assert_eq!(::std::mem::size_of::<__sbuf>() , 16usize , concat ! (
- "Size of: " , stringify ! ( __sbuf ) ));
- assert_eq! (::std::mem::align_of::<__sbuf>() , 8usize , concat ! (
- "Alignment of " , stringify ! ( __sbuf ) ));
+ fn bindgen_test_layout__IO_FILE() {
+ assert_eq!(::std::mem::size_of::<_IO_FILE>() , 216usize , concat ! (
+ "Size of: " , stringify ! ( _IO_FILE ) ));
+ assert_eq! (::std::mem::align_of::<_IO_FILE>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( _IO_FILE ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sbuf ) ) . _base as * const _ as
+ & ( * ( 0 as * const _IO_FILE ) ) . _flags as * const _ as
usize } , 0usize , concat ! (
- "Alignment of field: " , stringify ! ( __sbuf ) , "::" ,
- stringify ! ( _base ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const __sbuf ) ) . _size as * const _ as
- usize } , 8usize , concat ! (
- "Alignment of field: " , stringify ! ( __sbuf ) , "::" ,
- stringify ! ( _size ) ));
- }
- impl Clone for __sbuf {
- fn clone(&self) -> Self { *self }
- }
- #[repr(C)]
- #[derive(Debug, Copy, Clone)]
- pub struct __sFILEX {
- _unused: [u8; 0],
- }
- #[repr(C)]
- #[derive(Debug, Copy)]
- pub struct __sFILE {
- pub _p: *mut ::std::os::raw::c_uchar,
- pub _r: ::std::os::raw::c_int,
- pub _w: ::std::os::raw::c_int,
- pub _flags: ::std::os::raw::c_short,
- pub _file: ::std::os::raw::c_short,
- pub _bf: root::__sbuf,
- pub _lbfsize: ::std::os::raw::c_int,
- pub _cookie: *mut ::std::os::raw::c_void,
- pub _close: ::std::option::Option ::std::os::raw::c_int>,
- pub _read: ::std::option::Option ::std::os::raw::c_int>,
- pub _seek: ::std::option::Option root::fpos_t>,
- pub _write: ::std::option::Option ::std::os::raw::c_int>,
- pub _ub: root::__sbuf,
- pub _extra: *mut root::__sFILEX,
- pub _ur: ::std::os::raw::c_int,
- pub _ubuf: [::std::os::raw::c_uchar; 3usize],
- pub _nbuf: [::std::os::raw::c_uchar; 1usize],
- pub _lb: root::__sbuf,
- pub _blksize: ::std::os::raw::c_int,
- pub _offset: root::fpos_t,
- }
- #[test]
- fn bindgen_test_layout___sFILE() {
- assert_eq!(::std::mem::size_of::<__sFILE>() , 152usize , concat ! (
- "Size of: " , stringify ! ( __sFILE ) ));
- assert_eq! (::std::mem::align_of::<__sFILE>() , 8usize , concat ! (
- "Alignment of " , stringify ! ( __sFILE ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _p as * const _ as
- usize } , 0usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _p ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _r as * const _ as
- usize } , 8usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _r ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _w as * const _ as
- usize } , 12usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _w ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _flags as * const _ as
- usize } , 16usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
stringify ! ( _flags ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _file as * const _ as
- usize } , 18usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _file ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_ptr as *
+ const _ as usize } , 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_read_ptr ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _bf as * const _ as
- usize } , 24usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _bf ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_end as *
+ const _ as usize } , 16usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_read_end ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _lbfsize as * const _
- as usize } , 40usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _lbfsize ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_base as *
+ const _ as usize } , 24usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_read_base ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _cookie as * const _ as
- usize } , 48usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _cookie ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_base as *
+ const _ as usize } , 32usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_write_base ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _close as * const _ as
- usize } , 56usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _close ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_ptr as *
+ const _ as usize } , 40usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_write_ptr ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _read as * const _ as
- usize } , 64usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _read ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_end as *
+ const _ as usize } , 48usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_write_end ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _seek as * const _ as
- usize } , 72usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _seek ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_buf_base as *
+ const _ as usize } , 56usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_buf_base ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _write as * const _ as
- usize } , 80usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _write ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_buf_end as * const
+ _ as usize } , 64usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_buf_end ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _ub as * const _ as
- usize } , 88usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _ub ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_save_base as *
+ const _ as usize } , 72usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_save_base ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _extra as * const _ as
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_backup_base as *
+ const _ as usize } , 80usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_backup_base ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _IO_save_end as *
+ const _ as usize } , 88usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _IO_save_end ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _markers as * const _
+ as usize } , 96usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _markers ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _chain as * const _ as
usize } , 104usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _extra ) ));
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _chain ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _ur as * const _ as
- usize } , 112usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _ur ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _fileno as * const _
+ as usize } , 112usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _fileno ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _ubuf as * const _ as
- usize } , 116usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _ubuf ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _flags2 as * const _
+ as usize } , 116usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _flags2 ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _nbuf as * const _ as
- usize } , 119usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _nbuf ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _old_offset as * const
+ _ as usize } , 120usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _old_offset ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _lb as * const _ as
- usize } , 120usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _lb ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _cur_column as * const
+ _ as usize } , 128usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _cur_column ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _blksize as * const _
- as usize } , 136usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
- stringify ! ( _blksize ) ));
+ & ( * ( 0 as * const _IO_FILE ) ) . _vtable_offset as *
+ const _ as usize } , 130usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _vtable_offset ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const __sFILE ) ) . _offset as * const _ as
- usize } , 144usize , concat ! (
- "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ & ( * ( 0 as * const _IO_FILE ) ) . _shortbuf as * const _
+ as usize } , 131usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _shortbuf ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _lock as * const _ as
+ usize } , 136usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _lock ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _offset as * const _
+ as usize } , 144usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
stringify ! ( _offset ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . __pad1 as * const _ as
+ usize } , 152usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( __pad1 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . __pad2 as * const _ as
+ usize } , 160usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( __pad2 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . __pad3 as * const _ as
+ usize } , 168usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( __pad3 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . __pad4 as * const _ as
+ usize } , 176usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( __pad4 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . __pad5 as * const _ as
+ usize } , 184usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( __pad5 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _mode as * const _ as
+ usize } , 192usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _mode ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_FILE ) ) . _unused2 as * const _
+ as usize } , 196usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ stringify ! ( _unused2 ) ));
}
- impl Clone for __sFILE {
+ impl Clone for _IO_FILE {
fn clone(&self) -> Self { *self }
}
- pub type FILE = root::__sFILE;
+ pub type FILE = root::_IO_FILE;
+ pub type va_list = root::__builtin_va_list;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct InfallibleAllocPolicy {
@@ -11396,6 +11417,39 @@ pub mod root {
NS_OK_NO_NAME_CLAUSE_HANDLED = 7864354,
}
pub type nsrefcnt = root::MozRefCountType;
+ pub type _IO_lock_t = ::std::os::raw::c_void;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct _IO_marker {
+ pub _next: *mut root::_IO_marker,
+ pub _sbuf: *mut root::_IO_FILE,
+ pub _pos: ::std::os::raw::c_int,
+ }
+ #[test]
+ fn bindgen_test_layout__IO_marker() {
+ assert_eq!(::std::mem::size_of::<_IO_marker>() , 24usize , concat ! (
+ "Size of: " , stringify ! ( _IO_marker ) ));
+ assert_eq! (::std::mem::align_of::<_IO_marker>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( _IO_marker ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_marker ) ) . _next as * const _
+ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
+ , stringify ! ( _next ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_marker ) ) . _sbuf as * const _
+ as usize } , 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
+ , stringify ! ( _sbuf ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const _IO_marker ) ) . _pos as * const _ as
+ usize } , 16usize , concat ! (
+ "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
+ , stringify ! ( _pos ) ));
+ }
+ impl Clone for _IO_marker {
+ fn clone(&self) -> Self { *self }
+ }
#[repr(C)]
pub struct nsQueryFrame__bindgen_vtable(::std::os::raw::c_void);
#[repr(C)]
@@ -13343,11 +13397,6 @@ pub mod root {
AutoSetAsyncStackForNewCalls ) , "::" , stringify ! (
oldAsyncCallIsExplicit ) ));
}
- pub type WarningReporter =
- ::std::option::Option;
#[repr(C)]
#[derive(Debug)]
pub struct AutoHideScriptedCaller {
@@ -13509,103 +13558,6 @@ pub mod root {
pub struct JSCompartment {
_unused: [u8; 0],
}
- /**
- * Describes a single error or warning that occurs in the execution of script.
- */
- #[repr(C)]
- pub struct JSErrorReport {
- pub _base: root::JSErrorBase,
- pub linebuf_: *const u16,
- pub linebufLength_: usize,
- pub tokenOffset_: usize,
- pub notes: root::mozilla::UniquePtr,
- pub flags: ::std::os::raw::c_uint,
- pub exnType: i16,
- pub _bitfield_1: u8,
- pub __bindgen_padding_0: u8,
- }
- #[test]
- fn bindgen_test_layout_JSErrorReport() {
- assert_eq!(::std::mem::size_of::() , 72usize , concat !
- ( "Size of: " , stringify ! ( JSErrorReport ) ));
- assert_eq! (::std::mem::align_of::() , 8usize , concat
- ! ( "Alignment of " , stringify ! ( JSErrorReport ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . linebuf_ as *
- const _ as usize } , 32usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( linebuf_ ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . linebufLength_ as
- * const _ as usize } , 40usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( linebufLength_ ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . tokenOffset_ as *
- const _ as usize } , 48usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( tokenOffset_ ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . notes as * const
- _ as usize } , 56usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( notes ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . flags as * const
- _ as usize } , 64usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( flags ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const JSErrorReport ) ) . exnType as *
- const _ as usize } , 68usize , concat ! (
- "Alignment of field: " , stringify ! ( JSErrorReport ) ,
- "::" , stringify ! ( exnType ) ));
- }
- impl JSErrorReport {
- #[inline]
- pub fn isMuted(&self) -> bool {
- let mask = 1usize as u8;
- let unit_field_val: u8 =
- unsafe { ::std::mem::transmute(self._bitfield_1) };
- let val = (unit_field_val & mask) >> 0usize;
- unsafe { ::std::mem::transmute(val as u8) }
- }
- #[inline]
- pub fn set_isMuted(&mut self, val: bool) {
- let mask = 1usize as u8;
- let val = val as u8 as u8;
- let mut unit_field_val: u8 =
- unsafe { ::std::mem::transmute(self._bitfield_1) };
- unit_field_val &= !mask;
- unit_field_val |= (val << 0usize) & mask;
- self._bitfield_1 =
- unsafe { ::std::mem::transmute(unit_field_val) };
- }
- #[inline]
- pub fn ownsLinebuf_(&self) -> bool {
- let mask = 2usize as u8;
- let unit_field_val: u8 =
- unsafe { ::std::mem::transmute(self._bitfield_1) };
- let val = (unit_field_val & mask) >> 1usize;
- unsafe { ::std::mem::transmute(val as u8) }
- }
- #[inline]
- pub fn set_ownsLinebuf_(&mut self, val: bool) {
- let mask = 2usize as u8;
- let val = val as u8 as u8;
- let mut unit_field_val: u8 =
- unsafe { ::std::mem::transmute(self._bitfield_1) };
- unit_field_val &= !mask;
- unit_field_val |= (val << 1usize) & mask;
- self._bitfield_1 =
- unsafe { ::std::mem::transmute(unit_field_val) };
- }
- #[inline]
- pub fn new_bitfield_1(isMuted: bool, ownsLinebuf_: bool) -> u8 {
- ({ ({ 0 } | ((isMuted as u8 as u8) << 0usize) & (1usize as u8)) }
- | ((ownsLinebuf_ as u8 as u8) << 1usize) & (2usize as u8))
- }
- }
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JSRuntime {
@@ -14452,7 +14404,7 @@ pub mod root {
#[derive(Debug)]
pub struct gfxFontFeatureValueSet_ValueList {
pub name: ::nsstring::nsStringRepr,
- pub featureSelectors: root::nsTArray,
+ pub featureSelectors: root::nsTArray<::std::os::raw::c_uint>,
}
#[test]
fn bindgen_test_layout_gfxFontFeatureValueSet_ValueList() {
@@ -14557,7 +14509,7 @@ pub mod root {
pub struct gfxFontFeatureValueSet_FeatureValueHashEntry {
pub _base: root::PLDHashEntryHdr,
pub mKey: root::gfxFontFeatureValueSet_FeatureValueHashKey,
- pub mValues: root::nsTArray,
+ pub mValues: root::nsTArray<::std::os::raw::c_uint>,
}
pub type gfxFontFeatureValueSet_FeatureValueHashEntry_KeyType =
*const root::gfxFontFeatureValueSet_FeatureValueHashKey;
@@ -14667,7 +14619,7 @@ pub mod root {
pub alternateValues: root::nsTArray,
pub featureValueLookup: root::RefPtr,
pub fontFeatureSettings: root::nsTArray,
- pub fontVariationSettings: root::nsTArray,
+ pub fontVariationSettings: root::nsTArray,
pub languageOverride: u32,
}
#[test]
@@ -15347,7 +15299,7 @@ pub mod root {
* count is 1.
*/
#[repr(C)]
- #[derive(Debug, Copy)]
+ #[derive(Debug)]
pub struct nsStringBuffer {
pub mRefCount: u32,
pub mStorageSize: u32,
@@ -15369,9 +15321,6 @@ pub mod root {
"Alignment of field: " , stringify ! ( nsStringBuffer ) ,
"::" , stringify ! ( mStorageSize ) ));
}
- impl Clone for nsStringBuffer {
- fn clone(&self) -> Self { *self }
- }
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsIAtom {
@@ -17116,7 +17065,7 @@ pub mod root {
*/
pub mFrameRequestCallbackCounter: i32,
pub mStaticCloneCount: u32,
- pub mBlockedTrackingNodes: root::nsTArray,
+ pub mBlockedTrackingNodes: root::nsTArray>,
pub mWindow: *mut root::nsPIDOMWindowInner,
pub mCachedEncoder: root::nsCOMPtr,
pub mFrameRequestCallbacks: root::nsTArray,
@@ -21329,7 +21278,7 @@ pub mod root {
pub _base_1: root::nsWrapperCache,
pub mRefCnt: root::nsCycleCollectingAutoRefCnt,
pub _mOwningThread: root::nsAutoOwningThread,
- pub mContent: root::nsCOMPtr,
+ pub mContent: root::nsCOMPtr,
/**
* Cache of Attrs.
*/
@@ -22430,57 +22379,57 @@ pub mod root {
pub struct nsDOMMutationObserver {
_unused: [u8; 0],
}
- pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_LISTENERMANAGER;
- pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_PROPERTIES;
- pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_ANONYMOUS_ROOT;
- pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
- pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS_ROOT;
- pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_FORCE_XBL_BINDINGS;
- pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_MAY_BE_IN_BINDING_MNGR;
- pub const NODE_IS_EDITABLE: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_EDITABLE;
- pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS;
- pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_IN_SHADOW_TREE;
- pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_EMPTY_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR;
- pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_EDGE_CHILD_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
- pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_ALL_SELECTOR_FLAGS;
- pub const NODE_NEEDS_FRAME: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_NEEDS_FRAME;
- pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_DESCENDANTS_NEED_FRAMES;
- pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_ACCESSKEY;
- pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_DIRECTION_RTL;
- pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_HAS_DIRECTION_LTR;
- pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_ALL_DIRECTION_FLAGS;
- pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_CHROME_ONLY_ACCESS;
- pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
- pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_17 =
- _bindgen_ty_17::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+ pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_LISTENERMANAGER;
+ pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_PROPERTIES;
+ pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_ANONYMOUS_ROOT;
+ pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+ pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+ pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_FORCE_XBL_BINDINGS;
+ pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_MAY_BE_IN_BINDING_MNGR;
+ pub const NODE_IS_EDITABLE: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_EDITABLE;
+ pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_NATIVE_ANONYMOUS;
+ pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_IN_SHADOW_TREE;
+ pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_EMPTY_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_SLOW_SELECTOR;
+ pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_EDGE_CHILD_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+ pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_ALL_SELECTOR_FLAGS;
+ pub const NODE_NEEDS_FRAME: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_NEEDS_FRAME;
+ pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_DESCENDANTS_NEED_FRAMES;
+ pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_ACCESSKEY;
+ pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_DIRECTION_RTL;
+ pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_HAS_DIRECTION_LTR;
+ pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_ALL_DIRECTION_FLAGS;
+ pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_CHROME_ONLY_ACCESS;
+ pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+ pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_88 =
+ _bindgen_ty_88::NODE_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_17 {
+ pub enum _bindgen_ty_88 {
NODE_HAS_LISTENERMANAGER = 4,
NODE_HAS_PROPERTIES = 8,
NODE_IS_ANONYMOUS_ROOT = 16,
@@ -23265,6 +23214,7 @@ pub mod root {
NS_FRAME_IS_NONDISPLAY = 9007199254740992,
NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY = 18014398509481984,
NS_FRAME_OWNS_ANON_BOXES = 36028797018963968,
+ NS_FRAME_HAS_CSS_COUNTER_STYLE = 72057594037927936,
NS_FRAME_SIMPLE_DISPLAYLIST = 144115188075855872,
NS_FRAME_MATHML_SCRIPT_DESCENDANT = 288230376151711744,
NS_FRAME_IS_IN_SINGLE_CHAR_MI = 576460752303423488,
@@ -27651,7 +27601,7 @@ pub mod root {
pub mRefCnt: root::nsAutoRefCnt,
pub _mOwningThread: root::nsAutoOwningThread,
pub mBehaviour: root::mozilla::UniquePtr,
- pub mURI: root::RefPtr,
+ pub mURI: root::RefPtr,
pub mListener: *mut root::imgINotificationObserver,
pub mLoadGroup: root::nsCOMPtr,
pub mLoadFlags: root::nsLoadFlags,
@@ -28883,7 +28833,7 @@ pub mod root {
pub _mOwningThread: root::nsAutoOwningThread,
pub mLoader: *mut root::imgLoader,
pub mRequest: root::nsCOMPtr,
- pub mURI: root::RefPtr,
+ pub mURI: root::RefPtr,
pub mCurrentURI: root::nsCOMPtr,
pub mLoadingPrincipal: root::nsCOMPtr,
pub mPrincipal: root::nsCOMPtr,
@@ -28910,8 +28860,8 @@ pub mod root {
pub mImageErrorCode: root::nsresult,
pub mBoostCategoriesRequested: u32,
pub mMutex: root::mozilla::Mutex,
- pub mProgressTracker: root::RefPtr,
- pub mImage: root::RefPtr,
+ pub mProgressTracker: root::RefPtr,
+ pub mImage: root::RefPtr,
pub _bitfield_1: u8,
pub __bindgen_padding_0: [u8; 7usize],
}
@@ -28925,7 +28875,7 @@ pub mod root {
pub type imgRequest_HasThreadSafeRefCnt = root::mozilla::TrueType;
#[test]
fn bindgen_test_layout_imgRequest() {
- assert_eq!(::std::mem::size_of::() , 440usize , concat ! (
+ assert_eq!(::std::mem::size_of::() , 416usize , concat ! (
"Size of: " , stringify ! ( imgRequest ) ));
assert_eq! (::std::mem::align_of::() , 8usize , concat ! (
"Alignment of " , stringify ! ( imgRequest ) ));
@@ -30376,7 +30326,7 @@ pub mod root {
) , "::" , stringify ! ( mQuotePairs ) ));
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_20() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_91() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -30387,7 +30337,7 @@ pub mod root {
root::mozilla::StaticRefPtr ) ));
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_21() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_92() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32565,7 +32515,7 @@ pub mod root {
pub type RawGeckoURLExtraData = root::mozilla::URLExtraData;
pub type RawGeckoKeyframeList = root::nsTArray;
pub type RawGeckoComputedKeyframeValuesList =
- root::nsTArray;
+ root::nsTArray>;
pub type RawGeckoAnimationValueList =
root::nsTArray;
pub type RawGeckoStyleAnimationList =
@@ -33323,48 +33273,48 @@ pub mod root {
pub struct nsAttrValueOrString {
_unused: [u8; 0],
}
- pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_1;
pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
- root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_19
+ root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_90
=
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_3;
pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT:
- root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
- pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_PENDING_RESTYLE_FLAGS;
- pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
- pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_ALL_RESTYLE_FLAGS;
- pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_HAS_SCROLLGRAB;
- pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_19 =
- _bindgen_ty_19::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
+ root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
+ pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_PENDING_RESTYLE_FLAGS;
+ pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
+ pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_ALL_RESTYLE_FLAGS;
+ pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_HAS_SCROLLGRAB;
+ pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_90 =
+ _bindgen_ty_90::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_19 {
+ pub enum _bindgen_ty_90 {
ELEMENT_SHARED_RESTYLE_BIT_1 = 8388608,
ELEMENT_SHARED_RESTYLE_BIT_2 = 16777216,
ELEMENT_SHARED_RESTYLE_BIT_3 = 33554432,
@@ -34017,7 +33967,7 @@ pub mod root {
}
pub type __builtin_va_list = [root::__va_list_tag; 1usize];
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_22() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_93() {
assert_eq!(::std::mem::size_of::() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -34026,7 +33976,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_23() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_94() {
assert_eq!(::std::mem::size_of::() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -34035,7 +33985,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_24() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_95() {
assert_eq!(::std::mem::size_of::() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -34046,33 +33996,29 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_25() {
- assert_eq!(::std::mem::size_of::>()
- , 24usize , concat ! (
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_96() {
+ assert_eq!(::std::mem::size_of::>() ,
+ 24usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsReadingIterator
- ) ));
- assert_eq!(::std::mem::align_of::>()
- , 8usize , concat ! (
+ root::nsReadingIterator ) ));
+ assert_eq!(::std::mem::align_of::>() ,
+ 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsReadingIterator
- ) ));
+ root::nsReadingIterator ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_26() {
- assert_eq!(::std::mem::size_of::>()
- , 24usize , concat ! (
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_97() {
+ assert_eq!(::std::mem::size_of::>() ,
+ 24usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsWritingIterator
- ) ));
- assert_eq!(::std::mem::align_of::>()
- , 8usize , concat ! (
+ root::nsWritingIterator ) ));
+ assert_eq!(::std::mem::align_of::>() ,
+ 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsWritingIterator
- ) ));
+ root::nsWritingIterator ) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_27() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_98() {
assert_eq!(::std::mem::size_of::() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -34083,33 +34029,29 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_28() {
- assert_eq!(::std::mem::size_of::>()
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_99() {
+ assert_eq!(::std::mem::size_of::>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsReadingIterator
- ) ));
- assert_eq!(::std::mem::align_of::>()
+ root::nsReadingIterator<::std::os::raw::c_char> ) ));
+ assert_eq!(::std::mem::align_of::>()
, 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsReadingIterator
- ) ));
+ root::nsReadingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_29() {
- assert_eq!(::std::mem::size_of::>()
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_100() {
+ assert_eq!(::std::mem::size_of::>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsWritingIterator
- ) ));
- assert_eq!(::std::mem::align_of::>()
+ root::nsWritingIterator<::std::os::raw::c_char> ) ));
+ assert_eq!(::std::mem::align_of::>()
, 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsWritingIterator
- ) ));
+ root::nsWritingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_30() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_101() {
assert_eq!(::std::mem::size_of::() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -34120,7 +34062,7 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_31() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_102() {
assert_eq!(::std::mem::size_of::() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -34131,7 +34073,7 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_188182_instantiation_32() {
+ fn __bindgen_test_layout__bindgen_ty_id_214445_instantiation_103() {
assert_eq!(::std::mem::size_of::() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -34140,7 +34082,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_188218_instantiation_33() {
+ fn __bindgen_test_layout__bindgen_ty_id_214481_instantiation_104() {
assert_eq!(::std::mem::size_of::() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -34149,7 +34091,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_34() {
+ fn __bindgen_test_layout_nsTArray_instantiation_105() {
assert_eq!(::std::mem::size_of::>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34160,7 +34102,7 @@ pub mod root {
root::nsTArray ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_35() {
+ fn __bindgen_test_layout_Handle_instantiation_106() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34171,7 +34113,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_36() {
+ fn __bindgen_test_layout_Handle_instantiation_107() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34182,7 +34124,7 @@ pub mod root {
root::JS::Handle ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_37() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_108() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34193,7 +34135,7 @@ pub mod root {
root::JS::MutableHandle ) ));
}
#[test]
- fn __bindgen_test_layout_Rooted_instantiation_38() {
+ fn __bindgen_test_layout_Rooted_instantiation_109() {
assert_eq!(::std::mem::size_of::<[u64; 3usize]>() , 24usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -34204,7 +34146,7 @@ pub mod root {
[u64; 3usize] ) ));
}
#[test]
- fn __bindgen_test_layout_DeletePolicy_instantiation_39() {
+ fn __bindgen_test_layout_DeletePolicy_instantiation_110() {
assert_eq!(::std::mem::size_of::() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -34215,7 +34157,7 @@ pub mod root {
root::JS::DeletePolicy ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_40() {
+ fn __bindgen_test_layout_nsTArray_instantiation_111() {
assert_eq!(::std::mem::size_of::>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34226,7 +34168,7 @@ pub mod root {
root::nsTArray<::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_41() {
+ fn __bindgen_test_layout_nsTArray_instantiation_112() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34237,29 +34179,29 @@ pub mod root {
root::nsTArray ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_42() {
- assert_eq!(::std::mem::size_of::>() , 8usize ,
- concat ! (
+ fn __bindgen_test_layout_nsTArray_instantiation_113() {
+ assert_eq!(::std::mem::size_of::>()
+ , 8usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsTArray ) ));
- assert_eq!(::std::mem::align_of::>() , 8usize ,
- concat ! (
+ root::nsTArray<::std::os::raw::c_uint> ) ));
+ assert_eq!(::std::mem::align_of::>()
+ , 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsTArray ) ));
+ root::nsTArray<::std::os::raw::c_uint> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_43() {
- assert_eq!(::std::mem::size_of::>() , 8usize ,
- concat ! (
+ fn __bindgen_test_layout_nsTArray_instantiation_114() {
+ assert_eq!(::std::mem::size_of::>()
+ , 8usize , concat ! (
"Size of template specialization: " , stringify ! (
- root::nsTArray ) ));
- assert_eq!(::std::mem::align_of::>() , 8usize ,
- concat ! (
+ root::nsTArray<::std::os::raw::c_uint> ) ));
+ assert_eq!(::std::mem::align_of::>()
+ , 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- root::nsTArray ) ));
+ root::nsTArray<::std::os::raw::c_uint> ) ));
}
#[test]
- fn __bindgen_test_layout_BaseTimeDuration_instantiation_44() {
+ fn __bindgen_test_layout_BaseTimeDuration_instantiation_115() {
assert_eq!(::std::mem::size_of::() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34270,7 +34212,7 @@ pub mod root {
root::mozilla::BaseTimeDuration ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_45() {
+ fn __bindgen_test_layout_nsTArray_instantiation_116() {
assert_eq!(::std::mem::size_of::>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34281,7 +34223,7 @@ pub mod root {
root::nsTArray<::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_46() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_117() {
assert_eq!(::std::mem::size_of::()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34292,7 +34234,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_47() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_118() {
assert_eq!(::std::mem::size_of::()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34303,7 +34245,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_48() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_119() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34314,7 +34256,7 @@ pub mod root {
root::already_AddRefed ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_49() {
+ fn __bindgen_test_layout_Handle_instantiation_120() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34325,7 +34267,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_50() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_121() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34336,7 +34278,7 @@ pub mod root {
root::JS::MutableHandle ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_51() {
+ fn __bindgen_test_layout_Handle_instantiation_122() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34347,7 +34289,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_52() {
+ fn __bindgen_test_layout_nsTArray_instantiation_123() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34358,7 +34300,7 @@ pub mod root {
root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_53() {
+ fn __bindgen_test_layout_Handle_instantiation_124() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34369,7 +34311,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_54() {
+ fn __bindgen_test_layout_RefPtr_instantiation_125() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34380,7 +34322,7 @@ pub mod root {
root::RefPtr ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_55() {
+ fn __bindgen_test_layout_Handle_instantiation_126() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34391,7 +34333,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_56() {
+ fn __bindgen_test_layout_Handle_instantiation_127() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34402,7 +34344,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_57() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_128() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34413,7 +34355,7 @@ pub mod root {
root::already_AddRefed ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_58() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_129() {
assert_eq!(::std::mem::size_of::>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -34424,7 +34366,7 @@ pub mod root {
root::already_AddRefed ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_59() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_130() {
assert_eq!(::std::mem::size_of::