зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
a6ae5910bb
|
@ -457,8 +457,8 @@ var BrowserPageActions = {
|
|||
// like how #star-button is contained in #star-button-box, the latter
|
||||
// being the bookmark action's node. Look up the ancestor chain.
|
||||
for (let n = node.parentNode; n && !action; n = n.parentNode) {
|
||||
if (n.id == "urlbar-icons" || n.localName == "panelview") {
|
||||
// We reached the urlbar icons container or the panelview container.
|
||||
if (n.id == "page-action-buttons" || n.localName == "panelview") {
|
||||
// We reached the page-action-buttons or panelview container.
|
||||
// Stop looking; no acton was found.
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -663,8 +663,8 @@ html|input.urlbar-input[textoverflow]:not([focused]) {
|
|||
-moz-binding: url("chrome://global/content/bindings/datetimepopup.xml#datetime-popup");
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon,
|
||||
#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon-wrapper > .urlbar-icon,
|
||||
#urlbar[pageproxystate="invalid"] > #page-action-buttons > .urlbar-icon,
|
||||
#urlbar[pageproxystate="invalid"] > #page-action-buttons > .urlbar-icon-wrapper > .urlbar-icon,
|
||||
.urlbar-go-button[pageproxystate="valid"],
|
||||
.urlbar-go-button:not([parentfocused="true"]),
|
||||
#urlbar[pageproxystate="invalid"] > #identity-box > #blocked-permissions-container,
|
||||
|
|
|
@ -880,7 +880,7 @@
|
|||
<label id="switchtab" class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
|
||||
<label id="extension" class="urlbar-display urlbar-display-extension" value="&urlbar.extension.label;"/>
|
||||
</box>
|
||||
<hbox id="urlbar-icons">
|
||||
<hbox id="page-action-buttons">
|
||||
<image id="page-report-button"
|
||||
class="urlbar-icon"
|
||||
hidden="true"
|
||||
|
|
|
@ -57,8 +57,7 @@ add_task(async function() {
|
|||
modules: loader.loadedModules(),
|
||||
services: Object.keys(Cc).filter(c => {
|
||||
try {
|
||||
Cm.isServiceInstantiatedByContractID(c, Ci.nsISupports);
|
||||
return true;
|
||||
return Cm.isServiceInstantiatedByContractID(c, Ci.nsISupports);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
["history"]
|
||||
]
|
||||
},
|
||||
"identity": {
|
||||
"schema": "chrome://extensions/content/schemas/identity.json",
|
||||
"scopes": ["addon_parent"]
|
||||
},
|
||||
"menusInternal": {
|
||||
"url": "chrome://browser/content/ext-menus.js",
|
||||
"schema": "chrome://browser/content/schemas/menus.json",
|
||||
|
|
|
@ -163,7 +163,7 @@ this.pageAction = class extends ExtensionAPI {
|
|||
return {style};
|
||||
}
|
||||
|
||||
// Create an |image| node and add it to the |urlbar-icons|
|
||||
// Create an |image| node and add it to the |page-action-buttons|
|
||||
// container in the given window.
|
||||
addButton(window) {
|
||||
let document = window.document;
|
||||
|
@ -179,7 +179,7 @@ this.pageAction = class extends ExtensionAPI {
|
|||
document.addEventListener("popupshowing", this);
|
||||
}
|
||||
|
||||
document.getElementById("urlbar-icons").appendChild(button);
|
||||
document.getElementById("page-action-buttons").appendChild(button);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ skip-if = (os == 'win' && !debug) # bug 1352668
|
|||
[browser_ext_devtools_page.js]
|
||||
[browser_ext_devtools_panel.js]
|
||||
[browser_ext_devtools_panels_elements.js]
|
||||
skip-if = true # bug 1382487
|
||||
[browser_ext_geckoProfiler_symbolicate.js]
|
||||
[browser_ext_getViews.js]
|
||||
[browser_ext_identity_indication.js]
|
||||
|
|
|
@ -64,6 +64,7 @@ support-files =
|
|||
[browser_favicon_firstParty.js]
|
||||
[browser_favicon_userContextId.js]
|
||||
[browser_firstPartyIsolation.js]
|
||||
[browser_firstPartyIsolation_about_newtab.js]
|
||||
[browser_firstPartyIsolation_aboutPages.js]
|
||||
[browser_firstPartyIsolation_blobURI.js]
|
||||
[browser_firstPartyIsolation_js_uri.js]
|
||||
|
|
|
@ -157,7 +157,7 @@ add_task(async function test_aboutURL() {
|
|||
if ((flags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) &&
|
||||
!(flags & Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) &&
|
||||
networkURLs.indexOf(aboutType) == -1 &&
|
||||
// Exclude about:newtab see Bug 1021667
|
||||
// handle about:newtab in browser_firstPartyIsolation_about_newtab.js
|
||||
aboutType !== "newtab") {
|
||||
aboutURLs.push(aboutType);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
add_task(async function setup() {
|
||||
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("privacy.firstparty.isolate");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test about:newtab will have firstPartytDomain set when we enable the pref.
|
||||
*
|
||||
* We split about:newtab from browser_firstPartyIsolation_aboutPages.js because
|
||||
* about:newtab needs special care.
|
||||
*
|
||||
* In the original test browser_firstPartyIsolation_aboutPages.js, when calling
|
||||
* tabbrowser.addTab, if it found out the uri is about:newtab, it will use
|
||||
* the preloaded browser, however the preloaded browser is loaded before when we
|
||||
* turn on the firstPartyIsolation pref, which won't have the pref set.
|
||||
*
|
||||
* To prevent to use the preloaded browser, a simple trick is open a window
|
||||
* first.
|
||||
**/
|
||||
add_task(async function test_aboutNewTab() {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({remote: false});
|
||||
let gbrowser = win.gBrowser;
|
||||
let tab = BrowserTestUtils.addTab(gbrowser, "about:newtab");
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let attrs = { firstPartyDomain: "about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla" };
|
||||
await ContentTask.spawn(tab.linkedBrowser, { attrs }, async function(args) {
|
||||
info("principal " + content.document.nodePrincipal.origin);
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
args.attrs.firstPartyDomain, "about:newtab should have firstPartyDomain set");
|
||||
Assert.ok(content.document.nodePrincipal.isCodebasePrincipal,
|
||||
"The principal should be a codebase principal.");
|
||||
});
|
||||
|
||||
gbrowser.removeTab(tab);
|
||||
win.close();
|
||||
});
|
|
@ -46,8 +46,7 @@ startupRecorder.prototype = {
|
|||
modules: this.loader.loadedModules(),
|
||||
services: Object.keys(Cc).filter(c => {
|
||||
try {
|
||||
Cm.isServiceInstantiatedByContractID(c, Ci.nsISupports);
|
||||
return true;
|
||||
return Cm.isServiceInstantiatedByContractID(c, Ci.nsISupports);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ var PocketPageAction = {
|
|||
wrapper.appendChild(pocketButton);
|
||||
wrapper.appendChild(animatableBox);
|
||||
animatableBox.appendChild(animatableImage);
|
||||
let iconBox = doc.getElementById("urlbar-icons");
|
||||
let iconBox = doc.getElementById("page-action-buttons");
|
||||
iconBox.appendChild(wrapper);
|
||||
wrapper.hidden = true;
|
||||
wrapper.addEventListener("click", event => {
|
||||
|
|
|
@ -363,6 +363,7 @@ Section "-Application" APP_IDX
|
|||
${EndIf}
|
||||
|
||||
${RemoveDeprecatedKeys}
|
||||
${Set32to64DidMigrateReg}
|
||||
|
||||
; The previous installer adds several regsitry values to both HKLM and HKCU.
|
||||
; We now try to add to HKLM and if that fails to HKCU
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
${UpdateShortcutBranding}
|
||||
|
||||
${RemoveDeprecatedKeys}
|
||||
${Set32to64DidMigrateReg}
|
||||
|
||||
${SetAppKeys}
|
||||
${FixClassKeys}
|
||||
|
@ -617,6 +618,73 @@
|
|||
!macroend
|
||||
!define SetStartMenuInternet "!insertmacro SetStartMenuInternet"
|
||||
|
||||
; Add registry keys to support the Firefox 32 bit to 64 bit migration. These
|
||||
; registry entries are not removed on uninstall at this time. After the Firefox
|
||||
; 32 bit to 64 bit migration effort is completed these registry entries can be
|
||||
; removed during install, post update, and uninstall.
|
||||
!macro Set32to64DidMigrateReg
|
||||
${GetLongPath} "$INSTDIR" $1
|
||||
; These registry keys are always in the 32 bit hive since they are never
|
||||
; needed by a Firefox 64 bit install unless it has been updated from Firefox
|
||||
; 32 bit.
|
||||
SetRegView 32
|
||||
|
||||
!ifdef HAVE_64BIT_BUILD
|
||||
|
||||
; Running Firefox 64 bit on Windows 64 bit
|
||||
ClearErrors
|
||||
ReadRegDWORD $2 HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
|
||||
; If there were no errors then the system was updated from Firefox 32 bit to
|
||||
; Firefox 64 bit and if the value is already 1 then the registry value has
|
||||
; already been updated in the HKLM registry.
|
||||
${IfNot} ${Errors}
|
||||
${AndIf} $2 != 1
|
||||
ClearErrors
|
||||
WriteRegDWORD HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
|
||||
${If} ${Errors}
|
||||
; There was an error writing to HKLM so just write it to HKCU
|
||||
WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
|
||||
${Else}
|
||||
; This will delete the value from HKCU if it exists
|
||||
DeleteRegValue HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
ClearErrors
|
||||
ReadRegDWORD $2 HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
|
||||
; If there were no errors then the system was updated from Firefox 32 bit to
|
||||
; Firefox 64 bit and if the value is already 1 then the registry value has
|
||||
; already been updated in the HKCU registry.
|
||||
${IfNot} ${Errors}
|
||||
${AndIf} $2 != 1
|
||||
WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 1
|
||||
${EndIf}
|
||||
|
||||
!else
|
||||
|
||||
; Running Firefox 32 bit
|
||||
${If} ${RunningX64}
|
||||
; Running Firefox 32 bit on a Windows 64 bit system
|
||||
ClearErrors
|
||||
ReadRegDWORD $2 HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1"
|
||||
; If there were errors the value doesn't exist yet.
|
||||
${If} ${Errors}
|
||||
ClearErrors
|
||||
WriteRegDWORD HKLM "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 0
|
||||
; If there were errors write the value in HKCU.
|
||||
${If} ${Errors}
|
||||
WriteRegDWORD HKCU "Software\Mozilla\${AppName}\32to64DidMigrate" "$1" 0
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
!endif
|
||||
|
||||
ClearErrors
|
||||
SetRegView lastused
|
||||
!macroend
|
||||
!define Set32to64DidMigrateReg "!insertmacro Set32to64DidMigrateReg"
|
||||
|
||||
; The IconHandler reference for FirefoxHTML can end up in an inconsistent state
|
||||
; due to changes not being detected by the IconHandler for side by side
|
||||
; installs (see bug 268512). The symptoms can be either an incorrect icon or no
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
|
||||
/* Page action urlbar buttons */
|
||||
|
||||
#urlbar-icons {
|
||||
#page-action-buttons {
|
||||
-moz-box-align: center;
|
||||
/* Add more space between the last icon and the urlbar's edge. */
|
||||
margin-inline-end: 3px;
|
||||
|
|
|
@ -156,17 +156,16 @@ const ResponsePanel = createClass({
|
|||
sectionName = JSON_SCOPE_NAME;
|
||||
}
|
||||
object[sectionName] = json;
|
||||
} else {
|
||||
sectionName = RESPONSE_PAYLOAD;
|
||||
|
||||
object[sectionName] = {
|
||||
EDITOR_CONFIG: {
|
||||
text,
|
||||
mode: mimeType.replace(/;.+/, ""),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Others like text/html, text/plain, application/javascript
|
||||
object[RESPONSE_PAYLOAD] = {
|
||||
EDITOR_CONFIG: {
|
||||
text,
|
||||
mode: json ? "application/json" : mimeType.replace(/;.+/, ""),
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
div({ className: "panel-container" },
|
||||
error && div({ className: "response-error-header", title: error },
|
||||
|
@ -175,7 +174,7 @@ const ResponsePanel = createClass({
|
|||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: JSON_FILTER_TEXT,
|
||||
sectionNames: [sectionName],
|
||||
sectionNames: Object.keys(object),
|
||||
}),
|
||||
)
|
||||
);
|
||||
|
|
|
@ -170,7 +170,7 @@ add_task(function* () {
|
|||
box != "json",
|
||||
"The response json view doesn't display");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null,
|
||||
box != "textarea",
|
||||
(box !== "textarea" && box !== "json"),
|
||||
"The response editor doesn't display");
|
||||
is(tabpanel.querySelector(".response-image-box") === null,
|
||||
box != "image",
|
||||
|
@ -208,8 +208,8 @@ add_task(function* () {
|
|||
case "json": {
|
||||
checkVisibility("json");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
"The empty notice should not be displayed in this tabpanel.");
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ add_task(function* () {
|
|||
});
|
||||
yield wait;
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
@ -37,13 +37,13 @@ add_task(function* () {
|
|||
let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
|
|
@ -48,7 +48,7 @@ add_task(function* () {
|
|||
time: true
|
||||
});
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
@ -67,13 +67,13 @@ add_task(function* () {
|
|||
let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 2047,
|
||||
"There should be 2047 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
|
|
@ -62,7 +62,7 @@ add_task(function* () {
|
|||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), false,
|
||||
"The response json view doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ add_task(function* () {
|
|||
checkResponsePanelDisplaysJSON();
|
||||
|
||||
let tabpanel = document.querySelector("#response-panel");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
@ -55,8 +55,8 @@ add_task(function* () {
|
|||
let jsonView = panel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(panel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(panel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(panel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ add_task(function* () {
|
|||
* Returns a promise that will resolve when the response panel DOM element is available.
|
||||
*/
|
||||
function openResponsePanel() {
|
||||
let onReponsePanelReady = waitForDOM(document, "#response-panel");
|
||||
let onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
|
|
@ -42,7 +42,7 @@ add_task(function* () {
|
|||
time: true
|
||||
});
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
@ -61,13 +61,13 @@ add_task(function* () {
|
|||
let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
|
|
@ -43,7 +43,7 @@ add_task(function* () {
|
|||
time: true
|
||||
});
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
@ -62,13 +62,13 @@ add_task(function* () {
|
|||
let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
|
|
@ -57,7 +57,8 @@ add_task(function* () {
|
|||
time: true
|
||||
});
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
info("Testing first request");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
|
@ -66,7 +67,9 @@ add_task(function* () {
|
|||
|
||||
testResponseTab("$_0123Fun", "Hello JSONP!");
|
||||
|
||||
wait = waitForDOM(document, "#response-panel .tree-section");
|
||||
info("Testing second request");
|
||||
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[1]);
|
||||
yield wait;
|
||||
|
@ -83,13 +86,13 @@ add_task(function* () {
|
|||
is(tabpanel.querySelector(".tree-section .treeLabel").textContent,
|
||||
L10N.getFormatStr("jsonpScopeName", func),
|
||||
"The response json view has the intened visibility and correct title.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
|
||||
"The response editor has the intended visibility.");
|
||||
is(tabpanel.querySelector(".responseImageBox") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 2,
|
||||
"There should be 2 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
|
|
|
@ -1315,6 +1315,16 @@ nsFrameMessageManager::GetProcessMessageManager(nsIMessageSender** aPMM)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::GetRemoteType(nsAString& aRemoteType)
|
||||
{
|
||||
aRemoteType.Truncate();
|
||||
if (mCallback) {
|
||||
return mCallback->DoGetRemoteType(aRemoteType);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct MessageManagerReferentCount
|
||||
|
|
|
@ -92,6 +92,16 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual nsresult DoGetRemoteType(nsAString& aRemoteType) const
|
||||
{
|
||||
aRemoteType.Truncate();
|
||||
nsIMessageSender* parent = GetProcessMessageManager();
|
||||
if (parent) {
|
||||
return parent->GetRemoteType(aRemoteType);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
|
||||
StructuredCloneData& aData,
|
||||
|
|
|
@ -294,6 +294,12 @@ interface nsIMessageSender : nsIMessageListenerManager
|
|||
* is null.
|
||||
*/
|
||||
readonly attribute nsIMessageSender processMessageManager;
|
||||
|
||||
/**
|
||||
* For remote browsers, this contains the remoteType of the content child.
|
||||
* Otherwise, it is empty.
|
||||
*/
|
||||
readonly attribute AString remoteType;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -430,11 +430,22 @@ nsRange::UnregisterCommonAncestor(nsINode* aNode)
|
|||
MOZ_ASSERT(ranges);
|
||||
NS_ASSERTION(ranges->GetEntry(this), "unknown range");
|
||||
|
||||
bool isNativeAnon = aNode->IsInNativeAnonymousSubtree();
|
||||
bool removed = false;
|
||||
|
||||
if (ranges->Count() == 1) {
|
||||
aNode->ClearCommonAncestorForRangeInSelection();
|
||||
aNode->GetCommonAncestorRangesPtr().reset();
|
||||
if (!isNativeAnon) {
|
||||
// For nodes which are in native anonymous subtrees, we optimize away the
|
||||
// cost of deallocating the hashtable here because we may need to create
|
||||
// it again shortly afterward. We don't do this for all nodes in order
|
||||
// to avoid the additional memory usage unconditionally.
|
||||
aNode->GetCommonAncestorRangesPtr().reset();
|
||||
removed = true;
|
||||
}
|
||||
UnmarkDescendants(aNode);
|
||||
} else {
|
||||
}
|
||||
if (!removed) {
|
||||
ranges->RemoveEntry(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ support-files =
|
|||
[test_bug1303704.html]
|
||||
[test_bug1315862.html]
|
||||
[test_bug1323158.html]
|
||||
disabled = disabled # Bug 1389086 - Intermittent failures
|
||||
[test_empty_file.html]
|
||||
disabled = disabled # Bug 1150091 - Issue with support-files
|
||||
[test_pointerevent_attributes_hoverable_pointers-manual.html]
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: IndexedDB")
|
||||
|
||||
TEST_DIRS += ['test/extensions']
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
support-files = chromeHelpers.js
|
||||
|
||||
[test_globalObjects_chrome.xul]
|
||||
[test_globalObjects_other.xul]
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function testForExpectedSymbols(stage, data) {
|
||||
const expectedSymbols = [ "IDBKeyRange", "indexedDB" ];
|
||||
for (var symbol of expectedSymbols) {
|
||||
Services.prefs.setBoolPref("indexeddbtest.bootstrap." + stage + "." +
|
||||
symbol, symbol in this);
|
||||
}
|
||||
}
|
||||
|
||||
function GlobalObjectsComponent() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
GlobalObjectsComponent.prototype =
|
||||
{
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
||||
|
||||
runTest() {
|
||||
const name = "Splendid Test";
|
||||
|
||||
let ok = this.ok;
|
||||
let finishTest = this.finishTest;
|
||||
|
||||
let keyRange = IDBKeyRange.only(42);
|
||||
ok(keyRange, "Got keyRange");
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = function(event) {
|
||||
ok(false, "indexedDB error, '" + event.target.error.name + "'");
|
||||
finishTest();
|
||||
}
|
||||
request.onsuccess = function(event) {
|
||||
let db = event.target.result;
|
||||
ok(db, "Got database");
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var gFactory = {
|
||||
register() {
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
var classID = Components.ID("{d6f85dcb-537d-447e-b783-75d4b405622d}");
|
||||
var description = "IndexedDBTest";
|
||||
var contractID = "@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1";
|
||||
var factory = XPCOMUtils._getFactory(GlobalObjectsComponent);
|
||||
|
||||
registrar.registerFactory(classID, description, contractID, factory);
|
||||
|
||||
this.unregister = function() {
|
||||
registrar.unregisterFactory(classID, factory);
|
||||
delete this.unregister;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function install(data, reason) {
|
||||
testForExpectedSymbols("install");
|
||||
}
|
||||
|
||||
function startup(data, reason) {
|
||||
testForExpectedSymbols("startup");
|
||||
gFactory.register();
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
testForExpectedSymbols("shutdown");
|
||||
gFactory.unregister();
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
testForExpectedSymbols("uninstall");
|
||||
}
|
Двоичные данные
dom/indexedDB/test/extensions/indexedDB-test@mozilla.org.xpi
Двоичные данные
dom/indexedDB/test/extensions/indexedDB-test@mozilla.org.xpi
Двоичный файл не отображается.
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:name>IndexedDBTest</em:name>
|
||||
<em:description>IndexedDB functions for use in testing.</em:description>
|
||||
<em:creator>Mozilla</em:creator>
|
||||
<em:version>2016.03.09</em:version>
|
||||
<em:id>indexedDB-test@mozilla.org</em:id>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<!-- Firefox -->
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>45.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<!-- Fennec -->
|
||||
<em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id>
|
||||
<em:minVersion>45.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1,16 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPI_NAME = 'indexedDB'
|
||||
|
||||
FINAL_TARGET_FILES += [
|
||||
'bootstrap.js',
|
||||
'install.rdf',
|
||||
]
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.extensions += [
|
||||
'indexedDB-test@mozilla.org.xpi',
|
||||
]
|
|
@ -1,58 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Mozilla Bug 832883"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTest();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function* testSteps() {
|
||||
// Test for IDBKeyRange and indexedDB availability in bootstrap files.
|
||||
let test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
|
||||
createInstance(Ci.nsISupports).wrappedJSObject;
|
||||
test.ok = ok;
|
||||
test.finishTest = continueToNextStep;
|
||||
test.runTest();
|
||||
yield undefined;
|
||||
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
AddonManager.getAddonByID("indexedDB-test@mozilla.org",
|
||||
grabEventAndContinueHandler);
|
||||
let addon = yield undefined;
|
||||
addon.uninstall();
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
for (var stage of [ "install", "startup", "shutdown", "uninstall" ]) {
|
||||
for (var symbol of [ "IDBKeyRange", "indexedDB" ]) {
|
||||
let pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
|
||||
"." + symbol, false);
|
||||
ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
window.runTest = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
testGenerator.next();
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="chromeHelpers.js"></script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=832883"
|
||||
target="_blank">Mozilla Bug 832883</a>
|
||||
</body>
|
||||
</window>
|
|
@ -2670,6 +2670,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -2851,6 +2852,20 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentParent::GetInterface(const nsIID& aIID, void** aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
|
||||
nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
|
||||
mm.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "nsPluginTags.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsIDOMGeoPositionCallback.h"
|
||||
|
@ -109,6 +110,7 @@ class ContentParent final : public PContentParent
|
|||
, public nsIObserver
|
||||
, public nsIDOMGeoPositionCallback
|
||||
, public nsIDOMGeoPositionErrorCallback
|
||||
, public nsIInterfaceRequestor
|
||||
, public gfx::gfxVarReceiver
|
||||
, public mozilla::LinkedListElement<ContentParent>
|
||||
, public gfx::GPUProcessListener
|
||||
|
@ -198,6 +200,12 @@ public:
|
|||
|
||||
const nsAString& GetRemoteType() const;
|
||||
|
||||
virtual nsresult DoGetRemoteType(nsAString& aRemoteType) const override
|
||||
{
|
||||
aRemoteType = GetRemoteType();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
enum CPIteratorPolicy {
|
||||
eLive,
|
||||
eAll
|
||||
|
@ -310,6 +318,7 @@ public:
|
|||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMGEOPOSITIONCALLBACK
|
||||
NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
||||
/**
|
||||
* MessageManagerCallback methods that we override.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "MediaEngine.h"
|
||||
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
// conflicts with #include of scoped_ptr.h
|
||||
#undef FF
|
||||
|
@ -60,6 +61,20 @@ public:
|
|||
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
|
||||
const nsString& aDeviceId) const override;
|
||||
|
||||
void Shutdown() override
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
// Release mImage and it's resources just in case -- also we can be
|
||||
// held by something in a CC chain, and not be deleted until final-cc,
|
||||
// which is too late for releasing images. (This should be null'd on
|
||||
// Stop(), but apparently Stop() may not get called in this case
|
||||
// somehow.) (Bug 1374164)
|
||||
|
||||
Unused << NS_WARN_IF(mImage);
|
||||
|
||||
mImage = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct CapabilityCandidate {
|
||||
explicit CapabilityCandidate(uint8_t index, uint32_t distance = 0)
|
||||
|
|
|
@ -1538,8 +1538,14 @@ HTMLEditor::RelativeFontChangeHelper(int32_t aSizeChange,
|
|||
if (aNode->IsHTMLElement(nsGkAtoms::font) &&
|
||||
aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::size)) {
|
||||
// Cycle through children and adjust relative font size.
|
||||
for (uint32_t i = aNode->GetChildCount(); i--; ) {
|
||||
nsresult rv = RelativeFontChangeOnNode(aSizeChange, aNode->GetChildAt(i));
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> childList;
|
||||
for (nsIContent* child = aNode->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
childList.AppendElement(child);
|
||||
}
|
||||
|
||||
for (const auto& child: childList) {
|
||||
nsresult rv = RelativeFontChangeOnNode(aSizeChange, child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1549,8 +1555,14 @@ HTMLEditor::RelativeFontChangeHelper(int32_t aSizeChange,
|
|||
}
|
||||
|
||||
// Otherwise cycle through the children.
|
||||
for (uint32_t i = aNode->GetChildCount(); i--; ) {
|
||||
nsresult rv = RelativeFontChangeHelper(aSizeChange, aNode->GetChildAt(i));
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> childList;
|
||||
for (nsIContent* child = aNode->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
childList.AppendElement(child);
|
||||
}
|
||||
|
||||
for (const auto& child: childList) {
|
||||
nsresult rv = RelativeFontChangeHelper(aSizeChange, child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1616,8 +1628,14 @@ HTMLEditor::RelativeFontChangeOnNode(int32_t aSizeChange,
|
|||
// MOOSE: we should group the children together if possible
|
||||
// into a single "big" or "small". For the moment they are
|
||||
// each getting their own.
|
||||
for (uint32_t i = aNode->GetChildCount(); i--; ) {
|
||||
nsresult rv = RelativeFontChangeOnNode(aSizeChange, aNode->GetChildAt(i));
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> childList;
|
||||
for (nsIContent* child = aNode->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
childList.AppendElement(child);
|
||||
}
|
||||
|
||||
for (const auto& child: childList) {
|
||||
nsresult rv = RelativeFontChangeOnNode(aSizeChange, child);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -647,10 +647,6 @@ RangeItem::~RangeItem()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(RangeItem, mStartContainer, mEndContainer)
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(RangeItem, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(RangeItem, Release)
|
||||
|
||||
void
|
||||
RangeItem::StoreRange(nsRange* aRange)
|
||||
{
|
||||
|
@ -672,4 +668,18 @@ RangeItem::GetRange()
|
|||
return range.forget();
|
||||
}
|
||||
|
||||
void
|
||||
RangeItem::Unlink()
|
||||
{
|
||||
ImplCycleCollectionUnlink(mStartContainer);
|
||||
ImplCycleCollectionUnlink(mEndContainer);
|
||||
}
|
||||
|
||||
void
|
||||
RangeItem::Traverse(nsCycleCollectionTraversalCallback& aCallback, uint32_t aFlags)
|
||||
{
|
||||
CycleCollectionNoteChild(aCallback, mStartContainer.get(), "mStartContainer", aFlags);
|
||||
CycleCollectionNoteChild(aCallback, mEndContainer.get(), "mEndContainer", aFlags);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -37,8 +37,10 @@ public:
|
|||
void StoreRange(nsRange* aRange);
|
||||
already_AddRefed<nsRange> GetRange();
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RangeItem)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(RangeItem)
|
||||
NS_INLINE_DECL_REFCOUNTING(RangeItem)
|
||||
|
||||
void Unlink();
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCallback, uint32_t aFlags);
|
||||
|
||||
nsCOMPtr<nsINode> mStartContainer;
|
||||
int32_t mStartOffset;
|
||||
|
@ -46,6 +48,36 @@ public:
|
|||
int32_t mEndOffset;
|
||||
};
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionUnlink(RangeItem& aItem)
|
||||
{
|
||||
aItem.Unlink();
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
RangeItem& aItem,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
aItem.Traverse(aCallback, aFlags);
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionUnlink(RefPtr<RangeItem>& aItem)
|
||||
{
|
||||
aItem->Unlink();
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
RefPtr<RangeItem>& aItem,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
aItem->Traverse(aCallback, aFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* mozilla::SelectionState
|
||||
*
|
||||
|
|
|
@ -31,6 +31,7 @@ DrawTargetCaptureImpl::DrawTargetCaptureImpl(BackendType aBackend,
|
|||
RefPtr<DrawTarget> screenRefDT =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
|
||||
mFormat = aFormat;
|
||||
if (aBackend == screenRefDT->GetBackendType()) {
|
||||
mRefDT = screenRefDT;
|
||||
} else {
|
||||
|
@ -44,8 +45,6 @@ DrawTargetCaptureImpl::DrawTargetCaptureImpl(BackendType aBackend,
|
|||
IntSize size(1, 1);
|
||||
mRefDT = Factory::CreateDrawTarget(aBackend, size, mFormat);
|
||||
}
|
||||
|
||||
mFormat = aFormat;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -41,8 +41,8 @@ DrawTargetTiled::Init(const TileSet& aTiles)
|
|||
mRect.y = min(mRect.y, mTiles[i].mTileOrigin.y);
|
||||
mRect.width = newXMost - mRect.x;
|
||||
mRect.height = newYMost - mRect.y;
|
||||
mTiles[i].mDrawTarget->SetTransform(Matrix::Translation(mTiles[i].mTileOrigin.x,
|
||||
mTiles[i].mTileOrigin.y));
|
||||
mTiles[i].mDrawTarget->SetTransform(Matrix::Translation(-mTiles[i].mTileOrigin.x,
|
||||
-mTiles[i].mTileOrigin.y));
|
||||
}
|
||||
mFormat = mTiles[0].mDrawTarget->GetFormat();
|
||||
SetPermitSubpixelAA(IsOpaque(mFormat));
|
||||
|
|
|
@ -407,6 +407,15 @@ ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessManager::ResetCompositors()
|
||||
{
|
||||
// Note: this will recreate devices in addition to recreating compositors.
|
||||
// This isn't optimal, but this is only used on linux where acceleration
|
||||
// isn't enabled by default, and this way we don't need a new code path.
|
||||
SimulateDeviceReset();
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessManager::SimulateDeviceReset()
|
||||
{
|
||||
|
|
|
@ -143,6 +143,9 @@ public:
|
|||
uint64_t* aOutLayersId,
|
||||
CompositorOptions* aOutCompositorOptions);
|
||||
|
||||
// Destroy and recreate all of the compositors
|
||||
void ResetCompositors();
|
||||
|
||||
void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
|
||||
void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
|
||||
void SimulateDeviceReset();
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "base/task.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "mozilla/layers/SyncObject.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
@ -170,19 +172,15 @@ void
|
|||
PaintThread::FinishedLayerBatch()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<CompositorBridgeChild> cbc;
|
||||
if (!gfxPrefs::LayersOMTPForceSync()) {
|
||||
cbc = CompositorBridgeChild::Get();
|
||||
}
|
||||
|
||||
RefPtr<PaintThread> self = this;
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::EndAsyncPainting",
|
||||
[self, cbc]() -> void
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::EndAsyncPaintingLayer",
|
||||
[self]() -> void
|
||||
{
|
||||
self->EndAsyncPainting(cbc);
|
||||
self->EndAsyncPaintingLayer();
|
||||
});
|
||||
|
||||
if (cbc) {
|
||||
if (!gfxPrefs::LayersOMTPForceSync()) {
|
||||
sThread->Dispatch(task.forget());
|
||||
} else {
|
||||
SyncRunnable::DispatchToThread(sThread, task);
|
||||
|
@ -190,7 +188,7 @@ PaintThread::FinishedLayerBatch()
|
|||
}
|
||||
|
||||
void
|
||||
PaintThread::EndAsyncPainting(CompositorBridgeChild* aBridge)
|
||||
PaintThread::EndAsyncPaintingLayer()
|
||||
{
|
||||
MOZ_ASSERT(IsOnPaintThread());
|
||||
// Textureclient forces a flush once we "end paint", so
|
||||
|
@ -201,12 +199,47 @@ PaintThread::EndAsyncPainting(CompositorBridgeChild* aBridge)
|
|||
}
|
||||
|
||||
mDrawTargetsToFlush.Clear();
|
||||
}
|
||||
|
||||
if (aBridge) {
|
||||
aBridge->NotifyFinishedAsyncPaintLayer();
|
||||
void
|
||||
PaintThread::SynchronizePaintTextures(SyncObjectClient* aSyncObject)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSyncObject);
|
||||
|
||||
RefPtr<CompositorBridgeChild> cbc;
|
||||
if (!gfxPrefs::LayersOMTPForceSync()) {
|
||||
cbc = CompositorBridgeChild::Get();
|
||||
}
|
||||
|
||||
RefPtr<SyncObjectClient> syncObject(aSyncObject);
|
||||
RefPtr<PaintThread> self = this;
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::SyncTextureData",
|
||||
[self, cbc, syncObject]() -> void
|
||||
{
|
||||
self->SyncTextureData(cbc, syncObject);
|
||||
});
|
||||
|
||||
if (cbc) {
|
||||
sThread->Dispatch(task.forget());
|
||||
} else {
|
||||
SyncRunnable::DispatchToThread(sThread, task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PaintThread::SyncTextureData(CompositorBridgeChild* aBridge,
|
||||
SyncObjectClient* aSyncObject)
|
||||
{
|
||||
MOZ_ASSERT(IsOnPaintThread());
|
||||
MOZ_ASSERT(aSyncObject);
|
||||
|
||||
aSyncObject->Synchronize();
|
||||
|
||||
if (aBridge) {
|
||||
aBridge->NotifyFinishedAsyncPaintTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PaintThread::PaintContents(CapturedPaintState* aState,
|
||||
|
|
|
@ -75,6 +75,14 @@ public:
|
|||
// and the main thread is finished recording this layer.
|
||||
void FinishedLayerBatch();
|
||||
|
||||
// Must be called on the main thread. Tells the paint thread
|
||||
// to schedule a sync textures after all async paints are done.
|
||||
// NOTE: The other paint thread functions are on a per PAINT
|
||||
// or per paint layer basis. This MUST be called at the end
|
||||
// of a layer transaction as multiple paints can occur
|
||||
// with multiple layers. We only have to do this once per transaction.
|
||||
void SynchronizePaintTextures(SyncObjectClient* aSyncObject);
|
||||
|
||||
// Sync Runnables need threads to be ref counted,
|
||||
// But this thread lives through the whole process.
|
||||
// We're only temporarily using sync runnables so
|
||||
|
@ -92,7 +100,9 @@ private:
|
|||
void PaintContentsAsync(CompositorBridgeChild* aBridge,
|
||||
CapturedPaintState* aState,
|
||||
PrepDrawTargetForPaintingCallback aCallback);
|
||||
void EndAsyncPainting(CompositorBridgeChild* aBridge);
|
||||
void EndAsyncPaintingLayer();
|
||||
void SyncTextureData(CompositorBridgeChild* aBridge,
|
||||
SyncObjectClient* aSyncObject);
|
||||
|
||||
static StaticAutoPtr<PaintThread> sSingleton;
|
||||
static StaticRefPtr<nsIThread> sThread;
|
||||
|
|
|
@ -86,7 +86,6 @@ private:
|
|||
ViewID aScrollId,
|
||||
const std::string& aKey,
|
||||
const std::string& aValue) {
|
||||
MOZ_ASSERT(gfxPrefs::APZTestLoggingEnabled(), "don't call me");
|
||||
auto bucketIterator = aDataStore.find(aSequenceNumber);
|
||||
if (bucketIterator == aDataStore.end()) {
|
||||
MOZ_ASSERT(false, "LogTestDataImpl called with nonexistent sequence number");
|
||||
|
@ -105,8 +104,9 @@ class APZPaintLogHelper {
|
|||
public:
|
||||
APZPaintLogHelper(APZTestData* aTestData, SequenceNumber aPaintSequenceNumber)
|
||||
: mTestData(aTestData),
|
||||
mPaintSequenceNumber(aPaintSequenceNumber)
|
||||
{}
|
||||
mPaintSequenceNumber(aPaintSequenceNumber) {
|
||||
MOZ_ASSERT(!aTestData || gfxPrefs::APZTestLoggingEnabled(), "don't call me");
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
void LogTestData(FrameMetrics::ViewID aScrollId,
|
||||
|
|
|
@ -100,6 +100,7 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
|||
, mTransactionIncomplete(false)
|
||||
, mCompositorMightResample(false)
|
||||
, mNeedsComposite(false)
|
||||
, mTextureSyncOnPaintThread(false)
|
||||
, mPaintSequenceNumber(0)
|
||||
, mDeviceResetSequenceNumber(0)
|
||||
, mForwarder(new ShadowLayerForwarder(this))
|
||||
|
@ -358,6 +359,7 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
|||
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
|
||||
|
||||
mTransactionIncomplete = false;
|
||||
mTextureSyncOnPaintThread = false;
|
||||
|
||||
// Apply pending tree updates before recomputing effective
|
||||
// properties.
|
||||
|
@ -725,11 +727,17 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
|||
TimeStamp start = TimeStamp::Now();
|
||||
|
||||
// Skip the synchronization for buffer since we also skip the painting during
|
||||
// device-reset status.
|
||||
// device-reset status. With OMTP, we have to wait for async paints
|
||||
// before we synchronize and it's done on the paint thread.
|
||||
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
if (mForwarder->GetSyncObject() &&
|
||||
mForwarder->GetSyncObject()->IsSyncObjectValid()) {
|
||||
mForwarder->GetSyncObject()->Synchronize();
|
||||
if (mTextureSyncOnPaintThread) {
|
||||
// We have to wait for all async paints to finish to do this
|
||||
PaintThread::Get()->SynchronizePaintTextures(mForwarder->GetSyncObject());
|
||||
} else {
|
||||
mForwarder->GetSyncObject()->Synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/FocusTarget.h" // for FocusTarget
|
||||
#include "mozilla/layers/LayersTypes.h" // for BufferMode, LayersBackend, etc
|
||||
#include "mozilla/layers/PaintThread.h" // For PaintThread
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
|
||||
#include "mozilla/layers/APZTestData.h" // for APZTestData
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
|
@ -158,6 +159,7 @@ public:
|
|||
bool IsRepeatTransaction() { return mIsRepeatTransaction; }
|
||||
|
||||
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
|
||||
void SetNeedTextureSyncOnPaintThread() { mTextureSyncOnPaintThread = true; }
|
||||
|
||||
bool HasShadowTarget() { return !!mShadowTarget; }
|
||||
|
||||
|
@ -349,6 +351,7 @@ private:
|
|||
bool mTransactionIncomplete;
|
||||
bool mCompositorMightResample;
|
||||
bool mNeedsComposite;
|
||||
bool mTextureSyncOnPaintThread;
|
||||
|
||||
// An incrementing sequence number for paints.
|
||||
// Incremented in BeginTransaction(), but not for repeat transactions.
|
||||
|
|
|
@ -268,6 +268,7 @@ ClientPaintedLayer::PaintOffMainThread()
|
|||
|
||||
if (didUpdate) {
|
||||
UpdateContentClient(state);
|
||||
ClientManager()->SetNeedTextureSyncOnPaintThread();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1623,6 +1623,7 @@ SyncObjectD3D11Host::Synchronize()
|
|||
|
||||
SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle, ID3D11Device* aDevice)
|
||||
: mSyncHandle(aSyncHandle)
|
||||
, mSyncLock("SyncObjectD3D11")
|
||||
{
|
||||
if (!aDevice) {
|
||||
mDevice = DeviceManagerDx::Get()->GetContentDevice();
|
||||
|
@ -1678,9 +1679,19 @@ SyncObjectD3D11Client::IsSyncObjectValid()
|
|||
return true;
|
||||
}
|
||||
|
||||
// We have only 1 sync object. As a thing that somehow works,
|
||||
// we copy each of the textures that need to be synced with the compositor
|
||||
// into our sync object and only use a lock for this sync object.
|
||||
// This way, we don't have to sync every texture we send to the compositor.
|
||||
// We only have to do this once per transaction.
|
||||
void
|
||||
SyncObjectD3D11Client::Synchronize()
|
||||
{
|
||||
// Since this can be called from either the Paint or Main thread.
|
||||
// We don't want this to race since we initialize the sync texture here
|
||||
// too.
|
||||
MutexAutoLock syncLock(mSyncLock);
|
||||
|
||||
if (!mSyncedTextures.size()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -484,6 +484,7 @@ private:
|
|||
RefPtr<ID3D11Texture2D> mSyncTexture;
|
||||
RefPtr<IDXGIKeyedMutex> mKeyedMutex;
|
||||
std::vector<ID3D11Texture2D*> mSyncedTextures;
|
||||
Mutex mSyncLock;
|
||||
};
|
||||
|
||||
inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel)
|
||||
|
|
|
@ -1189,15 +1189,18 @@ CompositorBridgeChild::NotifyFinishedAsyncPaint(CapturedPaintState* aState)
|
|||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::NotifyFinishedAsyncPaintLayer()
|
||||
CompositorBridgeChild::NotifyFinishedAsyncPaintTransaction()
|
||||
{
|
||||
MOZ_ASSERT(PaintThread::IsOnPaintThread());
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
// Since this should happen after ALL paints are done and
|
||||
// at the end of a transaction, this should always be true.
|
||||
MOZ_RELEASE_ASSERT(mOutstandingAsyncPaints == 0);
|
||||
|
||||
// It's possible that we painted so fast that the main thread never reached
|
||||
// the code that starts delaying messages. If so, mIsWaitingForPaint will be
|
||||
// false, and we can safely return.
|
||||
if (mIsWaitingForPaint && mOutstandingAsyncPaints == 0) {
|
||||
if (mIsWaitingForPaint) {
|
||||
ResumeIPCAfterAsyncPaint();
|
||||
|
||||
// Notify the main thread in case it's blocking. We do this unconditionally
|
||||
|
|
|
@ -242,8 +242,9 @@ public:
|
|||
|
||||
// Must only be called from the paint thread. Notifies the CompositorBridge
|
||||
// that the paint thread has finished ALL async requests from a given
|
||||
// ClientPaintedLayer's batch.
|
||||
void NotifyFinishedAsyncPaintLayer();
|
||||
// transaction. We can resume IPC transactions after ALL
|
||||
// async paints are done.
|
||||
void NotifyFinishedAsyncPaintTransaction();
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
|
|
|
@ -463,9 +463,11 @@ CompositorBridgeParent::StopAndClearResources()
|
|||
});
|
||||
mWrBridge->Destroy();
|
||||
mWrBridge = nullptr;
|
||||
mAsyncImageManager->Destroy();
|
||||
// WebRenderAPI should be already destructed
|
||||
mAsyncImageManager = nullptr;
|
||||
if (mAsyncImageManager) {
|
||||
mAsyncImageManager->Destroy();
|
||||
// WebRenderAPI should be already destructed
|
||||
mAsyncImageManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCompositor) {
|
||||
|
|
|
@ -265,21 +265,6 @@ public:
|
|||
|
||||
void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override { }
|
||||
|
||||
/**
|
||||
* Request that the compositor be recreated due to a shared device reset.
|
||||
* This must be called on the main thread, and blocks until a task posted
|
||||
* to the compositor thread has completed.
|
||||
*
|
||||
* Note that this posts a task directly, rather than using synchronous
|
||||
* IPDL, and waits on a monitor notification from the compositor thread.
|
||||
* We do this as a best-effort attempt to jump any IPDL messages that
|
||||
* have not yet been posted (and are sitting around in the IO pipe), to
|
||||
* minimize the amount of time the main thread is blocked.
|
||||
*/
|
||||
bool ResetCompositor(const nsTArray<LayersBackend>& aBackendHints,
|
||||
uint64_t aSeqNo,
|
||||
TextureFactoryIdentifier* aOutIdentifier);
|
||||
|
||||
/**
|
||||
* This forces the is-first-paint flag to true. This is intended to
|
||||
* be called by the widget code when it loses its viewport information
|
||||
|
|
|
@ -244,22 +244,26 @@ CompositorManagerChild::ProcessingError(Result aCode, const char* aReason)
|
|||
already_AddRefed<nsIEventTarget>
|
||||
CompositorManagerChild::GetSpecificMessageEventTarget(const Message& aMsg)
|
||||
{
|
||||
if (aMsg.type() != PCompositorBridge::Msg_DidComposite__ID) {
|
||||
return nullptr;
|
||||
if (aMsg.type() == PCompositorBridge::Msg_DidComposite__ID) {
|
||||
uint64_t layersId;
|
||||
PickleIterator iter(aMsg);
|
||||
if (!IPC::ReadParam(&aMsg, &iter, &layersId)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TabChild* tabChild = TabChild::GetFrom(layersId);
|
||||
if (!tabChild) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return do_AddRef(tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
|
||||
}
|
||||
|
||||
uint64_t layersId;
|
||||
PickleIterator iter(aMsg);
|
||||
if (!IPC::ReadParam(&aMsg, &iter, &layersId)) {
|
||||
return nullptr;
|
||||
if (aMsg.type() == PCompositorBridge::Msg_ParentAsyncMessages__ID) {
|
||||
return do_AddRef(SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
}
|
||||
|
||||
TabChild* tabChild = TabChild::GetFrom(layersId);
|
||||
if (!tabChild) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return do_AddRef(tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1496,10 +1496,10 @@ static void aaa_walk_edges(SkAnalyticEdge* prevHead, SkAnalyticEdge* nextTail,
|
|||
} else {
|
||||
SkFixed rite = currE->fX;
|
||||
currE->goY(nextY, yShift);
|
||||
leftE->fX = SkTMax(leftClip, leftE->fX);
|
||||
SkFixed nextLeft = SkTMax(leftClip, leftE->fX);
|
||||
rite = SkTMin(rightClip, rite);
|
||||
currE->fX = SkTMin(rightClip, currE->fX);
|
||||
blit_trapezoid_row(blitter, y >> 16, left, rite, leftE->fX, currE->fX,
|
||||
SkFixed nextRite = SkTMin(rightClip, currE->fX);
|
||||
blit_trapezoid_row(blitter, y >> 16, left, rite, nextLeft, nextRite,
|
||||
leftDY, currE->fDY, fullAlpha, maskRow, isUsingMask,
|
||||
noRealBlitter || (fullAlpha == 0xFF && (
|
||||
edges_too_close(prevRite, left, leftE->fX) ||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
typedef gfxTextRun::Range Range;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
struct Params
|
||||
struct MOZ_STACK_CLASS Params
|
||||
{
|
||||
nsIAtom* language = nullptr;
|
||||
bool explicitLanguage = false;
|
||||
|
@ -250,7 +250,9 @@ private:
|
|||
nsFont mFont;
|
||||
RefPtr<gfxFontGroup> mFontGroup;
|
||||
nsCOMPtr<nsIAtom> mLanguage;
|
||||
nsDeviceContext* mDeviceContext;
|
||||
// Pointer to the device context for which this fontMetrics object was
|
||||
// created.
|
||||
nsDeviceContext* MOZ_NON_OWNING_REF mDeviceContext;
|
||||
int32_t mP2A;
|
||||
|
||||
// The font orientation (horizontal or vertical) for which these metrics
|
||||
|
|
|
@ -337,7 +337,7 @@ protected:
|
|||
|
||||
static gfxFontCache *gGlobalCache;
|
||||
|
||||
struct Key {
|
||||
struct MOZ_STACK_CLASS Key {
|
||||
const gfxFontEntry* mFontEntry;
|
||||
const gfxFontStyle* mStyle;
|
||||
const gfxCharacterMap* mUnicodeRangeMap;
|
||||
|
@ -367,7 +367,11 @@ protected:
|
|||
}
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
gfxFont* mFont;
|
||||
// The cache tracks gfxFont objects whose refcount has dropped to zero,
|
||||
// so they are not immediately deleted but may be "resurrected" if they
|
||||
// have not yet expired from the tracker when they are needed again.
|
||||
// See the custom AddRef/Release methods in gfxFont.
|
||||
gfxFont* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont;
|
||||
};
|
||||
|
||||
nsTHashtable<HashEntry> mFonts;
|
||||
|
@ -543,7 +547,7 @@ public:
|
|||
/**
|
||||
* This record contains all the parameters needed to initialize a textrun.
|
||||
*/
|
||||
struct Parameters {
|
||||
struct MOZ_STACK_CLASS Parameters {
|
||||
// Shape text params suggesting where the textrun will be rendered
|
||||
DrawTarget *mDrawTarget;
|
||||
// Pointer to arbitrary user data (which should outlive the textrun)
|
||||
|
@ -2221,7 +2225,7 @@ protected:
|
|||
// The TextRunDrawParams are set up once per textrun; the FontDrawParams
|
||||
// are dependent on the specific font, so they are set per GlyphRun.
|
||||
|
||||
struct TextRunDrawParams {
|
||||
struct MOZ_STACK_CLASS TextRunDrawParams {
|
||||
RefPtr<mozilla::gfx::DrawTarget> dt;
|
||||
gfxContext *context;
|
||||
gfxFont::Spacing *spacing;
|
||||
|
@ -2240,7 +2244,7 @@ struct TextRunDrawParams {
|
|||
bool paintSVGGlyphs;
|
||||
};
|
||||
|
||||
struct FontDrawParams {
|
||||
struct MOZ_STACK_CLASS FontDrawParams {
|
||||
RefPtr<mozilla::gfx::ScaledFont> scaledFont;
|
||||
RefPtr<mozilla::gfx::GlyphRenderingOptions> renderingOptions;
|
||||
mozilla::SVGContextPaint *contextPaint;
|
||||
|
@ -2254,7 +2258,7 @@ struct FontDrawParams {
|
|||
bool haveColorGlyphs;
|
||||
};
|
||||
|
||||
struct EmphasisMarkDrawParams {
|
||||
struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
|
||||
gfxContext* context;
|
||||
gfxFont::Spacing* spacing;
|
||||
gfxTextRun* mark;
|
||||
|
|
|
@ -45,8 +45,12 @@ protected:
|
|||
gr_font *mGrFont; // owned by the shaper itself
|
||||
|
||||
struct CallbackData {
|
||||
gfxFont* mFont;
|
||||
mozilla::gfx::DrawTarget* mDrawTarget;
|
||||
// mFont is a pointer to the font that owns this shaper, so it will
|
||||
// remain valid throughout our lifetime
|
||||
gfxFont* MOZ_NON_OWNING_REF mFont;
|
||||
// initialized to a DrawTarget owned by our caller on every call to
|
||||
// ShapeText
|
||||
mozilla::gfx::DrawTarget* MOZ_NON_OWNING_REF mDrawTarget;
|
||||
};
|
||||
|
||||
CallbackData mCallbackData;
|
||||
|
|
|
@ -23,7 +23,9 @@ public:
|
|||
*/
|
||||
struct FontCallbackData {
|
||||
gfxHarfBuzzShaper* mShaper;
|
||||
mozilla::gfx::DrawTarget* mDrawTarget;
|
||||
// initialized to a DrawTarget owned by our caller on every call to
|
||||
// ShapeText
|
||||
mozilla::gfx::DrawTarget* MOZ_NON_OWNING_REF mDrawTarget;
|
||||
};
|
||||
|
||||
bool Initialize();
|
||||
|
|
|
@ -67,7 +67,9 @@ public:
|
|||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
gfxCharacterMap *mCharMap;
|
||||
// charMaps are not owned by the shared cmap cache, but it will be notified
|
||||
// by gfxCharacterMap::Release() when an entry is about to be deleted
|
||||
gfxCharacterMap* MOZ_NON_OWNING_REF mCharMap;
|
||||
};
|
||||
|
||||
// gfxPlatformFontList is an abstract class for the global font list on the system;
|
||||
|
|
|
@ -140,7 +140,9 @@ private:
|
|||
nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
|
||||
|
||||
hb_blob_t *mSVGData;
|
||||
gfxFontEntry *mFontEntry;
|
||||
|
||||
// pointer to the font entry that owns this gfxSVGGlyphs object
|
||||
gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
|
||||
|
||||
const struct Header {
|
||||
mozilla::AutoSwap_PRUint16 mVersion;
|
||||
|
|
|
@ -561,7 +561,7 @@ HasNonOpaqueNonTransparentColor(gfxContext *aContext, Color& aCurrentColorOut)
|
|||
}
|
||||
|
||||
// helper class for double-buffering drawing with non-opaque color
|
||||
struct BufferAlphaColor {
|
||||
struct MOZ_STACK_CLASS BufferAlphaColor {
|
||||
explicit BufferAlphaColor(gfxContext *aContext)
|
||||
: mContext(aContext)
|
||||
{
|
||||
|
|
|
@ -241,7 +241,7 @@ public:
|
|||
virtual uint32_t GetAppUnitsPerDevUnit() const = 0;
|
||||
};
|
||||
|
||||
struct DrawParams
|
||||
struct MOZ_STACK_CLASS DrawParams
|
||||
{
|
||||
gfxContext* context;
|
||||
DrawMode drawMode = DrawMode::GLYPH_FILL;
|
||||
|
@ -464,7 +464,7 @@ public:
|
|||
uint8_t mMatchType;
|
||||
};
|
||||
|
||||
class GlyphRunIterator {
|
||||
class MOZ_STACK_CLASS GlyphRunIterator {
|
||||
public:
|
||||
GlyphRunIterator(const gfxTextRun *aTextRun, Range aRange)
|
||||
: mTextRun(aTextRun)
|
||||
|
@ -813,8 +813,12 @@ private:
|
|||
}
|
||||
|
||||
void *mUserData;
|
||||
gfxFontGroup *mFontGroup; // addrefed on creation, but our reference
|
||||
// may be released by ReleaseFontGroup()
|
||||
|
||||
// mFontGroup is usually a strong reference, but refcounting is managed
|
||||
// manually because it may be explicitly released by ReleaseFontGroup()
|
||||
// in the case where the font group actually owns the textrun.
|
||||
gfxFontGroup* MOZ_OWNING_REF mFontGroup;
|
||||
|
||||
gfxSkipChars mSkipChars;
|
||||
|
||||
nsTextFrameUtils::Flags mFlags2; // additional flags (see also gfxShapedText::mFlags)
|
||||
|
@ -1129,8 +1133,10 @@ protected:
|
|||
RefPtr<gfxFontFamily> mFamily;
|
||||
// either a font or a font entry exists
|
||||
union {
|
||||
gfxFont* mFont;
|
||||
gfxFontEntry* mFontEntry;
|
||||
// Whichever of these fields is actually present will be a strong
|
||||
// reference, with refcounting handled manually.
|
||||
gfxFont* MOZ_OWNING_REF mFont;
|
||||
gfxFontEntry* MOZ_OWNING_REF mFontEntry;
|
||||
};
|
||||
bool mNeedsBold : 1;
|
||||
bool mFontCreated : 1;
|
||||
|
|
|
@ -171,7 +171,7 @@ gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeeds
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
class gfxOTSContext : public ots::OTSContext {
|
||||
class MOZ_STACK_CLASS gfxOTSContext : public ots::OTSContext {
|
||||
public:
|
||||
explicit gfxOTSContext(gfxUserFontEntry* aUserFontEntry)
|
||||
: mUserFontEntry(aUserFontEntry)
|
||||
|
|
|
@ -746,7 +746,7 @@ protected:
|
|||
// This field is managed by the nsFontFaceLoader. In the destructor and Cancel()
|
||||
// methods of nsFontFaceLoader this reference is nulled out.
|
||||
nsFontFaceLoader* MOZ_NON_OWNING_REF mLoader; // current loader for this entry, if any
|
||||
gfxUserFontSet* mFontSet; // font-set which owns this userfont entry
|
||||
gfxUserFontSet* MOZ_NON_OWNING_REF mFontSet; // font-set which owns this userfont entry
|
||||
RefPtr<gfxFontSrcPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
|
|
|
@ -785,7 +785,7 @@ pub unsafe extern "C" fn wr_api_set_root_display_list(dh: &mut DocumentHandle,
|
|||
let color = if color.a == 0.0 {
|
||||
None
|
||||
} else {
|
||||
Some(color.into())
|
||||
Some(color)
|
||||
};
|
||||
// See the documentation of set_display_list in api.rs. I don't think
|
||||
// it makes a difference in gecko at the moment(until APZ is figured out)
|
||||
|
@ -802,7 +802,7 @@ pub unsafe extern "C" fn wr_api_set_root_display_list(dh: &mut DocumentHandle,
|
|||
epoch,
|
||||
color,
|
||||
LayoutSize::new(viewport_width, viewport_height),
|
||||
(pipeline_id, content_size.into(), dl),
|
||||
(pipeline_id, content_size, dl),
|
||||
preserve_frame_state,
|
||||
ResourceUpdates::new());
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ impl WebRenderFrameBuilder {
|
|||
content_size: LayoutSize) -> WebRenderFrameBuilder {
|
||||
WebRenderFrameBuilder {
|
||||
root_pipeline_id: root_pipeline_id,
|
||||
dl_builder: webrender_api::DisplayListBuilder::new(root_pipeline_id, content_size.into()),
|
||||
dl_builder: webrender_api::DisplayListBuilder::new(root_pipeline_id, content_size),
|
||||
scroll_clips_defined: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
@ -1004,8 +1004,6 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
|
|||
filter_count: usize) {
|
||||
assert!(unsafe { !is_in_render_thread() });
|
||||
|
||||
let bounds = bounds.into();
|
||||
|
||||
let c_filters = make_slice(filters, filter_count);
|
||||
let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
|
||||
match c_filter.filter_type {
|
||||
|
@ -1063,13 +1061,12 @@ pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_define_clip(state: &mut WrState,
|
||||
rect: LayoutRect,
|
||||
clip_rect: LayoutRect,
|
||||
complex: *const WrComplexClipRegion,
|
||||
complex_count: usize,
|
||||
mask: *const WrImageMask)
|
||||
-> u64 {
|
||||
assert!(unsafe { is_in_main_thread() });
|
||||
let clip_rect: LayoutRect = rect.into();
|
||||
let complex_slice = make_slice(complex, complex_count);
|
||||
let complex_iter = complex_slice.iter().map(|x| x.into());
|
||||
let mask : Option<ImageMask> = unsafe { mask.as_ref() }.map(|x| x.into());
|
||||
|
@ -1109,8 +1106,6 @@ pub extern "C" fn wr_dp_push_scroll_layer(state: &mut WrState,
|
|||
// Avoid defining multiple scroll clips with the same clip id, as that
|
||||
// results in undefined behaviour or assertion failures.
|
||||
if !state.frame_builder.scroll_clips_defined.contains(&clip_id) {
|
||||
let content_rect: LayoutRect = content_rect.into();
|
||||
let clip_rect: LayoutRect = clip_rect.into();
|
||||
|
||||
state.frame_builder.dl_builder.define_scroll_frame(
|
||||
Some(clip_id), content_rect, clip_rect, vec![], None,
|
||||
|
@ -1133,7 +1128,7 @@ pub extern "C" fn wr_scroll_layer_with_id(dh: &mut DocumentHandle,
|
|||
new_scroll_origin: LayoutPoint) {
|
||||
assert!(unsafe { is_in_compositor_thread() });
|
||||
let clip_id = ClipId::new(scroll_id, pipeline_id);
|
||||
dh.api.scroll_node_with_id(dh.document_id, new_scroll_origin.into(), clip_id, ScrollClamping::NoClamping);
|
||||
dh.api.scroll_node_with_id(dh.document_id, new_scroll_origin, clip_id, ScrollClamping::NoClamping);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1164,7 +1159,7 @@ pub extern "C" fn wr_dp_push_iframe(state: &mut WrState,
|
|||
pipeline_id: WrPipelineId) {
|
||||
assert!(unsafe { is_in_main_thread() });
|
||||
|
||||
state.frame_builder.dl_builder.push_iframe(rect.into(), None, pipeline_id);
|
||||
state.frame_builder.dl_builder.push_iframe(rect, None, pipeline_id);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1174,9 +1169,9 @@ pub extern "C" fn wr_dp_push_rect(state: &mut WrState,
|
|||
color: ColorF) {
|
||||
assert!(unsafe { !is_in_render_thread() });
|
||||
|
||||
state.frame_builder.dl_builder.push_rect(rect.into(),
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
color.into());
|
||||
state.frame_builder.dl_builder.push_rect(rect,
|
||||
Some(LocalClip::Rect(clip)),
|
||||
color);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1191,10 +1186,10 @@ pub extern "C" fn wr_dp_push_image(state: &mut WrState,
|
|||
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_image(bounds.into(),
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
stretch_size.into(),
|
||||
tile_spacing.into(),
|
||||
.push_image(bounds,
|
||||
Some(LocalClip::Rect(clip)),
|
||||
stretch_size,
|
||||
tile_spacing,
|
||||
image_rendering,
|
||||
key);
|
||||
}
|
||||
|
@ -1213,7 +1208,7 @@ pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
|
|||
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_yuv_image(bounds.into(),
|
||||
.push_yuv_image(bounds,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
|
||||
color_space,
|
||||
|
@ -1233,7 +1228,7 @@ pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
|
|||
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_yuv_image(bounds.into(),
|
||||
.push_yuv_image(bounds,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
YuvData::NV12(image_key_0, image_key_1),
|
||||
color_space,
|
||||
|
@ -1252,7 +1247,7 @@ pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
|
|||
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_yuv_image(bounds.into(),
|
||||
.push_yuv_image(bounds,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
YuvData::InterleavedYCbCr(image_key_0),
|
||||
color_space,
|
||||
|
@ -1277,7 +1272,7 @@ pub extern "C" fn wr_dp_push_text(state: &mut WrState,
|
|||
let glyph_options = None; // TODO
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_text(bounds.into(),
|
||||
.push_text(bounds,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
&glyph_slice,
|
||||
font_key,
|
||||
|
@ -1307,9 +1302,9 @@ pub extern "C" fn wr_dp_push_border(state: &mut WrState,
|
|||
});
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_border(rect.into(),
|
||||
.push_border(rect,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
widths.into(),
|
||||
widths,
|
||||
border_details);
|
||||
}
|
||||
|
||||
|
@ -1465,11 +1460,11 @@ pub extern "C" fn wr_dp_push_radial_gradient(state: &mut WrState,
|
|||
extend_mode.into());
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_radial_gradient(rect.into(),
|
||||
.push_radial_gradient(rect,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
gradient,
|
||||
tile_size.into(),
|
||||
tile_spacing.into());
|
||||
tile_size,
|
||||
tile_spacing);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1487,11 +1482,11 @@ pub extern "C" fn wr_dp_push_box_shadow(state: &mut WrState,
|
|||
|
||||
state.frame_builder
|
||||
.dl_builder
|
||||
.push_box_shadow(rect.into(),
|
||||
.push_box_shadow(rect,
|
||||
Some(LocalClip::Rect(clip.into())),
|
||||
box_bounds.into(),
|
||||
box_bounds,
|
||||
offset,
|
||||
color.into(),
|
||||
color,
|
||||
blur_radius,
|
||||
spread_radius,
|
||||
border_radius,
|
||||
|
|
|
@ -774,7 +774,7 @@ WR_FUNC;
|
|||
|
||||
WR_INLINE
|
||||
uint64_t wr_dp_define_clip(WrState *aState,
|
||||
LayoutRect aRect,
|
||||
LayoutRect aClipRect,
|
||||
const WrComplexClipRegion *aComplex,
|
||||
size_t aComplexCount,
|
||||
const WrImageMask *aMask)
|
||||
|
|
|
@ -157,13 +157,15 @@ ImageResource::SendOnUnlockedDraw(uint32_t aFlags)
|
|||
mProgressTracker->OnUnlockedDraw();
|
||||
} else {
|
||||
NotNull<RefPtr<ImageResource>> image = WrapNotNull(this);
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
nsCOMPtr<nsIEventTarget> eventTarget = mProgressTracker->GetEventTarget();
|
||||
nsCOMPtr<nsIRunnable> ev = NS_NewRunnableFunction(
|
||||
"image::ImageResource::SendOnUnlockedDraw", [=]() -> void {
|
||||
RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
|
||||
if (tracker) {
|
||||
tracker->OnUnlockedDraw();
|
||||
}
|
||||
}));
|
||||
});
|
||||
eventTarget->Dispatch(ev.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -456,12 +456,20 @@ RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey)
|
|||
bool animatedFramesDiscarded =
|
||||
mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> eventTarget;
|
||||
if (mProgressTracker) {
|
||||
eventTarget = mProgressTracker->GetEventTarget();
|
||||
} else {
|
||||
eventTarget = do_GetMainThread();
|
||||
}
|
||||
|
||||
RefPtr<RasterImage> image = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
nsCOMPtr<nsIRunnable> ev = NS_NewRunnableFunction(
|
||||
"RasterImage::OnSurfaceDiscarded",
|
||||
[=]() -> void {
|
||||
image->OnSurfaceDiscardedInternal(animatedFramesDiscarded);
|
||||
}));
|
||||
});
|
||||
eventTarget->Dispatch(ev.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -246,11 +246,11 @@ public:
|
|||
|
||||
bool IsEmpty() const { return mSurfaces.Count() == 0; }
|
||||
|
||||
void Insert(NotNull<CachedSurface*> aSurface)
|
||||
MOZ_MUST_USE bool Insert(NotNull<CachedSurface*> aSurface)
|
||||
{
|
||||
MOZ_ASSERT(!mLocked || aSurface->IsPlaceholder() || aSurface->IsLocked(),
|
||||
"Inserting an unlocked surface for a locked image");
|
||||
mSurfaces.Put(aSurface->GetSurfaceKey(), aSurface);
|
||||
return mSurfaces.Put(aSurface->GetSurfaceKey(), aSurface, fallible);
|
||||
}
|
||||
|
||||
void Remove(NotNull<CachedSurface*> aSurface)
|
||||
|
@ -480,7 +480,8 @@ public:
|
|||
// We require that locking succeed if the image is locked and we're not
|
||||
// inserting a placeholder; the caller may need to know this to handle
|
||||
// errors correctly.
|
||||
if (cache->IsLocked() && !surface->IsPlaceholder()) {
|
||||
bool mustLock = cache->IsLocked() && !surface->IsPlaceholder();
|
||||
if (mustLock) {
|
||||
surface->SetLocked(true);
|
||||
if (!surface->IsLocked()) {
|
||||
return InsertOutcome::FAILURE;
|
||||
|
@ -489,9 +490,14 @@ public:
|
|||
|
||||
// Insert.
|
||||
MOZ_ASSERT(cost <= mAvailableCost, "Inserting despite too large a cost");
|
||||
cache->Insert(surface);
|
||||
StartTracking(surface, aAutoLock);
|
||||
if (!cache->Insert(surface)) {
|
||||
if (mustLock) {
|
||||
surface->SetLocked(false);
|
||||
}
|
||||
return InsertOutcome::FAILURE;
|
||||
}
|
||||
|
||||
StartTracking(surface, aAutoLock);
|
||||
return InsertOutcome::SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -909,7 +915,8 @@ private:
|
|||
explicit SurfaceTracker(uint32_t aSurfaceCacheExpirationTimeMS)
|
||||
: ExpirationTrackerImpl<CachedSurface, 2,
|
||||
StaticMutex, StaticMutexAutoLock>(
|
||||
aSurfaceCacheExpirationTimeMS, "SurfaceTracker")
|
||||
aSurfaceCacheExpirationTimeMS, "SurfaceTracker",
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other))
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1104,7 +1104,8 @@ protected:
|
|||
|
||||
imgCacheExpirationTracker::imgCacheExpirationTracker()
|
||||
: nsExpirationTracker<imgCacheEntry, 3>(TIMEOUT_SECONDS * 1000,
|
||||
"imgCacheExpirationTracker")
|
||||
"imgCacheExpirationTracker",
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other))
|
||||
{ }
|
||||
|
||||
void
|
||||
|
|
|
@ -347,7 +347,10 @@ imgRequest::Cancel(nsresult aStatus)
|
|||
if (NS_IsMainThread()) {
|
||||
ContinueCancel(aStatus);
|
||||
} else {
|
||||
NS_DispatchToMainThread(new imgRequestMainThreadCancel(this, aStatus));
|
||||
RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
|
||||
nsCOMPtr<nsIEventTarget> eventTarget = progressTracker->GetEventTarget();
|
||||
nsCOMPtr<nsIRunnable> ev = new imgRequestMainThreadCancel(this, aStatus);
|
||||
eventTarget->Dispatch(ev.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,22 +1144,35 @@ imgRequest::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
|
|||
|
||||
if (result.mImage) {
|
||||
image = result.mImage;
|
||||
nsCOMPtr<nsIEventTarget> eventTarget;
|
||||
|
||||
// Update our state to reflect this new part.
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mImage = image;
|
||||
|
||||
// We only get an event target if we are not on the main thread, because
|
||||
// we have to dispatch in that case. If we are on the main thread, but
|
||||
// on a different scheduler group than ProgressTracker would give us,
|
||||
// that is okay because nothing in imagelib requires that, just our
|
||||
// listeners (which have their own checks).
|
||||
if (!NS_IsMainThread()) {
|
||||
eventTarget = mProgressTracker->GetEventTarget();
|
||||
MOZ_ASSERT(eventTarget);
|
||||
}
|
||||
|
||||
mProgressTracker = nullptr;
|
||||
}
|
||||
|
||||
// Some property objects are not threadsafe, and we need to send
|
||||
// OnImageAvailable on the main thread, so finish on the main thread.
|
||||
if (NS_IsMainThread()) {
|
||||
if (!eventTarget) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
FinishPreparingForNewPart(result);
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new FinishPreparingForNewPartRunnable(this, Move(result));
|
||||
NS_DispatchToMainThread(runnable);
|
||||
eventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// Check that setters throw TypeError when passed no arguments, instead of crashing.
|
||||
|
||||
function check(obj) {
|
||||
let proto = Object.getPrototypeOf(obj);
|
||||
let props = Object.getOwnPropertyNames(proto);
|
||||
for (let prop of props) {
|
||||
let desc = Object.getOwnPropertyDescriptor(proto, prop);
|
||||
if (desc.set) {
|
||||
print("bleah: " + uneval(prop));
|
||||
assertEq(typeof desc.set, 'function');
|
||||
try {
|
||||
desc.set.call(obj);
|
||||
assertEq("should have thrown TypeError", false);
|
||||
} catch (e) {
|
||||
assertEq(e instanceof TypeError, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dbg = new Debugger;
|
||||
var g = newGlobal();
|
||||
var gw = dbg.addDebuggee(g);
|
||||
|
||||
// Debugger
|
||||
check(dbg);
|
||||
|
||||
// Debugger.Memory
|
||||
check(dbg.memory);
|
||||
|
||||
// Debugger.Object
|
||||
g.eval('function f() { debugger; }');
|
||||
var fw = gw.getOwnPropertyDescriptor('f').value;
|
||||
check(fw);
|
||||
|
||||
// Debugger.Script
|
||||
check(fw.script);
|
||||
|
||||
// Debugger.Source
|
||||
check(fw.script.source);
|
||||
|
||||
// Debugger.Environment
|
||||
check(fw.environment);
|
||||
|
||||
// Debugger.Frame
|
||||
var log = '';
|
||||
dbg.onDebuggerStatement = function(frame) {
|
||||
log += 'd';
|
||||
check(frame);
|
||||
}
|
||||
g.eval('f()');
|
||||
assertEq(log, 'd');
|
|
@ -7641,9 +7641,11 @@ DebuggerSource_getIntroductionType(JSContext* cx, unsigned argc, Value* vp)
|
|||
static bool
|
||||
DebuggerSource_setSourceMapURL(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGSOURCE_SOURCE(cx, argc, vp, "sourceMapURL", args, obj, sourceObject);
|
||||
THIS_DEBUGSOURCE_SOURCE(cx, argc, vp, "set sourceMapURL", args, obj, sourceObject);
|
||||
ScriptSource* ss = sourceObject->source();
|
||||
MOZ_ASSERT(ss);
|
||||
if (!args.requireAtLeast(cx, "set sourceMapURL", 1))
|
||||
return false;
|
||||
|
||||
JSString* str = ToString<CanGC>(cx, args[0]);
|
||||
if (!str)
|
||||
|
|
|
@ -1706,6 +1706,12 @@ AssembleSandboxMemoryReporterName(JSContext* cx, nsCString& sandboxName)
|
|||
// Use a default name when the caller did not provide a sandboxName.
|
||||
if (sandboxName.IsEmpty())
|
||||
sandboxName = NS_LITERAL_CSTRING("[anonymous sandbox]");
|
||||
#ifndef DEBUG
|
||||
// Adding the caller location is fairly expensive, so in non-debug builds,
|
||||
// only add it if we don't have an explicit sandbox name.
|
||||
else
|
||||
return NS_OK;
|
||||
#endif
|
||||
|
||||
// Get the xpconnect native call context.
|
||||
XPCCallContext* cc = XPCJSContext::Get()->GetCallContext();
|
||||
|
|
|
@ -251,16 +251,23 @@ bool CompartmentPrivate::TryParseLocationURI(CompartmentPrivate::LocationHint aL
|
|||
return false;
|
||||
|
||||
// Handle Sandbox location strings.
|
||||
// A sandbox string looks like this:
|
||||
// A sandbox string looks like this, for anonymous sandboxes, and builds
|
||||
// where Sandbox location tagging is enabled:
|
||||
//
|
||||
// <sandboxName> (from: <js-stack-frame-filename>:<lineno>)
|
||||
//
|
||||
// where <sandboxName> is user-provided via Cu.Sandbox()
|
||||
// and <js-stack-frame-filename> and <lineno> is the stack frame location
|
||||
// from where Cu.Sandbox was called.
|
||||
//
|
||||
// Otherwise, it is simply the caller-provided name, which is usually a URI.
|
||||
//
|
||||
// <js-stack-frame-filename> furthermore is "free form", often using a
|
||||
// "uri -> uri -> ..." chain. The following code will and must handle this
|
||||
// common case.
|
||||
//
|
||||
// It should be noted that other parts of the code may already rely on the
|
||||
// "format" of these strings, such as the add-on SDK.
|
||||
// "format" of these strings.
|
||||
|
||||
static const nsDependentCString from("(from: ");
|
||||
static const nsDependentCString arrow(" -> ");
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
#include "jsprf.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
|
@ -449,6 +451,97 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
class WrappedJSNamed final : public nsINamed
|
||||
{
|
||||
nsCString mName;
|
||||
|
||||
~WrappedJSNamed() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit WrappedJSNamed(const nsACString& aName) : mName(aName) {}
|
||||
|
||||
NS_IMETHOD GetName(nsACString& aName) override
|
||||
{
|
||||
aName = mName;
|
||||
aName.AppendLiteral(":JS");
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WrappedJSNamed, nsINamed)
|
||||
|
||||
nsCString
|
||||
GetFunctionName(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
RootedObject inner(cx, js::UncheckedUnwrap(obj));
|
||||
JSAutoCompartment ac(cx, inner);
|
||||
|
||||
RootedFunction fun(cx, JS_GetObjectFunction(inner));
|
||||
if (!fun) {
|
||||
// If the object isn't a function, it's likely that it has a single
|
||||
// function property (for things like nsITimerCallback). In this case,
|
||||
// return the name of that function property.
|
||||
|
||||
Rooted<IdVector> idArray(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, inner, &idArray)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("error");
|
||||
}
|
||||
|
||||
if (idArray.length() != 1)
|
||||
return nsCString("nonfunction");
|
||||
|
||||
RootedId id(cx, idArray[0]);
|
||||
RootedValue v(cx);
|
||||
if (!JS_GetPropertyById(cx, inner, id, &v)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("nonfunction");
|
||||
}
|
||||
|
||||
if (!v.isObject())
|
||||
return nsCString("nonfunction");
|
||||
|
||||
RootedObject vobj(cx, &v.toObject());
|
||||
return GetFunctionName(cx, vobj);
|
||||
}
|
||||
|
||||
RootedString funName(cx, JS_GetFunctionDisplayId(fun));
|
||||
RootedScript script(cx, JS_GetFunctionScript(cx, fun));
|
||||
const char* filename = script ? JS_GetScriptFilename(script) : "anonymous";
|
||||
const char* filenameSuffix = strrchr(filename, '/');
|
||||
|
||||
if (filenameSuffix) {
|
||||
filenameSuffix++;
|
||||
} else {
|
||||
filenameSuffix = filename;
|
||||
}
|
||||
|
||||
nsCString displayName("anonymous");
|
||||
if (funName) {
|
||||
nsCString* displayNamePtr = &displayName;
|
||||
RootedValue funNameVal(cx, StringValue(funName));
|
||||
if (!XPCConvert::JSData2Native(&displayNamePtr, funNameVal, nsXPTType::T_UTF8STRING,
|
||||
nullptr, nullptr))
|
||||
{
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("anonymous");
|
||||
}
|
||||
}
|
||||
|
||||
displayName.Append('[');
|
||||
displayName.Append(filenameSuffix, strlen(filenameSuffix));
|
||||
displayName.Append(']');
|
||||
return displayName;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// static
|
||||
bool
|
||||
nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
|
||||
|
@ -590,6 +683,16 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
}
|
||||
}
|
||||
|
||||
// If we're asked to QI to nsINamed, we pretend that this is possible. We'll
|
||||
// try to return a name that makes sense for the wrapped JS value.
|
||||
if (aIID.Equals(NS_GET_IID(nsINamed))) {
|
||||
RootedObject obj(RootingCx(), self->GetJSObject());
|
||||
nsCString name = GetFunctionName(ccx, obj);
|
||||
RefPtr<WrappedJSNamed> named = new WrappedJSNamed(name);
|
||||
*aInstancePtr = named.forget().take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// else...
|
||||
// no can do
|
||||
*aInstancePtr = nullptr;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function callback() {}
|
||||
|
||||
let sandbox = Cu.Sandbox(this);
|
||||
let callbackWrapped = Cu.evalInSandbox("(function wrapped() {})", sandbox);
|
||||
|
||||
function run_test() {
|
||||
let functions = [
|
||||
[{ notify: callback }, "callback[test_function_names.js]:JS"],
|
||||
[{ notify: { notify: callback } }, "callback[test_function_names.js]:JS"],
|
||||
[callback, "callback[test_function_names.js]:JS"],
|
||||
[function() {}, "run_test/functions<[test_function_names.js]:JS"],
|
||||
[function foobar() {}, "foobar[test_function_names.js]:JS"],
|
||||
[function Δ() {}, "Δ[test_function_names.js]:JS"],
|
||||
[{ notify1: callback, notify2: callback }, "nonfunction:JS"],
|
||||
[{ notify: 10 }, "nonfunction:JS"],
|
||||
[{}, "nonfunction:JS"],
|
||||
[{ notify: callbackWrapped }, "wrapped[test_function_names.js]:JS"],
|
||||
];
|
||||
|
||||
// Use the observer service so we can get double-wrapped functions.
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
|
||||
function observer(subject, topic, data)
|
||||
{
|
||||
let named = subject.QueryInterface(Ci.nsINamed);
|
||||
do_check_eq(named.name, data);
|
||||
dump(`name: ${named.name}\n`);
|
||||
}
|
||||
obs.addObserver(observer, "test-obs-fun", false);
|
||||
|
||||
for (let [f, requiredName] of functions) {
|
||||
obs.notifyObservers(f, "test-obs-fun", requiredName);
|
||||
}
|
||||
}
|
|
@ -136,3 +136,4 @@ head = head_watchdog.js
|
|||
[test_xray_regexp.js]
|
||||
[test_resolve_dead_promise.js]
|
||||
[test_asyncLoadSubScriptError.js]
|
||||
[test_function_names.js]
|
||||
|
|
|
@ -159,8 +159,8 @@ HTTP == background-referrer.html background-referrer-ref.html
|
|||
== attachment-local-clipping-color-1.html attachment-local-clipping-color-1-ref.html
|
||||
== attachment-local-clipping-color-2.html attachment-local-clipping-color-1-ref.html # Same ref as the previous test.
|
||||
== attachment-local-clipping-color-3.html attachment-local-clipping-color-3-ref.html
|
||||
fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,14-14,1134-1134) == attachment-local-clipping-color-4.html attachment-local-clipping-color-4-ref.html
|
||||
fuzzy-if(skiaContent,1,400) fuzzy-if(webrender,14-14,1134-1134) == attachment-local-clipping-color-5.html attachment-local-clipping-color-4-ref.html
|
||||
fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,14-14,1119-1134) == attachment-local-clipping-color-4.html attachment-local-clipping-color-4-ref.html
|
||||
fuzzy-if(skiaContent,1,400) fuzzy-if(webrender,14-14,1119-1134) == attachment-local-clipping-color-5.html attachment-local-clipping-color-4-ref.html
|
||||
fuzzy(50,500) fuzzy-if(skiaContent,51,320) fails-if(webrender) == attachment-local-clipping-color-6.html attachment-local-clipping-color-6-ref.html
|
||||
|
||||
== attachment-local-clipping-image-1.html attachment-local-clipping-image-1-ref.html
|
||||
|
|
|
@ -52,7 +52,7 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html
|
|||
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html
|
||||
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html
|
||||
fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
|
||||
fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) fuzzy-if(d3d11&&advancedLayers,120,319) fuzzy-if(webrender,7-7,62-62) fuzzy-if(winWidget&&stylo,137,226-319) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
|
||||
fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) fuzzy-if(d3d11&&advancedLayers,120,319) fuzzy-if(webrender,7-7,59-62) fuzzy-if(winWidget&&stylo,137,226-319) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
|
||||
fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
|
||||
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
|
||||
fuzzy-if(cocoaWidget,1,4) fuzzy-if(d3d11&&advancedLayers,30,3) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
|
||||
|
|
|
@ -1138,7 +1138,7 @@ fails-if(!styloVsGecko) == 428810-3e-rtl-insets.html 428810-empty-rtl-insets-ref
|
|||
== 433700.html 433700-ref.html
|
||||
== 436356-1.html 436356-1-ref.html
|
||||
== 436356-2.html 436356-2-ref.html
|
||||
fuzzy-if(skiaContent,3,1) == 438537-1.html 438537-1-ref.html
|
||||
fuzzy-if(skiaContent,4,2) == 438537-1.html 438537-1-ref.html
|
||||
== 438981-1.xhtml about:blank
|
||||
== 438987-1.html 438987-1-ref.html
|
||||
fuzzy-if(skiaContent,1,3280) == 438987-2a.html 438987-2-ref.html
|
||||
|
@ -1663,7 +1663,7 @@ HTTP(..) == 635639-1.html 635639-1-ref.html
|
|||
HTTP(..) == 635639-2.html 635639-2-ref.html
|
||||
random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
|
||||
fuzzy-if(Android,8,500) == 637852-1.html 637852-1-ref.html
|
||||
fuzzy-if(Android,8,500) fuzzy-if(skiaContent,2,1) fuzzy-if(webrender,3,19) == 637852-2.html 637852-2-ref.html
|
||||
fuzzy-if(Android,8,500) fuzzy-if(skiaContent,3,1) fuzzy-if(webrender,3,19) == 637852-2.html 637852-2-ref.html
|
||||
fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html
|
||||
fails-if(webrender&&asyncPan) == 641770-1.html 641770-1-ref.html # bug 1374326 for webrender+APZ
|
||||
== 641856-1.html 641856-1-ref.html
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
== 318022-1.html 318022-1-ref.html
|
||||
== 403669-1.html 403669-1-ref.html
|
||||
== 381497-n.html 381497-f.html
|
||||
== test-async-print.html 272830-1-ref.html
|
||||
== test-async-paged.html 272830-1-ref.html
|
||||
== 129941-1a.html 129941-1-ref.html
|
||||
== 129941-1b.html 129941-1-ref.html
|
||||
== 129941-1c.html 129941-1-ref.html
|
||||
|
|
|
@ -565,6 +565,11 @@ pref("apz.overscroll.enabled", true);
|
|||
pref("apz.touch_move_tolerance", "0.03");
|
||||
pref("apz.touch_start_tolerance", "0.06");
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Temporary fix of Bug 1390145 for Fennec Nightly
|
||||
pref("apz.frame_delay.enabled", false);
|
||||
#endif
|
||||
|
||||
pref("layers.progressive-paint", true);
|
||||
pref("layers.low-precision-buffer", true);
|
||||
pref("layers.low-precision-resolution", "0.25");
|
||||
|
|
|
@ -131,18 +131,6 @@ public class GeckoAppShell
|
|||
return extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(final Thread thread, final Throwable exc) {
|
||||
if (GeckoThread.isState(GeckoThread.State.EXITING) ||
|
||||
GeckoThread.isState(GeckoThread.State.EXITED)) {
|
||||
// We've called System.exit. All exceptions after this point are Android
|
||||
// berating us for being nasty to it.
|
||||
return;
|
||||
}
|
||||
|
||||
super.uncaughtException(thread, exc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reportException(final Thread thread, final Throwable exc) {
|
||||
try {
|
||||
|
|
|
@ -79,17 +79,28 @@ public final class HardwareUtils {
|
|||
return SysInfo.getMemSize();
|
||||
}
|
||||
|
||||
private static String getPreferredAbi() {
|
||||
String abi = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
abi = Build.SUPPORTED_ABIS[0];
|
||||
}
|
||||
if (abi == null) {
|
||||
abi = Build.CPU_ABI;
|
||||
}
|
||||
return abi;
|
||||
}
|
||||
|
||||
public static boolean isARMSystem() {
|
||||
return Build.CPU_ABI != null && Build.CPU_ABI.equals("armeabi-v7a");
|
||||
return "armeabi-v7a".equals(getPreferredAbi());
|
||||
}
|
||||
|
||||
public static boolean isARM64System() {
|
||||
// 64-bit support was introduced in 21.
|
||||
return Build.VERSION.SDK_INT >= 21 && "arm64-v8a".equals(Build.SUPPORTED_ABIS[0]);
|
||||
return "arm64-v8a".equals(getPreferredAbi());
|
||||
}
|
||||
|
||||
public static boolean isX86System() {
|
||||
if (Build.CPU_ABI != null && Build.CPU_ABI.equals("x86")) {
|
||||
if ("x86".equals(getPreferredAbi())) {
|
||||
return true;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
|
@ -109,7 +120,7 @@ public final class HardwareUtils {
|
|||
// in which case CPU_ABI is not reliable.
|
||||
return "x86";
|
||||
}
|
||||
return Build.CPU_ABI;
|
||||
return getPreferredAbi();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +152,8 @@ public final class HardwareUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
Log.w(LOGTAG, "Unknown app/system ABI combination: " + BuildConfig.MOZ_APP_ABI + " / " + Build.CPU_ABI);
|
||||
Log.w(LOGTAG, "Unknown app/system ABI combination: " +
|
||||
BuildConfig.MOZ_APP_ABI + " / " + getRealAbi());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2020,7 +2020,6 @@ nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
|
|||
mLock.AssertCurrentThreadOwns();
|
||||
|
||||
NS_ASSERTION(mFD == fd, "wrong fd");
|
||||
SOCKET_LOG(("JIMB: ReleaseFD_Locked: mFDref = %" PRIuPTR "\n", mFDref));
|
||||
|
||||
if (--mFDref == 0) {
|
||||
if (gIOService->IsNetTearingDown() &&
|
||||
|
|
|
@ -18,28 +18,17 @@ pre, #log {
|
|||
<div id="trailing-space" class="spacer"></div>
|
||||
|
||||
<script>
|
||||
// Pick this number to be comfortably greater than the length of two frames at 60Hz.
|
||||
var timeSkew = 40;
|
||||
|
||||
var topWindowEntries = [];
|
||||
var iframeWindowEntries = [];
|
||||
var targetIframe;
|
||||
var topWindowTimeOnTestStart;
|
||||
var topWindowTimeBeforeCreatingIframe;
|
||||
var topWindowTimeBeforeNotification;
|
||||
var iframeWindowTimeBeforeNotification;
|
||||
var timeSkew;
|
||||
|
||||
function waitFor(numFrames, callback) {
|
||||
if (numFrames <= 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
window.requestAnimationFrame(waitFor.bind(null, numFrames - 1, callback));
|
||||
}
|
||||
|
||||
async_test(function(t) {
|
||||
topWindowTimeOnTestStart = performance.now();
|
||||
waitFor(3, function () {
|
||||
topWindowTimeBeforeCreatingIframe = performance.now();
|
||||
timeSkew = topWindowTimeBeforeCreatingIframe - topWindowTimeOnTestStart;
|
||||
t.step_timeout(function() {
|
||||
targetIframe = document.createElement("iframe");
|
||||
assert_true(!!targetIframe, "iframe exists");
|
||||
targetIframe.src = "resources/timestamp-subframe.html";
|
||||
|
@ -66,7 +55,7 @@ async_test(function(t) {
|
|||
runTestCycle(step1, "First rAF after iframe is loaded.");
|
||||
t.done();
|
||||
};
|
||||
});
|
||||
}, timeSkew);
|
||||
}, "Check that timestamps correspond to the to execution context that created the observer.");
|
||||
|
||||
function step1() {
|
||||
|
@ -84,16 +73,14 @@ function step2() {
|
|||
var topWindowTimeAfterNotification = performance.now();
|
||||
var iframeWindowTimeAfterNotification = targetIframe.contentWindow.performance.now();
|
||||
|
||||
// Test results are only significant if there's a gap between
|
||||
// top window time and iframe window time.
|
||||
assert_greater_than(topWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
|
||||
"Time ranges for top and iframe windows are disjoint. Times: " +
|
||||
[topWindowTimeOnTestStart, topWindowTimeBeforeCreatingIframe,
|
||||
topWindowTimeBeforeNotification, topWindowTimeAfterNotification,
|
||||
iframeWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
|
||||
topWindowEntries[1].time - topWindowTimeBeforeNotification,
|
||||
iframeWindowEntries[1].time - iframeWindowTimeBeforeNotification
|
||||
]);
|
||||
assert_approx_equals(
|
||||
topWindowEntries[1].time - topWindowTimeBeforeNotification,
|
||||
iframeWindowEntries[1].time - iframeWindowTimeBeforeNotification,
|
||||
// Since all intersections are computed in a tight loop between 2 frames,
|
||||
// an epsilon of 16ms (the length of one frame at 60Hz) turned out to be
|
||||
// reliable, even at slow frame rates.
|
||||
16,
|
||||
"Notification times are relative to the expected time origins");
|
||||
|
||||
assert_equals(topWindowEntries.length, 2, "Top window observer has two notifications.");
|
||||
assert_between_inclusive(
|
||||
|
|
|
@ -41,10 +41,6 @@ Cu.importGlobalProperties(["TextEncoder"]);
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/* globals processCount */
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount.extension");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
AddonManagerPrivate: "resource://gre/modules/AddonManager.jsm",
|
||||
|
@ -75,6 +71,7 @@ XPCOMUtils.defineLazyServiceGetters(this, {
|
|||
uuidGen: ["@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"],
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount.extension");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
|
||||
"extensions.webextensions.remote", false);
|
||||
|
||||
|
@ -231,8 +228,6 @@ var UninstallObserver = {
|
|||
init() {
|
||||
if (!this.initialized) {
|
||||
AddonManager.addAddonListener(this);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "leaveStorage", LEAVE_STORAGE_PREF, false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "leaveUuid", LEAVE_UUID_PREF, false);
|
||||
this.initialized = true;
|
||||
}
|
||||
},
|
||||
|
@ -252,7 +247,7 @@ var UninstallObserver = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.leaveStorage) {
|
||||
if (!Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false)) {
|
||||
// Clear browser.local.storage
|
||||
AsyncShutdown.profileChangeTeardown.addBlocker(
|
||||
`Clear Extension Storage ${addon.id}`,
|
||||
|
@ -277,7 +272,7 @@ var UninstallObserver = {
|
|||
Services.perms.removeFromPrincipal(principal, "persistent-storage");
|
||||
}
|
||||
|
||||
if (!this.leaveUuid) {
|
||||
if (!Services.prefs.getBoolPref(LEAVE_UUID_PREF, false)) {
|
||||
// Clear the entry in the UUID map
|
||||
UUIDMap.remove(addon.id);
|
||||
}
|
||||
|
@ -297,6 +292,7 @@ UninstallObserver.init();
|
|||
this.ExtensionData = class {
|
||||
constructor(rootURI) {
|
||||
this.rootURI = rootURI;
|
||||
this.resourceURL = rootURI.spec;
|
||||
|
||||
this.manifest = null;
|
||||
this.id = null;
|
||||
|
@ -529,67 +525,90 @@ this.ExtensionData = class {
|
|||
let normalized = Schemas.normalize(this.manifest, "manifest.WebExtensionManifest", context);
|
||||
if (normalized.error) {
|
||||
this.manifestError(normalized.error);
|
||||
} else {
|
||||
return normalized.value;
|
||||
return null;
|
||||
}
|
||||
|
||||
let manifest = normalized.value;
|
||||
|
||||
let id;
|
||||
try {
|
||||
if (manifest.applications.gecko.id) {
|
||||
id = manifest.applications.gecko.id;
|
||||
}
|
||||
} catch (e) {
|
||||
// Errors are handled by the type checks above.
|
||||
}
|
||||
|
||||
let apiNames = new Set();
|
||||
let dependencies = new Set();
|
||||
let hostPermissions = new Set();
|
||||
let permissions = new Set();
|
||||
|
||||
for (let perm of manifest.permissions) {
|
||||
if (perm === "geckoProfiler") {
|
||||
const acceptedExtensions = Services.prefs.getStringPref("extensions.geckoProfiler.acceptedExtensionIds", "");
|
||||
if (!acceptedExtensions.split(",").includes(id)) {
|
||||
this.manifestError("Only whitelisted extensions are allowed to access the geckoProfiler.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let type = classifyPermission(perm);
|
||||
if (type.origin) {
|
||||
let matcher = new MatchPattern(perm, {ignorePath: true});
|
||||
|
||||
perm = matcher.pattern;
|
||||
hostPermissions.add(perm);
|
||||
} else if (type.api) {
|
||||
apiNames.add(type.api);
|
||||
}
|
||||
|
||||
permissions.add(perm);
|
||||
}
|
||||
|
||||
// An extension always gets permission to its own url.
|
||||
if (this.id) {
|
||||
let matcher = new MatchPattern(this.getURL(), {ignorePath: true});
|
||||
hostPermissions.add(matcher.pattern);
|
||||
}
|
||||
|
||||
for (let api of apiNames) {
|
||||
dependencies.add(`${api}@experiments.addons.mozilla.org`);
|
||||
}
|
||||
|
||||
// Normalize all patterns to contain a single leading /
|
||||
let webAccessibleResources = (manifest.web_accessible_resources || [])
|
||||
.map(path => path.replace(/^\/*/, "/"));
|
||||
|
||||
return {apiNames, dependencies, hostPermissions, id, manifest, permissions,
|
||||
webAccessibleResources};
|
||||
});
|
||||
}
|
||||
|
||||
// Reads the extension's |manifest.json| file, and stores its
|
||||
// parsed contents in |this.manifest|.
|
||||
async loadManifest() {
|
||||
[this.manifest] = await Promise.all([
|
||||
let [manifestData] = await Promise.all([
|
||||
this.parseManifest(),
|
||||
Management.lazyInit(),
|
||||
]);
|
||||
|
||||
if (!this.manifest) {
|
||||
if (!manifestData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Do not override the add-on id that has been already assigned.
|
||||
if (!this.id && this.manifest.applications.gecko.id) {
|
||||
this.id = this.manifest.applications.gecko.id;
|
||||
}
|
||||
} catch (e) {
|
||||
// Errors are handled by the type checks above.
|
||||
// Do not override the add-on id that has been already assigned.
|
||||
if (!this.id) {
|
||||
this.id = manifestData.id;
|
||||
}
|
||||
|
||||
let whitelist = [];
|
||||
for (let perm of this.manifest.permissions) {
|
||||
if (perm === "geckoProfiler") {
|
||||
const acceptedExtensions = Services.prefs.getStringPref("extensions.geckoProfiler.acceptedExtensionIds", "");
|
||||
if (!acceptedExtensions.split(",").includes(this.id)) {
|
||||
this.manifestError("Only whitelisted extensions are allowed to access the geckoProfiler.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.manifest = manifestData.manifest;
|
||||
this.apiNames = manifestData.apiNames;
|
||||
this.dependencies = manifestData.dependencies;
|
||||
this.permissions = manifestData.permissions;
|
||||
|
||||
let type = classifyPermission(perm);
|
||||
if (type.origin) {
|
||||
let matcher = new MatchPattern(perm, {ignorePath: true});
|
||||
|
||||
whitelist.push(matcher);
|
||||
perm = matcher.pattern;
|
||||
} else if (type.api) {
|
||||
this.apiNames.add(type.api);
|
||||
}
|
||||
|
||||
this.permissions.add(perm);
|
||||
}
|
||||
|
||||
// An extension always gets permission to its own url.
|
||||
if (this.id) {
|
||||
let matcher = new MatchPattern(this.getURL(), {ignorePath: true});
|
||||
whitelist.push(matcher);
|
||||
}
|
||||
|
||||
this.whiteListedHosts = new MatchPatternSet(whitelist);
|
||||
|
||||
for (let api of this.apiNames) {
|
||||
this.dependencies.add(`${api}@experiments.addons.mozilla.org`);
|
||||
}
|
||||
this.webAccessibleResources = manifestData.webAccessibleResources.map(res => new MatchGlob(res));
|
||||
this.whiteListedHosts = new MatchPatternSet(manifestData.hostPermissions);
|
||||
|
||||
return this.manifest;
|
||||
}
|
||||
|
@ -947,23 +966,24 @@ this.Extension = class extends ExtensionData {
|
|||
() => super.parseManifest());
|
||||
}
|
||||
|
||||
loadManifest() {
|
||||
return super.loadManifest().then(manifest => {
|
||||
if (this.errors.length) {
|
||||
return Promise.reject({errors: this.errors});
|
||||
}
|
||||
async loadManifest() {
|
||||
let manifest = await super.loadManifest();
|
||||
|
||||
if (this.errors.length) {
|
||||
return Promise.reject({errors: this.errors});
|
||||
}
|
||||
|
||||
if (this.apiNames.size) {
|
||||
// Load Experiments APIs that this extension depends on.
|
||||
return Promise.all(
|
||||
Array.from(this.apiNames, api => ExtensionCommon.ExtensionAPIs.load(api))
|
||||
).then(apis => {
|
||||
for (let API of apis) {
|
||||
this.apis.push(new API(this));
|
||||
}
|
||||
let apis = await Promise.all(
|
||||
Array.from(this.apiNames, api => ExtensionCommon.ExtensionAPIs.load(api)));
|
||||
|
||||
return manifest;
|
||||
});
|
||||
});
|
||||
for (let API of apis) {
|
||||
this.apis.push(new API(this));
|
||||
}
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
// Representation of the extension to send to content
|
||||
|
@ -975,9 +995,9 @@ this.Extension = class extends ExtensionData {
|
|||
uuid: this.uuid,
|
||||
instanceId: this.instanceId,
|
||||
manifest: this.manifest,
|
||||
resourceURL: this.addonData.resourceURI.spec,
|
||||
resourceURL: this.resourceURL,
|
||||
baseURL: this.baseURI.spec,
|
||||
content_scripts: this.manifest.content_scripts || [], // eslint-disable-line camelcase
|
||||
contentScripts: this.contentScripts,
|
||||
webAccessibleResources: this.webAccessibleResources.map(res => res.glob),
|
||||
whiteListedHosts: this.whiteListedHosts.patterns.map(pat => pat.pattern),
|
||||
localeData: this.localeData.serialize(),
|
||||
|
@ -987,6 +1007,10 @@ this.Extension = class extends ExtensionData {
|
|||
};
|
||||
}
|
||||
|
||||
get contentScripts() {
|
||||
return this.manifest.content_scripts || [];
|
||||
}
|
||||
|
||||
broadcast(msg, data) {
|
||||
return new Promise(resolve => {
|
||||
let {ppmm} = Services;
|
||||
|
@ -1075,28 +1099,44 @@ this.Extension = class extends ExtensionData {
|
|||
return super.initLocale(locale);
|
||||
}
|
||||
|
||||
initUnlimitedStoragePermission() {
|
||||
const principal = this.principal;
|
||||
updatePermissions(reason) {
|
||||
const {principal} = this;
|
||||
|
||||
// Check if the site permission has already been set for the extension by the WebExtensions
|
||||
// internals (instead of being manually allowed by the user).
|
||||
const hasSitePermission = Services.perms.testPermissionFromPrincipal(
|
||||
principal, "WebExtensions-unlimitedStorage"
|
||||
);
|
||||
const testPermission = perm =>
|
||||
Services.perms.testPermissionFromPrincipal(principal, perm);
|
||||
|
||||
if (this.hasPermission("unlimitedStorage")) {
|
||||
// Set the indexedDB permission and a custom "WebExtensions-unlimitedStorage" to remember
|
||||
// that the permission hasn't been selected manually by the user.
|
||||
Services.perms.addFromPrincipal(principal, "WebExtensions-unlimitedStorage",
|
||||
Services.perms.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(principal, "indexedDB", Services.perms.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(principal, "persistent-storage", Services.perms.ALLOW_ACTION);
|
||||
} else if (hasSitePermission) {
|
||||
// Remove the indexedDB permission if it has been enabled using the
|
||||
// unlimitedStorage WebExtensions permissions.
|
||||
Services.perms.removeFromPrincipal(principal, "WebExtensions-unlimitedStorage");
|
||||
Services.perms.removeFromPrincipal(principal, "indexedDB");
|
||||
Services.perms.removeFromPrincipal(principal, "persistent-storage");
|
||||
// Only update storage permissions when the extension changes in
|
||||
// some way.
|
||||
if (reason !== "APP_STARTUP" && reason !== "APP_SHUTDOWN") {
|
||||
if (this.hasPermission("unlimitedStorage")) {
|
||||
// Set the indexedDB permission and a custom "WebExtensions-unlimitedStorage" to remember
|
||||
// that the permission hasn't been selected manually by the user.
|
||||
Services.perms.addFromPrincipal(principal, "WebExtensions-unlimitedStorage",
|
||||
Services.perms.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(principal, "indexedDB", Services.perms.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(principal, "persistent-storage", Services.perms.ALLOW_ACTION);
|
||||
} else {
|
||||
// Remove the indexedDB permission if it has been enabled using the
|
||||
// unlimitedStorage WebExtensions permissions.
|
||||
Services.perms.removeFromPrincipal(principal, "WebExtensions-unlimitedStorage");
|
||||
Services.perms.removeFromPrincipal(principal, "indexedDB");
|
||||
Services.perms.removeFromPrincipal(principal, "persistent-storage");
|
||||
}
|
||||
}
|
||||
|
||||
// Never change geolocation permissions at shutdown, since it uses a
|
||||
// session-only permission.
|
||||
if (reason !== "APP_SHUTDOWN") {
|
||||
if (this.hasPermission("geolocation")) {
|
||||
if (testPermission("geo") === Services.perms.UNKNOWN_ACTION) {
|
||||
Services.perms.addFromPrincipal(principal, "geo",
|
||||
Services.perms.ALLOW_ACTION,
|
||||
Services.perms.EXPIRE_SESSION);
|
||||
}
|
||||
} else if (reason !== "APP_STARTUP" &&
|
||||
testPermission("geo") === Services.perms.ALLOW_ACTION) {
|
||||
Services.perms.removeFromPrincipal(principal, "geo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1160,17 +1200,10 @@ this.Extension = class extends ExtensionData {
|
|||
{ignorePath: true});
|
||||
}
|
||||
|
||||
// Normalize all patterns to contain a single leading /
|
||||
let resources = (this.manifest.web_accessible_resources || [])
|
||||
.map(path => path.replace(/^\/*/, "/"));
|
||||
|
||||
this.webAccessibleResources = resources.map(res => new MatchGlob(res));
|
||||
|
||||
|
||||
this.policy.active = false;
|
||||
this.policy = processScript.initExtension(this.serialize(), this);
|
||||
this.policy = processScript.initExtension(this);
|
||||
|
||||
this.initUnlimitedStoragePermission();
|
||||
this.updatePermissions(this.startupReason);
|
||||
|
||||
// The "startup" Management event sent on the extension instance itself
|
||||
// is emitted just before the Management "startup" event,
|
||||
|
@ -1281,6 +1314,8 @@ this.Extension = class extends ExtensionData {
|
|||
|
||||
Services.ppmm.removeMessageListener(this.MESSAGE_EMIT_EVENT, this);
|
||||
|
||||
this.updatePermissions(this.shutdownReason);
|
||||
|
||||
if (!this.manifest) {
|
||||
this.policy.active = false;
|
||||
|
||||
|
|
|
@ -499,7 +499,7 @@ class BrowserExtensionContent extends EventEmitter {
|
|||
Services.cpmm.addMessageListener(this.MESSAGE_EMIT_EVENT, this);
|
||||
|
||||
defineLazyGetter(this, "scripts", () => {
|
||||
return data.content_scripts.map(scriptData => new ExtensionContent.Script(this, scriptData));
|
||||
return data.contentScripts.map(scriptData => new ExtensionContent.Script(this, scriptData));
|
||||
});
|
||||
|
||||
this.webAccessibleResources = data.webAccessibleResources.map(res => new MatchGlob(res));
|
||||
|
|
|
@ -941,7 +941,7 @@ class SchemaAPIManager extends EventEmitter {
|
|||
|
||||
this._modulesJSONLoaded = false;
|
||||
|
||||
this.schemaURLs = new Set();
|
||||
this.schemaURLs = new Map();
|
||||
|
||||
this.apis = new DefaultWeakMap(() => new Map());
|
||||
|
||||
|
@ -1002,7 +1002,10 @@ class SchemaAPIManager extends EventEmitter {
|
|||
this.modules.set(name, details);
|
||||
|
||||
if (details.schema) {
|
||||
this.schemaURLs.add(details.schema);
|
||||
let content = (details.scopes &&
|
||||
(details.scopes.includes("content_parent") ||
|
||||
details.scopes.includes("content_child")));
|
||||
this.schemaURLs.set(details.schema, {content});
|
||||
}
|
||||
|
||||
for (let event of details.events || []) {
|
||||
|
@ -1245,7 +1248,7 @@ class SchemaAPIManager extends EventEmitter {
|
|||
_createExtGlobal() {
|
||||
let global = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), {
|
||||
wantXrays: false,
|
||||
sandboxName: `Namespace of ext-*.js scripts for ${this.processType}`,
|
||||
sandboxName: `Namespace of ext-*.js scripts for ${this.processType} (from: resource://gre/modules/ExtensionCommon.jsm)`,
|
||||
});
|
||||
|
||||
Object.assign(global, {global, Cc, Ci, Cu, Cr, XPCOMUtils, ChromeWorker, ExtensionAPI, ExtensionCommon, MatchPattern, MatchPatternSet, StructuredCloneHolder, extensions: this});
|
||||
|
|
|
@ -118,13 +118,13 @@ let apiManager = new class extends SchemaAPIManager {
|
|||
|
||||
// Load order matters here. The base manifest defines types which are
|
||||
// extended by other schemas, so needs to be loaded first.
|
||||
return Schemas.load(BASE_SCHEMA).then(() => {
|
||||
return Schemas.load(BASE_SCHEMA, AppConstants.DEBUG).then(() => {
|
||||
let promises = [];
|
||||
for (let [/* name */, url] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCHEMAS)) {
|
||||
promises.push(Schemas.load(url));
|
||||
}
|
||||
for (let url of this.schemaURLs) {
|
||||
promises.push(Schemas.load(url));
|
||||
for (let [url, {content}] of this.schemaURLs) {
|
||||
promises.push(Schemas.load(url, content));
|
||||
}
|
||||
for (let url of schemaURLs) {
|
||||
promises.push(Schemas.load(url));
|
||||
|
@ -447,7 +447,7 @@ defineLazyGetter(ProxyContextParent.prototype, "apiObj", function() {
|
|||
});
|
||||
|
||||
defineLazyGetter(ProxyContextParent.prototype, "sandbox", function() {
|
||||
return Cu.Sandbox(this.principal);
|
||||
return Cu.Sandbox(this.principal, {sandboxName: this.uri.spec});
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -564,17 +564,26 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
|||
ParentAPIManager = {
|
||||
proxyContexts: new Map(),
|
||||
|
||||
parentMessageManagers: new Set(),
|
||||
|
||||
init() {
|
||||
Services.obs.addObserver(this, "message-manager-close");
|
||||
Services.obs.addObserver(this, "ipc:content-created");
|
||||
|
||||
Services.mm.addMessageListener("API:CreateProxyContext", this);
|
||||
Services.mm.addMessageListener("API:CloseProxyContext", this, true);
|
||||
Services.mm.addMessageListener("API:Call", this);
|
||||
Services.mm.addMessageListener("API:AddListener", this);
|
||||
Services.mm.addMessageListener("API:RemoveListener", this);
|
||||
|
||||
this.schemaHook = this.schemaHook.bind(this);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
attachMessageManager(extension, processMessageManager) {
|
||||
extension.parentMessageManager = processMessageManager;
|
||||
},
|
||||
|
||||
async observe(subject, topic, data) {
|
||||
if (topic === "message-manager-close") {
|
||||
let mm = subject;
|
||||
for (let [childId, context] of this.proxyContexts) {
|
||||
|
@ -589,6 +598,23 @@ ParentAPIManager = {
|
|||
extension.parentMessageManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.parentMessageManagers.delete(mm);
|
||||
} else if (topic === "ipc:content-created") {
|
||||
let mm = subject.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIMessageSender);
|
||||
if (mm.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE) {
|
||||
this.parentMessageManagers.add(mm);
|
||||
mm.sendAsyncMessage("Schema:Add", Schemas.schemaJSON);
|
||||
|
||||
Schemas.schemaHook = this.schemaHook;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
schemaHook(schemas) {
|
||||
for (let mm of this.parentMessageManagers) {
|
||||
mm.sendAsyncMessage("Schema:Add", schemas);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -648,7 +674,7 @@ ParentAPIManager = {
|
|||
if (!extension.parentMessageManager) {
|
||||
let expectedRemoteType = extension.remote ? E10SUtils.EXTENSION_REMOTE_TYPE : null;
|
||||
if (target.remoteType === expectedRemoteType) {
|
||||
extension.parentMessageManager = processMessageManager;
|
||||
this.attachMessageManager(extension, processMessageManager);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -236,25 +236,38 @@ class EventEmitter {
|
|||
|
||||
|
||||
/**
|
||||
* Triggers all listeners for the given event, and returns a promise
|
||||
* which resolves when all listeners have been called, and any
|
||||
* promises they have returned have likewise resolved.
|
||||
* Triggers all listeners for the given event. If any listeners return
|
||||
* a value, returns a promise which resolves when all returned
|
||||
* promises have resolved. Otherwise, returns undefined.
|
||||
*
|
||||
* @param {string} event
|
||||
* The name of the event to emit.
|
||||
* @param {any} args
|
||||
* Arbitrary arguments to pass to the listener functions, after
|
||||
* the event name.
|
||||
* @returns {Promise}
|
||||
* @returns {Promise?}
|
||||
*/
|
||||
emit(event, ...args) {
|
||||
let listeners = this[LISTENERS].get(event) || new Set();
|
||||
let listeners = this[LISTENERS].get(event);
|
||||
|
||||
let promises = Array.from(listeners, listener => {
|
||||
return runSafeSyncWithoutClone(listener, event, ...args);
|
||||
});
|
||||
if (listeners) {
|
||||
let promises = [];
|
||||
|
||||
return Promise.all(promises);
|
||||
for (let listener of listeners) {
|
||||
try {
|
||||
let result = listener(event, ...args);
|
||||
if (result !== undefined) {
|
||||
promises.push(result);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (promises.length) {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,16 +105,12 @@ const Cc = Components.classes;
|
|||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
|
||||
"resource://gre/modules/ExtensionUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "MessageManagerProxy",
|
||||
() => ExtensionUtils.MessageManagerProxy);
|
||||
const {
|
||||
MessageManagerProxy,
|
||||
} = ExtensionUtils;
|
||||
|
||||
/**
|
||||
* Handles the mapping and dispatching of messages to their registered
|
||||
|
@ -538,7 +534,11 @@ this.MessageChannel = {
|
|||
return Promise.resolve(); // Not expecting any reply.
|
||||
}
|
||||
|
||||
let deferred = PromiseUtils.defer();
|
||||
let deferred = {};
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
deferred.sender = recipient;
|
||||
deferred.messageManager = target;
|
||||
deferred.channelId = channelId;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче