Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-03-03 13:06:37 +01:00
commit 06813a3df9
190 changed files with 2802 additions and 1378 deletions

View File

@ -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);

View File

@ -4647,8 +4647,6 @@ var XULBrowserWindow = {
SocialUI.updateState();
UITour.onLocationChange(location);
gTabletModePageCounter.inc();
// Utility functions for disabling find

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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 = [

View File

@ -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");
});
});

View File

@ -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"),

View File

@ -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": "",

View File

@ -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"),

View File

@ -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);
},

View File

@ -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();
},

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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 "";
}

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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-ons 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

View File

@ -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;
},

View File

@ -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

View File

@ -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.
*/

View File

@ -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
};

View File

@ -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 });
}
};

View File

@ -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
};

View File

@ -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 = "";
},
};

View File

@ -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";
}
/**

View File

@ -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)

View File

@ -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;

View File

@ -52,3 +52,4 @@ DEPRECATED_OPERATION(FileLastModifiedDate)
DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap)
DEPRECATED_OPERATION(URLCreateObjectURL_MediaStream)
DEPRECATED_OPERATION(XMLBaseAttribute)
DEPRECATED_OPERATION(XMLBaseAttributeWithStyledElement)

View File

@ -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);
}

View File

@ -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,

View File

@ -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;

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -140,6 +140,8 @@ protected:
PrincipalHandle mPendingPrincipalHandle;
// The FrameID for which mPendingPrincipal is first valid.
ImageContainer::FrameID mFrameIDForPendingPrincipalHandle;
const RefPtr<AbstractThread> mMainThread;
};
} // namespace mozilla

View File

@ -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

View File

@ -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();

View File

@ -22,7 +22,6 @@ using media::TimeIntervals;
MediaSourceDemuxer::MediaSourceDemuxer(AbstractThread* aAbstractMainThread)
: mTaskQueue(new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
aAbstractMainThread,
/* aSupportsTailDispatch = */ false))
, mMonitor("MediaSourceDemuxer")
{

View File

@ -127,6 +127,7 @@ EXPORTS += [
'MediaResourceCallback.h',
'MediaResult.h',
'MediaSegment.h',
'MediaShutdownManager.h',
'MediaStatistics.h',
'MediaStreamGraph.h',
'MediaStreamListener.h',

View File

@ -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);
}
}

View File

@ -89,7 +89,7 @@ partial interface Range {
dictionary ClientRectsAndTexts {
required DOMRectList rectList;
required DOMStringList textList;
required sequence<DOMString> textList;
};
partial interface Range {

View File

@ -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

View File

@ -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);
/**

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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);
};

View File

@ -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);

View File

@ -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.

View 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}");

View 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);
}
);

View File

@ -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;

View File

@ -423,7 +423,7 @@ AbstractFramePtr::returnValue() const
if (isInterpreterFrame())
return asInterpreterFrame()->returnValue();
if (isWasmDebugFrame())
return UndefinedHandleValue;
return asWasmDebugFrame()->returnValue();
return asBaselineFrame()->returnValue();
}

View File

@ -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,

View File

@ -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:

View File

@ -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");

View File

@ -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_); }

View File

@ -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_);

View File

@ -237,6 +237,7 @@ class MOZ_STACK_CLASS ModuleGenerator
uint32_t startOfUnpatchedCallsites_;
Uint32Vector debugTrapFarJumps_;
FuncArgTypesVector debugFuncArgTypes_;
FuncReturnTypesVector debugFuncReturnTypes_;
// Parallel compilation
bool parallel_;

View File

@ -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.

View File

@ -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);

View File

@ -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);
/**

View File

@ -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();

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}
/*

View File

@ -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___ */

View File

@ -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/*

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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"

View File

@ -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())

View File

@ -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 => {

View File

@ -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))),

View File

@ -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
}
}
}

View File

@ -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;

View File

@ -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.

View File

@ -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());
}

View File

@ -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(_) |

View File

@ -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()
}
}

View File

@ -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",

View File

@ -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.

View File

@ -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;
}

View File

@ -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>>>>,

View File

@ -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