mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
06813a3df9
@ -185,8 +185,6 @@ pref("browser.uitour.loglevel", "Error");
|
||||
pref("browser.uitour.requireSecure", true);
|
||||
pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
|
||||
pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
|
||||
// This is used as a regexp match against the page's URL.
|
||||
pref("browser.uitour.readerViewTrigger", "^https:\\/\\/www\\.mozilla\\.org\\/[^\\/]+\\/firefox\\/reading\\/start");
|
||||
// How long to show a Hearbeat survey (two hours, in seconds)
|
||||
pref("browser.uitour.surveyDuration", 7200);
|
||||
|
||||
|
@ -4647,8 +4647,6 @@ var XULBrowserWindow = {
|
||||
|
||||
SocialUI.updateState();
|
||||
|
||||
UITour.onLocationChange(location);
|
||||
|
||||
gTabletModePageCounter.inc();
|
||||
|
||||
// Utility functions for disabling find
|
||||
|
@ -206,8 +206,10 @@ add_task(function* () {
|
||||
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
|
||||
|
||||
// Check the contents of the notification, then choose "Cancel"
|
||||
let icon = panel.getAttribute("icon");
|
||||
is(icon, ICON_URL, "Permissions notification has the addon icon");
|
||||
checkNotification(panel, ICON_URL, [
|
||||
["webextPerms.hostDescription.allUrls"],
|
||||
["webextPerms.description.history"],
|
||||
]);
|
||||
|
||||
let disablePromise = promiseSetDisabled(mock1);
|
||||
panel.secondaryButton.click();
|
||||
@ -242,9 +244,10 @@ add_task(function* () {
|
||||
ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
|
||||
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
|
||||
|
||||
// Check the notification contents, this time accept the install
|
||||
icon = panel.getAttribute("icon");
|
||||
is(icon, DEFAULT_ICON_URL, "Permissions notification has the default icon");
|
||||
// Check the notification contents.
|
||||
checkNotification(panel, DEFAULT_ICON_URL, []);
|
||||
|
||||
// This time accept the install.
|
||||
disablePromise = promiseSetDisabled(mock2);
|
||||
panel.button.click();
|
||||
|
||||
@ -285,6 +288,7 @@ add_task(function* () {
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(item._enableBtn, {},
|
||||
gBrowser.selectedBrowser);
|
||||
panel = yield popupPromise;
|
||||
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
|
||||
|
||||
// Accept the permissions
|
||||
disablePromise = promiseSetDisabled(mock3);
|
||||
@ -312,6 +316,7 @@ add_task(function* () {
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(button, {},
|
||||
gBrowser.selectedBrowser);
|
||||
panel = yield popupPromise;
|
||||
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
|
||||
|
||||
// Accept the permissions
|
||||
disablePromise = promiseSetDisabled(mock4);
|
||||
|
@ -29,7 +29,7 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
|
||||
// Trigger an update check, manually applying the update if we're testing
|
||||
// without auto-update.
|
||||
function* triggerUpdate(win, addon) {
|
||||
async function triggerUpdate(win, addon) {
|
||||
let manualUpdatePromise;
|
||||
if (!autoUpdate) {
|
||||
manualUpdatePromise = new Promise(resolve => {
|
||||
@ -43,10 +43,10 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
});
|
||||
}
|
||||
|
||||
checkFn(win, addon);
|
||||
let promise = checkFn(win, addon);
|
||||
|
||||
if (manualUpdatePromise) {
|
||||
yield manualUpdatePromise;
|
||||
await manualUpdatePromise;
|
||||
|
||||
let list = win.document.getElementById("addon-list");
|
||||
|
||||
@ -56,6 +56,8 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
let item = list.children.find(_item => _item.value == ID);
|
||||
EventUtils.synthesizeMouseAtCenter(item._updateBtn, {}, win);
|
||||
}
|
||||
|
||||
return {promise};
|
||||
}
|
||||
|
||||
// Navigate away from the starting page to force about:addons to load
|
||||
@ -72,7 +74,7 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
|
||||
// Trigger an update check
|
||||
let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
|
||||
yield triggerUpdate(win, addon);
|
||||
let {promise: checkPromise} = yield triggerUpdate(win, addon);
|
||||
let panel = yield popupPromise;
|
||||
|
||||
// Click the cancel button, wait to see the cancel event
|
||||
@ -83,9 +85,12 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
addon = yield AddonManager.getAddonByID(ID);
|
||||
is(addon.version, "1.0", "Should still be running the old version");
|
||||
|
||||
// Make sure the update check is completely finished.
|
||||
yield checkPromise;
|
||||
|
||||
// Trigger a new update check
|
||||
popupPromise = promisePopupNotificationShown("addon-webext-permissions");
|
||||
yield triggerUpdate(win, addon);
|
||||
checkPromise = (yield triggerUpdate(win, addon)).promise;
|
||||
|
||||
// This time, accept the upgrade
|
||||
let updatePromise = promiseInstallEvent(addon, "onInstallEnded");
|
||||
@ -95,6 +100,8 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
addon = yield updatePromise;
|
||||
is(addon.version, "2.0", "Should have upgraded");
|
||||
|
||||
yield checkPromise;
|
||||
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
addon.uninstall();
|
||||
yield SpecialPowers.popPrefEnv();
|
||||
@ -103,6 +110,15 @@ function* interactiveUpdateTest(autoUpdate, checkFn) {
|
||||
// Invoke the "Check for Updates" menu item
|
||||
function checkAll(win) {
|
||||
win.gViewController.doCommand("cmd_findAllUpdates");
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, "EM-update-check-finished");
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(observer, "EM-update-check-finished", false);
|
||||
});
|
||||
}
|
||||
|
||||
// Test "Check for Updates" with both auto-update settings
|
||||
|
@ -149,6 +149,50 @@ function checkPermissionString(string, key, param, msg) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the contents of a permission popup notification
|
||||
*
|
||||
* @param {Window} panel
|
||||
* The popup window.
|
||||
* @param {string|regexp|function} checkIcon
|
||||
* The icon expected to appear in the notification. If this is a
|
||||
* string, it must match the icon url exactly. If it is a
|
||||
* regular expression it is tested against the icon url, and if
|
||||
* it is a function, it is called with the icon url and returns
|
||||
* true if the url is correct.
|
||||
* @param {array} permissions
|
||||
* The expected entries in the permissions list. Each element
|
||||
* in this array is itself a 2-element array with the string key
|
||||
* for the item (e.g., "webextPerms.description.foo") and an
|
||||
* optional formatting parameter.
|
||||
*/
|
||||
function checkNotification(panel, checkIcon, permissions) {
|
||||
let icon = panel.getAttribute("icon");
|
||||
let ul = document.getElementById("addon-webext-perm-list");
|
||||
let header = document.getElementById("addon-webext-perm-intro");
|
||||
|
||||
if (checkIcon instanceof RegExp) {
|
||||
ok(checkIcon.test(icon), "Notification icon is correct");
|
||||
} else if (typeof checkIcon == "function") {
|
||||
ok(checkIcon(icon), "Notification icon is correct");
|
||||
} else {
|
||||
is(icon, checkIcon, "Notification icon is correct");
|
||||
}
|
||||
|
||||
is(ul.childElementCount, permissions.length, `Permissions list has ${permissions.length} entries`);
|
||||
if (permissions.length == 0) {
|
||||
is(header.getAttribute("hidden"), "true", "Permissions header is hidden");
|
||||
} else {
|
||||
is(header.getAttribute("hidden"), "", "Permissions header is visible");
|
||||
}
|
||||
|
||||
for (let i in permissions) {
|
||||
let [key, param] = permissions[i];
|
||||
checkPermissionString(ul.children[i].textContent, key, param,
|
||||
`Permission number ${i + 1} is correct`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that install-time permission prompts work for a given
|
||||
* installation method.
|
||||
@ -213,44 +257,19 @@ async function testInstallMethod(installFn) {
|
||||
let installMethodPromise = installFn(filename);
|
||||
|
||||
let panel = await promisePopupNotificationShown("addon-webext-permissions");
|
||||
let icon = panel.getAttribute("icon");
|
||||
|
||||
let ul = document.getElementById("addon-webext-perm-list");
|
||||
let header = document.getElementById("addon-webext-perm-intro");
|
||||
|
||||
if (filename == PERMS_XPI) {
|
||||
// The icon should come from the extension, don't bother with the precise
|
||||
// path, just make sure we've got a jar url pointing to the right path
|
||||
// inside the jar.
|
||||
ok(icon.startsWith("jar:file://"), "Icon is a jar url");
|
||||
ok(icon.endsWith("/icon.png"), "Icon is icon.png inside a jar");
|
||||
|
||||
is(header.getAttribute("hidden"), "", "Permission list header is visible");
|
||||
is(ul.childElementCount, 5, "Permissions list has 5 entries");
|
||||
|
||||
checkPermissionString(ul.children[0].textContent,
|
||||
"webextPerms.hostDescription.wildcard",
|
||||
"wildcard.domain",
|
||||
"First permission is domain permission");
|
||||
checkPermissionString(ul.children[1].textContent,
|
||||
"webextPerms.hostDescription.oneSite",
|
||||
"singlehost.domain",
|
||||
"Second permission is single host permission");
|
||||
checkPermissionString(ul.children[2].textContent,
|
||||
"webextPerms.description.nativeMessaging", null,
|
||||
"Third permission is nativeMessaging");
|
||||
checkPermissionString(ul.children[3].textContent,
|
||||
"webextPerms.description.tabs", null,
|
||||
"Fourth permission is tabs");
|
||||
checkPermissionString(ul.children[4].textContent,
|
||||
"webextPerms.description.history", null,
|
||||
"Fifth permission is history");
|
||||
checkNotification(panel, /^jar:file:\/\/.*\/icon\.png$/, [
|
||||
["webextPerms.hostDescription.wildcard", "wildcard.domain"],
|
||||
["webextPerms.hostDescription.oneSite", "singlehost.domain"],
|
||||
["webextPerms.description.nativeMessaging"],
|
||||
["webextPerms.description.tabs"],
|
||||
["webextPerms.description.history"],
|
||||
]);
|
||||
} else if (filename == NO_PERMS_XPI) {
|
||||
// This extension has no icon, it should have the default
|
||||
ok(isDefaultIcon(icon), "Icon is the default extension icon");
|
||||
|
||||
is(header.getAttribute("hidden"), "true", "Permission list header is hidden");
|
||||
is(ul.childElementCount, 0, "Permissions list has 0 entries");
|
||||
checkNotification(panel, isDefaultIcon, []);
|
||||
}
|
||||
|
||||
if (cancel) {
|
||||
|
@ -74,15 +74,14 @@ CommandList.prototype = {
|
||||
// For Windows, chrome.runtime expects 'win' while chrome.commands
|
||||
// expects 'windows'. We can special case this for now.
|
||||
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
|
||||
for (let name of Object.keys(manifest.commands)) {
|
||||
let command = manifest.commands[name];
|
||||
let shortcut = command.suggested_key[os] || command.suggested_key.default;
|
||||
if (shortcut) {
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut: shortcut.replace(/\s+/g, ""),
|
||||
});
|
||||
}
|
||||
for (let [name, command] of Object.entries(manifest.commands)) {
|
||||
let suggested_key = command.suggested_key || {};
|
||||
let shortcut = suggested_key[os] || suggested_key.default;
|
||||
shortcut = shortcut ? shortcut.replace(/\s+/g, "") : null;
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut,
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
@ -96,8 +95,10 @@ CommandList.prototype = {
|
||||
let keyset = doc.createElementNS(XUL_NS, "keyset");
|
||||
keyset.id = `ext-keyset-id-${this.id}`;
|
||||
this.commands.forEach((command, name) => {
|
||||
let keyElement = this.buildKey(doc, name, command.shortcut);
|
||||
keyset.appendChild(keyElement);
|
||||
if (command.shortcut) {
|
||||
let keyElement = this.buildKey(doc, name, command.shortcut);
|
||||
keyset.appendChild(keyElement);
|
||||
}
|
||||
});
|
||||
doc.documentElement.appendChild(keyset);
|
||||
this.keysetsMap.set(window, keyset);
|
||||
|
@ -175,7 +175,7 @@ add_task(function* testTabSwitchContext() {
|
||||
"2.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
getTests: function(tabs, expectDefaults) {
|
||||
const DEFAULT_BADGE_COLOR = [0xd9, 0, 0, 255];
|
||||
|
||||
let details = [
|
||||
@ -331,7 +331,7 @@ add_task(function* testDefaultTitle() {
|
||||
"icon.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
getTests: function(tabs, expectDefaults) {
|
||||
const DEFAULT_BADGE_COLOR = [0xd9, 0, 0, 255];
|
||||
|
||||
let details = [
|
||||
|
@ -26,6 +26,11 @@ add_task(function* () {
|
||||
"android": "Ctrl+Shift+A",
|
||||
},
|
||||
},
|
||||
"without-suggested-key": {
|
||||
"description": "has no suggested_key",
|
||||
},
|
||||
"without-suggested-key-nor-description": {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -33,7 +38,7 @@ add_task(function* () {
|
||||
browser.test.onMessage.addListener((message, additionalScope) => {
|
||||
browser.commands.getAll((commands) => {
|
||||
let errorMessage = "getAll should return an array of commands";
|
||||
browser.test.assertEq(commands.length, 3, errorMessage);
|
||||
browser.test.assertEq(commands.length, 5, errorMessage);
|
||||
|
||||
let command = commands.find(c => c.name == "with-desciption");
|
||||
|
||||
@ -64,6 +69,18 @@ add_task(function* () {
|
||||
errorMessage = `The shortcut should match the one provided in the manifest for OS='${additionalScope.platform}'`;
|
||||
browser.test.assertEq(shortcut, command.shortcut, errorMessage);
|
||||
|
||||
command = commands.find(c => c.name == "without-suggested-key");
|
||||
|
||||
browser.test.assertEq("has no suggested_key", command.description, "The description should match what is provided in the manifest");
|
||||
|
||||
browser.test.assertEq(null, command.shortcut, "The shortcut should be empty if not provided");
|
||||
|
||||
command = commands.find(c => c.name == "without-suggested-key-nor-description");
|
||||
|
||||
browser.test.assertEq(null, command.description, "The description should be empty when it is not provided");
|
||||
|
||||
browser.test.assertEq(null, command.shortcut, "The shortcut should be empty if not provided");
|
||||
|
||||
browser.test.notifyPass("commands");
|
||||
});
|
||||
});
|
||||
|
@ -53,7 +53,7 @@ add_task(function* testTabSwitchContext() {
|
||||
"2.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs) {
|
||||
getTests: function(tabs) {
|
||||
let details = [
|
||||
{"icon": browser.runtime.getURL("default.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
|
@ -53,7 +53,7 @@ add_task(function* testTabSwitchContext() {
|
||||
"2.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs) {
|
||||
getTests: function(tabs) {
|
||||
let details = [
|
||||
{"icon": browser.runtime.getURL("default.png"),
|
||||
"popup": browser.runtime.getURL("default.html"),
|
||||
@ -190,7 +190,7 @@ add_task(function* testDefaultTitle() {
|
||||
"icon.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs) {
|
||||
getTests: function(tabs) {
|
||||
let details = [
|
||||
{"title": "Foo Extension",
|
||||
"popup": "",
|
||||
|
@ -171,7 +171,7 @@ add_task(function* testTabSwitchContext() {
|
||||
"2.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
getTests: function(tabs, expectDefaults) {
|
||||
let details = [
|
||||
{"icon": browser.runtime.getURL("default.png"),
|
||||
"panel": browser.runtime.getURL("default.html"),
|
||||
@ -324,7 +324,7 @@ add_task(function* testDefaultTitle() {
|
||||
"icon.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
getTests: function(tabs, expectDefaults) {
|
||||
let details = [
|
||||
{"title": "Foo Extension",
|
||||
"panel": browser.runtime.getURL("sidebar.html"),
|
||||
|
@ -90,7 +90,7 @@ add_task(function* testBadPermissions() {
|
||||
},
|
||||
},
|
||||
},
|
||||
contentSetup() {
|
||||
contentSetup: function() {
|
||||
browser.commands.onCommand.addListener(function(command) {
|
||||
if (command == "test-tabs-executeScript") {
|
||||
browser.test.sendMessage("tabs-command-key-pressed");
|
||||
@ -132,7 +132,7 @@ add_task(function* testBadPermissions() {
|
||||
"permissions": ["http://example.com/", "activeTab"],
|
||||
"page_action": {},
|
||||
},
|
||||
async contentSetup() {
|
||||
contentSetup: async function() {
|
||||
let [tab] = await browser.tabs.query({active: true, currentWindow: true});
|
||||
await browser.pageAction.show(tab.id);
|
||||
},
|
||||
|
@ -86,7 +86,7 @@ add_task(function* testGoodPermissions() {
|
||||
},
|
||||
},
|
||||
},
|
||||
contentSetup() {
|
||||
contentSetup: function() {
|
||||
browser.commands.onCommand.addListener(function(command) {
|
||||
if (command == "test-tabs-executeScript") {
|
||||
browser.test.sendMessage("tabs-command-key-pressed");
|
||||
@ -106,7 +106,7 @@ add_task(function* testGoodPermissions() {
|
||||
"permissions": ["activeTab"],
|
||||
"browser_action": {},
|
||||
},
|
||||
contentSetup() {
|
||||
contentSetup: function() {
|
||||
browser.browserAction.onClicked.addListener(() => {
|
||||
browser.test.log("Clicked.");
|
||||
});
|
||||
@ -162,7 +162,7 @@ add_task(function* testGoodPermissions() {
|
||||
manifest: {
|
||||
"permissions": ["activeTab", "contextMenus"],
|
||||
},
|
||||
contentSetup() {
|
||||
contentSetup: function() {
|
||||
browser.contextMenus.create({title: "activeTab", contexts: ["all"]});
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
@ -32,15 +32,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
|
||||
"resource://gre/modules/ReaderMode.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
|
||||
"resource:///modules/ReaderParent.jsm");
|
||||
|
||||
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
|
||||
const PREF_LOG_LEVEL = "browser.uitour.loglevel";
|
||||
const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
|
||||
const PREF_READERVIEW_TRIGGER = "browser.uitour.readerViewTrigger";
|
||||
const PREF_SURVEY_DURATION = "browser.uitour.surveyDuration";
|
||||
|
||||
const BACKGROUND_PAGE_ACTIONS_ALLOWED = new Set([
|
||||
@ -297,23 +294,6 @@ this.UITour = {
|
||||
JSON.stringify([...this.seenPageIDs]));
|
||||
},
|
||||
|
||||
get _readerViewTriggerRegEx() {
|
||||
delete this._readerViewTriggerRegEx;
|
||||
let readerViewUITourTrigger = Services.prefs.getCharPref(PREF_READERVIEW_TRIGGER);
|
||||
return this._readerViewTriggerRegEx = new RegExp(readerViewUITourTrigger, "i");
|
||||
},
|
||||
|
||||
onLocationChange(aLocation) {
|
||||
// The ReaderView tour page is expected to run in Reader View,
|
||||
// which disables JavaScript on the page. To get around that, we
|
||||
// automatically start a pre-defined tour on page load (for hysterical
|
||||
// raisins the ReaderView tour is known as "readinglist")
|
||||
let originalUrl = ReaderMode.getOriginalUrl(aLocation);
|
||||
if (this._readerViewTriggerRegEx.test(originalUrl)) {
|
||||
this.startSubTour("readinglist");
|
||||
}
|
||||
},
|
||||
|
||||
onPageEvent(aMessage, aEvent) {
|
||||
let browser = aMessage.target;
|
||||
let window = browser.ownerGlobal;
|
||||
@ -1938,19 +1918,6 @@ this.UITour = {
|
||||
});
|
||||
},
|
||||
|
||||
startSubTour(aFeature) {
|
||||
if (aFeature != "string") {
|
||||
log.error("startSubTour: No feature option specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aFeature == "readinglist") {
|
||||
ReaderParent.showReaderModeInfoPanel(browser);
|
||||
} else {
|
||||
log.error("startSubTour: Unknown feature option specified");
|
||||
}
|
||||
},
|
||||
|
||||
addNavBarWidget(aTarget, aMessageManager, aCallbackID) {
|
||||
if (aTarget.node) {
|
||||
log.error("addNavBarWidget: can't add a widget already present:", aTarget);
|
||||
|
@ -3,6 +3,7 @@
|
||||
ac_add_options --enable-valgrind
|
||||
ac_add_options --disable-jemalloc
|
||||
ac_add_options --disable-install-strip
|
||||
ac_add_options --disable-gtest-in-build
|
||||
|
||||
# Include the override mozconfig again (even though the above includes it)
|
||||
# since it's supposed to override everything.
|
||||
|
@ -3,6 +3,7 @@
|
||||
ac_add_options --enable-valgrind
|
||||
ac_add_options --disable-jemalloc
|
||||
ac_add_options --disable-install-strip
|
||||
ac_add_options --disable-gtest-in-build
|
||||
|
||||
# Include the override mozconfig again (even though the above includes it)
|
||||
# since it's supposed to override everything.
|
||||
|
28
browser/extensions/e10srollout/bootstrap.js
vendored
28
browser/extensions/e10srollout/bootstrap.js
vendored
@ -73,9 +73,7 @@ function defineCohort() {
|
||||
|
||||
Preferences.set(PREF_E10S_ADDON_BLOCKLIST,
|
||||
// bug 1185672 - Tab Mix Plus
|
||||
"{dc572301-7619-498c-a57d-39143191b318};" +
|
||||
// bug 1332692 - LastPass
|
||||
"support@lastpass.com;");
|
||||
"{dc572301-7619-498c-a57d-39143191b318};");
|
||||
} else {
|
||||
Preferences.reset(PREF_E10S_ADDON_POLICY);
|
||||
}
|
||||
@ -86,6 +84,7 @@ function defineCohort() {
|
||||
let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]);
|
||||
let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
|
||||
let temporaryDisqualification = getTemporaryDisqualification();
|
||||
let temporaryQualification = getTemporaryQualification();
|
||||
|
||||
let cohortPrefix = "";
|
||||
if (disqualified) {
|
||||
@ -109,6 +108,9 @@ function defineCohort() {
|
||||
// here will be accumulated as "2 - Disabled", which is fine too.
|
||||
setCohort(`temp-disqualified-${temporaryDisqualification}`);
|
||||
Preferences.reset(PREF_TOGGLE_E10S);
|
||||
} else if (!disqualified && temporaryQualification != "") {
|
||||
setCohort(`temp-qualified-${temporaryQualification}`);
|
||||
Preferences.set(PREF_TOGGLE_E10S, true);
|
||||
} else if (testGroup) {
|
||||
setCohort(`${cohortPrefix}test`);
|
||||
Preferences.set(PREF_TOGGLE_E10S, true);
|
||||
@ -176,3 +178,23 @@ function optedOut() {
|
||||
function getTemporaryDisqualification() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/* If this function returns a non-empty string, it
|
||||
* means that this particular user should be temporarily
|
||||
* qualified due to some particular reason.
|
||||
* If a user shouldn't be qualified, then an empty
|
||||
* string must be returned.
|
||||
*/
|
||||
function getTemporaryQualification() {
|
||||
// Whenever the DevTools toolbox is opened for the first time in a release, it
|
||||
// records this fact in the following pref as part of the DevTools telemetry
|
||||
// system. If this pref is set, then it means the user has opened DevTools at
|
||||
// some point in time.
|
||||
const PREF_OPENED_DEVTOOLS = "devtools.telemetry.tools.opened.version";
|
||||
let hasOpenedDevTools = Preferences.isSet(PREF_OPENED_DEVTOOLS);
|
||||
if (hasOpenedDevTools) {
|
||||
return "devtools";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>e10srollout@mozilla.org</em:id>
|
||||
<em:version>1.9</em:version>
|
||||
<em:version>1.11</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
@ -10,7 +10,6 @@ DIRS += [
|
||||
'pdfjs',
|
||||
'pocket',
|
||||
'webcompat',
|
||||
'shield-recipe-client',
|
||||
]
|
||||
|
||||
# Only include the following system add-ons if building Aurora or Nightly
|
||||
@ -19,6 +18,7 @@ if not CONFIG['RELEASE_OR_BETA']:
|
||||
'flyweb',
|
||||
'formautofill',
|
||||
'presentation',
|
||||
'shield-recipe-client',
|
||||
]
|
||||
|
||||
# Only include mortar system add-ons if we locally enable it
|
||||
|
@ -550,6 +550,11 @@
|
||||
@RESPATH@/components/PresentationDataChannelSessionTransport.js
|
||||
@RESPATH@/components/PresentationDataChannelSessionTransport.manifest
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
@RESPATH@/components/mozIntl.manifest
|
||||
@RESPATH@/components/mozIntl.js
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)
|
||||
@RESPATH@/components/TestInterfaceJS.js
|
||||
@RESPATH@/components/TestInterfaceJS.manifest
|
||||
|
@ -556,6 +556,7 @@ Section "-InstallEndCleanup"
|
||||
SetDetailsPrint none
|
||||
|
||||
${Unless} ${Silent}
|
||||
ClearErrors
|
||||
${MUI_INSTALLOPTIONS_READ} $0 "summary.ini" "Field 4" "State"
|
||||
${If} "$0" == "1"
|
||||
; NB: this code is duplicated in stub.nsi. Please keep in sync.
|
||||
@ -592,7 +593,7 @@ Section "-InstallEndCleanup"
|
||||
GetFunctionAddress $0 SetAsDefaultAppUserHKCU
|
||||
UAC::ExecCodeSegment $0
|
||||
${EndIf}
|
||||
${Else}
|
||||
${ElseIfNot} ${Errors}
|
||||
${LogHeader} "Writing default-browser opt-out"
|
||||
ClearErrors
|
||||
WriteRegStr HKCU "Software\Mozilla\Firefox" "DefaultBrowserOptOut" "True"
|
||||
|
@ -62,6 +62,7 @@ webextPerms.sideloadMenuItem=%1$S added to %2$S
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.sideloadHeader=%S added
|
||||
webextPerms.sideloadText2=Another program on your computer installed an add-on that may affect your browser. Please review this add-on’s permissions requests and choose to Enable or Cancel (to leave it disabled).
|
||||
webextPerms.sideloadTextNoPerms=Another program on your computer installed an add-on that may affect your browser. Please choose to Enable or Cancel (to leave it disabled).
|
||||
|
||||
webextPerms.sideloadEnable.label=Enable
|
||||
webextPerms.sideloadEnable.accessKey=E
|
||||
|
@ -192,32 +192,6 @@ this.ExtensionsUI = {
|
||||
|
||||
let bundle = Services.strings.createBundle(BROWSER_PROPERTIES);
|
||||
|
||||
let name = this._sanitizeName(info.addon.name);
|
||||
let addonName = `<span class="addon-webext-name">${name}</span>`;
|
||||
|
||||
result.header = bundle.formatStringFromName("webextPerms.header", [addonName], 1);
|
||||
result.text = "";
|
||||
result.listIntro = bundle.GetStringFromName("webextPerms.listIntro");
|
||||
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.add.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.add.accessKey");
|
||||
result.cancelText = bundle.GetStringFromName("webextPerms.cancel.label");
|
||||
result.cancelKey = bundle.GetStringFromName("webextPerms.cancel.accessKey");
|
||||
|
||||
if (info.type == "sideload") {
|
||||
result.header = bundle.formatStringFromName("webextPerms.sideloadHeader", [addonName], 1);
|
||||
result.text = bundle.GetStringFromName("webextPerms.sideloadText2");
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.sideloadEnable.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.sideloadEnable.accessKey");
|
||||
result.cancelText = bundle.GetStringFromName("webextPerms.sideloadCancel.label");
|
||||
result.cancelKey = bundle.GetStringFromName("webextPerms.sideloadCancel.accessKey");
|
||||
} else if (info.type == "update") {
|
||||
result.header = "";
|
||||
result.text = bundle.formatStringFromName("webextPerms.updateText", [addonName], 1);
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.updateAccept.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.updateAccept.accessKey");
|
||||
}
|
||||
|
||||
let perms = info.permissions || {hosts: [], permissions: []};
|
||||
|
||||
// First classify our host permissions
|
||||
@ -295,6 +269,35 @@ this.ExtensionsUI = {
|
||||
}
|
||||
}
|
||||
|
||||
// Now figure out all the rest of the notification text.
|
||||
let name = this._sanitizeName(info.addon.name);
|
||||
let addonName = `<span class="addon-webext-name">${name}</span>`;
|
||||
|
||||
result.header = bundle.formatStringFromName("webextPerms.header", [addonName], 1);
|
||||
result.text = "";
|
||||
result.listIntro = bundle.GetStringFromName("webextPerms.listIntro");
|
||||
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.add.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.add.accessKey");
|
||||
result.cancelText = bundle.GetStringFromName("webextPerms.cancel.label");
|
||||
result.cancelKey = bundle.GetStringFromName("webextPerms.cancel.accessKey");
|
||||
|
||||
if (info.type == "sideload") {
|
||||
result.header = bundle.formatStringFromName("webextPerms.sideloadHeader", [addonName], 1);
|
||||
let key = result.msgs.length == 0 ?
|
||||
"webextPerms.sideloadTextNoPerms" : "webextPerms.sideloadText2";
|
||||
result.text = bundle.GetStringFromName(key);
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.sideloadEnable.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.sideloadEnable.accessKey");
|
||||
result.cancelText = bundle.GetStringFromName("webextPerms.sideloadCancel.label");
|
||||
result.cancelKey = bundle.GetStringFromName("webextPerms.sideloadCancel.accessKey");
|
||||
} else if (info.type == "update") {
|
||||
result.header = "";
|
||||
result.text = bundle.formatStringFromName("webextPerms.updateText", [addonName], 1);
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.updateAccept.label");
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.updateAccept.accessKey");
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
|
@ -601,12 +601,14 @@ endif
|
||||
endif
|
||||
|
||||
ifneq (,$(MOZ_PROFILE_GENERATE)$(MOZ_PROFILE_USE))
|
||||
ifneq (,$(filter target,$(MAKECMDGOALS)))
|
||||
ifdef GNU_CC
|
||||
# Force rebuilding libraries and programs in both passes because each
|
||||
# pass uses different object files.
|
||||
$(PROGRAM) $(SHARED_LIBRARY) $(LIBRARY): FORCE
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
endif # NO_PROFILE_GUIDED_OPTIMIZE
|
||||
|
||||
|
@ -161,7 +161,10 @@ BrowserToolboxProcess.prototype = {
|
||||
_initProfile: function () {
|
||||
dumpn("Initializing the chrome toolbox user profile.");
|
||||
|
||||
let debuggingProfileDir = Services.dirsvc.get("ProfLD", Ci.nsIFile);
|
||||
// We used to use `ProfLD` instead of `ProfD`, so migrate old profiles if they exist.
|
||||
this._migrateProfileDir();
|
||||
|
||||
let debuggingProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
debuggingProfileDir.append(CHROME_DEBUGGER_PROFILE_NAME);
|
||||
try {
|
||||
debuggingProfileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
@ -194,6 +197,35 @@ BrowserToolboxProcess.prototype = {
|
||||
this._dbgProfilePath);
|
||||
},
|
||||
|
||||
/**
|
||||
* Originally, the profile was placed in `ProfLD` instead of `ProfD`. On some systems,
|
||||
* such as macOS, `ProfLD` is in the user's Caches directory, which is not an
|
||||
* appropriate place to store supposedly persistent profile data.
|
||||
*/
|
||||
_migrateProfileDir() {
|
||||
let oldDebuggingProfileDir = Services.dirsvc.get("ProfLD", Ci.nsIFile);
|
||||
oldDebuggingProfileDir.append(CHROME_DEBUGGER_PROFILE_NAME);
|
||||
if (!oldDebuggingProfileDir.exists()) {
|
||||
return;
|
||||
}
|
||||
dumpn(`Old debugging profile exists: ${oldDebuggingProfileDir.path}`);
|
||||
try {
|
||||
// Remove the directory from the target location, if it exists
|
||||
let newDebuggingProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
newDebuggingProfileDir.append(CHROME_DEBUGGER_PROFILE_NAME);
|
||||
if (newDebuggingProfileDir.exists()) {
|
||||
dumpn(`Removing folder at destination: ${newDebuggingProfileDir.path}`);
|
||||
newDebuggingProfileDir.remove(true);
|
||||
}
|
||||
// Move profile from old to new location
|
||||
let newDebuggingProfileParent = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
oldDebuggingProfileDir.moveTo(newDebuggingProfileParent, null);
|
||||
dumpn("Debugging profile migrated successfully");
|
||||
} catch (e) {
|
||||
dumpn(`Debugging profile migration failed: ${e}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates and initializes the profile & process for the remote debugger.
|
||||
*/
|
||||
|
@ -1,20 +0,0 @@
|
||||
function originalToGeneratedId(originalId) {
|
||||
const match = originalId.match(/(.*)\/originalSource/);
|
||||
return match ? match[1] : "";
|
||||
}
|
||||
|
||||
function generatedToOriginalId(generatedId, url) {
|
||||
return generatedId + "/originalSource-" + url.replace(/ \//, '-');
|
||||
}
|
||||
|
||||
function isOriginalId(id) {
|
||||
return !!id.match(/\/originalSource/);
|
||||
}
|
||||
|
||||
function isGeneratedId(id) {
|
||||
return !isOriginalId(id);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
originalToGeneratedId, generatedToOriginalId, isOriginalId, isGeneratedId
|
||||
};
|
@ -1,220 +0,0 @@
|
||||
const { fetch, assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { joinURI } = require("devtools/shared/path");
|
||||
const path = require("sdk/fs/path");
|
||||
const { SourceMapConsumer, SourceMapGenerator } = require("source-map");
|
||||
const { isJavaScript } = require("./source");
|
||||
const {
|
||||
originalToGeneratedId,
|
||||
generatedToOriginalId,
|
||||
isGeneratedId,
|
||||
isOriginalId
|
||||
} = require("./source-map-util");
|
||||
|
||||
let sourceMapRequests = new Map();
|
||||
let sourceMapsEnabled = false;
|
||||
|
||||
function clearSourceMaps() {
|
||||
sourceMapRequests.clear();
|
||||
}
|
||||
|
||||
function enableSourceMaps() {
|
||||
sourceMapsEnabled = true;
|
||||
}
|
||||
|
||||
function _resolveSourceMapURL(source) {
|
||||
const { url = "", sourceMapURL = "" } = source;
|
||||
if (path.isURL(sourceMapURL) || url == "") {
|
||||
// If it's already a full URL or the source doesn't have a URL,
|
||||
// don't resolve anything.
|
||||
return sourceMapURL;
|
||||
} else if (path.isAbsolute(sourceMapURL)) {
|
||||
// If it's an absolute path, it should be resolved relative to the
|
||||
// host of the source.
|
||||
const { protocol = "", host = "" } = parse(url);
|
||||
return `${protocol}//${host}${sourceMapURL}`;
|
||||
}
|
||||
// Otherwise, it's a relative path and should be resolved relative
|
||||
// to the source.
|
||||
return dirname(url) + "/" + sourceMapURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source map's sourceRoot to be relative to the source map url.
|
||||
* @memberof utils/source-map-worker
|
||||
* @static
|
||||
*/
|
||||
function _setSourceMapRoot(sourceMap, absSourceMapURL, source) {
|
||||
// No need to do this fiddling if we won't be fetching any sources over the
|
||||
// wire.
|
||||
if (sourceMap.hasContentsOfAllSources()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const base = dirname(
|
||||
(absSourceMapURL.indexOf("data:") === 0 && source.url) ?
|
||||
source.url :
|
||||
absSourceMapURL
|
||||
);
|
||||
|
||||
if (sourceMap.sourceRoot) {
|
||||
sourceMap.sourceRoot = joinURI(base, sourceMap.sourceRoot);
|
||||
} else {
|
||||
sourceMap.sourceRoot = base;
|
||||
}
|
||||
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
function _getSourceMap(generatedSourceId)
|
||||
: ?Promise<SourceMapConsumer> {
|
||||
return sourceMapRequests.get(generatedSourceId);
|
||||
}
|
||||
|
||||
async function _resolveAndFetch(generatedSource) : SourceMapConsumer {
|
||||
// Fetch the sourcemap over the network and create it.
|
||||
const sourceMapURL = _resolveSourceMapURL(generatedSource);
|
||||
const fetched = await fetch(
|
||||
sourceMapURL, { loadFromCache: false }
|
||||
);
|
||||
|
||||
// Create the source map and fix it up.
|
||||
const map = new SourceMapConsumer(fetched.content);
|
||||
_setSourceMapRoot(map, sourceMapURL, generatedSource);
|
||||
return map;
|
||||
}
|
||||
|
||||
function _fetchSourceMap(generatedSource) {
|
||||
const existingRequest = sourceMapRequests.get(generatedSource.id);
|
||||
if (existingRequest) {
|
||||
// If it has already been requested, return the request. Make sure
|
||||
// to do this even if sourcemapping is turned off, because
|
||||
// pretty-printing uses sourcemaps.
|
||||
//
|
||||
// An important behavior here is that if it's in the middle of
|
||||
// requesting it, all subsequent calls will block on the initial
|
||||
// request.
|
||||
return existingRequest;
|
||||
} else if (!generatedSource.sourceMapURL || !sourceMapsEnabled) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
// Fire off the request, set it in the cache, and return it.
|
||||
// Suppress any errors and just return null (ignores bogus
|
||||
// sourcemaps).
|
||||
const req = _resolveAndFetch(generatedSource).catch(() => null);
|
||||
sourceMapRequests.set(generatedSource.id, req);
|
||||
return req;
|
||||
}
|
||||
|
||||
async function getOriginalURLs(generatedSource) {
|
||||
const map = await _fetchSourceMap(generatedSource);
|
||||
return map && map.sources;
|
||||
}
|
||||
|
||||
async function getGeneratedLocation(location: Location, originalSource: Source)
|
||||
: Promise<Location> {
|
||||
if (!isOriginalId(location.sourceId)) {
|
||||
return location;
|
||||
}
|
||||
|
||||
const generatedSourceId = originalToGeneratedId(location.sourceId);
|
||||
const map = await _getSourceMap(generatedSourceId);
|
||||
if (!map) {
|
||||
return location;
|
||||
}
|
||||
|
||||
const { line, column } = map.generatedPositionFor({
|
||||
source: originalSource.url,
|
||||
line: location.line,
|
||||
column: location.column == null ? 0 : location.column
|
||||
});
|
||||
|
||||
return {
|
||||
sourceId: generatedSourceId,
|
||||
line: line,
|
||||
// Treat 0 as no column so that line breakpoints work correctly.
|
||||
column: column === 0 ? undefined : column
|
||||
};
|
||||
}
|
||||
|
||||
async function getOriginalLocation(location) {
|
||||
if (!isGeneratedId(location.sourceId)) {
|
||||
return location;
|
||||
}
|
||||
|
||||
const map = await _getSourceMap(location.sourceId);
|
||||
if (!map) {
|
||||
return location;
|
||||
}
|
||||
|
||||
const { source: url, line, column } = map.originalPositionFor({
|
||||
line: location.line,
|
||||
column: location.column == null ? Infinity : location.column
|
||||
});
|
||||
|
||||
if (url == null) {
|
||||
// No url means the location didn't map.
|
||||
return location;
|
||||
}
|
||||
|
||||
return {
|
||||
sourceId: generatedToOriginalId(location.sourceId, url),
|
||||
line,
|
||||
column
|
||||
};
|
||||
}
|
||||
|
||||
async function getOriginalSourceText(originalSource) {
|
||||
assert(isOriginalId(originalSource.id),
|
||||
"Source is not an original source");
|
||||
|
||||
const generatedSourceId = originalToGeneratedId(originalSource.id);
|
||||
const map = await _getSourceMap(generatedSourceId);
|
||||
if (!map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let text = map.sourceContentFor(originalSource.url);
|
||||
if (!text) {
|
||||
text = (await fetch(
|
||||
originalSource.url, { loadFromCache: false }
|
||||
)).content;
|
||||
}
|
||||
|
||||
return {
|
||||
text,
|
||||
contentType: isJavaScript(originalSource.url || "") ?
|
||||
"text/javascript" :
|
||||
"text/plain"
|
||||
};
|
||||
}
|
||||
|
||||
function applySourceMap(generatedId, url, code, mappings) {
|
||||
const generator = new SourceMapGenerator({ file: url });
|
||||
mappings.forEach(mapping => generator.addMapping(mapping));
|
||||
generator.setSourceContent(url, code);
|
||||
|
||||
const map = SourceMapConsumer(generator.toJSON());
|
||||
sourceMapRequests.set(generatedId, Promise.resolve(map));
|
||||
}
|
||||
|
||||
const publicInterface = {
|
||||
getOriginalURLs,
|
||||
getGeneratedLocation,
|
||||
getOriginalLocation,
|
||||
getOriginalSourceText,
|
||||
enableSourceMaps,
|
||||
applySourceMap,
|
||||
clearSourceMaps
|
||||
};
|
||||
|
||||
self.onmessage = function(msg) {
|
||||
const { id, method, args } = msg.data;
|
||||
const response = publicInterface[method].apply(undefined, args);
|
||||
if (response instanceof Promise) {
|
||||
response.then(val => self.postMessage({ id, response: val }),
|
||||
err => self.postMessage({ id, error: err }));
|
||||
} else {
|
||||
self.postMessage({ id, response });
|
||||
}
|
||||
};
|
@ -1,84 +0,0 @@
|
||||
// @flow
|
||||
|
||||
const {
|
||||
originalToGeneratedId,
|
||||
generatedToOriginalId,
|
||||
isGeneratedId,
|
||||
isOriginalId
|
||||
} = require("./source-map-util");
|
||||
|
||||
function workerTask(worker, method) {
|
||||
return function(...args: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = msgId++;
|
||||
worker.postMessage({ id, method, args });
|
||||
|
||||
const listener = ({ data: result }) => {
|
||||
if (result.id !== id) {
|
||||
return;
|
||||
}
|
||||
|
||||
worker.removeEventListener("message", listener);
|
||||
if (result.error) {
|
||||
reject(result.error);
|
||||
} else {
|
||||
resolve(result.response);
|
||||
}
|
||||
};
|
||||
|
||||
worker.addEventListener("message", listener);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
let sourceMapWorker;
|
||||
function restartWorker() {
|
||||
if (sourceMapWorker) {
|
||||
sourceMapWorker.terminate();
|
||||
}
|
||||
sourceMapWorker = new Worker(
|
||||
"resource://devtools/client/framework/source-map-worker.js"
|
||||
);
|
||||
|
||||
if (Services.prefs.getBoolPref("devtools.debugger.client-source-maps-enabled")) {
|
||||
sourceMapWorker.postMessage({ id: 0, method: "enableSourceMaps" });
|
||||
}
|
||||
}
|
||||
restartWorker();
|
||||
|
||||
function destroyWorker() {
|
||||
if (sourceMapWorker) {
|
||||
sourceMapWorker.terminate();
|
||||
sourceMapWorker = null;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldSourceMap() {
|
||||
return Services.prefs.getBoolPref("devtools.debugger.client-source-maps-enabled");
|
||||
}
|
||||
|
||||
const getOriginalURLs = workerTask(sourceMapWorker, "getOriginalURLs");
|
||||
const getGeneratedLocation = workerTask(sourceMapWorker,
|
||||
"getGeneratedLocation");
|
||||
const getOriginalLocation = workerTask(sourceMapWorker,
|
||||
"getOriginalLocation");
|
||||
const getOriginalSourceText = workerTask(sourceMapWorker,
|
||||
"getOriginalSourceText");
|
||||
const applySourceMap = workerTask(sourceMapWorker, "applySourceMap");
|
||||
const clearSourceMaps = workerTask(sourceMapWorker, "clearSourceMaps");
|
||||
|
||||
module.exports = {
|
||||
originalToGeneratedId,
|
||||
generatedToOriginalId,
|
||||
isGeneratedId,
|
||||
isOriginalId,
|
||||
|
||||
getOriginalURLs,
|
||||
getGeneratedLocation,
|
||||
getOriginalLocation,
|
||||
getOriginalSourceText,
|
||||
applySourceMap,
|
||||
clearSourceMaps,
|
||||
destroyWorker,
|
||||
shouldSourceMap
|
||||
};
|
@ -55,6 +55,10 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
|
||||
start: Task.async(function* () {
|
||||
tab.isResponsiveDesignMode = true;
|
||||
|
||||
// Hide the browser content temporarily while things move around to avoid displaying
|
||||
// strange intermediate states.
|
||||
tab.linkedBrowser.style.visibility = "hidden";
|
||||
|
||||
// Freeze navigation temporarily to avoid "blinking" in the location bar.
|
||||
freezeNavigationState(tab);
|
||||
|
||||
@ -135,9 +139,16 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
|
||||
thawNavigationState(tab);
|
||||
gBrowser.setTabTitle(tab);
|
||||
gBrowser.updateCurrentBrowser(true);
|
||||
|
||||
// Show the browser content again now that the move is done.
|
||||
tab.linkedBrowser.style.visibility = "";
|
||||
}),
|
||||
|
||||
stop() {
|
||||
// Hide the browser content temporarily while things move around to avoid displaying
|
||||
// strange intermediate states.
|
||||
tab.linkedBrowser.style.visibility = "hidden";
|
||||
|
||||
// 1. Stop the tunnel between outer and inner browsers.
|
||||
tunnel.stop();
|
||||
tunnel = null;
|
||||
@ -197,6 +208,9 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
|
||||
tab.linkedBrowser.frameLoader.activateRemoteFrame();
|
||||
|
||||
delete tab.isResponsiveDesignMode;
|
||||
|
||||
// Show the browser content again now that the move is done.
|
||||
tab.linkedBrowser.style.visibility = "";
|
||||
},
|
||||
|
||||
};
|
||||
|
@ -801,8 +801,7 @@ TabSources.prototype = {
|
||||
* it's either internal or we don't support in the UI yet.
|
||||
*/
|
||||
function isHiddenSource(source) {
|
||||
// Ignore the internal Function.prototype script
|
||||
return source.text === "() {\n}";
|
||||
return source.introductionType === "Function.prototype";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,19 +59,14 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
|
||||
{
|
||||
if (aEntry) {
|
||||
aEntry->SetParent(nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsSHEntry::~nsSHEntry()
|
||||
{
|
||||
// Null out the mParent pointers on all our kids.
|
||||
mChildren.EnumerateForwards(ClearParentPtr, nullptr);
|
||||
for (nsISHEntry* entry : mChildren) {
|
||||
if (entry) {
|
||||
entry->SetParent(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal)
|
||||
|
@ -390,6 +390,9 @@ nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const
|
||||
|
||||
if (!baseAttrs.IsEmpty()) {
|
||||
doc->WarnOnceAbout(nsIDocument::eXMLBaseAttribute);
|
||||
if (IsHTMLElement() || IsSVGElement() || IsXULElement()) {
|
||||
doc->WarnOnceAbout(nsIDocument::eXMLBaseAttributeWithStyledElement);
|
||||
}
|
||||
// Now resolve against all xml:base attrs
|
||||
for (uint32_t i = baseAttrs.Length() - 1; i != uint32_t(-1); --i) {
|
||||
nsCOMPtr<nsIURI> newBase;
|
||||
|
@ -52,3 +52,4 @@ DEPRECATED_OPERATION(FileLastModifiedDate)
|
||||
DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap)
|
||||
DEPRECATED_OPERATION(URLCreateObjectURL_MediaStream)
|
||||
DEPRECATED_OPERATION(XMLBaseAttribute)
|
||||
DEPRECATED_OPERATION(XMLBaseAttributeWithStyledElement)
|
||||
|
@ -2899,7 +2899,7 @@ GetTextFrameForContent(nsIContent* aContent, bool aFlushLayout)
|
||||
}
|
||||
|
||||
static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
Sequence<nsString>* aTextList,
|
||||
nsIContent* aContent, int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aClampToEdge,
|
||||
bool aFlushLayout)
|
||||
@ -2947,7 +2947,7 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
|
||||
Substring(textContent,
|
||||
textContentStart,
|
||||
(textContentEnd - textContentStart));
|
||||
aTextList->Add(textSubstring);
|
||||
aTextList->AppendElement(textSubstring, fallible);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2956,7 +2956,7 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
|
||||
|
||||
/* static */ void
|
||||
nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
Sequence<nsString>* aTextList,
|
||||
nsRange* aRange,
|
||||
nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
@ -3097,11 +3097,10 @@ nsRange::GetClientRectsAndTexts(
|
||||
}
|
||||
|
||||
aResult.mRectList = new DOMRectList(static_cast<nsIDOMRange*>(this));
|
||||
aResult.mTextList = new DOMStringList();
|
||||
|
||||
nsLayoutUtils::RectListBuilder builder(aResult.mRectList);
|
||||
|
||||
CollectClientRectsAndText(&builder, aResult.mTextList, this,
|
||||
CollectClientRectsAndText(&builder, &aResult.mTextList, this,
|
||||
mStartParent, mStartOffset, mEndParent, mEndOffset, true, true);
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ public:
|
||||
* @param aTextList optional where nullptr = don't retrieve text
|
||||
*/
|
||||
static void CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
mozilla::dom::Sequence<nsString>* aTextList,
|
||||
nsRange* aRange,
|
||||
nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
|
@ -710,6 +710,22 @@ bool
|
||||
WebGLContext::CreateAndInitGL(bool forceEnabled,
|
||||
std::vector<FailureReason>* const out_failReasons)
|
||||
{
|
||||
// WebGL2 is separately blocked:
|
||||
if (IsWebGL2()) {
|
||||
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
const auto feature = nsIGfxInfo::FEATURE_WEBGL2;
|
||||
|
||||
FailureReason reason;
|
||||
if (IsFeatureInBlacklist(gfxInfo, feature, &reason.key)) {
|
||||
reason.info = "Refused to create WebGL2 context because of blacklist"
|
||||
" entry: ";
|
||||
reason.info.Append(reason.key);
|
||||
out_failReasons->push_back(reason);
|
||||
GenerateWarning("%s", reason.info.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
|
||||
gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION;
|
||||
bool tryNativeGL = true;
|
||||
|
@ -749,6 +749,8 @@ public:
|
||||
|
||||
void SetMediaInfo(const MediaInfo& aInfo);
|
||||
|
||||
virtual AbstractThread* AbstractMainThread() const final override;
|
||||
|
||||
// Telemetry: to record the usage of a {visible / invisible} video element as
|
||||
// the source of {drawImage(), createPattern(), createImageBitmap() and
|
||||
// captureStream()} APIs.
|
||||
@ -1188,8 +1190,6 @@ protected:
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual AbstractThread* AbstractMainThread() const final override;
|
||||
|
||||
// Return true if decoding should be paused
|
||||
virtual bool GetPaused() final override
|
||||
{
|
||||
|
@ -63,6 +63,8 @@ LazyLogModule gMediaDecoderLog("MediaDecoder");
|
||||
#define DUMP_LOG(x, ...) \
|
||||
NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Decoder=%p " x, this, ##__VA_ARGS__).get(), nullptr, nullptr, -1)
|
||||
|
||||
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
|
||||
|
||||
static const char*
|
||||
ToPlayStateStr(MediaDecoder::PlayState aState)
|
||||
{
|
||||
@ -154,6 +156,7 @@ MediaDecoder::ResourceCallback::Connect(MediaDecoder* aDecoder)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDecoder = aDecoder;
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mTimer->SetTarget(mAbstractMainThread->AsEventTarget());
|
||||
}
|
||||
|
||||
void
|
||||
@ -465,7 +468,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
|
||||
&MediaDecoder::NotifyAudibleStateChanged);
|
||||
|
||||
MediaShutdownManager::InitStatics();
|
||||
MediaShutdownManager::Instance().Register(this);
|
||||
}
|
||||
|
||||
#undef INIT_MIRROR
|
||||
@ -633,7 +635,12 @@ MediaDecoder::Load(nsIStreamListener** aStreamListener)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mResource, "Can't load without a MediaResource");
|
||||
|
||||
nsresult rv = OpenResource(aStreamListener);
|
||||
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = OpenResource(aStreamListener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetStateMachine(CreateStateMachine());
|
||||
@ -1655,8 +1662,8 @@ MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsCOMPtr<nsISupports> data = aData;
|
||||
|
||||
resourceSizes->Promise()->Then(
|
||||
// Non-DocGroup version of AbstractThread::MainThread is fine for memory
|
||||
// report.
|
||||
// Don't use SystemGroup::AbstractMainThreadFor() for
|
||||
// handleReport->Callback() will run scripts.
|
||||
AbstractThread::MainThread(),
|
||||
__func__,
|
||||
[handleReport, data] (size_t size) {
|
||||
@ -1815,7 +1822,7 @@ MediaDecoder::DumpDebugInfo()
|
||||
|
||||
RefPtr<MediaDecoder> self = this;
|
||||
GetStateMachine()->RequestDebugInfo()->Then(
|
||||
AbstractThread::MainThread(), __func__,
|
||||
SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
|
||||
[this, self, str] (const nsACString& aString) {
|
||||
DUMP_LOG("%s", str.get());
|
||||
DUMP_LOG("%s", aString.Data());
|
||||
@ -1836,7 +1843,7 @@ MediaDecoder::RequestDebugInfo()
|
||||
}
|
||||
|
||||
return GetStateMachine()->RequestDebugInfo()->Then(
|
||||
AbstractThread::MainThread(), __func__,
|
||||
SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
|
||||
[str] (const nsACString& aString) {
|
||||
nsCString result = str + nsCString("\n") + aString;
|
||||
return DebugInfoPromise::CreateAndResolve(result, __func__);
|
||||
@ -1872,3 +1879,4 @@ MediaMemoryTracker::~MediaMemoryTracker()
|
||||
|
||||
// avoid redefined macro in unified build
|
||||
#undef DECODER_LOG
|
||||
#undef NS_DispatchToMainThread
|
||||
|
@ -43,6 +43,8 @@ mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");
|
||||
#define LOG(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define LOGV(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
|
||||
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
@ -116,11 +118,13 @@ GlobalAllocPolicy::GlobalAllocPolicy()
|
||||
: mMonitor("DecoderAllocPolicy::mMonitor")
|
||||
, mDecoderLimit(MediaPrefs::MediaDecoderLimit())
|
||||
{
|
||||
// Non DocGroup-version AbstractThread::MainThread is fine for
|
||||
// ClearOnShutdown().
|
||||
AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction([this] () {
|
||||
ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
|
||||
}));
|
||||
SystemGroup::Dispatch(
|
||||
"GlobalAllocPolicy::ClearOnShutdown",
|
||||
TaskCategory::Other,
|
||||
NS_NewRunnableFunction([this] () {
|
||||
ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
GlobalAllocPolicy::~GlobalAllocPolicy()
|
||||
@ -652,10 +656,9 @@ class MediaFormatReader::DemuxerProxy
|
||||
class Wrapper;
|
||||
|
||||
public:
|
||||
explicit DemuxerProxy(MediaDataDemuxer* aDemuxer, AbstractThread* aMainThread)
|
||||
explicit DemuxerProxy(MediaDataDemuxer* aDemuxer)
|
||||
: mTaskQueue(new AutoTaskQueue(
|
||||
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
|
||||
aMainThread))
|
||||
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER)))
|
||||
, mData(new Data(aDemuxer))
|
||||
{
|
||||
MOZ_COUNT_CTOR(DemuxerProxy);
|
||||
@ -992,9 +995,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
Preferences::GetUint("media.audio-max-decode-error", 3))
|
||||
, mVideo(this, MediaData::VIDEO_DATA,
|
||||
Preferences::GetUint("media.video-max-decode-error", 2))
|
||||
, mDemuxer(new DemuxerProxy(aDemuxer, aDecoder
|
||||
? aDecoder->AbstractMainThread()
|
||||
: AbstractThread::MainThread()))
|
||||
, mDemuxer(new DemuxerProxy(aDemuxer))
|
||||
, mDemuxerInitDone(false)
|
||||
, mLastReportedNumDecodedFrames(0)
|
||||
, mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
|
||||
@ -1339,9 +1340,10 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
||||
if (mDecoder && crypto && crypto->IsEncrypted()) {
|
||||
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
|
||||
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
|
||||
NS_DispatchToMainThread(
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData,
|
||||
crypto->mInitDatas[i].mType));
|
||||
crypto->mInitDatas[i].mType);
|
||||
mDecoder->AbstractMainThread()->Dispatch(r.forget());
|
||||
}
|
||||
mInfo.mCrypto = *crypto;
|
||||
}
|
||||
@ -1704,6 +1706,7 @@ MediaFormatReader::NotifyWaitingForKey(TrackType aTrack)
|
||||
}
|
||||
if (!decoder.mDecodeRequest.Exists()) {
|
||||
LOGV("WaitingForKey received while no pending decode. Ignoring");
|
||||
return;
|
||||
}
|
||||
decoder.mWaitingForKey = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
@ -2261,15 +2264,21 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
|
||||
bool needInput = NeedInput(decoder);
|
||||
|
||||
LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
|
||||
" qs=%u decoding:%d flushing:%d "
|
||||
"shutdown:%d pending:%u waiting:%d promise:%d sid:%u",
|
||||
TrackTypeToStr(aTrack), needInput, needOutput, decoder.mNumSamplesInput,
|
||||
decoder.mNumSamplesOutput, uint32_t(size_t(decoder.mSizeOfQueue)),
|
||||
decoder.mDecodeRequest.Exists(), decoder.mFlushRequest.Exists(),
|
||||
decoder.mShutdownRequest.Exists(), uint32_t(decoder.mOutput.Length()),
|
||||
decoder.mWaitingForData, decoder.HasPromise(),
|
||||
decoder.mLastStreamSourceID);
|
||||
LOGV(
|
||||
"Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
|
||||
" qs=%u decoding:%d flushing:%d shutdown:%d pending:%u waiting:%d sid:%u",
|
||||
TrackTypeToStr(aTrack),
|
||||
needInput,
|
||||
needOutput,
|
||||
decoder.mNumSamplesInput,
|
||||
decoder.mNumSamplesOutput,
|
||||
uint32_t(size_t(decoder.mSizeOfQueue)),
|
||||
decoder.mDecodeRequest.Exists(),
|
||||
decoder.mFlushRequest.Exists(),
|
||||
decoder.mShutdownRequest.Exists(),
|
||||
uint32_t(decoder.mOutput.Length()),
|
||||
decoder.mWaitingForData,
|
||||
decoder.mLastStreamSourceID);
|
||||
|
||||
if ((decoder.mWaitingForData
|
||||
&& (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
|
||||
@ -2279,13 +2288,9 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder.mWaitingForKey) {
|
||||
decoder.mWaitingForKey = false;
|
||||
if (decoder.HasWaitingPromise() && !decoder.IsWaiting()) {
|
||||
LOGV("No longer waiting for key. Resolving waiting promise");
|
||||
decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
|
||||
return;
|
||||
}
|
||||
if (decoder.CancelWaitingForKey()) {
|
||||
LOGV("No longer waiting for key. Resolving waiting promise");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!needInput) {
|
||||
@ -2938,36 +2943,55 @@ MediaFormatReader::GetMozDebugReaderData(nsACString& aString)
|
||||
mAudio.mNumSamplesOutputTotal);
|
||||
if (HasAudio()) {
|
||||
result += nsPrintfCString(
|
||||
"audio state: ni=%d no=%d demuxr:%d demuxq:%d tt:%f tths:%d in:%" PRIu64
|
||||
" out:%" PRIu64 " qs=%u pending:%u waiting:%d sid:%u\n",
|
||||
NeedInput(mAudio), mAudio.HasPromise(), mAudio.mDemuxRequest.Exists(),
|
||||
int(mAudio.mQueuedSamples.Length()),
|
||||
"audio state: ni=%d no=%d wp:%d demuxr:%d demuxq:%u decoder:%d tt:%.1f "
|
||||
"tths:%d in:%" PRIu64 " out:%" PRIu64
|
||||
" qs=%u pending:%u wfd:%d wfk:%d sid:%u\n",
|
||||
NeedInput(mAudio),
|
||||
mAudio.HasPromise(),
|
||||
!mAudio.mWaitingPromise.IsEmpty(),
|
||||
mAudio.mDemuxRequest.Exists(),
|
||||
uint32_t(mAudio.mQueuedSamples.Length()),
|
||||
mAudio.mDecodeRequest.Exists(),
|
||||
mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().Time().ToSeconds()
|
||||
: -1.0,
|
||||
mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().mHasSeeked : -1,
|
||||
mAudio.mNumSamplesInput, mAudio.mNumSamplesOutput,
|
||||
unsigned(size_t(mAudio.mSizeOfQueue)), unsigned(mAudio.mOutput.Length()),
|
||||
mAudio.mWaitingForData, mAudio.mLastStreamSourceID);
|
||||
mAudio.mNumSamplesInput,
|
||||
mAudio.mNumSamplesOutput,
|
||||
unsigned(size_t(mAudio.mSizeOfQueue)),
|
||||
unsigned(mAudio.mOutput.Length()),
|
||||
mAudio.mWaitingForData,
|
||||
mAudio.mWaitingForKey,
|
||||
mAudio.mLastStreamSourceID);
|
||||
}
|
||||
result += nsPrintfCString("video decoder: %s\n", videoName);
|
||||
result +=
|
||||
nsPrintfCString("hardware video decoding: %s\n",
|
||||
VideoIsHardwareAccelerated() ? "enabled" : "disabled");
|
||||
result += nsPrintfCString("video frames decoded: %" PRIu64 " (skipped:%" PRIu64 ")\n",
|
||||
mVideo.mNumSamplesOutputTotal,
|
||||
mVideo.mNumSamplesSkippedTotal);
|
||||
result +=
|
||||
nsPrintfCString("video frames decoded: %" PRIu64 " (skipped:%" PRIu64 ")\n",
|
||||
mVideo.mNumSamplesOutputTotal,
|
||||
mVideo.mNumSamplesSkippedTotal);
|
||||
if (HasVideo()) {
|
||||
result += nsPrintfCString(
|
||||
"video state: ni=%d no=%d demuxr:%d demuxq:%d tt:%f tths:%d in:%" PRIu64
|
||||
" out:%" PRIu64 " qs=%u pending:%u waiting:%d sid:%u\n",
|
||||
NeedInput(mVideo), mVideo.HasPromise(), mVideo.mDemuxRequest.Exists(),
|
||||
int(mVideo.mQueuedSamples.Length()),
|
||||
"video state: ni=%d no=%d wp:%d demuxr:%d demuxq:%u decoder:%d tt:%.1f "
|
||||
"tths:%d in:%" PRIu64 " out:%" PRIu64
|
||||
" qs=%u pending:%u wfd:%d wfk:%d sid:%u\n",
|
||||
NeedInput(mVideo),
|
||||
mVideo.HasPromise(),
|
||||
!mVideo.mWaitingPromise.IsEmpty(),
|
||||
mVideo.mDemuxRequest.Exists(),
|
||||
uint32_t(mVideo.mQueuedSamples.Length()),
|
||||
mVideo.mDecodeRequest.Exists(),
|
||||
mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().Time().ToSeconds()
|
||||
: -1.0,
|
||||
mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().mHasSeeked : -1,
|
||||
mVideo.mNumSamplesInput, mVideo.mNumSamplesOutput,
|
||||
unsigned(size_t(mVideo.mSizeOfQueue)), unsigned(mVideo.mOutput.Length()),
|
||||
mVideo.mWaitingForData, mVideo.mLastStreamSourceID);
|
||||
mVideo.mNumSamplesInput,
|
||||
mVideo.mNumSamplesOutput,
|
||||
unsigned(size_t(mVideo.mSizeOfQueue)),
|
||||
unsigned(mVideo.mOutput.Length()),
|
||||
mVideo.mWaitingForData,
|
||||
mVideo.mWaitingForKey,
|
||||
mVideo.mLastStreamSourceID);
|
||||
}
|
||||
aString += result;
|
||||
}
|
||||
@ -3030,3 +3054,5 @@ MediaFormatReader::OnFirstDemuxFailed(TrackInfo::TrackType aType,
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef NS_DispatchToMainThread
|
||||
|
@ -349,6 +349,7 @@ private:
|
||||
mDecodeRequest.DisconnectIfExists();
|
||||
mDrainRequest.DisconnectIfExists();
|
||||
mDrainState = DrainState::None;
|
||||
CancelWaitingForKey();
|
||||
mOutput.Clear();
|
||||
mNumSamplesInput = 0;
|
||||
mNumSamplesOutput = 0;
|
||||
@ -381,6 +382,19 @@ private:
|
||||
mFlushed = true;
|
||||
}
|
||||
|
||||
bool CancelWaitingForKey()
|
||||
{
|
||||
if (!mWaitingForKey) {
|
||||
return false;
|
||||
}
|
||||
mWaitingForKey = false;
|
||||
if (IsWaiting() || !HasWaitingPromise()) {
|
||||
return false;
|
||||
}
|
||||
mWaitingPromise.Resolve(mType, __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset the state of the DecoderData, clearing all queued frames
|
||||
// (pending demuxed and decoded).
|
||||
// The track demuxer is *not* reset.
|
||||
@ -389,11 +403,11 @@ private:
|
||||
MOZ_ASSERT(mOwner->OnTaskQueue());
|
||||
mDemuxEOS = false;
|
||||
mWaitingForData = false;
|
||||
mWaitingForKey = false;
|
||||
mQueuedSamples.Clear();
|
||||
mDecodeRequest.DisconnectIfExists();
|
||||
mDrainRequest.DisconnectIfExists();
|
||||
mDrainState = DrainState::None;
|
||||
CancelWaitingForKey();
|
||||
mTimeThreshold.reset();
|
||||
mLastSampleTime.reset();
|
||||
mOutput.Clear();
|
||||
|
@ -91,24 +91,29 @@ MediaShutdownManager::RemoveBlocker()
|
||||
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
MediaShutdownManager::Register(MediaDecoder* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_RELEASE_ASSERT(!mIsDoingXPCOMShutDown);
|
||||
if (mIsDoingXPCOMShutDown) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
// Don't call Register() after you've Unregistered() all the decoders,
|
||||
// that's not going to work.
|
||||
MOZ_ASSERT(!mDecoders.Contains(aDecoder));
|
||||
mDecoders.PutEntry(aDecoder);
|
||||
MOZ_ASSERT(mDecoders.Contains(aDecoder));
|
||||
MOZ_ASSERT(mDecoders.Count() > 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDecoders.Contains(aDecoder));
|
||||
if (!mDecoders.Contains(aDecoder)) {
|
||||
return;
|
||||
}
|
||||
mDecoders.RemoveEntry(aDecoder);
|
||||
if (mIsDoingXPCOMShutDown && mDecoders.Count() == 0) {
|
||||
RemoveBlocker();
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
|
||||
// Notifies the MediaShutdownManager that it needs to track the shutdown
|
||||
// of this MediaDecoder.
|
||||
void Register(MediaDecoder* aDecoder);
|
||||
nsresult Register(MediaDecoder* aDecoder);
|
||||
|
||||
// Notifies the MediaShutdownManager that a MediaDecoder that it was
|
||||
// tracking has shutdown, and it no longer needs to be shutdown in the
|
||||
|
@ -17,6 +17,8 @@ namespace mozilla {
|
||||
static LazyLogModule gVideoFrameContainerLog("VideoFrameContainer");
|
||||
#define CONTAINER_LOG(type, msg) MOZ_LOG(gVideoFrameContainerLog, type, msg)
|
||||
|
||||
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
|
||||
|
||||
VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement,
|
||||
already_AddRefed<ImageContainer> aContainer)
|
||||
: mElement(aElement),
|
||||
@ -24,7 +26,9 @@ VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement,
|
||||
mBlackImage(nullptr),
|
||||
mFrameID(0),
|
||||
mIntrinsicSizeChanged(false), mImageSizeChanged(false),
|
||||
mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE), mFrameIDForPendingPrincipalHandle(0)
|
||||
mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE),
|
||||
mFrameIDForPendingPrincipalHandle(0),
|
||||
mMainThread(aElement->AbstractMainThread())
|
||||
{
|
||||
NS_ASSERTION(aElement, "aElement must not be null");
|
||||
NS_ASSERTION(mImageContainer, "aContainer must not be null");
|
||||
@ -78,7 +82,8 @@ SetImageToBlackPixel(PlanarYCbCrImage* aImage)
|
||||
class VideoFrameContainerInvalidateRunnable : public Runnable {
|
||||
public:
|
||||
explicit VideoFrameContainerInvalidateRunnable(VideoFrameContainer* aVideoFrameContainer)
|
||||
: mVideoFrameContainer(aVideoFrameContainer)
|
||||
: Runnable("VideoFrameContainerInvalidateRunnable")
|
||||
, mVideoFrameContainer(aVideoFrameContainer)
|
||||
{}
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
@ -171,7 +176,7 @@ void VideoFrameContainer::SetCurrentFrames(const VideoSegment& aSegment)
|
||||
SetCurrentFramesLocked(mLastPlayedVideoFrame.GetIntrinsicSize(), images);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new VideoFrameContainerInvalidateRunnable(this);
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
mMainThread->Dispatch(event.forget());
|
||||
|
||||
images.ClearAndRetainStorage();
|
||||
}
|
||||
@ -242,11 +247,16 @@ void VideoFrameContainer::SetCurrentFramesLocked(const gfx::IntSize& aIntrinsicS
|
||||
mLastPrincipalHandle = mPendingPrincipalHandle;
|
||||
mPendingPrincipalHandle = PRINCIPAL_HANDLE_NONE;
|
||||
mFrameIDForPendingPrincipalHandle = 0;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([self, principalHandle]() {
|
||||
if (self->mElement) {
|
||||
self->mElement->PrincipalHandleChangedForVideoFrameContainer(self, principalHandle);
|
||||
}
|
||||
}));
|
||||
mMainThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
"PrincipalHandleChangedForVideoFrameContainer",
|
||||
[self, principalHandle]() {
|
||||
if (self->mElement) {
|
||||
self->mElement->PrincipalHandleChangedForVideoFrameContainer(self, principalHandle);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (aImages.IsEmpty()) {
|
||||
@ -357,3 +367,5 @@ void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags)
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef NS_DispatchToMainThread
|
||||
|
@ -140,6 +140,8 @@ protected:
|
||||
PrincipalHandle mPendingPrincipalHandle;
|
||||
// The FrameID for which mPendingPrincipal is first valid.
|
||||
ImageContainer::FrameID mFrameIDForPendingPrincipalHandle;
|
||||
|
||||
const RefPtr<AbstractThread> mMainThread;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -18,11 +18,9 @@ class AutoTaskQueue : public AbstractThread
|
||||
{
|
||||
public:
|
||||
explicit AutoTaskQueue(already_AddRefed<SharedThreadPool> aPool,
|
||||
AbstractThread* aAbstractMainThread,
|
||||
bool aSupportsTailDispatch = false)
|
||||
: AbstractThread(aSupportsTailDispatch)
|
||||
, mTaskQueue(new TaskQueue(Move(aPool), aSupportsTailDispatch))
|
||||
, mAbstractMainThread(aAbstractMainThread)
|
||||
{}
|
||||
|
||||
TaskDispatcher& TailDispatcher() override
|
||||
@ -52,10 +50,9 @@ private:
|
||||
RefPtr<TaskQueue> taskqueue = mTaskQueue;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([taskqueue]() { taskqueue->BeginShutdown(); });
|
||||
mAbstractMainThread->Dispatch(task.forget());
|
||||
SystemGroup::Dispatch("~AutoTaskQueue", TaskCategory::Other, task.forget());
|
||||
}
|
||||
RefPtr<TaskQueue> mTaskQueue;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaShutdownManager.h"
|
||||
#include "MediaSource.h"
|
||||
#include "MediaSourceResource.h"
|
||||
#include "MediaSourceUtils.h"
|
||||
@ -54,13 +55,19 @@ MediaSourceDecoder::Load(nsIStreamListener**)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!GetStateMachine());
|
||||
|
||||
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SetStateMachine(CreateStateMachine());
|
||||
if (!GetStateMachine()) {
|
||||
NS_WARNING("Failed to create state machine!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = GetStateMachine()->Init(this);
|
||||
rv = GetStateMachine()->Init(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetStateMachineParameters();
|
||||
|
@ -22,7 +22,6 @@ using media::TimeIntervals;
|
||||
|
||||
MediaSourceDemuxer::MediaSourceDemuxer(AbstractThread* aAbstractMainThread)
|
||||
: mTaskQueue(new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
|
||||
aAbstractMainThread,
|
||||
/* aSupportsTailDispatch = */ false))
|
||||
, mMonitor("MediaSourceDemuxer")
|
||||
{
|
||||
|
@ -127,6 +127,7 @@ EXPORTS += [
|
||||
'MediaResourceCallback.h',
|
||||
'MediaResult.h',
|
||||
'MediaSegment.h',
|
||||
'MediaShutdownManager.h',
|
||||
'MediaStatistics.h',
|
||||
'MediaStreamGraph.h',
|
||||
'MediaStreamListener.h',
|
||||
|
@ -45,8 +45,8 @@ VREventObserver::DisconnectFromOwner()
|
||||
mWindow = nullptr;
|
||||
|
||||
// Unregister from VRManagerChild
|
||||
VRManagerChild* vmc = VRManagerChild::Get();
|
||||
if (vmc) {
|
||||
if (VRManagerChild::IsCreated()) {
|
||||
VRManagerChild* vmc = VRManagerChild::Get();
|
||||
vmc->RemoveListener(this);
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ partial interface Range {
|
||||
|
||||
dictionary ClientRectsAndTexts {
|
||||
required DOMRectList rectList;
|
||||
required DOMStringList textList;
|
||||
required sequence<DOMString> textList;
|
||||
};
|
||||
|
||||
partial interface Range {
|
||||
|
@ -582,11 +582,11 @@ CSSEditUtils::GetComputedStyle(Element* aElement)
|
||||
// remove the CSS style "aProperty : aPropertyValue" and possibly remove the whole node
|
||||
// if it is a span and if its only attribute is _moz_dirty
|
||||
nsresult
|
||||
CSSEditUtils::RemoveCSSInlineStyle(nsIDOMNode* aNode,
|
||||
CSSEditUtils::RemoveCSSInlineStyle(nsINode& aNode,
|
||||
nsIAtom* aProperty,
|
||||
const nsAString& aPropertyValue)
|
||||
{
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aNode);
|
||||
RefPtr<Element> element = aNode.AsElement();
|
||||
NS_ENSURE_STATE(element);
|
||||
|
||||
// remove the property from the style attribute
|
||||
|
@ -153,7 +153,7 @@ public:
|
||||
* @param aPropertyValue [IN] The value of the property we have to remove
|
||||
* if the property accepts more than one value.
|
||||
*/
|
||||
nsresult RemoveCSSInlineStyle(nsIDOMNode* aNode, nsIAtom* aProperty,
|
||||
nsresult RemoveCSSInlineStyle(nsINode& aNode, nsIAtom* aProperty,
|
||||
const nsAString& aPropertyValue);
|
||||
|
||||
/**
|
||||
|
@ -534,7 +534,7 @@ HTMLEditor::AbsolutelyPositionElement(nsIDOMElement* aElement,
|
||||
RefPtr<HTMLEditRules> htmlRules =
|
||||
static_cast<HTMLEditRules*>(mRules.get());
|
||||
NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
|
||||
nsresult rv = htmlRules->MakeSureElemStartsOrEndsOnCR(aElement);
|
||||
nsresult rv = htmlRules->MakeSureElemStartsOrEndsOnCR(*element);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = RemoveContainer(element);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -889,7 +889,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
|
||||
// of html tables regarding to text alignment
|
||||
return NS_OK;
|
||||
}
|
||||
if (HTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(nodeToExamine))) {
|
||||
if (HTMLEditUtils::SupportsAlignAttr(*nodeToExamine)) {
|
||||
// Check for alignment
|
||||
nsAutoString typeAttrVal;
|
||||
nodeToExamine->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::align,
|
||||
@ -4632,7 +4632,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
|
||||
if (nodeArray.Length() == 1) {
|
||||
OwningNonNull<nsINode> node = nodeArray[0];
|
||||
|
||||
if (HTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(node))) {
|
||||
if (HTMLEditUtils::SupportsAlignAttr(*node)) {
|
||||
// The node is a table element, an hr, a paragraph, a div or a section
|
||||
// header; in HTML 4, it can directly carry the ALIGN attribute and we
|
||||
// don't need to make a div! If we are in CSS mode, all the work is done
|
||||
@ -4731,7 +4731,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
|
||||
// header; in HTML 4, it can directly carry the ALIGN attribute and we
|
||||
// don't need to nest it, just set the alignment. In CSS, assign the
|
||||
// corresponding CSS styles in AlignBlock
|
||||
if (HTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(curNode))) {
|
||||
if (HTMLEditUtils::SupportsAlignAttr(*curNode)) {
|
||||
rv = AlignBlock(*curNode->AsElement(), aAlignType, ContentsOnly::no);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Clear out curDiv so that we don't put nodes after this one into it
|
||||
@ -4758,7 +4758,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
|
||||
// and instead put divs inside the appropriate block (td, li, etc.)
|
||||
if (HTMLEditUtils::IsListItem(curNode) ||
|
||||
HTMLEditUtils::IsList(curNode)) {
|
||||
rv = RemoveAlignment(GetAsDOMNode(curNode), aAlignType, true);
|
||||
rv = RemoveAlignment(*curNode, aAlignType, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (useCSS) {
|
||||
htmlEditor->mCSSEditUtils->SetCSSEquivalentToHTMLStyle(
|
||||
@ -8328,19 +8328,19 @@ HTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
|
||||
// element (here we have to remove the container and keep its
|
||||
// children). We break on tables and don't look at their children.
|
||||
nsresult
|
||||
HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode,
|
||||
HTMLEditRules::RemoveAlignment(nsINode& aNode,
|
||||
const nsAString& aAlignType,
|
||||
bool aChildrenOnly)
|
||||
{
|
||||
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
|
||||
|
||||
if (EditorBase::IsTextNode(aNode) || HTMLEditUtils::IsTable(aNode)) {
|
||||
if (EditorBase::IsTextNode(&aNode) || HTMLEditUtils::IsTable(&aNode)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child = aNode,tmp;
|
||||
nsCOMPtr<nsINode> child, tmp;
|
||||
if (aChildrenOnly) {
|
||||
aNode->GetFirstChild(getter_AddRefs(child));
|
||||
child = aNode.GetFirstChild();
|
||||
} else {
|
||||
child = &aNode;
|
||||
}
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
bool useCSS = mHTMLEditor->IsCSSEnabled();
|
||||
@ -8348,65 +8348,60 @@ HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode,
|
||||
while (child) {
|
||||
if (aChildrenOnly) {
|
||||
// get the next sibling right now because we could have to remove child
|
||||
child->GetNextSibling(getter_AddRefs(tmp));
|
||||
tmp = child->GetNextSibling();
|
||||
} else {
|
||||
tmp = nullptr;
|
||||
}
|
||||
bool isBlock;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsresult rv = mHTMLEditor->NodeIsBlockStatic(child, &isBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (EditorBase::NodeIsType(child, nsGkAtoms::center)) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::center)) {
|
||||
// the current node is a CENTER element
|
||||
// first remove children's alignment
|
||||
rv = RemoveAlignment(child, aAlignType, true);
|
||||
nsresult rv = RemoveAlignment(*child, aAlignType, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we may have to insert BRs in first and last position of element's children
|
||||
// if the nodes before/after are not blocks and not BRs
|
||||
rv = MakeSureElemStartsOrEndsOnCR(child);
|
||||
rv = MakeSureElemStartsOrEndsOnCR(*child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// now remove the CENTER container
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> childAsElement = do_QueryInterface(child);
|
||||
NS_ENSURE_STATE(childAsElement);
|
||||
rv = mHTMLEditor->RemoveContainer(childAsElement);
|
||||
rv = mHTMLEditor->RemoveContainer(child->AsElement());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (isBlock || HTMLEditUtils::IsHR(child)) {
|
||||
} else if (IsBlockNode(*child) || child->IsHTMLElement(nsGkAtoms::hr)) {
|
||||
// the current node is a block element
|
||||
nsCOMPtr<Element> curElem = do_QueryInterface(child);
|
||||
if (HTMLEditUtils::SupportsAlignAttr(child)) {
|
||||
if (HTMLEditUtils::SupportsAlignAttr(*child)) {
|
||||
// remove the ALIGN attribute if this element can have it
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->RemoveAttribute(curElem, nsGkAtoms::align);
|
||||
nsresult rv = mHTMLEditor->RemoveAttribute(child->AsElement(),
|
||||
nsGkAtoms::align);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
if (useCSS) {
|
||||
if (HTMLEditUtils::IsTable(child) || HTMLEditUtils::IsHR(child)) {
|
||||
if (child->IsAnyOfHTMLElements(nsGkAtoms::table, nsGkAtoms::hr)) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->SetAttributeOrEquivalent(curElem,
|
||||
nsGkAtoms::align,
|
||||
aAlignType, false);
|
||||
nsresult rv =
|
||||
mHTMLEditor->SetAttributeOrEquivalent(child->AsElement(),
|
||||
nsGkAtoms::align,
|
||||
aAlignType, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
nsAutoString dummyCssValue;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->mCSSEditUtils->RemoveCSSInlineStyle(
|
||||
child,
|
||||
nsGkAtoms::textAlign,
|
||||
dummyCssValue);
|
||||
nsresult rv = mHTMLEditor->mCSSEditUtils->RemoveCSSInlineStyle(
|
||||
*child,
|
||||
nsGkAtoms::textAlign,
|
||||
dummyCssValue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!HTMLEditUtils::IsTable(child)) {
|
||||
if (!child->IsHTMLElement(nsGkAtoms::table)) {
|
||||
// unless this is a table, look at children
|
||||
rv = RemoveAlignment(child, aAlignType, true);
|
||||
nsresult rv = RemoveAlignment(*child, aAlignType, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
@ -8419,49 +8414,32 @@ HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode,
|
||||
// first (resp. last) child is not a block nor a BR, and if the
|
||||
// previous (resp. next) sibling is not a block nor a BR
|
||||
nsresult
|
||||
HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode* aNode,
|
||||
HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode,
|
||||
bool aStarts)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsCOMPtr<nsINode> child;
|
||||
if (aStarts) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
child = GetAsDOMNode(mHTMLEditor->GetFirstEditableChild(*node));
|
||||
child = mHTMLEditor->GetFirstEditableChild(aNode);
|
||||
} else {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
child = GetAsDOMNode(mHTMLEditor->GetLastEditableChild(*node));
|
||||
child = mHTMLEditor->GetLastEditableChild(aNode);
|
||||
}
|
||||
NS_ENSURE_TRUE(child, NS_OK);
|
||||
bool isChildBlock;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsresult rv = mHTMLEditor->NodeIsBlockStatic(child, &isChildBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
bool foundCR = false;
|
||||
if (isChildBlock || TextEditUtils::IsBreak(child)) {
|
||||
if (IsBlockNode(*child) || child->IsHTMLElement(nsGkAtoms::br)) {
|
||||
foundCR = true;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMNode> sibling;
|
||||
nsCOMPtr<nsINode> sibling;
|
||||
if (aStarts) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
sibling = mHTMLEditor->GetPriorHTMLSibling(&aNode);
|
||||
} else {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
sibling = mHTMLEditor->GetNextHTMLSibling(&aNode);
|
||||
}
|
||||
if (sibling) {
|
||||
bool isBlock;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->NodeIsBlockStatic(sibling, &isBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isBlock || TextEditUtils::IsBreak(sibling)) {
|
||||
if (IsBlockNode(*sibling) || sibling->IsHTMLElement(nsGkAtoms::br)) {
|
||||
foundCR = true;
|
||||
}
|
||||
} else {
|
||||
@ -8471,20 +8449,19 @@ HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode* aNode,
|
||||
if (!foundCR) {
|
||||
int32_t offset = 0;
|
||||
if (!aStarts) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||
NS_ENSURE_STATE(node);
|
||||
offset = node->GetChildCount();
|
||||
offset = aNode.GetChildCount();
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->CreateBR(aNode, offset, address_of(brNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> brNode = mHTMLEditor->CreateBR(&aNode, offset);
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode* aNode)
|
||||
HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode)
|
||||
{
|
||||
nsresult rv = MakeSureElemStartsOrEndsOnCR(aNode, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -8504,7 +8481,7 @@ HTMLEditRules::AlignBlock(Element& aElement,
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
nsresult rv = RemoveAlignment(aElement.AsDOMNode(), aAlignType,
|
||||
nsresult rv = RemoveAlignment(aElement, aAlignType,
|
||||
aContentsOnly == ContentsOnly::yes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (htmlEditor->IsCSSEnabled()) {
|
||||
@ -8516,7 +8493,7 @@ HTMLEditRules::AlignBlock(Element& aElement,
|
||||
} else {
|
||||
// HTML case; this code is supposed to be called ONLY if the element
|
||||
// supports the align attribute but we'll never know...
|
||||
if (HTMLEditUtils::SupportsAlignAttr(aElement.AsDOMNode())) {
|
||||
if (HTMLEditUtils::SupportsAlignAttr(aElement)) {
|
||||
rv = htmlEditor->SetAttribute(&aElement, nsGkAtoms::align, aAlignType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
nsresult GetIndentState(bool* aCanIndent, bool* aCanOutdent);
|
||||
nsresult GetAlignment(bool* aMixed, nsIHTMLEditor::EAlignment* aAlign);
|
||||
nsresult GetParagraphState(bool* aMixed, nsAString& outFormat);
|
||||
nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode* aNode);
|
||||
nsresult MakeSureElemStartsOrEndsOnCR(nsINode& aNode);
|
||||
|
||||
// nsIEditActionListener methods
|
||||
|
||||
@ -403,9 +403,9 @@ protected:
|
||||
nsresult InsertMozBRIfNeeded(nsINode& aNode);
|
||||
bool IsEmptyInline(nsINode& aNode);
|
||||
bool ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& arrayOfNodes);
|
||||
nsresult RemoveAlignment(nsIDOMNode* aNode, const nsAString& aAlignType,
|
||||
nsresult RemoveAlignment(nsINode& aNode, const nsAString& aAlignType,
|
||||
bool aChildrenOnly);
|
||||
nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode* aNode, bool aStarts);
|
||||
nsresult MakeSureElemStartsOrEndsOnCR(nsINode& aNode, bool aStarts);
|
||||
enum class ContentsOnly { no, yes };
|
||||
nsresult AlignBlock(Element& aElement,
|
||||
const nsAString& aAlignType, ContentsOnly aContentsOnly);
|
||||
|
@ -130,15 +130,6 @@ HTMLEditUtils::IsParagraph(nsIDOMNode* aNode)
|
||||
return EditorBase::NodeIsType(aNode, nsGkAtoms::p);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsHR() returns true if aNode is an horizontal rule.
|
||||
*/
|
||||
bool
|
||||
HTMLEditUtils::IsHR(nsIDOMNode* aNode)
|
||||
{
|
||||
return EditorBase::NodeIsType(aNode, nsGkAtoms::hr);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsListItem() returns true if aNode is an html list item.
|
||||
*/
|
||||
@ -462,26 +453,24 @@ HTMLEditUtils::IsFormWidget(nsINode* aNode)
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLEditUtils::SupportsAlignAttr(nsIDOMNode* aNode)
|
||||
HTMLEditUtils::SupportsAlignAttr(nsINode& aNode)
|
||||
{
|
||||
MOZ_ASSERT(aNode);
|
||||
nsCOMPtr<nsIAtom> nodeAtom = EditorBase::GetTag(aNode);
|
||||
return (nodeAtom == nsGkAtoms::hr)
|
||||
|| (nodeAtom == nsGkAtoms::table)
|
||||
|| (nodeAtom == nsGkAtoms::tbody)
|
||||
|| (nodeAtom == nsGkAtoms::tfoot)
|
||||
|| (nodeAtom == nsGkAtoms::thead)
|
||||
|| (nodeAtom == nsGkAtoms::tr)
|
||||
|| (nodeAtom == nsGkAtoms::td)
|
||||
|| (nodeAtom == nsGkAtoms::th)
|
||||
|| (nodeAtom == nsGkAtoms::div)
|
||||
|| (nodeAtom == nsGkAtoms::p)
|
||||
|| (nodeAtom == nsGkAtoms::h1)
|
||||
|| (nodeAtom == nsGkAtoms::h2)
|
||||
|| (nodeAtom == nsGkAtoms::h3)
|
||||
|| (nodeAtom == nsGkAtoms::h4)
|
||||
|| (nodeAtom == nsGkAtoms::h5)
|
||||
|| (nodeAtom == nsGkAtoms::h6);
|
||||
return aNode.IsAnyOfHTMLElements(nsGkAtoms::hr,
|
||||
nsGkAtoms::table,
|
||||
nsGkAtoms::tbody,
|
||||
nsGkAtoms::tfoot,
|
||||
nsGkAtoms::thead,
|
||||
nsGkAtoms::tr,
|
||||
nsGkAtoms::td,
|
||||
nsGkAtoms::th,
|
||||
nsGkAtoms::div,
|
||||
nsGkAtoms::p,
|
||||
nsGkAtoms::h1,
|
||||
nsGkAtoms::h2,
|
||||
nsGkAtoms::h3,
|
||||
nsGkAtoms::h4,
|
||||
nsGkAtoms::h5,
|
||||
nsGkAtoms::h6);
|
||||
}
|
||||
|
||||
// We use bitmasks to test containment of elements. Elements are marked to be
|
||||
|
@ -25,7 +25,6 @@ public:
|
||||
static bool IsHeader(nsINode& aNode);
|
||||
static bool IsHeader(nsIDOMNode* aNode);
|
||||
static bool IsParagraph(nsIDOMNode* aNode);
|
||||
static bool IsHR(nsIDOMNode* aNode);
|
||||
static bool IsListItem(nsINode* aNode);
|
||||
static bool IsListItem(nsIDOMNode* aNode);
|
||||
static bool IsTable(nsIDOMNode* aNode);
|
||||
@ -58,7 +57,7 @@ public:
|
||||
static bool IsMailCite(nsIDOMNode* aNode);
|
||||
static bool IsFormWidget(nsINode* aNode);
|
||||
static bool IsFormWidget(nsIDOMNode* aNode);
|
||||
static bool SupportsAlignAttr(nsIDOMNode* aNode);
|
||||
static bool SupportsAlignAttr(nsINode& aNode);
|
||||
static bool CanContain(int32_t aParent, int32_t aChild);
|
||||
static bool IsContainer(int32_t aTag);
|
||||
};
|
||||
|
@ -464,7 +464,7 @@ private:
|
||||
DECL_GFX_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false);
|
||||
DECL_GFX_PREF(Skip, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
|
||||
@ -515,7 +515,7 @@ private:
|
||||
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
|
||||
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
|
||||
DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
|
||||
DECL_GFX_PREF(Skip, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaint, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false);
|
||||
|
@ -156,6 +156,8 @@ from its prototype:
|
||||
|
||||
* `"Function"`, for code passed to the `Function` constructor.
|
||||
|
||||
* `"Function.prototype"`, for `Function.prototype` internally generated code.
|
||||
|
||||
* `"Worker"`, for code loaded by calling the Web worker constructor—the
|
||||
worker's main script.
|
||||
|
||||
|
11
js/src/jit-test/tests/debug/bug1338914.js
Normal file
11
js/src/jit-test/tests/debug/bug1338914.js
Normal file
@ -0,0 +1,11 @@
|
||||
// In a debuggee, the Function.prototype script source has the introductionType
|
||||
// property set to "Function.prototype".
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
var scripts = dbg.findScripts();
|
||||
assertEq(scripts.length > 0, true);
|
||||
var fpScripts = scripts.filter(s => s.source.introductionType == "Function.prototype");
|
||||
assertEq(fpScripts.length, 1);
|
||||
var source = fpScripts[0].source;
|
||||
assertEq(source.text, "() {\n}");
|
62
js/src/jit-test/tests/debug/wasm-get-return.js
Normal file
62
js/src/jit-test/tests/debug/wasm-get-return.js
Normal file
@ -0,0 +1,62 @@
|
||||
// |jit-test| test-also-wasm-baseline
|
||||
// Tests that wasm frame opPop event can access function resumption value.
|
||||
|
||||
load(libdir + "wasm.js");
|
||||
load(libdir + 'eqArrayHelper.js');
|
||||
|
||||
function monitorFrameOnPopReturns(wast, expected) {
|
||||
var values = [];
|
||||
wasmRunWithDebugger(
|
||||
wast,
|
||||
undefined,
|
||||
function ({dbg}) {
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
if (frame.type != 'wasmcall') return;
|
||||
frame.onPop = function (value) {
|
||||
values.push(value.return);
|
||||
};
|
||||
};
|
||||
},
|
||||
function ({error}) {
|
||||
assertEq(error, undefined);
|
||||
}
|
||||
);
|
||||
assertEqArray(values, expected);
|
||||
}
|
||||
|
||||
monitorFrameOnPopReturns(
|
||||
`(module (func (export "test")))`,
|
||||
[undefined]);
|
||||
monitorFrameOnPopReturns(
|
||||
`(module (func (export "test") (result i32) (i32.const 42)))`,
|
||||
[42]);
|
||||
monitorFrameOnPopReturns(
|
||||
`(module (func (export "test") (result f32) (f32.const 0.5)))`,
|
||||
[0.5]);
|
||||
monitorFrameOnPopReturns(
|
||||
`(module (func (export "test") (result f64) (f64.const -42.75)))`,
|
||||
[-42.75]);
|
||||
monitorFrameOnPopReturns(
|
||||
`(module (func (result i64) (i64.const 2)) (func (export "test") (call 0) (drop)))`,
|
||||
[2, undefined]);
|
||||
|
||||
// Checking if throwing frame has right resumption value.
|
||||
var throwCount = 0;
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (unreachable)) (func (export "test") (result i32) (call 0) (i32.const 1)))',
|
||||
undefined,
|
||||
function ({dbg, g}) {
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
if (frame.type != 'wasmcall') return;
|
||||
frame.onPop = function (value) {
|
||||
if ('throw' in value)
|
||||
throwCount++;
|
||||
};
|
||||
};
|
||||
},
|
||||
function ({error}) {
|
||||
assertEq(error != undefined, true);
|
||||
assertEq(throwCount, 2);
|
||||
}
|
||||
);
|
||||
|
@ -854,8 +854,11 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||
return nullptr;
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setNoScriptRval(true)
|
||||
options.setIntroductionType("Function.prototype")
|
||||
.setNoScriptRval(true)
|
||||
.setVersion(JSVERSION_DEFAULT);
|
||||
if (!ss->initFromOptions(cx, options))
|
||||
return nullptr;
|
||||
RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss));
|
||||
if (!sourceObject || !ScriptSourceObject::initFromOptions(cx, sourceObject, options))
|
||||
return nullptr;
|
||||
|
@ -423,7 +423,7 @@ AbstractFramePtr::returnValue() const
|
||||
if (isInterpreterFrame())
|
||||
return asInterpreterFrame()->returnValue();
|
||||
if (isWasmDebugFrame())
|
||||
return UndefinedHandleValue;
|
||||
return asWasmDebugFrame()->returnValue();
|
||||
return asBaselineFrame()->returnValue();
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,8 @@ uint8_t*
|
||||
Metadata::serialize(uint8_t* cursor) const
|
||||
{
|
||||
MOZ_ASSERT(!debugEnabled && debugTrapFarJumpOffsets.empty() &&
|
||||
debugFuncArgTypes.empty() && debugFuncToCodeRange.empty());
|
||||
debugFuncArgTypes.empty() && debugFuncReturnTypes.empty() &&
|
||||
debugFuncToCodeRange.empty());
|
||||
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
|
||||
cursor = SerializeVector(cursor, funcImports);
|
||||
cursor = SerializeVector(cursor, funcExports);
|
||||
@ -512,6 +513,7 @@ Metadata::deserialize(const uint8_t* cursor)
|
||||
debugTrapFarJumpOffsets.clear();
|
||||
debugFuncToCodeRange.clear();
|
||||
debugFuncArgTypes.clear();
|
||||
debugFuncReturnTypes.clear();
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@ -1177,6 +1179,13 @@ Code::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* args
|
||||
return DecodeLocalEntries(d, metadata_->kind, locals);
|
||||
}
|
||||
|
||||
ExprType
|
||||
Code::debugGetResultType(uint32_t funcIndex)
|
||||
{
|
||||
MOZ_ASSERT(metadata_->debugEnabled);
|
||||
return metadata_->debugFuncReturnTypes[funcIndex];
|
||||
}
|
||||
|
||||
void
|
||||
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
||||
Metadata::SeenSet* seenMetadata,
|
||||
|
@ -428,6 +428,7 @@ struct CustomSection
|
||||
|
||||
typedef Vector<CustomSection, 0, SystemAllocPolicy> CustomSectionVector;
|
||||
typedef Vector<ValTypeVector, 0, SystemAllocPolicy> FuncArgTypesVector;
|
||||
typedef Vector<ExprType, 0, SystemAllocPolicy> FuncReturnTypesVector;
|
||||
|
||||
// Metadata holds all the data that is needed to describe compiled wasm code
|
||||
// at runtime (as opposed to data that is only used to statically link or
|
||||
@ -479,6 +480,7 @@ struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
|
||||
Uint32Vector debugTrapFarJumpOffsets;
|
||||
Uint32Vector debugFuncToCodeRange;
|
||||
FuncArgTypesVector debugFuncArgTypes;
|
||||
FuncReturnTypesVector debugFuncReturnTypes;
|
||||
|
||||
bool usesMemory() const { return UsesMemory(memoryUsage); }
|
||||
bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
|
||||
@ -644,6 +646,7 @@ class Code
|
||||
// Stack inspection helpers.
|
||||
|
||||
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
|
||||
ExprType debugGetResultType(uint32_t funcIndex);
|
||||
|
||||
// about:memory reporting:
|
||||
|
||||
|
@ -65,6 +65,40 @@ DebugFrame::leaveFrame(JSContext* cx)
|
||||
observing_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
DebugFrame::clearReturnJSValue()
|
||||
{
|
||||
hasCachedReturnJSValue_ = true;
|
||||
cachedReturnJSValue_.setUndefined();
|
||||
}
|
||||
|
||||
void
|
||||
DebugFrame::updateReturnJSValue()
|
||||
{
|
||||
hasCachedReturnJSValue_ = true;
|
||||
ExprType returnType = instance()->code().debugGetResultType(funcIndex());
|
||||
switch (returnType) {
|
||||
case ExprType::Void:
|
||||
cachedReturnJSValue_.setUndefined();
|
||||
break;
|
||||
case ExprType::I32:
|
||||
cachedReturnJSValue_.setInt32(resultI32_);
|
||||
break;
|
||||
case ExprType::I64:
|
||||
// Just display as a Number; it's ok if we lose some precision
|
||||
cachedReturnJSValue_.setDouble((double)resultI64_);
|
||||
break;
|
||||
case ExprType::F32:
|
||||
cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_));
|
||||
break;
|
||||
case ExprType::F64:
|
||||
cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("result type");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
|
||||
{
|
||||
@ -89,10 +123,10 @@ DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
|
||||
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
|
||||
break;
|
||||
case jit::MIRType::Float32:
|
||||
vp.set(NumberValue(*static_cast<float*>(dataPtr)));
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
|
||||
break;
|
||||
case jit::MIRType::Double:
|
||||
vp.set(NumberValue(*static_cast<double*>(dataPtr)));
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("local type");
|
||||
|
@ -40,6 +40,8 @@ class DebugFrame
|
||||
double resultF64_;
|
||||
};
|
||||
|
||||
js::Value cachedReturnJSValue_;
|
||||
|
||||
// The fields below are initialized by the baseline compiler.
|
||||
uint32_t funcIndex_;
|
||||
uint32_t reserved0_;
|
||||
@ -52,6 +54,7 @@ class DebugFrame
|
||||
bool isDebuggee_ : 1;
|
||||
bool prevUpToDate_ : 1;
|
||||
bool hasCachedSavedFrame_ : 1;
|
||||
bool hasCachedReturnJSValue_ : 1;
|
||||
};
|
||||
void* reserved1_;
|
||||
};
|
||||
@ -91,6 +94,13 @@ class DebugFrame
|
||||
|
||||
inline void* resultsPtr() { return &resultI32_; }
|
||||
|
||||
inline HandleValue returnValue() const {
|
||||
MOZ_ASSERT(hasCachedReturnJSValue_);
|
||||
return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
|
||||
}
|
||||
void updateReturnJSValue();
|
||||
void clearReturnJSValue();
|
||||
|
||||
bool getLocal(uint32_t localIndex, MutableHandleValue vp);
|
||||
|
||||
static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
|
||||
|
@ -204,9 +204,12 @@ ModuleGenerator::initWasm(const CompileArgs& args)
|
||||
if (metadata_->debugEnabled) {
|
||||
if (!debugFuncArgTypes_.resize(env_->funcSigs.length()))
|
||||
return false;
|
||||
if (!debugFuncReturnTypes_.resize(env_->funcSigs.length()))
|
||||
return false;
|
||||
for (size_t i = 0; i < debugFuncArgTypes_.length(); i++) {
|
||||
if (!debugFuncArgTypes_[i].appendAll(env_->funcSigs[i]->args()))
|
||||
return false;
|
||||
debugFuncReturnTypes_[i] = env_->funcSigs[i]->ret();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1160,6 +1163,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
||||
|
||||
// Additional debug information to copy.
|
||||
metadata_->debugFuncArgTypes = Move(debugFuncArgTypes_);
|
||||
metadata_->debugFuncReturnTypes = Move(debugFuncReturnTypes_);
|
||||
if (metadata_->debugEnabled)
|
||||
metadata_->debugFuncToCodeRange = Move(funcToCodeRange_);
|
||||
|
||||
|
@ -237,6 +237,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
uint32_t startOfUnpatchedCallsites_;
|
||||
Uint32Vector debugTrapFarJumps_;
|
||||
FuncArgTypesVector debugFuncArgTypes_;
|
||||
FuncReturnTypesVector debugFuncReturnTypes_;
|
||||
|
||||
// Parallel compilation
|
||||
bool parallel_;
|
||||
|
@ -129,6 +129,7 @@ WasmHandleDebugTrap()
|
||||
}
|
||||
if (site->kind() == CallSite::LeaveFrame) {
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->updateReturnJSValue();
|
||||
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
|
||||
frame->leaveFrame(cx);
|
||||
return ok;
|
||||
@ -174,6 +175,7 @@ WasmHandleThrow()
|
||||
continue;
|
||||
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->clearReturnJSValue();
|
||||
|
||||
// Assume JSTRAP_ERROR status if no exception is pending --
|
||||
// no onExceptionUnwind handlers must be fired.
|
||||
|
@ -3972,11 +3972,11 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
|
||||
}
|
||||
};
|
||||
|
||||
struct BoxToRectAndText : public BoxToRect {
|
||||
mozilla::dom::DOMStringList* mTextList;
|
||||
struct MOZ_RAII BoxToRectAndText : public BoxToRect {
|
||||
Sequence<nsString>* mTextList;
|
||||
|
||||
BoxToRectAndText(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
mozilla::dom::DOMStringList* aTextList, uint32_t aFlags)
|
||||
Sequence<nsString>* aTextList, uint32_t aFlags)
|
||||
: BoxToRect(aRelativeTo, aCallback, aFlags), mTextList(aTextList) {}
|
||||
|
||||
static void AccumulateText(nsIFrame* aFrame, nsAString& aResult) {
|
||||
@ -4009,9 +4009,10 @@ struct BoxToRectAndText : public BoxToRect {
|
||||
virtual void AddBox(nsIFrame* aFrame) override {
|
||||
BoxToRect::AddBox(aFrame);
|
||||
if (mTextList) {
|
||||
nsAutoString textForFrame;
|
||||
AccumulateText(aFrame, textForFrame);
|
||||
mTextList->Add(textForFrame);
|
||||
nsString* textForFrame = mTextList->AppendElement(fallible);
|
||||
if (textForFrame) {
|
||||
AccumulateText(aFrame, *textForFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -4027,7 +4028,7 @@ nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
Sequence<nsString>* aTextList,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
BoxToRectAndText converter(aRelativeTo, aCallback, aTextList, aFlags);
|
||||
|
@ -1213,7 +1213,7 @@ public:
|
||||
|
||||
static void GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
mozilla::dom::Sequence<nsString>* aTextList,
|
||||
uint32_t aFlags = 0);
|
||||
|
||||
/**
|
||||
|
@ -135,14 +135,6 @@ CSSStyleSheetInner::CSSStyleSheetInner(CORSMode aCORSMode,
|
||||
MOZ_COUNT_CTOR(CSSStyleSheetInner);
|
||||
}
|
||||
|
||||
static bool SetStyleSheetReference(css::Rule* aRule, void* aSheet)
|
||||
{
|
||||
if (aRule) {
|
||||
aRule->SetStyleSheet(static_cast<CSSStyleSheet*>(aSheet));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ChildSheetListBuilder {
|
||||
RefPtr<StyleSheet>* sheetSlot;
|
||||
StyleSheet* parent;
|
||||
@ -165,7 +157,8 @@ struct ChildSheetListBuilder {
|
||||
};
|
||||
|
||||
bool
|
||||
CSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder)
|
||||
CSSStyleSheet::RebuildChildList(css::Rule* aRule,
|
||||
ChildSheetListBuilder* aBuilder)
|
||||
{
|
||||
int32_t type = aRule->GetType();
|
||||
if (type < css::Rule::IMPORT_RULE) {
|
||||
@ -178,9 +171,6 @@ CSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder)
|
||||
return false;
|
||||
}
|
||||
|
||||
ChildSheetListBuilder* builder =
|
||||
static_cast<ChildSheetListBuilder*>(aBuilder);
|
||||
|
||||
// XXXbz We really need to decomtaminate all this stuff. Is there a reason
|
||||
// that I can't just QI to ImportRule and get a CSSStyleSheet
|
||||
// directly from it?
|
||||
@ -197,9 +187,9 @@ CSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder)
|
||||
return true;
|
||||
}
|
||||
|
||||
(*builder->sheetSlot) = sheet;
|
||||
builder->SetParentLinks(*builder->sheetSlot);
|
||||
builder->sheetSlot = &(*builder->sheetSlot)->mNext;
|
||||
(*aBuilder->sheetSlot) = sheet;
|
||||
aBuilder->SetParentLinks(*aBuilder->sheetSlot);
|
||||
aBuilder->sheetSlot = &(*aBuilder->sheetSlot)->mNext;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -238,11 +228,18 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||
: StyleSheetInfo(aCopy, aPrimarySheet)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CSSStyleSheetInner);
|
||||
aCopy.mOrderedRules.EnumerateForwards(css::GroupRule::CloneRuleInto, &mOrderedRules);
|
||||
mOrderedRules.EnumerateForwards(SetStyleSheetReference, aPrimarySheet);
|
||||
for (css::Rule* rule : aCopy.mOrderedRules) {
|
||||
RefPtr<css::Rule> clone = rule->Clone();
|
||||
mOrderedRules.AppendObject(clone);
|
||||
clone->SetStyleSheet(aPrimarySheet);
|
||||
}
|
||||
|
||||
ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet };
|
||||
mOrderedRules.EnumerateForwards(CSSStyleSheet::RebuildChildList, &builder);
|
||||
for (css::Rule* rule : mOrderedRules) {
|
||||
if (!CSSStyleSheet::RebuildChildList(rule, &builder)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RebuildNameSpaces();
|
||||
}
|
||||
@ -250,7 +247,9 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||
CSSStyleSheetInner::~CSSStyleSheetInner()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CSSStyleSheetInner);
|
||||
mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr);
|
||||
for (css::Rule* rule : mOrderedRules) {
|
||||
rule->SetStyleSheet(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
CSSStyleSheetInner*
|
||||
@ -262,8 +261,11 @@ CSSStyleSheetInner::CloneFor(CSSStyleSheet* aPrimarySheet)
|
||||
void
|
||||
CSSStyleSheetInner::RemoveSheet(StyleSheet* aSheet)
|
||||
{
|
||||
if ((aSheet == mSheets.ElementAt(0)) && (mSheets.Length() > 1)) {
|
||||
mOrderedRules.EnumerateForwards(SetStyleSheetReference, mSheets[1]);
|
||||
if (aSheet == mSheets.ElementAt(0) && mSheets.Length() > 1) {
|
||||
StyleSheet* sheet = mSheets[1];
|
||||
for (css::Rule* rule : mOrderedRules) {
|
||||
rule->SetStyleSheet(sheet);
|
||||
}
|
||||
|
||||
ChildSheetListBuilder::ReparentChildList(mSheets[1], mFirstChild);
|
||||
}
|
||||
@ -286,26 +288,22 @@ AddNamespaceRuleToMap(css::Rule* aRule, nsXMLNameSpaceMap* aMap)
|
||||
aMap->AddPrefix(nameSpaceRule->GetPrefix(), urlSpec);
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateNameSpace(css::Rule* aRule, void* aNameSpacePtr)
|
||||
{
|
||||
int32_t type = aRule->GetType();
|
||||
if (css::Rule::NAMESPACE_RULE == type) {
|
||||
AddNamespaceRuleToMap(aRule,
|
||||
static_cast<nsXMLNameSpaceMap*>(aNameSpacePtr));
|
||||
return true;
|
||||
}
|
||||
// stop if not namespace, import or charset because namespace can't follow
|
||||
// anything else
|
||||
return (css::Rule::CHARSET_RULE == type || css::Rule::IMPORT_RULE == type);
|
||||
}
|
||||
|
||||
void
|
||||
CSSStyleSheetInner::RebuildNameSpaces()
|
||||
{
|
||||
// Just nuke our existing namespace map, if any
|
||||
if (NS_SUCCEEDED(CreateNamespaceMap())) {
|
||||
mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap);
|
||||
for (css::Rule* rule : mOrderedRules) {
|
||||
switch (rule->GetType()) {
|
||||
case css::Rule::NAMESPACE_RULE:
|
||||
AddNamespaceRuleToMap(rule, mNameSpaceMap);
|
||||
continue;
|
||||
case css::Rule::CHARSET_RULE:
|
||||
case css::Rule::IMPORT_RULE:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,7 +435,9 @@ CSSStyleSheet::UnlinkInner()
|
||||
return;
|
||||
}
|
||||
|
||||
Inner()->mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr);
|
||||
for (css::Rule* rule : Inner()->mOrderedRules) {
|
||||
rule->SetStyleSheet(nullptr);
|
||||
}
|
||||
Inner()->mOrderedRules.Clear();
|
||||
|
||||
StyleSheet::UnlinkInner();
|
||||
|
@ -38,6 +38,7 @@ class nsXMLNameSpaceMap;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
struct ChildSheetListBuilder;
|
||||
|
||||
namespace css {
|
||||
class GroupRule;
|
||||
@ -164,7 +165,8 @@ public:
|
||||
|
||||
// Function used as a callback to rebuild our inner's child sheet
|
||||
// list after we clone a unique inner for ourselves.
|
||||
static bool RebuildChildList(css::Rule* aRule, void* aBuilder);
|
||||
static bool RebuildChildList(css::Rule* aRule,
|
||||
ChildSheetListBuilder* aBuilder);
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
int32_t StyleRuleCount() const { return mRules.Count(); }
|
||||
Rule* GetStyleRuleAt(int32_t aIndex) const;
|
||||
|
||||
typedef IncrementalClearCOMRuleArray::nsCOMArrayEnumFunc RuleEnumFunc;
|
||||
typedef bool (*RuleEnumFunc)(Rule* aElement, void* aData);
|
||||
bool EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const;
|
||||
|
||||
/*
|
||||
@ -76,14 +76,6 @@ public:
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override = 0;
|
||||
|
||||
static bool
|
||||
CloneRuleInto(Rule* aRule, void* aArray)
|
||||
{
|
||||
RefPtr<Rule> clone = aRule->Clone();
|
||||
static_cast<IncrementalClearCOMRuleArray*>(aArray)->AppendObject(clone);
|
||||
return true;
|
||||
}
|
||||
|
||||
// WebIDL API
|
||||
dom::CSSRuleList* CssRules();
|
||||
uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
|
||||
|
@ -3673,9 +3673,11 @@ nsCSSRuleProcessor::CascadeSheet(CSSStyleSheet* aSheet, CascadeEnumData* aData)
|
||||
child = child->mNext;
|
||||
}
|
||||
|
||||
if (!aSheet->Inner()->mOrderedRules.EnumerateForwards(CascadeRuleEnumFunc,
|
||||
aData))
|
||||
return false;
|
||||
for (css::Rule* rule : aSheet->Inner()->mOrderedRules) {
|
||||
if (!CascadeRuleEnumFunc(rule, aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -431,25 +431,22 @@ GroupRule::GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
SetParentRuleReference(Rule* aRule, void* aParentRule)
|
||||
{
|
||||
GroupRule* parentRule = static_cast<GroupRule*>(aParentRule);
|
||||
aRule->SetParentRule(parentRule);
|
||||
return true;
|
||||
}
|
||||
|
||||
GroupRule::GroupRule(const GroupRule& aCopy)
|
||||
: Rule(aCopy)
|
||||
{
|
||||
const_cast<GroupRule&>(aCopy).mRules.EnumerateForwards(GroupRule::CloneRuleInto, &mRules);
|
||||
mRules.EnumerateForwards(SetParentRuleReference, this);
|
||||
for (const Rule* rule : aCopy.mRules) {
|
||||
RefPtr<Rule> clone = rule->Clone();
|
||||
mRules.AppendObject(clone);
|
||||
clone->SetParentRule(this);
|
||||
}
|
||||
}
|
||||
|
||||
GroupRule::~GroupRule()
|
||||
{
|
||||
MOZ_ASSERT(!mSheet, "SetStyleSheet should have been called");
|
||||
mRules.EnumerateForwards(SetParentRuleReference, nullptr);
|
||||
for (Rule* rule : mRules) {
|
||||
rule->SetParentRule(nullptr);
|
||||
}
|
||||
if (mRuleCollection) {
|
||||
mRuleCollection->DropReference();
|
||||
}
|
||||
@ -468,17 +465,12 @@ GroupRule::IsCCLeaf() const
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetStyleSheetReference(Rule* aRule, void* aSheet)
|
||||
{
|
||||
aRule->SetStyleSheet(reinterpret_cast<StyleSheet*>(aSheet));
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(GroupRule)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
|
||||
tmp->mRules.EnumerateForwards(SetParentRuleReference, nullptr);
|
||||
for (Rule* rule : tmp->mRules) {
|
||||
rule->SetParentRule(nullptr);
|
||||
}
|
||||
// If tmp does not have a stylesheet, neither do its descendants. In that
|
||||
// case, don't try to null out their stylesheet, to avoid O(N^2) behavior in
|
||||
// depth of group rule nesting. But if tmp _does_ have a stylesheet (which
|
||||
@ -486,7 +478,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
|
||||
// need to null out the stylesheet pointer on descendants now, before we clear
|
||||
// tmp->mRules.
|
||||
if (tmp->GetStyleSheet()) {
|
||||
tmp->mRules.EnumerateForwards(SetStyleSheetReference, nullptr);
|
||||
for (Rule* rule : tmp->mRules) {
|
||||
rule->SetStyleSheet(nullptr);
|
||||
}
|
||||
}
|
||||
tmp->mRules.Clear();
|
||||
if (tmp->mRuleCollection) {
|
||||
@ -514,7 +508,9 @@ GroupRule::SetStyleSheet(StyleSheet* aSheet)
|
||||
// depth when seting the sheet to null during unlink, if we happen to unlin in
|
||||
// order from most nested rule up to least nested rule.
|
||||
if (aSheet != GetStyleSheet()) {
|
||||
mRules.EnumerateForwards(SetStyleSheetReference, aSheet);
|
||||
for (Rule* rule : mRules) {
|
||||
rule->SetStyleSheet(aSheet);
|
||||
}
|
||||
Rule::SetStyleSheet(aSheet);
|
||||
}
|
||||
}
|
||||
@ -550,8 +546,12 @@ GroupRule::GetStyleRuleAt(int32_t aIndex) const
|
||||
bool
|
||||
GroupRule::EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const
|
||||
{
|
||||
return
|
||||
const_cast<GroupRule*>(this)->mRules.EnumerateForwards(aFunc, aData);
|
||||
for (const Rule* rule : mRules) {
|
||||
if (!aFunc(const_cast<Rule*>(rule), aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4078,4 +4078,21 @@ STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleTransition>,
|
||||
STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleAnimation>,
|
||||
nsTArray_Simple<mozilla::StyleAnimation>);
|
||||
|
||||
/**
|
||||
* <div rustbindgen replaces="nsCOMArray"></div>
|
||||
*
|
||||
* mozilla::ArrayIterator doesn't work well with bindgen.
|
||||
*/
|
||||
template<typename T>
|
||||
class nsCOMArray_Simple {
|
||||
nsTArray<nsISupports*> mBuffer;
|
||||
};
|
||||
|
||||
STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsCOMArray<nsIContent>,
|
||||
nsCOMArray_Simple<nsIContent>);
|
||||
STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsCOMArray<nsINode>,
|
||||
nsCOMArray_Simple<nsINode>);
|
||||
STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsCOMArray<imgIContainer>,
|
||||
nsCOMArray_Simple<imgIContainer>);
|
||||
|
||||
#endif /* nsStyleStruct_h___ */
|
||||
|
@ -398,6 +398,11 @@
|
||||
@BINPATH@/components/TVSimulatorService.js
|
||||
@BINPATH@/components/TVSimulatorService.manifest
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
@BINPATH@/components/mozIntl.manifest
|
||||
@BINPATH@/components/mozIntl.js
|
||||
#endif
|
||||
|
||||
; Modules
|
||||
@BINPATH@/modules/*
|
||||
|
||||
|
@ -4711,9 +4711,6 @@ pref("gfx.direct2d.disabled", false);
|
||||
pref("gfx.direct2d.force-enabled", false);
|
||||
|
||||
pref("layers.prefer-opengl", false);
|
||||
pref("layers.prefer-d3d9", false);
|
||||
// Disable for now due to bug 1304360
|
||||
pref("layers.allow-d3d9-fallback", false);
|
||||
#endif
|
||||
|
||||
// Copy-on-write canvas
|
||||
@ -5572,11 +5569,7 @@ pref("dom.webkitBlink.dirPicker.enabled", true);
|
||||
pref("dom.webkitBlink.filesystem.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("media.block-autoplay-until-in-foreground", true);
|
||||
#else
|
||||
pref("media.block-autoplay-until-in-foreground", false);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_STYLO
|
||||
// Is the Servo-backed style system enabled?
|
||||
|
@ -157,12 +157,18 @@ def build_backends(backends):
|
||||
|
||||
set_config('BUILD_BACKENDS', build_backends)
|
||||
|
||||
option('--disable-gtest-in-build',
|
||||
help='Force disable building the gtest libxul during the build.',
|
||||
when='--enable-compile-environment')
|
||||
|
||||
# Determine whether to build the gtest xul. This happens in automation
|
||||
# on Desktop platforms with the exception of Windows PGO, where linking
|
||||
# xul-gtest.dll takes too long.
|
||||
@depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION',
|
||||
@depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
|
||||
when='--enable-compile-environment')
|
||||
def build_gtest(pgo, build_project, target, automation):
|
||||
def build_gtest(pgo, build_project, target, automation, enabled):
|
||||
if not enabled:
|
||||
return None
|
||||
if (automation and build_project == 'browser' and
|
||||
not (pgo and target.os == 'WINNT')):
|
||||
return True
|
||||
|
@ -5312,7 +5312,11 @@ dnl ========================================================
|
||||
dnl ICU Support
|
||||
dnl ========================================================
|
||||
|
||||
_INTL_API=yes
|
||||
if test "$MOZ_WIDGET_TOOLKIT" != "android" -o -z "$RELEASE_OR_BETA"; then
|
||||
_INTL_API=yes
|
||||
else
|
||||
_INTL_API=no
|
||||
fi
|
||||
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
|
||||
USE_ICU=1
|
||||
|
@ -2459,6 +2459,8 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
|
||||
if (range.max > SSL_LIBRARY_VERSION_TLS_1_2) {
|
||||
SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, false);
|
||||
SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, false);
|
||||
SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
|
||||
SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
|
||||
}
|
||||
|
||||
// Include a modest set of named groups.
|
||||
|
50
servo/Cargo.lock
generated
50
servo/Cargo.lock
generated
@ -283,7 +283,7 @@ dependencies = [
|
||||
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"offscreen_gl_context 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_config 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -297,7 +297,7 @@ dependencies = [
|
||||
"ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -418,8 +418,8 @@ dependencies = [
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender 0.21.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender 0.22.1 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -452,7 +452,7 @@ dependencies = [
|
||||
"servo_remutex 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
|
||||
@ -707,7 +707,7 @@ dependencies = [
|
||||
"servo_geometry 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -994,7 +994,7 @@ dependencies = [
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1073,7 +1073,7 @@ dependencies = [
|
||||
"servo_url 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1375,7 +1375,7 @@ dependencies = [
|
||||
"style_traits 0.0.1",
|
||||
"unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1415,7 +1415,7 @@ dependencies = [
|
||||
"servo_geometry 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"style 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1429,7 +1429,7 @@ dependencies = [
|
||||
"profile_traits 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1514,8 +1514,8 @@ dependencies = [
|
||||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"webdriver_server 0.0.1",
|
||||
"webrender 0.21.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender 0.22.1 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"webvr 0.0.1",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
@ -1662,7 +1662,7 @@ dependencies = [
|
||||
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1701,7 +1701,7 @@ dependencies = [
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1760,7 +1760,7 @@ dependencies = [
|
||||
"servo_url 0.0.1",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2298,7 +2298,7 @@ dependencies = [
|
||||
"tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"webvr 0.0.1",
|
||||
"webvr_traits 0.0.1",
|
||||
"xml5ever 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3175,8 +3175,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webrender"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/servo/webrender#040805f31650527311c0a0d58ccf9620b0f3eca9"
|
||||
version = "0.22.1"
|
||||
source = "git+https://github.com/servo/webrender#68f5b72fb3f871f6930c772c7e2705412512dde2"
|
||||
dependencies = [
|
||||
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.0.0-alpha2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3198,13 +3198,13 @@ dependencies = [
|
||||
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webrender_traits"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/servo/webrender#040805f31650527311c0a0d58ccf9620b0f3eca9"
|
||||
version = "0.23.1"
|
||||
source = "git+https://github.com/servo/webrender#68f5b72fb3f871f6930c772c7e2705412512dde2"
|
||||
dependencies = [
|
||||
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3228,7 +3228,7 @@ dependencies = [
|
||||
"msg 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"servo_config 0.0.1",
|
||||
"webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
|
||||
"webrender_traits 0.23.1 (git+https://github.com/servo/webrender)",
|
||||
"webvr_traits 0.0.1",
|
||||
]
|
||||
|
||||
@ -3568,8 +3568,8 @@ dependencies = [
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum webdriver 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc28802daddee94267a657ffeac2593a33881fb7a3a44fedd320b1319efcaf6"
|
||||
"checksum webrender 0.21.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender_traits 0.22.0 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender 0.22.1 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum webrender_traits 0.23.1 (git+https://github.com/servo/webrender)" = "<none>"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04614a58714f3fd4a8b1da4bcae9f031c532d35988c3d39627619248113f8be8"
|
||||
|
@ -182,17 +182,25 @@ impl DisplayList {
|
||||
*client_point
|
||||
} else {
|
||||
let point = *translated_point - stacking_context.bounds.origin;
|
||||
let inv_transform = match stacking_context.transform.inverse() {
|
||||
Some(transform) => transform,
|
||||
None => {
|
||||
// If a transform function causes the current transformation matrix of an object
|
||||
// to be non-invertible, the object and its content do not get displayed.
|
||||
return;
|
||||
|
||||
match stacking_context.transform {
|
||||
Some(transform) => {
|
||||
let inv_transform = match transform.inverse() {
|
||||
Some(transform) => transform,
|
||||
None => {
|
||||
// If a transform function causes the current transformation matrix of an object
|
||||
// to be non-invertible, the object and its content do not get displayed.
|
||||
return;
|
||||
}
|
||||
};
|
||||
let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
|
||||
point.y.to_f32_px()));
|
||||
Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
|
||||
}
|
||||
};
|
||||
let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
|
||||
point.y.to_f32_px()));
|
||||
Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
|
||||
None => {
|
||||
point
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -360,10 +368,10 @@ pub struct StackingContext {
|
||||
pub blend_mode: mix_blend_mode::T,
|
||||
|
||||
/// A transform to be applied to this stacking context.
|
||||
pub transform: Matrix4D<f32>,
|
||||
pub transform: Option<Matrix4D<f32>>,
|
||||
|
||||
/// The perspective matrix to be applied to children.
|
||||
pub perspective: Matrix4D<f32>,
|
||||
pub perspective: Option<Matrix4D<f32>>,
|
||||
|
||||
/// Whether this stacking context creates a new 3d rendering context.
|
||||
pub establishes_3d_context: bool,
|
||||
@ -385,8 +393,8 @@ impl StackingContext {
|
||||
z_index: i32,
|
||||
filters: filter::T,
|
||||
blend_mode: mix_blend_mode::T,
|
||||
transform: Matrix4D<f32>,
|
||||
perspective: Matrix4D<f32>,
|
||||
transform: Option<Matrix4D<f32>>,
|
||||
perspective: Option<Matrix4D<f32>>,
|
||||
establishes_3d_context: bool,
|
||||
scroll_policy: ScrollPolicy,
|
||||
parent_scroll_id: ScrollRootId)
|
||||
@ -416,8 +424,8 @@ impl StackingContext {
|
||||
0,
|
||||
filter::T::new(Vec::new()),
|
||||
mix_blend_mode::T::normal,
|
||||
Matrix4D::identity(),
|
||||
Matrix4D::identity(),
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
ScrollPolicy::Scrollable,
|
||||
ScrollRootId::root())
|
||||
|
@ -31,7 +31,7 @@ use app_units::{Au, MAX_AU};
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
|
||||
use display_list_builder::BlockFlowDisplayListBuilding;
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use euclid::{Matrix4D, Point2D, Rect, Size2D};
|
||||
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
|
||||
use flow::{self, BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ForceNonfloatedFlag};
|
||||
use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT};
|
||||
@ -1811,6 +1811,7 @@ impl BlockFlow {
|
||||
}
|
||||
let transform = match self.fragment
|
||||
.transform_matrix(&stacking_relative_border_box)
|
||||
.unwrap_or(Matrix4D::identity())
|
||||
.inverse() {
|
||||
Some(transform) => transform,
|
||||
None => {
|
||||
|
@ -29,7 +29,7 @@ use app_units::Au;
|
||||
use block::{BlockFlow, FormattingContextType};
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::DisplayListBuildState;
|
||||
use euclid::{Point2D, Size2D};
|
||||
use euclid::{Matrix4D, Point2D, Size2D};
|
||||
use flex::FlexFlow;
|
||||
use floats::{Floats, SpeculatedFloatPlacement};
|
||||
use flow_list::{FlowList, MutFlowListIterator};
|
||||
@ -272,7 +272,11 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
|
||||
|
||||
// TODO: Take into account 3d transforms, even though it's a fairly
|
||||
// uncommon case.
|
||||
let transform_2d = self.as_block().fragment.transform_matrix(&position).to_2d();
|
||||
let transform_2d = self.as_block()
|
||||
.fragment
|
||||
.transform_matrix(&position)
|
||||
.unwrap_or(Matrix4D::identity())
|
||||
.to_2d();
|
||||
let transformed_overflow = Overflow {
|
||||
paint: f32_rect_to_au_rect(transform_2d.transform_rect(
|
||||
&au_rect_to_f32_rect(overflow.paint))),
|
||||
|
@ -2873,13 +2873,13 @@ impl Fragment {
|
||||
}
|
||||
|
||||
/// Returns the 4D matrix representing this fragment's transform.
|
||||
pub fn transform_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Matrix4D<f32> {
|
||||
let mut transform = Matrix4D::identity();
|
||||
pub fn transform_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<Matrix4D<f32>> {
|
||||
let operations = match self.style.get_box().transform.0 {
|
||||
None => return transform,
|
||||
None => return None,
|
||||
Some(ref operations) => operations,
|
||||
};
|
||||
|
||||
let mut transform = Matrix4D::identity();
|
||||
let transform_origin = &self.style.get_box().transform_origin;
|
||||
let transform_origin_x = model::specified(transform_origin.horizontal,
|
||||
stacking_relative_border_box.size
|
||||
@ -2928,11 +2928,11 @@ impl Fragment {
|
||||
transform = transform.pre_mul(&matrix);
|
||||
}
|
||||
|
||||
pre_transform.pre_mul(&transform).pre_mul(&post_transform)
|
||||
Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
|
||||
}
|
||||
|
||||
/// Returns the 4D matrix representing this fragment's perspective.
|
||||
pub fn perspective_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Matrix4D<f32> {
|
||||
pub fn perspective_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<Matrix4D<f32>> {
|
||||
match self.style().get_box().perspective {
|
||||
Either::First(length) => {
|
||||
let perspective_origin = self.style().get_box().perspective_origin;
|
||||
@ -2951,10 +2951,10 @@ impl Fragment {
|
||||
|
||||
let perspective_matrix = create_perspective_matrix(length);
|
||||
|
||||
pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform)
|
||||
Some(pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform))
|
||||
}
|
||||
Either::Second(values::None_) => {
|
||||
Matrix4D::identity()
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ mod linked_list;
|
||||
mod list_item;
|
||||
mod model;
|
||||
mod multicol;
|
||||
mod opaque_node;
|
||||
pub mod opaque_node;
|
||||
pub mod parallel;
|
||||
mod persistent_list;
|
||||
pub mod query;
|
||||
|
@ -94,6 +94,9 @@ pub struct LayoutThreadData {
|
||||
|
||||
/// A list of images requests that need to be initiated.
|
||||
pub pending_images: Vec<PendingImage>,
|
||||
|
||||
/// A queued response for the list of nodes at a given point.
|
||||
pub nodes_from_point_response: Vec<UntrustedNodeAddress>,
|
||||
}
|
||||
|
||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
|
||||
@ -144,33 +147,10 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||
}
|
||||
}
|
||||
|
||||
fn nodes_from_point(&self,
|
||||
page_point: Point2D<f32>,
|
||||
client_point: Point2D<f32>) -> Vec<UntrustedNodeAddress> {
|
||||
let page_point = Point2D::new(Au::from_f32_px(page_point.x),
|
||||
Au::from_f32_px(page_point.y));
|
||||
let client_point = Point2D::new(Au::from_f32_px(client_point.x),
|
||||
Au::from_f32_px(client_point.y));
|
||||
|
||||
let nodes_from_point_list = {
|
||||
let &LayoutRPCImpl(ref rw_data) = self;
|
||||
let rw_data = rw_data.lock().unwrap();
|
||||
let result = match rw_data.display_list {
|
||||
None => panic!("Tried to hit test without a DisplayList"),
|
||||
Some(ref display_list) => {
|
||||
display_list.hit_test(&page_point,
|
||||
&client_point,
|
||||
&rw_data.stacking_context_scroll_offsets)
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
nodes_from_point_list.iter()
|
||||
.rev()
|
||||
.map(|metadata| metadata.node.to_untrusted_node_address())
|
||||
.collect()
|
||||
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress> {
|
||||
let &LayoutRPCImpl(ref rw_data) = self;
|
||||
let rw_data = rw_data.lock().unwrap();
|
||||
rw_data.nodes_from_point_response.clone()
|
||||
}
|
||||
|
||||
fn node_geometry(&self) -> NodeGeometryResponse {
|
||||
@ -193,8 +173,8 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||
|
||||
fn node_scroll_root_id(&self) -> NodeScrollRootIdResponse {
|
||||
NodeScrollRootIdResponse(self.0.lock()
|
||||
.unwrap().scroll_root_id_response
|
||||
.expect("scroll_root_id is not correctly fetched"))
|
||||
.unwrap().scroll_root_id_response
|
||||
.expect("scroll_root_id is not correctly fetched"))
|
||||
}
|
||||
|
||||
/// Retrieves the resolved value for a CSS style property.
|
||||
|
@ -381,12 +381,19 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||
vec![],
|
||||
None);
|
||||
|
||||
let transform = stacking_context.transform.map(|transform| {
|
||||
LayoutTransform::from_untyped(&transform).into()
|
||||
});
|
||||
let perspective = stacking_context.perspective.map(|perspective| {
|
||||
LayoutTransform::from_untyped(&perspective)
|
||||
});
|
||||
|
||||
builder.push_stacking_context(stacking_context.scroll_policy,
|
||||
stacking_context.bounds.to_rectf(),
|
||||
clip,
|
||||
stacking_context.z_index,
|
||||
LayoutTransform::from_untyped(&stacking_context.transform).into(),
|
||||
LayoutTransform::from_untyped(&stacking_context.perspective),
|
||||
transform,
|
||||
perspective,
|
||||
stacking_context.blend_mode.to_blend_mode(),
|
||||
stacking_context.filters.to_filter_ops());
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwne
|
||||
use layout::flow_ref::FlowRef;
|
||||
use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT};
|
||||
use layout::layout_debug;
|
||||
use layout::opaque_node::OpaqueNodeMethods;
|
||||
use layout::parallel;
|
||||
use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
|
||||
use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request};
|
||||
@ -459,6 +460,7 @@ impl LayoutThread {
|
||||
stacking_context_scroll_offsets: HashMap::new(),
|
||||
text_index_response: TextIndexResponse(None),
|
||||
pending_images: vec![],
|
||||
nodes_from_point_response: vec![],
|
||||
})),
|
||||
error_reporter: CSSErrorReporter {
|
||||
pipelineid: id,
|
||||
@ -494,8 +496,6 @@ impl LayoutThread {
|
||||
// Create a layout context for use in building display lists, hit testing, &c.
|
||||
fn build_layout_context(&self,
|
||||
rw_data: &LayoutThreadData,
|
||||
screen_size_changed: bool,
|
||||
goal: ReflowGoal,
|
||||
request_images: bool)
|
||||
-> LayoutContext {
|
||||
let thread_local_style_context_creation_data =
|
||||
@ -504,9 +504,7 @@ impl LayoutThread {
|
||||
LayoutContext {
|
||||
style_context: SharedStyleContext {
|
||||
viewport_size: self.viewport_size.clone(),
|
||||
screen_size_changed: screen_size_changed,
|
||||
stylist: rw_data.stylist.clone(),
|
||||
goal: goal,
|
||||
running_animations: self.running_animations.clone(),
|
||||
expired_animations: self.expired_animations.clone(),
|
||||
error_reporter: self.error_reporter.clone(),
|
||||
@ -977,6 +975,9 @@ impl LayoutThread {
|
||||
ReflowQueryType::HitTestQuery(..) => {
|
||||
rw_data.hit_test_response = (None, false);
|
||||
},
|
||||
ReflowQueryType::NodesFromPoint(..) => {
|
||||
rw_data.nodes_from_point_response = Vec::new();
|
||||
},
|
||||
ReflowQueryType::NodeGeometryQuery(_) => {
|
||||
rw_data.client_rect_response = Rect::zero();
|
||||
},
|
||||
@ -1030,9 +1031,6 @@ impl LayoutThread {
|
||||
Au::from_f32_px(constraints.size.height))
|
||||
});
|
||||
|
||||
// Handle conditions where the entire flow tree is invalid.
|
||||
let mut needs_dirtying = false;
|
||||
|
||||
let viewport_size_changed = self.viewport_size != old_viewport_size;
|
||||
if viewport_size_changed {
|
||||
if let Some(constraints) = rw_data.stylist.viewport_constraints() {
|
||||
@ -1066,9 +1064,9 @@ impl LayoutThread {
|
||||
}
|
||||
|
||||
// If the entire flow tree is invalid, then it will be reflowed anyhow.
|
||||
needs_dirtying |= Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets,
|
||||
Some(&*UA_STYLESHEETS),
|
||||
data.stylesheets_changed);
|
||||
let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets,
|
||||
Some(&*UA_STYLESHEETS),
|
||||
data.stylesheets_changed);
|
||||
let needs_reflow = viewport_size_changed && !needs_dirtying;
|
||||
if needs_dirtying {
|
||||
if let Some(mut d) = element.mutate_data() {
|
||||
@ -1114,10 +1112,7 @@ impl LayoutThread {
|
||||
}
|
||||
|
||||
// Create a layout context for use throughout the following passes.
|
||||
let mut layout_context = self.build_layout_context(&*rw_data,
|
||||
viewport_size_changed,
|
||||
data.reflow_info.goal,
|
||||
true);
|
||||
let mut layout_context = self.build_layout_context(&*rw_data, true);
|
||||
|
||||
// NB: Type inference falls apart here for some reason, so we need to be very verbose. :-(
|
||||
let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() {
|
||||
@ -1279,6 +1274,29 @@ impl LayoutThread {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
rw_data.margin_style_response = process_margin_style_query(node);
|
||||
},
|
||||
ReflowQueryType::NodesFromPoint(page_point, client_point) => {
|
||||
let page_point = Point2D::new(Au::from_f32_px(page_point.x),
|
||||
Au::from_f32_px(page_point.y));
|
||||
let client_point = Point2D::new(Au::from_f32_px(client_point.x),
|
||||
Au::from_f32_px(client_point.y));
|
||||
let nodes_from_point_list = {
|
||||
let result = match rw_data.display_list {
|
||||
None => panic!("Tried to hit test without a DisplayList"),
|
||||
Some(ref display_list) => {
|
||||
display_list.hit_test(&page_point,
|
||||
&client_point,
|
||||
&rw_data.stacking_context_scroll_offsets)
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
rw_data.nodes_from_point_response = nodes_from_point_list.iter()
|
||||
.rev()
|
||||
.map(|metadata| metadata.node.to_untrusted_node_address())
|
||||
.collect()
|
||||
},
|
||||
ReflowQueryType::NoQuery => {}
|
||||
}
|
||||
}
|
||||
@ -1322,10 +1340,7 @@ impl LayoutThread {
|
||||
page_clip_rect: max_rect(),
|
||||
};
|
||||
|
||||
let mut layout_context = self.build_layout_context(&*rw_data,
|
||||
false,
|
||||
reflow_info.goal,
|
||||
false);
|
||||
let mut layout_context = self.build_layout_context(&*rw_data, false);
|
||||
|
||||
if let Some(mut root_flow) = self.root_flow.clone() {
|
||||
// Perform an abbreviated style recalc that operates without access to the DOM.
|
||||
@ -1358,10 +1373,7 @@ impl LayoutThread {
|
||||
page_clip_rect: max_rect(),
|
||||
};
|
||||
|
||||
let mut layout_context = self.build_layout_context(&*rw_data,
|
||||
false,
|
||||
reflow_info.goal,
|
||||
false);
|
||||
let mut layout_context = self.build_layout_context(&*rw_data, false);
|
||||
|
||||
// No need to do a style recalc here.
|
||||
if self.root_flow.is_none() {
|
||||
@ -1488,7 +1500,9 @@ impl LayoutThread {
|
||||
|
||||
fn reflow_all_nodes(flow: &mut Flow) {
|
||||
debug!("reflowing all nodes!");
|
||||
flow::mut_base(flow).restyle_damage.insert(REPAINT | STORE_OVERFLOW | REFLOW);
|
||||
flow::mut_base(flow)
|
||||
.restyle_damage
|
||||
.insert(REPAINT | STORE_OVERFLOW | REFLOW | REPOSITION);
|
||||
|
||||
for child in flow::child_iter_mut(flow) {
|
||||
LayoutThread::reflow_all_nodes(child);
|
||||
@ -1585,7 +1599,8 @@ fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
|
||||
/// or false if it only needs stacking-relative positions.
|
||||
fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool {
|
||||
match *query_type {
|
||||
ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) => true,
|
||||
ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) |
|
||||
ReflowQueryType::NodesFromPoint(..) => true,
|
||||
ReflowQueryType::ContentBoxQuery(_) | ReflowQueryType::ContentBoxesQuery(_) |
|
||||
ReflowQueryType::NodeGeometryQuery(_) | ReflowQueryType::NodeScrollGeometryQuery(_) |
|
||||
ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::NodeScrollRootIdQuery(_) |
|
||||
|
@ -1877,7 +1877,13 @@ impl Document {
|
||||
Point2D::new(client_point.x + self.window.PageXOffset() as f32,
|
||||
client_point.y + self.window.PageYOffset() as f32);
|
||||
|
||||
self.window.layout().nodes_from_point(page_point, *client_point)
|
||||
if !self.window.reflow(ReflowGoal::ForScriptQuery,
|
||||
ReflowQueryType::NodesFromPoint(page_point, *client_point),
|
||||
ReflowReason::Query) {
|
||||
return vec!();
|
||||
};
|
||||
|
||||
self.window.layout().nodes_from_point_response()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1811,6 +1811,7 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue
|
||||
ReflowQueryType::ContentBoxQuery(_n) => "\tContentBoxQuery",
|
||||
ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
|
||||
ReflowQueryType::HitTestQuery(..) => "\tHitTestQuery",
|
||||
ReflowQueryType::NodesFromPoint(..) => "\tNodesFromPoint",
|
||||
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
|
||||
ReflowQueryType::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery",
|
||||
ReflowQueryType::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
|
||||
|
@ -101,6 +101,7 @@ pub enum ReflowQueryType {
|
||||
OffsetParentQuery(TrustedNodeAddress),
|
||||
MarginStyleQuery(TrustedNodeAddress),
|
||||
TextIndexQuery(TrustedNodeAddress, i32, i32),
|
||||
NodesFromPoint(Point2D<f32>, Point2D<f32>),
|
||||
}
|
||||
|
||||
/// Information needed for a reflow.
|
||||
|
@ -40,7 +40,8 @@ pub trait LayoutRPC {
|
||||
fn margin_style(&self) -> MarginStyleResponse;
|
||||
/// Requests the list of not-yet-loaded images that were encountered in the last reflow.
|
||||
fn pending_images(&self) -> Vec<PendingImage>;
|
||||
fn nodes_from_point(&self, page_point: Point2D<f32>, client_point: Point2D<f32>) -> Vec<UntrustedNodeAddress>;
|
||||
/// Requests the list of nodes from the given point.
|
||||
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>;
|
||||
|
||||
fn text_index(&self) -> TextIndexResponse;
|
||||
}
|
||||
|
@ -64,15 +64,9 @@ pub struct SharedStyleContext {
|
||||
/// The current viewport size.
|
||||
pub viewport_size: Size2D<Au>,
|
||||
|
||||
/// Screen sized changed?
|
||||
pub screen_size_changed: bool,
|
||||
|
||||
/// The CSS selector stylist.
|
||||
pub stylist: Arc<Stylist>,
|
||||
|
||||
/// Why is this reflow occurring
|
||||
pub goal: ReflowGoal,
|
||||
|
||||
/// The animations that are currently running.
|
||||
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
|
||||
|
@ -20,7 +20,7 @@ use std::fmt::Write;
|
||||
use std::ptr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use style::arc_ptr_eq;
|
||||
use style::context::{QuirksMode, ReflowGoal, SharedStyleContext, StyleContext};
|
||||
use style::context::{QuirksMode, SharedStyleContext, StyleContext};
|
||||
use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo};
|
||||
use style::data::{ElementData, ElementStyles, RestyleData};
|
||||
use style::dom::{ShowSubtreeData, TElement, TNode};
|
||||
@ -164,8 +164,6 @@ fn create_shared_context(per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyle
|
||||
SharedStyleContext {
|
||||
// FIXME (bug 1303229): Use the actual viewport size here
|
||||
viewport_size: Size2D::new(Au(0), Au(0)),
|
||||
screen_size_changed: false,
|
||||
goal: ReflowGoal::ForScriptQuery,
|
||||
stylist: per_doc_data.stylist.clone(),
|
||||
running_animations: per_doc_data.running_animations.clone(),
|
||||
expired_animations: per_doc_data.expired_animations.clone(),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user