Merge autoland to mozilla-central a=merge

This commit is contained in:
Razvan Maries 2019-11-20 06:00:05 +02:00
Родитель e5bd731a73 3906df9ebd
Коммит 22aa841729
89 изменённых файлов: 1136 добавлений и 1053 удалений

Просмотреть файл

@ -39,9 +39,10 @@ class ChildDevToolsPanel extends ExtensionCommon.EventEmitter {
this.id = id;
this._panelContext = null;
this.mm = context.messageManager;
this.mm.addMessageListener("Extension:DevToolsPanelShown", this);
this.mm.addMessageListener("Extension:DevToolsPanelHidden", this);
this.conduit = context.openConduit(this, {
id: this.id,
recv: ["PanelHidden", "PanelShown"],
});
}
get panelContext() {
@ -69,29 +70,11 @@ class ChildDevToolsPanel extends ExtensionCommon.EventEmitter {
return null;
}
receiveMessage({ name, data }) {
// Filter out any message that is not related to the id of this
// toolbox panel.
if (!data || data.toolboxPanelId !== this.id) {
recvPanelShown() {
// Ignore received call before the panel context exist.
if (!this.panelContext || !this.panelContext.contentWindow) {
return;
}
switch (name) {
case "Extension:DevToolsPanelShown":
// Filter out *Shown message received while the panel context do not yet
// exist.
if (!this.panelContext || !this.panelContext.contentWindow) {
return;
}
this.onParentPanelShown();
break;
case "Extension:DevToolsPanelHidden":
this.onParentPanelHidden();
break;
}
}
onParentPanelShown() {
const { document } = this.panelContext.contentWindow;
// Ensure that the onShown event is fired when the panel document has
@ -101,7 +84,7 @@ class ChildDevToolsPanel extends ExtensionCommon.EventEmitter {
});
}
onParentPanelHidden() {
recvPanelHidden() {
this.emit("hidden");
}
@ -140,9 +123,7 @@ class ChildDevToolsPanel extends ExtensionCommon.EventEmitter {
}
close() {
this.mm.removeMessageListener("Extension:DevToolsPanelShown", this);
this.mm.removeMessageListener("Extension:DevToolsPanelHidden", this);
this.conduit.close();
this._panelContext = null;
this.context = null;
}
@ -166,50 +147,23 @@ class ChildDevToolsInspectorSidebar extends ExtensionCommon.EventEmitter {
this.id = id;
this.mm = context.messageManager;
this.mm.addMessageListener("Extension:DevToolsInspectorSidebarShown", this);
this.mm.addMessageListener(
"Extension:DevToolsInspectorSidebarHidden",
this
);
this.conduit = context.openConduit(this, {
id: this.id,
recv: ["InspectorSidebarHidden", "InspectorSidebarShown"],
});
}
close() {
this.mm.removeMessageListener(
"Extension:DevToolsInspectorSidebarShown",
this
);
this.mm.removeMessageListener(
"Extension:DevToolsInspectorSidebarHidden",
this
);
this.conduit.close();
this.content = null;
}
receiveMessage({ name, data }) {
// Filter out any message that is not related to the id of this
// toolbox panel.
if (!data || data.inspectorSidebarId !== this.id) {
return;
}
switch (name) {
case "Extension:DevToolsInspectorSidebarShown":
this.onParentSidebarShown();
break;
case "Extension:DevToolsInspectorSidebarHidden":
this.onParentSidebarHidden();
break;
}
}
onParentSidebarShown() {
recvInspectorSidebarShown() {
// TODO: wait and emit sidebar contentWindow once sidebar.setPage is supported.
this.emit("shown");
}
onParentSidebarHidden() {
recvInspectorSidebarHidden() {
this.emit("hidden");
}

Просмотреть файл

@ -10,6 +10,12 @@ var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BroadcastConduit",
"resource://gre/modules/ConduitsParent.jsm"
);
var { IconDetails, watchExtensionProxyContextLoad } = ExtensionParent;
var { promiseDocumentLoaded } = ExtensionUtils;
@ -120,6 +126,11 @@ class ParentDevToolsPanel extends BaseDevToolsPanel {
this.context.callOnClose(this);
this.conduit = new BroadcastConduit(this, {
id: `${this.id}-parent`,
send: ["PanelHidden", "PanelShown"],
});
this.onToolboxPanelSelect = this.onToolboxPanelSelect.bind(this);
this.onToolboxHostWillChange = this.onToolboxHostWillChange.bind(this);
this.onToolboxHostChanged = this.onToolboxHostChanged.bind(this);
@ -201,12 +212,7 @@ class ParentDevToolsPanel extends BaseDevToolsPanel {
// Fires a panel.onHidden event before destroying the browser element because
// the toolbox hosts is changing.
if (this.visible) {
this.context.parentMessageManager.sendAsyncMessage(
"Extension:DevToolsPanelHidden",
{
toolboxPanelId: this.id,
}
);
this.conduit.sendPanelHidden(this.id);
}
this.destroyBrowserElement();
@ -222,13 +228,7 @@ class ParentDevToolsPanel extends BaseDevToolsPanel {
// object to the extension page that has created the devtools panel).
if (this.visible) {
await this.waitTopLevelContext;
this.context.parentMessageManager.sendAsyncMessage(
"Extension:DevToolsPanelShown",
{
toolboxPanelId: this.id,
}
);
this.conduit.sendPanelShown(this.id);
}
}
}
@ -243,16 +243,11 @@ class ParentDevToolsPanel extends BaseDevToolsPanel {
if (!this.visible && id === this.id) {
this.visible = true;
this.conduit.sendPanelShown(this.id);
} else if (this.visible && id !== this.id) {
this.visible = false;
this.conduit.sendPanelHidden(this.id);
}
const extensionMessage = `Extension:DevToolsPanel${
this.visible ? "Shown" : "Hidden"
}`;
this.context.parentMessageManager.sendAsyncMessage(extensionMessage, {
toolboxPanelId: this.id,
});
}
close() {
@ -262,6 +257,8 @@ class ParentDevToolsPanel extends BaseDevToolsPanel {
throw new Error("Unable to destroy a closed devtools panel");
}
this.conduit.close();
// Explicitly remove the panel if it is registered and the toolbox is not
// closing itself.
if (this.panelAdded && toolbox.isToolRegistered(this.id)) {
@ -360,6 +357,11 @@ class ParentDevToolsInspectorSidebar extends BaseDevToolsPanel {
this.context.callOnClose(this);
this.conduit = new BroadcastConduit(this, {
id: `${this.id}-parent`,
send: ["InspectorSidebarHidden", "InspectorSidebarShown"],
});
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onSidebarCreated = this.onSidebarCreated.bind(this);
this.onExtensionPageMount = this.onExtensionPageMount.bind(this);
@ -393,6 +395,8 @@ class ParentDevToolsInspectorSidebar extends BaseDevToolsPanel {
throw new Error("Unable to close a destroyed DevToolsSelectionObserver");
}
this.conduit.close();
if (this.extensionSidebar) {
this.extensionSidebar.off(
"extension-page-mount",
@ -476,20 +480,10 @@ class ParentDevToolsInspectorSidebar extends BaseDevToolsPanel {
if (!this.visible && id === this.id) {
this.visible = true;
this.context.parentMessageManager.sendAsyncMessage(
"Extension:DevToolsInspectorSidebarShown",
{
inspectorSidebarId: this.id,
}
);
this.conduit.sendInspectorSidebarShown(this.id);
} else if (this.visible && id !== this.id) {
this.visible = false;
this.context.parentMessageManager.sendAsyncMessage(
"Extension:DevToolsInspectorSidebarHidden",
{
inspectorSidebarId: this.id,
}
);
this.conduit.sendInspectorSidebarHidden(this.id);
}
}

Просмотреть файл

@ -114,8 +114,7 @@ support-files = !/browser/components/places/tests/browser/head.js
[browser_ext_devtools_inspectedWindow_eval_bindings.js]
[browser_ext_devtools_inspectedWindow_reload.js]
[browser_ext_devtools_network.js]
fail-if = fission
skip-if = os == 'linux' || (os == 'mac' && debug) || (debug && os == 'win' && bits == 64) # Bug1570478
skip-if = fission || os == 'linux' || (os == 'mac' && debug) || (debug && os == 'win' && bits == 64) # Bug1570478
[browser_ext_devtools_page.js]
[browser_ext_devtools_page_incognito.js]
[browser_ext_devtools_panel.js]

Просмотреть файл

@ -22,12 +22,10 @@ add_task(async function testExecuteScriptAtOnUpdated() {
let ignore = false;
let url;
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (
url &&
changeInfo.status === "loading" &&
tab.url === url &&
!ignore
) {
if (ignore) {
return;
}
if (url && changeInfo.status === "loading" && tab.url === url) {
ignore = true;
browser.tabs
.executeScript(tabId, {

Просмотреть файл

@ -18,12 +18,6 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/ExtensionCommon.jsm"
);
const { PromiseTestUtils } = ChromeUtils.import(
"resource://testing-common/PromiseTestUtils.jsm"
);
PromiseTestUtils.whitelistRejectionsGlobally(/Message manager disconnected/);
add_task(async function test_delete() {
function background() {
let historyClearedCount = 0;
@ -502,7 +496,7 @@ add_task(async function test_add_url() {
});
add_task(async function test_get_visits() {
function background() {
async function background() {
const TEST_DOMAIN = "http://example.com/";
const FIRST_DATE = Date.now();
const INITIAL_DETAILS = {
@ -513,7 +507,7 @@ add_task(async function test_get_visits() {
let visitIds = new Set();
function checkVisit(visit, expected) {
async function checkVisit(visit, expected) {
visitIds.add(visit.visitId);
browser.test.assertEq(
expected.visitTime,
@ -525,67 +519,52 @@ add_task(async function test_get_visits() {
visit.transition,
"visit has the correct transition"
);
browser.history.search({ text: expected.url }).then(results => {
// all results will have the same id, so we only need to use the first one
browser.test.assertEq(
results[0].id,
visit.id,
"visit has the correct id"
);
});
let results = await browser.history.search({ text: expected.url });
// all results will have the same id, so we only need to use the first one
browser.test.assertEq(
results[0].id,
visit.id,
"visit has the correct id"
);
}
let details = Object.assign({}, INITIAL_DETAILS);
browser.history
.addUrl(details)
.then(() => {
return browser.history.getVisits({ url: details.url });
})
.then(results => {
browser.test.assertEq(
1,
results.length,
"the expected number of visits were returned"
);
checkVisit(results[0], details);
details.url = `${TEST_DOMAIN}/1/`;
return browser.history.addUrl(details);
})
.then(() => {
return browser.history.getVisits({ url: details.url });
})
.then(results => {
browser.test.assertEq(
1,
results.length,
"the expected number of visits were returned"
);
checkVisit(results[0], details);
details.visitTime = FIRST_DATE - 1000;
details.transition = "typed";
return browser.history.addUrl(details);
})
.then(() => {
return browser.history.getVisits({ url: details.url });
})
.then(results => {
browser.test.assertEq(
2,
results.length,
"the expected number of visits were returned"
);
checkVisit(results[0], INITIAL_DETAILS);
checkVisit(results[1], details);
})
.then(() => {
browser.test.assertEq(
3,
visitIds.size,
"each visit has a unique visitId"
);
browser.test.notifyPass("get-visits");
});
await browser.history.addUrl(details);
let results = await browser.history.getVisits({ url: details.url });
browser.test.assertEq(
1,
results.length,
"the expected number of visits were returned"
);
await checkVisit(results[0], details);
details.url = `${TEST_DOMAIN}/1/`;
await browser.history.addUrl(details);
results = await browser.history.getVisits({ url: details.url });
browser.test.assertEq(
1,
results.length,
"the expected number of visits were returned"
);
await checkVisit(results[0], details);
details.visitTime = FIRST_DATE - 1000;
details.transition = "typed";
await browser.history.addUrl(details);
results = await browser.history.getVisits({ url: details.url });
browser.test.assertEq(
2,
results.length,
"the expected number of visits were returned"
);
await checkVisit(results[0], INITIAL_DETAILS);
await checkVisit(results[1], details);
browser.test.assertEq(3, visitIds.size, "each visit has a unique visitId");
await browser.test.notifyPass("get-visits");
}
let extension = ExtensionTestUtils.loadExtension({

Просмотреть файл

@ -62,7 +62,7 @@
next="importItems">
<description control="profiles">&selectProfile.label;</description>
<radiogroup id="profiles" align="left"/>
<radiogroup id="profiles" align="start"/>
</wizardpage>
<wizardpage id="importItems" pageid="importItems" label="&importItems.title;"
@ -70,20 +70,20 @@
oncommand="MigrationWizard.onImportItemCommand();">
<description control="dataSources">&importItems.label;</description>
<vbox id="dataSources" style="overflow: auto; -moz-appearance: listbox" align="left" flex="1" role="group"/>
<vbox id="dataSources" style="overflow: auto; -moz-appearance: listbox" align="start" flex="1" role="group"/>
</wizardpage>
<wizardpage id="migrating" pageid="migrating" label="&migrating.title;"
next="done">
<description control="migratingItems">&migrating.label;</description>
<vbox id="migratingItems" style="overflow: auto;" align="left" role="group"/>
<vbox id="migratingItems" style="overflow: auto;" align="start" role="group"/>
</wizardpage>
<wizardpage id="done" pageid="done" label="&done.title;">
<description control="doneItems">&done.label;</description>
<vbox id="doneItems" style="overflow: auto;" align="left" role="group"/>
<vbox id="doneItems" style="overflow: auto;" align="start" role="group"/>
</wizardpage>
</wizard>

Просмотреть файл

@ -44,6 +44,7 @@ Please note that some targeting attributes require stricter controls on the tele
* [platformName](#platformname)
* [personalizedCfrScores](#personalizedcfrscores)
* [personalizedCfrThreshold](#personalizedcfrthreshold)
* [messageImpressions](#messageimpressions)
## Detailed usage
@ -615,4 +616,23 @@ See more in [CFR Machine Learning Experiment](https://bugzilla.mozilla.org/show_
```
declare const personalizedCfrThreshold = float;
```
```
### `messageImpressions`
Dictionary that maps message ids to impression timestamps. Timestamps are stored in
consecutive order. Can be used to detect first impression of a message, number of
impressions. Can be used in targeting to show a message if another message has been
seen.
Impressions are used for frequency capping so we only store them if the message has
`frequency` configured.
Impressions for badges might not work as expected: we add a badge for every opened
window so the number of impressions stored might be higher than expected. Additionally
not all badges have `frequency` cap so `messageImpressions` might not be defined.
Badge impressions should not be used for targeting.
#### Definition
```
declare const messageImpressions: { [key: string]: Array<UnixEpochNumber> };
```

Просмотреть файл

@ -1,6 +1,6 @@
# Guide to targeting with JEXL
For a more in-depth explanation of JEXL syntax you can read the [Normady project docs](https://normandy.readthedocs.io/en/stable/user/filters.html#jexl-basics).
For a more in-depth explanation of JEXL syntax you can read the [Normady project docs](https://mozilla.github.io/normandy/user/filters.html?highlight=jexl).
### How to write JEXL targeting expressions
A message needs to contain the `targeting` property (JEXL string) which is evaluated against the provided attributes.

Просмотреть файл

@ -265,6 +265,11 @@ class _ToolbarBadgeHub {
toolbarbutton.addEventListener("keypress", this.removeAllNotifications);
this.state = { notification: { id: message.id } };
// Impression should be added when the badge becomes visible
this._addImpression(message);
// Send a telemetry ping when adding the notification badge
this.sendUserEventTelemetry("IMPRESSION", message);
return toolbarbutton;
}
@ -278,11 +283,6 @@ class _ToolbarBadgeHub {
return;
}
// Impression should be added when the badge becomes visible
this._addImpression(message);
// Send a telemetry ping when adding the notification badge
this.sendUserEventTelemetry("IMPRESSION", message);
EveryWindow.registerCallback(
this.id,
win => {

Просмотреть файл

@ -74,7 +74,11 @@ describe("ASRTargeting docs", () => {
// whitelist includes targeting attributes that are not implemented by
// ASRTargetingAttributes. For example trigger context passed to the evaluation
// context in when a trigger runs or ASRouter state used in the evaluation.
const whitelist = ["personalizedCfrThreshold", "personalizedCfrScores"];
const whitelist = [
"personalizedCfrThreshold",
"personalizedCfrScores",
"messageImpressions",
];
for (const targetingParam of DOCS_TARGETING_HEADINGS.filter(
doc => !whitelist.includes(doc)
)) {

Просмотреть файл

@ -206,7 +206,11 @@ describe("ToolbarBadgeHub", () => {
describe("addToolbarNotification", () => {
let target;
let fakeDocument;
beforeEach(() => {
beforeEach(async () => {
await instance.init(sandbox.stub().resolves(), {
addImpression: fakeAddImpression,
dispatch: fakeDispatch,
});
fakeDocument = {
getElementById: sandbox.stub().returns(fakeElement),
createElement: sandbox.stub().returns(fakeElement),
@ -214,6 +218,9 @@ describe("ToolbarBadgeHub", () => {
};
target = { ...fakeWindow, browser: { ownerDocument: fakeDocument } };
});
afterEach(() => {
instance.uninit();
});
it("shouldn't do anything if target element is not found", () => {
fakeDocument.getElementById.returns(null);
instance.addToolbarNotification(target, fxaMessage);
@ -296,6 +303,23 @@ describe("ToolbarBadgeHub", () => {
whatsnewMessage.content.badgeDescription.string_id
);
});
it("should add an impression for the message", () => {
instance.addToolbarNotification(target, whatsnewMessage);
assert.calledOnce(instance._addImpression);
assert.calledWithExactly(instance._addImpression, whatsnewMessage);
});
it("should send an impression ping", async () => {
sandbox.stub(instance, "sendUserEventTelemetry");
instance.addToolbarNotification(target, whatsnewMessage);
assert.calledOnce(instance.sendUserEventTelemetry);
assert.calledWithExactly(
instance.sendUserEventTelemetry,
"IMPRESSION",
whatsnewMessage
);
});
});
describe("registerBadgeNotificationListener", () => {
let msg_no_delay;
@ -317,12 +341,6 @@ describe("ToolbarBadgeHub", () => {
afterEach(() => {
instance.uninit();
});
it("should add an impression for the message", () => {
instance.registerBadgeNotificationListener(msg_no_delay);
assert.calledOnce(instance._addImpression);
assert.calledWithExactly(instance._addImpression, msg_no_delay);
});
it("should register a callback that adds/removes the notification", () => {
instance.registerBadgeNotificationListener(msg_no_delay);
@ -356,18 +374,6 @@ describe("ToolbarBadgeHub", () => {
assert.calledOnce(instance.removeToolbarNotification);
assert.calledWithExactly(instance.removeToolbarNotification, fakeElement);
});
it("should send an impression", async () => {
sandbox.stub(instance, "sendUserEventTelemetry");
instance.registerBadgeNotificationListener(msg_no_delay);
assert.calledOnce(instance.sendUserEventTelemetry);
assert.calledWithExactly(
instance.sendUserEventTelemetry,
"IMPRESSION",
msg_no_delay
);
});
it("should unregister notifications when forcing a badge via devtools", () => {
instance.registerBadgeNotificationListener(msg_no_delay, { force: true });

Просмотреть файл

@ -47,7 +47,7 @@
</tree>
</vbox>
<hbox class="actionButtons" align="right" flex="1">
<hbox class="actionButtons" align="end" flex="1">
<button oncommand="window.close();" icon="close"
data-l10n-id="blocklist-button-cancel"/>
<button id="btnApplyChanges" oncommand="gBlocklistManager.onApplyChanges();" icon="save"

Просмотреть файл

@ -41,7 +41,7 @@
</vbox>
</vbox>
<hbox class="actionButtons" align="right" flex="1">
<hbox class="actionButtons" align="end" flex="1">
<button id="cancelButton" icon="close"
data-l10n-id="clear-site-data-cancel"/>
<button id="clearButton" icon="save"

Просмотреть файл

@ -73,7 +73,7 @@
<html:input id="networkProxyHTTP" type="text" style="-moz-box-flex: 1;"
preference="network.proxy.http"/>
<label data-l10n-id="connection-proxy-http-port" control="networkProxyHTTP_Port" />
<html:input id="networkProxyHTTP_Port" class="proxy-port-input" hidespinbuttons="true" type="number" min="0" max="65535"
<html:input id="networkProxyHTTP_Port" class="proxy-port-input input-number-mozbox" hidespinbuttons="true" type="number" min="0" max="65535"
preference="network.proxy.http_port"/>
</hbox>
<hbox/>
@ -87,7 +87,7 @@
<hbox align="center">
<html:input id="networkProxySSL" type="text" style="-moz-box-flex: 1;" preference="network.proxy.ssl"/>
<label data-l10n-id="connection-proxy-ssl-port" control="networkProxySSL_Port" />
<html:input id="networkProxySSL_Port" class="proxy-port-input" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
<html:input id="networkProxySSL_Port" class="proxy-port-input input-number-mozbox" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
preference="network.proxy.ssl_port"/>
</hbox>
<hbox pack="end">
@ -96,7 +96,7 @@
<hbox align="center">
<html:input id="networkProxyFTP" type="text" style="-moz-box-flex: 1;" preference="network.proxy.ftp"/>
<label data-l10n-id="connection-proxy-ftp-port" control="networkProxyFTP_Port"/>
<html:input id="networkProxyFTP_Port" class="proxy-port-input" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
<html:input id="networkProxyFTP_Port" class="proxy-port-input input-number-mozbox" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
preference="network.proxy.ftp_port"/>
</hbox>
<hbox pack="end">
@ -105,7 +105,7 @@
<hbox align="center">
<html:input id="networkProxySOCKS" type="text" style="-moz-box-flex: 1;" preference="network.proxy.socks"/>
<label data-l10n-id="connection-proxy-socks-port" control="networkProxySOCKS_Port"/>
<html:input id="networkProxySOCKS_Port" class="proxy-port-input" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
<html:input id="networkProxySOCKS_Port" class="proxy-port-input input-number-mozbox" hidespinbuttons="true" type="number" min="0" max="65535" size="5"
preference="network.proxy.socks_port"/>
</hbox>
<spacer/>

Просмотреть файл

@ -45,7 +45,7 @@
</hbox>
</vbox>
<hbox class="actionButtons" align="right" flex="1">
<hbox class="actionButtons" align="end" flex="1">
<button id="btnApplyChanges" disabled="true" oncommand="gContainersManager.onApplyChanges();" icon="save"
data-l10n-id="containers-button-done"/>
</hbox>

Просмотреть файл

@ -65,7 +65,7 @@ let gContainersPane = {
let containerButtons = document.createXULElement("hbox");
containerButtons.className = "container-buttons";
containerButtons.setAttribute("flex", 1);
containerButtons.setAttribute("align", "right");
containerButtons.setAttribute("align", "end");
item.appendChild(containerButtons);
let prefsButton = document.createXULElement("button");

Просмотреть файл

@ -59,7 +59,7 @@
onselect="gPermissionManager.onPermissionSelect();"/>
</vbox>
<hbox class="actionButtons" align="left" flex="1">
<hbox class="actionButtons" align="start" flex="1">
<button id="removePermission" disabled="true"
data-l10n-id="permissions-remove"
icon="remove"
@ -70,7 +70,7 @@
oncommand="gPermissionManager.onAllPermissionsDelete();"/>
</hbox>
<spacer flex="1"/>
<hbox class="actionButtons" align="right" flex="1">
<hbox class="actionButtons" align="end" flex="1">
<button oncommand="window.close();" icon="close"
data-l10n-id="permissions-button-cancel" />
<button id="btnApplyChanges" oncommand="gPermissionManager.onApplyChanges();" icon="save"

Просмотреть файл

@ -57,7 +57,7 @@
onselect="gSitePermissionsManager.onPermissionSelect();"/>
</vbox>
<hbox class="actionButtons" align="left" flex="1">
<hbox class="actionButtons" align="start" flex="1">
<button id="removePermission" disabled="true"
data-l10n-id="permissions-remove"
icon="remove"
@ -79,7 +79,7 @@
class="extension-controlled-button accessory-button"
data-l10n-id="disable-extension"/>
</hbox>
<hbox class="actionButtons" align="right" flex="1">
<hbox class="actionButtons" align="end" flex="1">
<button oncommand="window.close();" icon="close" id="cancel"
data-l10n-id="permissions-button-cancel" />
<button id="btnApplyChanges" oncommand="gSitePermissionsManager.onApplyChanges();" icon="save"

Просмотреть файл

@ -76,7 +76,7 @@
#ifdef XP_MACOSX
<separator/>
<hbox align="right">
<hbox align="end">
<button id="setDesktopBackground"
label="&setDesktopBackground.title;"
oncommand="gSetBackground.setDesktopBackground();"/>

Просмотреть файл

@ -296,6 +296,13 @@ class TouchBarHelper {
layoutItems.appendElement(input);
}
// Every input must be updated at least once so that all assets (titles,
// icons) are loaded. We keep track of which inputs haven't updated and
// run an update on them after the first location change.
this._inputsNotUpdated = new Set(Object.keys(kBuiltInInputs));
// This is a temporary workaround until bug 1596723 is resolved.
this._inputsNotUpdated.delete("SearchPopover");
return layoutItems;
}
@ -356,6 +363,9 @@ class TouchBarHelper {
kBuiltInInputs[inputName].localTitle = result; // Cache result.
// Checking TouchBarHelper.window since this callback can fire after all windows are closed.
if (TouchBarHelper.window) {
if (this._inputsNotUpdated) {
this._inputsNotUpdated.delete(inputName);
}
gTouchBarUpdater.updateTouchBarInputs(TouchBarHelper.baseWindow, [
item,
]);
@ -367,22 +377,23 @@ class TouchBarHelper {
/**
* Fetches a specific Touch Bar Input by name and updates it on the Touch Bar.
* @param {string} inputName
* A key to a value in the kBuiltInInputs object in this file.
* @param {...*} [otherInputs] (optional)
* Additional keys to values in the kBuiltInInputs object in this file.
* @param {...*} inputNames
* A key/keys to a value/values in the kBuiltInInputs object in this file.
*/
_updateTouchBarInputs(...inputNames) {
if (!TouchBarHelper.window) {
if (!TouchBarHelper.window || !inputNames.length) {
return;
}
let inputs = [];
for (let inputName of inputNames) {
for (let inputName of new Set(inputNames)) {
let input = this.getTouchBarInput(inputName);
if (!input) {
continue;
}
if (this._inputsNotUpdated) {
this._inputsNotUpdated.delete(inputName);
}
inputs.push(input);
}
@ -419,7 +430,12 @@ class TouchBarHelper {
.canGoBack;
kBuiltInInputs.Forward.disabled = !TouchBarHelper.window.gBrowser
.canGoForward;
this._updateTouchBarInputs("ReaderView", "Back", "Forward");
this._updateTouchBarInputs(
"ReaderView",
"Back",
"Forward",
...this._inputsNotUpdated
);
break;
case "bookmark-icon-updated":
data == "starred"

Просмотреть файл

@ -9,7 +9,6 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
Preferences: "resource://gre/modules/Preferences.jsm",
ProfileAge: "resource://gre/modules/ProfileAge.jsm",
Services: "resource://gre/modules/Services.jsm",
ResetProfile: "resource://gre/modules/ResetProfile.jsm",
@ -28,12 +27,6 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIUpdateManager"
);
XPCOMUtils.defineLazyGetter(
this,
"defaultPreferences",
() => new Preferences({ defaultBranch: true })
);
function updateStateIs(prefix) {
let update = updateManager.activeUpdate;
return !!(update && update.state.startsWith(prefix));
@ -44,10 +37,6 @@ this.experiments_urlbar = class extends ExtensionAPI {
return {
experiments: {
urlbar: {
engagementTelemetry: this._getDefaultSettingsAPI(
"browser.urlbar.eventTelemetry.enabled"
),
isBrowserShowingNotification() {
let window = BrowserWindowTracker.getTopWindow();
@ -134,10 +123,6 @@ this.experiments_urlbar = class extends ExtensionAPI {
return (await age.firstUse) || age.created;
},
openViewOnFocus: this._getDefaultSettingsAPI(
"browser.urlbar.openViewOnFocus"
),
restartBrowser() {
// Notify all windows that an application quit has been requested.
let cancelQuit = Cc[
@ -173,40 +158,4 @@ this.experiments_urlbar = class extends ExtensionAPI {
},
};
}
onShutdown() {
// Reset the default prefs. This is necessary because
// ExtensionPreferencesManager doesn't properly reset prefs set on the
// default branch. See bug 1586543, bug 1578513, bug 1578508.
if (this._initialDefaultPrefs) {
for (let [pref, value] of this._initialDefaultPrefs.entries()) {
defaultPreferences.set(pref, value);
}
}
}
_getDefaultSettingsAPI(pref) {
return {
get: details => {
return { value: Preferences.get(pref) };
},
set: details => {
if (!this._initialDefaultPrefs) {
this._initialDefaultPrefs = new Map();
}
if (!this._initialDefaultPrefs.has(pref)) {
this._initialDefaultPrefs.set(pref, defaultPreferences.get(pref));
}
defaultPreferences.set(pref, details.value);
return true;
},
clear: details => {
if (this._initialDefaultPrefs && this._initialDefaultPrefs.has(pref)) {
defaultPreferences.set(pref, this._initialDefaultPrefs.get(pref));
return true;
}
return false;
},
};
}
};

Просмотреть файл

@ -9,9 +9,7 @@ support-files =
../schema.json
head.js
[browser_ext_urlbar_engagementTelemetry.js]
[browser_ext_urlbar_isBrowserShowingNotification.js]
[browser_ext_urlbar_isBrowserUpdateReadyToInstall.js]
[browser_ext_urlbar_lastBrowserUpdateDate.js]
[browser_ext_urlbar_openViewOnFocus.js]
[browser_ext_urlbar_resetBrowser.js]

Просмотреть файл

@ -1,18 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global browser */
// This tests the browser.experiments.urlbar.engagementTelemetry WebExtension
// Experiment API.
"use strict";
add_settings_tasks("browser.urlbar.eventTelemetry.enabled", () => {
browser.test.onMessage.addListener(async (method, arg) => {
let result = await browser.experiments.urlbar.engagementTelemetry[method](
arg
);
browser.test.sendMessage("done", result);
});
});

Просмотреть файл

@ -1,16 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global browser */
// This tests the browser.experiments.urlbar.openViewOnFocus WebExtension
// Experiment API.
"use strict";
add_settings_tasks("browser.urlbar.openViewOnFocus", () => {
browser.test.onMessage.addListener(async (method, arg) => {
let result = await browser.experiments.urlbar.openViewOnFocus[method](arg);
browser.test.sendMessage("done", result);
});
});

Просмотреть файл

@ -25,10 +25,6 @@ Services.scriptloader.loadSubScript(
this
);
XPCOMUtils.defineLazyModuleGetters(this, {
Preferences: "resource://gre/modules/Preferences.jsm",
});
const SCHEMA_BASENAME = "schema.json";
const SCRIPT_BASENAME = "api.js";
@ -68,140 +64,3 @@ async function loadExtension(background) {
await ext.startup();
return ext;
}
function add_settings_tasks(prefName, background) {
let defaultPreferences = new Preferences({ defaultBranch: true });
let originalValue = defaultPreferences.get(prefName);
registerCleanupFunction(() => {
defaultPreferences.set(prefName, originalValue);
});
add_task(async function get() {
let ext = await loadExtension(background);
defaultPreferences.set(prefName, false);
ext.sendMessage("get", {});
let result = await ext.awaitMessage("done");
Assert.strictEqual(result.value, false);
defaultPreferences.set(prefName, true);
ext.sendMessage("get", {});
result = await ext.awaitMessage("done");
Assert.strictEqual(result.value, true);
await ext.unload();
});
add_task(async function set() {
let ext = await loadExtension(background);
defaultPreferences.set(prefName, false);
ext.sendMessage("set", { value: true });
let result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), true);
ext.sendMessage("set", { value: false });
result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), false);
await ext.unload();
});
add_task(async function clear() {
// no set()
defaultPreferences.set(prefName, false);
let ext = await loadExtension(background);
ext.sendMessage("clear", {});
let result = await ext.awaitMessage("done");
Assert.strictEqual(result, false);
Assert.strictEqual(defaultPreferences.get(prefName), false);
await ext.unload();
// false -> true
defaultPreferences.set(prefName, false);
ext = await loadExtension(background);
ext.sendMessage("set", { value: true });
await ext.awaitMessage("done");
ext.sendMessage("clear", {});
result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), false);
await ext.unload();
// true -> false
defaultPreferences.set(prefName, true);
ext = await loadExtension(background);
ext.sendMessage("set", { value: false });
await ext.awaitMessage("done");
ext.sendMessage("clear", {});
result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), true);
await ext.unload();
// false -> false
defaultPreferences.set(prefName, false);
ext = await loadExtension(background);
ext.sendMessage("set", { value: false });
await ext.awaitMessage("done");
ext.sendMessage("clear", {});
result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), false);
await ext.unload();
// true -> true
defaultPreferences.set(prefName, true);
ext = await loadExtension(background);
ext.sendMessage("set", { value: true });
await ext.awaitMessage("done");
ext.sendMessage("clear", {});
result = await ext.awaitMessage("done");
Assert.strictEqual(result, true);
Assert.strictEqual(defaultPreferences.get(prefName), true);
await ext.unload();
});
add_task(async function shutdown() {
// no set()
defaultPreferences.set(prefName, false);
let ext = await loadExtension(background);
await ext.unload();
Assert.strictEqual(defaultPreferences.get(prefName), false);
// false -> true
defaultPreferences.set(prefName, false);
ext = await loadExtension(background);
ext.sendMessage("set", { value: true });
await ext.awaitMessage("done");
await ext.unload();
Assert.strictEqual(defaultPreferences.get(prefName), false);
// true -> false
defaultPreferences.set(prefName, true);
ext = await loadExtension(background);
ext.sendMessage("set", { value: false });
await ext.awaitMessage("done");
await ext.unload();
Assert.strictEqual(defaultPreferences.get(prefName), true);
// false -> false
defaultPreferences.set(prefName, false);
ext = await loadExtension(background);
ext.sendMessage("set", { value: false });
await ext.awaitMessage("done");
await ext.unload();
Assert.strictEqual(defaultPreferences.get(prefName), false);
// true -> true
defaultPreferences.set(prefName, true);
ext = await loadExtension(background);
ext.sendMessage("set", { value: true });
await ext.awaitMessage("done");
await ext.unload();
Assert.strictEqual(defaultPreferences.get(prefName), true);
});
}

Просмотреть файл

@ -2,16 +2,6 @@
{
"namespace": "experiments.urlbar",
"description": "APIs supporting urlbar experiments",
"properties": {
"engagementTelemetry": {
"$ref": "types.Setting",
"description": "Enables or disables the engagement telemetry for the current browser session."
},
"openViewOnFocus": {
"$ref": "types.Setting",
"description": "Enables or disables the open-view-on-focus mode for the current browser session."
}
},
"functions": [
{
"name": "isBrowserShowingNotification",

Просмотреть файл

@ -137,19 +137,33 @@
.urlbarView:not(.megabar) .urlbarView-row,
.urlbarView.megabar .urlbarView-row-inner {
border-radius: 2px;
padding-block: 6px;
padding-inline-start: calc(@urlbarViewItemPaddingStart@);
}
.urlbarView:not(.megabar) .urlbarView-row:not([type=tip]),
.urlbarView.megabar .urlbarView-row-inner {
padding-block: 6px;
}
.urlbarView:not(.megabar) .urlbarView-row {
padding-inline-start: calc(var(--item-padding-start, calc(5px + @urlbarViewFaviconOffset@)) - @urlbarViewFaviconOffset@);
padding-inline-end: var(--item-padding-end, 5px);
}
:root[uidensity=touch] .urlbarView-row {
:root[uidensity=touch] .urlbarView-row:not([type=tip]) {
padding-block: 11px;
}
.urlbarView:not(.megabar) .urlbarView-row[type=tip] {
padding-block: 24px;
}
.urlbarView.megabar .urlbarView-row[type=tip] {
padding-block: 18px;
/* Compensating for the 4px focus ring on tip buttons. */
padding-inline-end: calc(@urlbarViewItemPaddingStart@ + 4px);
}
.urlbarView-row-inner {
display: flex;
flex-wrap: nowrap;
@ -251,11 +265,6 @@
background-image: url(chrome://browser/skin/tab.svg);
}
.urlbarView-row[type=tip] {
padding-block: 24px;
padding-inline-end: @urlbarViewPaddingInline@;
}
.urlbarView-row[type=tip]:not(:last-child) {
border-bottom: 1px solid var(--panel-separator-color);
margin-bottom: 4px;

Просмотреть файл

@ -34,6 +34,12 @@ def main(argv):
sandbox = ConfigureSandbox(config, os.environ, argv)
clobber_file = 'CLOBBER'
if not os.path.exists(clobber_file):
# Simply touch the file.
with open(clobber_file, 'a'):
pass
if os.environ.get('MOZ_CONFIGURE_TRACE'):
sandbox._logger.setLevel(TRACE)

Просмотреть файл

@ -14,7 +14,7 @@ add_task(async function() {
const uri = Services.io.newFileURI(dir);
const tab = await addJsonViewTab(uri.spec);
// perform sanity checks for URI and pricnipals in loadInfo
// perform sanity checks for URI and principals in loadInfo
await ContentTask.spawn(tab.linkedBrowser, {TEST_JSON_FILE}, async function ({TEST_JSON_FILE}) { // eslint-disable-line
const channel = content.docShell.currentDocumentChannel;
const channelURI = channel.URI.spec;

Просмотреть файл

@ -455,7 +455,11 @@ async function getBackgroundColor({ rawNode: node, walker }) {
// - not element node
// - more than one child
// Avoid calculating bounds and creating doc walker by returning early.
if (node.nodeType != Node.ELEMENT_NODE || node.children.length > 0) {
if (
node.nodeType != Node.ELEMENT_NODE ||
node.childNodes.length > 1 ||
!node.firstChild
) {
return {
value: colorUtils.colorToRGBA(
getClosestBackgroundColor(node),

Просмотреть файл

@ -118,6 +118,7 @@ skip-if = true # Bug 1593562
[browser_inspector-search.js]
[browser_inspector-shadow.js]
[browser_inspector-traversal.js]
[browser_inspector-utils.js]
[browser_layout_getGrids.js]
[browser_layout_simple.js]
[browser_markers-cycle-collection.js]

Просмотреть файл

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* import-globals-from inspector-helpers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/server/tests/browser/inspector-helpers.js",
this
);
const COLOR_WHITE = [255, 255, 255, 1];
add_task(async function loadNewChild() {
const { walker } = await initInspectorFront(
`data:text/html,<style>body{color:red;background-color:white;}body::before{content:"test";}</style>`
);
const body = await walker.querySelector(walker.rootNode, "body");
const color = await body.getBackgroundColor();
Assert.deepEqual(
color.value,
COLOR_WHITE,
"Background color is calculated correctly for an element with a pseudo child."
);
});

Просмотреть файл

@ -483,6 +483,10 @@ bool WebGLContext::CreateAndInitGL(
flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
}
if (StaticPrefs::webgl_cgl_multithreaded()) {
flags |= gl::CreateContextFlags::PREFER_MULTITHREADED;
}
if (IsWebGL2()) {
flags |= gl::CreateContextFlags::PREFER_ES3;
} else {

Просмотреть файл

@ -52,8 +52,6 @@ class GLContextCGL : public GLContext {
virtual GLenum GetPreferredARGB32Format() const override;
virtual bool IsDoubleBuffered() const override;
virtual bool SwapBuffers() override;
virtual void GetWSIInfo(nsCString* const out) const override;

Просмотреть файл

@ -21,10 +21,6 @@
#include <OpenGL/OpenGL.h>
// When running inside a VM, creating an accelerated OpenGL context usually
// fails. Uncomment this line to emulate that behavior.
// #define EMULATE_VM
namespace mozilla {
namespace gl {
@ -45,25 +41,14 @@ class CGLLibrary {
}
}
const char* db = PR_GetEnv("MOZ_CGL_DB");
if (db) {
mUseDoubleBufferedWindows = *db != '0';
}
mInitialized = true;
return true;
}
bool UseDoubleBufferedWindows() const {
MOZ_ASSERT(mInitialized);
return mUseDoubleBufferedWindows;
}
const auto& Library() const { return mOGLLibrary; }
private:
bool mInitialized = false;
bool mUseDoubleBufferedWindows = true;
PRLibrary* mOGLLibrary = nullptr;
};
@ -111,8 +96,6 @@ bool GLContextCGL::IsCurrentImpl() const { return [NSOpenGLContext currentContex
GLenum GLContextCGL::GetPreferredARGB32Format() const { return LOCAL_GL_BGRA; }
bool GLContextCGL::IsDoubleBuffered() const { return sCGLLibrary.UseDoubleBufferedWindows(); }
bool GLContextCGL::SwapBuffers() {
AUTO_PROFILER_LABEL("GLContextCGL::SwapBuffers", GRAPHICS);
@ -135,28 +118,6 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateWrappingExisting(void*,
return nullptr;
}
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
NSOpenGLPFAAllowOfflineRenderers, 0};
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered_accel[] = {
NSOpenGLPFAAccelerated, NSOpenGLPFAAllowOfflineRenderers, 0};
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
NSOpenGLPFAAllowOfflineRenderers, NSOpenGLPFADoubleBuffer, 0};
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel[] = {
NSOpenGLPFAAccelerated, NSOpenGLPFAAllowOfflineRenderers, NSOpenGLPFADoubleBuffer, 0};
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel_webrender[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAOpenGLProfile,
NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADepthSize,
24,
0};
static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) {
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
if (!format) {
@ -173,55 +134,15 @@ static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* att
already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
CompositorWidget* aCompositorWidget, bool aWebRender, bool aForceAccelerated) {
if (!aCompositorWidget) {
MOZ_ASSERT(false);
return nullptr;
}
return CreateForWindow(aCompositorWidget->RealWidget(), aWebRender, aForceAccelerated);
}
already_AddRefed<GLContext> GLContextProviderCGL::CreateForWindow(nsIWidget* aWidget,
bool aWebRender,
bool aForceAccelerated) {
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
#ifdef EMULATE_VM
CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER;
if (aForceAccelerated) {
return nullptr;
flags |= CreateContextFlags::FORCE_ENABLE_HARDWARE;
}
#endif
const NSOpenGLPixelFormatAttribute* attribs;
SurfaceCaps caps = SurfaceCaps::ForRGBA();
if (sCGLLibrary.UseDoubleBufferedWindows()) {
if (aWebRender) {
MOZ_RELEASE_ASSERT(aForceAccelerated,
"At the moment, aForceAccelerated is always true if aWebRender is true. "
"If this changes, please update the code here.");
attribs = kAttribs_doubleBuffered_accel_webrender;
caps.depth = true;
} else {
attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
}
} else {
attribs = aForceAccelerated ? kAttribs_singleBuffered_accel : kAttribs_singleBuffered;
if (!aWebRender) {
flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
NSOpenGLContext* context = CreateWithFormat(attribs);
if (!context) {
return nullptr;
}
RefPtr<GLContextCGL> glContext = new GLContextCGL(CreateContextFlags::NONE, caps, context, false);
if (!glContext->Init()) {
glContext = nullptr;
[context release];
return nullptr;
}
return glContext.forget();
nsCString failureUnused;
return CreateHeadless(flags, &failureUnused);
}
static already_AddRefed<GLContextCGL> CreateOffscreenFBOContext(CreateContextFlags flags) {
@ -243,7 +164,7 @@ static already_AddRefed<GLContextCGL> CreateOffscreenFBOContext(CreateContextFla
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
}
if (StaticPrefs::gl_require_hardware()) {
if (flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) {
attribs.push_back(NSOpenGLPFAAccelerated);
}
@ -267,7 +188,7 @@ static already_AddRefed<GLContextCGL> CreateOffscreenFBOContext(CreateContextFla
RefPtr<GLContextCGL> glContext = new GLContextCGL(flags, SurfaceCaps::Any(), context, true);
if (StaticPrefs::gl_multithreaded()) {
if (flags & CreateContextFlags::PREFER_MULTITHREADED) {
CGLEnable(glContext->GetCGLContext(), kCGLCEMPEngine);
}
return glContext.forget();

Просмотреть файл

@ -170,19 +170,14 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
MOZ_ASSERT(false);
return nullptr;
}
return CreateForWindow(aCompositorWidget->RealWidget(), aWebRender, aForceAccelerated);
}
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget,
bool aWebRender,
bool aForceAccelerated) {
RefPtr<GLContext> glContext =
CreateEAGLContext(CreateContextFlags::NONE, false, GetGlobalContextEAGL());
if (!glContext) {
return nullptr;
}
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aWidget)) {
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aCompositorWidget->RealWidget())) {
return nullptr;
}

Просмотреть файл

@ -904,13 +904,6 @@ already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget(
return GLContextEGLFactory::Create(window, aWebRender);
}
already_AddRefed<GLContext> GLContextProviderEGL::CreateForWindow(
nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) {
MOZ_ASSERT(aWidget);
return GLContextEGLFactory::Create(
GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget), aWebRender);
}
#if defined(MOZ_WIDGET_ANDROID)
EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) {
if (mConfig == EGL_NO_CONFIG) {

Просмотреть файл

@ -759,15 +759,6 @@ already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
aWebRender, aForceAccelerated);
}
already_AddRefed<GLContext> GLContextProviderGLX::CreateForWindow(
nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) {
Display* display =
(Display*)aWidget->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
Window window = GET_NATIVE_WINDOW(aWidget);
return CreateForWidget(display, window, aWebRender, aForceAccelerated);
}
static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
const SurfaceCaps& minCaps,
ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,

Просмотреть файл

@ -43,33 +43,6 @@ class GL_CONTEXT_PROVIDER_NAME {
mozilla::widget::CompositorWidget* aCompositorWidget, bool aWebRender,
bool aForceAccelerated);
/**
* Create a context that renders to the surface of the widget that is
* passed in. The context is always created with an RGB pixel format,
* with no alpha, depth or stencil. If any of those features are needed,
* either use a framebuffer, or use CreateOffscreen.
*
* This context will attempt to share resources with all other window
* contexts. As such, it's critical that resources allocated that are not
* needed by other contexts be deleted before the context is destroyed.
*
* The GetSharedContext() method will return non-null if sharing
* was successful.
*
* Note: a context created for a widget /must not/ hold a strong
* reference to the widget; otherwise a cycle can be created through
* a GL layer manager.
*
* @param aWidget Widget whose surface to create a context for
* @param aWebRender If the compositor is a WebRender compositor
* @param aForceAccelerated true if only accelerated contexts are allowed
*
* @return Context to use for the window
*/
static already_AddRefed<GLContext> CreateForWindow(nsIWidget* aWidget,
bool aWebRender,
bool aForceAccelerated);
/**
* Create a context for offscreen rendering. The target of this
* context should be treated as opaque -- it might be a FBO, or a

Просмотреть файл

@ -16,11 +16,6 @@ already_AddRefed<GLContext> GLContextProviderNull::CreateForCompositorWidget(
return nullptr;
}
already_AddRefed<GLContext> GLContextProviderNull::CreateForWindow(
nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) {
return nullptr;
}
already_AddRefed<GLContext> GLContextProviderNull::CreateWrappingExisting(
void*, void*) {
return nullptr;

Просмотреть файл

@ -463,13 +463,6 @@ already_AddRefed<GLContext> GLContextProviderWGL::CreateForCompositorWidget(
.forget();
}
already_AddRefed<GLContext> GLContextProviderWGL::CreateForWindow(
nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) {
return CreateForWidget((HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW),
aWebRender, aForceAccelerated)
.forget();
}
/*static*/
already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(
const CreateContextFlags flags, nsACString* const out_failureId) {

Просмотреть файл

@ -40,17 +40,6 @@ already_AddRefed<GLContext> GLContextProviderWayland::CreateForCompositorWidget(
}
}
already_AddRefed<GLContext> GLContextProviderWayland::CreateForWindow(
nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated) {
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
return sGLContextProviderGLX.CreateForWindow(aWidget, aWebRender,
aForceAccelerated);
} else {
return sGLContextProviderEGL.CreateForWindow(aWidget, aWebRender,
aForceAccelerated);
}
}
/*static*/
already_AddRefed<GLContext> GLContextProviderWayland::CreateHeadless(
CreateContextFlags flags, nsACString* const out_failureId) {

Просмотреть файл

@ -44,6 +44,7 @@ enum class CreateContextFlags : uint16_t {
HIGH_POWER = 1 << 6,
PROVOKING_VERTEX_DONT_CARE = 1 << 7,
PREFER_EXACT_VERSION = 1 << 8,
PREFER_MULTITHREADED = 1 << 9,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)

Просмотреть файл

@ -589,15 +589,9 @@ void CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget) {
// Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
// 2, 2) and flip the contents.
Matrix viewMatrix;
if (mGLContext->IsOffscreen() && !gIsGtest) {
// In case of rendering via GL Offscreen context, disable Y-Flipping
viewMatrix.PreTranslate(-1.0, -1.0);
viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
} else {
viewMatrix.PreTranslate(-1.0, 1.0);
viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
viewMatrix.PreScale(1.0f, -1.0f);
}
viewMatrix.PreTranslate(-1.0, 1.0);
viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
viewMatrix.PreScale(1.0f, -1.0f);
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
// If we're drawing directly to the window then we want to offset

Просмотреть файл

@ -9,6 +9,7 @@
#include "GLContext.h"
#include "GLContextProvider.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/widget/CompositorWidget.h"
namespace mozilla {
@ -17,9 +18,11 @@ namespace wr {
/* static */
UniquePtr<RenderCompositor> RenderCompositorOGL::Create(
RefPtr<widget::CompositorWidget>&& aWidget) {
RefPtr<gl::GLContext> gl;
gl = gl::GLContextProvider::CreateForCompositorWidget(
aWidget, /* aWebRender */ true, /* aForceAccelerated */ true);
RefPtr<gl::GLContext> gl = RenderThread::Get()->SharedGL();
if (!gl) {
gl = gl::GLContextProvider::CreateForCompositorWidget(
aWidget, /* aWebRender */ true, /* aForceAccelerated */ true);
}
if (!gl || !gl->MakeCurrent()) {
gfxCriticalNote << "Failed GL context creation for WebRender: "
<< gfx::hexa(gl.get());

Просмотреть файл

@ -952,6 +952,16 @@ static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
}
#endif
#ifdef XP_MACOSX
static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
nsCString failureUnused;
return gl::GLContextProvider::CreateHeadless(
gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
gl::CreateContextFlags::FORCE_ENABLE_HARDWARE,
&failureUnused);
}
#endif
static already_AddRefed<gl::GLContext> CreateGLContext() {
#ifdef XP_WIN
if (gfx::gfxVars::UseWebRenderANGLE()) {
@ -966,8 +976,11 @@ static already_AddRefed<gl::GLContext> CreateGLContext() {
return CreateGLContextEGL();
}
#endif
// We currently only support a shared GLContext
// with ANGLE.
#ifdef XP_MACOSX
return CreateGLContextCGL();
#endif
return nullptr;
}

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<menulist style="color: transparent">
<menupopup>
<menuitem value="1" label="short" />

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<menulist style="color: transparent">
<menupopup>
<menuitem value="1" label="long item" />

Просмотреть файл

@ -8,7 +8,7 @@
]]>
</style>
<stack>
<vbox align="left">
<vbox align="start">
<menulist>
<menupopup>
<menuitem value="1" label="long item" />

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<window class="reftest-wait"
align="left"
align="start"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<html:style type="text/css">

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<window class="reftest-wait"
align="left"
align="start"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<html:style type="text/css">

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<hbox style="font: 40px monospace;" align="baseline">
<label value="lowercase"/>
<label value="SMALLCAPS" style="font-size: 32px;"/>

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<hbox style="font: 40px monospace;">
<label value="lowercase" style="font-variant: normal;"/>
<label value="smallcaps" style="font-variant: small-caps;"/>

Просмотреть файл

@ -2,7 +2,7 @@
<!-- bug 749658 - The cropped label should *not* cause a scroll bar to appear.
If it does, the scrollbars in the testcase and reference will differ
because the total scroll-overflow extent will be different. -->
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<hbox width="150px" style="overflow: scroll">
<label value="A very long label for a small item"
width="120px" crop="right"/>

Просмотреть файл

@ -2,7 +2,7 @@
<!-- bug 749658 - The cropped label should *not* cause a scroll bar to appear.
If it does, the scrollbars in the testcase and reference will differ
because the total scroll-overflow extent will be different. -->
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="start">
<hbox width="150px" style="overflow: scroll">
<label value="A very long label for a small item that should not trigger a scroll bar"
width="120px" crop="right"/>

Просмотреть файл

@ -231,44 +231,10 @@ void nsBoxFrame::CacheAttributes() {
}
bool nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign) {
if (!GetContent() || !GetContent()->IsElement()) return false;
if (!GetContent()) return false;
Element* element = GetContent()->AsElement();
// XXXdwh Everything inside this if statement is deprecated code.
static Element::AttrValuesArray alignStrings[] = {nsGkAtoms::left,
nsGkAtoms::right, nullptr};
static const Halignment alignValues[] = {hAlign_Left, hAlign_Right};
int32_t index = element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
alignStrings, eCaseMatters);
if (index >= 0) {
aHalign = alignValues[index];
return true;
}
// Now that the deprecated stuff is out of the way, we move on to check the
// appropriate attribute. For horizontal boxes, we are checking the PACK
// attribute. For vertical boxes we are checking the ALIGN attribute.
nsAtom* attrName = IsXULHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align;
static Element::AttrValuesArray strings[] = {
nsGkAtoms::_empty, nsGkAtoms::start, nsGkAtoms::center, nsGkAtoms::end,
nullptr};
static const Halignment values[] = {hAlign_Left /*not used*/, hAlign_Left,
hAlign_Center, hAlign_Right};
index = element->FindAttrValueIn(kNameSpaceID_None, attrName, strings,
eCaseMatters);
if (index == Element::ATTR_VALUE_NO_MATCH) {
// The attr was present but had a nonsensical value. Revert to the default.
return false;
}
if (index > 0) {
aHalign = values[index];
return true;
}
// Now that we've checked for the attribute it's time to check CSS. For
// horizontal boxes we're checking PACK. For vertical boxes we are checking
// ALIGN.
// For horizontal boxes we're checking PACK. For vertical boxes we are
// checking ALIGN.
const nsStyleXUL* boxInfo = StyleXUL();
if (IsXULHorizontal()) {
switch (boxInfo->mBoxPack) {
@ -304,46 +270,9 @@ bool nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign) {
}
bool nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign) {
if (!GetContent() || !GetContent()->IsElement()) return false;
Element* element = GetContent()->AsElement();
static Element::AttrValuesArray valignStrings[] = {
nsGkAtoms::top, nsGkAtoms::baseline, nsGkAtoms::middle, nsGkAtoms::bottom,
nullptr};
static const Valignment valignValues[] = {vAlign_Top, vAlign_BaseLine,
vAlign_Middle, vAlign_Bottom};
int32_t index = element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign,
valignStrings, eCaseMatters);
if (index >= 0) {
aValign = valignValues[index];
return true;
}
// Now that the deprecated stuff is out of the way, we move on to check the
// appropriate attribute. For horizontal boxes, we are checking the ALIGN
// attribute. For vertical boxes we are checking the PACK attribute.
nsAtom* attrName = IsXULHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack;
static Element::AttrValuesArray strings[] = {
nsGkAtoms::_empty, nsGkAtoms::start, nsGkAtoms::center,
nsGkAtoms::baseline, nsGkAtoms::end, nullptr};
static const Valignment values[] = {vAlign_Top /*not used*/, vAlign_Top,
vAlign_Middle, vAlign_BaseLine,
vAlign_Bottom};
index = element->FindAttrValueIn(kNameSpaceID_None, attrName, strings,
eCaseMatters);
if (index == Element::ATTR_VALUE_NO_MATCH) {
// The attr was present but had a nonsensical value. Revert to the default.
return false;
}
if (index > 0) {
aValign = values[index];
return true;
}
// Now that we've checked for the attribute it's time to check CSS. For
// horizontal boxes we're checking ALIGN. For vertical boxes we are checking
// PACK.
if (!GetContent()) return false;
// For horizontal boxes we're checking ALIGN. For vertical boxes we are
// checking PACK.
const nsStyleXUL* boxInfo = StyleXUL();
if (IsXULHorizontal()) {
switch (boxInfo->mBoxAlign) {
@ -385,25 +314,12 @@ void nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal) {
// see if we are a vertical or horizontal box.
if (!GetContent()) return;
// Check the style system first.
const nsStyleXUL* boxInfo = StyleXUL();
if (boxInfo->mBoxOrient == StyleBoxOrient::Horizontal) {
aIsHorizontal = true;
} else {
aIsHorizontal = false;
}
// Now see if we have an attribute. The attribute overrides
// the style system value.
if (!GetContent()->IsElement()) return;
static Element::AttrValuesArray strings[] = {nsGkAtoms::vertical,
nsGkAtoms::horizontal, nullptr};
int32_t index = GetContent()->AsElement()->FindAttrValueIn(
kNameSpaceID_None, nsGkAtoms::orient, strings, eCaseMatters);
if (index >= 0) {
aIsHorizontal = index == 1;
}
}
void nsBoxFrame::GetInitialDirection(bool& aIsNormal) {
@ -461,18 +377,6 @@ bool nsBoxFrame::GetInitialEqualSize(bool& aEqualSize) {
bool nsBoxFrame::GetInitialAutoStretch(bool& aStretch) {
if (!GetContent()) return false;
// Check the align attribute.
if (GetContent()->IsElement()) {
static Element::AttrValuesArray strings[] = {nsGkAtoms::_empty,
nsGkAtoms::stretch, nullptr};
int32_t index = GetContent()->AsElement()->FindAttrValueIn(
kNameSpaceID_None, nsGkAtoms::align, strings, eCaseMatters);
if (index != Element::ATTR_MISSING && index != 0) {
aStretch = index == 1;
return true;
}
}
// Check the CSS box-align property.
const nsStyleXUL* boxInfo = StyleXUL();
aStretch = (boxInfo->mBoxAlign == StyleBoxAlign::Stretch);

Просмотреть файл

@ -381,10 +381,6 @@ nsresult nsScrollbarFrame::CreateAnonymousContent(
nodeInfoManager->GetNodeInfo(nsGkAtoms::thumb, nullptr,
kNameSpaceID_XUL, nsINode::ELEMENT_NODE));
mThumb->SetAttr(kNameSpaceID_None, nsGkAtoms::orient, orient, false);
mThumb->SetAttr(kNameSpaceID_None, nsGkAtoms::align,
NS_LITERAL_STRING("center"), false);
mThumb->SetAttr(kNameSpaceID_None, nsGkAtoms::pack,
NS_LITERAL_STRING("center"), false);
mSlider->AppendChildTo(mThumb, false);
}

Просмотреть файл

@ -520,8 +520,10 @@ function startup() {
},
{
name: "GeckoViewContentBlocking",
onEnable: {
onInit: {
resource: "resource://gre/modules/GeckoViewContentBlocking.jsm",
},
onEnable: {
frameScript:
"chrome://geckoview/content/GeckoViewContentBlockingChild.js",
},

Просмотреть файл

@ -15,6 +15,7 @@ import org.mozilla.geckoview.ContentBlocking
import org.mozilla.geckoview.ContentBlockingController
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
import org.mozilla.geckoview.test.util.Callbacks
import org.junit.Assume.assumeThat
@ -146,16 +147,19 @@ class ContentBlockingControllerTest : BaseSessionTest() {
sessionRule.runtime.contentBlockingController.clearExceptionList()
}
@Ignore //Bug 1581657 - ignore test to reduce frequent failures
@Test
fun getLog() {
val category = ContentBlocking.AntiTracking.TEST
sessionRule.runtime.settings.contentBlocking.setAntiTracking(category)
sessionRule.session.settings.useTrackingProtection = true
sessionRule.session.loadTestPath(TRACKERS_PATH)
sessionRule.waitForPageStop()
sessionRule.waitUntilCalled(object : Callbacks.ContentBlockingDelegate {
@AssertCalled(count = 1)
override fun onContentBlocked(session: GeckoSession,
event: ContentBlocking.BlockEvent) {
}
})
sessionRule.waitForResult(sessionRule.runtime.contentBlockingController.getLog(sessionRule.session).accept {
assertThat("Log must not be null", it, Matchers.notNullValue())

Просмотреть файл

@ -3713,18 +3713,6 @@
value: false
mirror: always
#if defined(XP_MACOSX)
- name: gl.multithreaded
type: RelaxedAtomicBool
value: true
mirror: always
#endif
- name: gl.require-hardware
type: RelaxedAtomicBool
value: false
mirror: always
- name: gl.use-tls-is-current
type: RelaxedAtomicInt32
value: 0
@ -7587,7 +7575,6 @@
#endif
mirror: always
- name: webgl.all-angle-options
type: RelaxedAtomicBool
value: false
@ -7617,6 +7604,11 @@
value: true
mirror: always
- name: webgl.cgl.multithreaded
type: RelaxedAtomicBool
value: true
mirror: always
- name: webgl.default-antialias
type: RelaxedAtomicBool
value: @IS_NOT_ANDROID@

Просмотреть файл

@ -2051,7 +2051,7 @@ bool NS_IsSameSiteForeign(nsIChannel* aChannel, nsIURI* aHostURI) {
if (loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_DOCUMENT) {
// for loads of TYPE_DOCUMENT we query the hostURI from the
// triggeringPricnipal which returns the URI of the document that caused the
// triggeringPrincipal which returns the URI of the document that caused the
// navigation.
loadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(uri));
} else {

Просмотреть файл

@ -166,20 +166,6 @@ class Clobberer(object):
paths = self.collect_subdirs(cargo_path, {'incremental', })
self.delete_dirs(cargo_path, paths)
def ensure_objdir_state(self):
"""Ensure the CLOBBER file in the objdir exists.
This is called as part of the build to ensure the clobber information
is configured properly for the objdir.
"""
if not os.path.exists(self.topobjdir):
os.makedirs(self.topobjdir)
if not os.path.exists(self.obj_clobber):
# Simply touch the file.
with open(self.obj_clobber, 'a'):
pass
def maybe_do_clobber(self, cwd, allow_auto=False, fh=sys.stderr):
"""Perform a clobber if it is required. Maybe.
@ -199,7 +185,6 @@ class Clobberer(object):
if not self.clobber_needed():
print('Clobber not needed.', file=fh)
self.ensure_objdir_state()
return False, False, None
# So a clobber is needed. We only perform a clobber if we are
@ -223,7 +208,6 @@ class Clobberer(object):
print('Automatically clobbering %s' % objdir, file=fh)
try:
self.remove_objdir(False)
self.ensure_objdir_state()
print('Successfully completed auto clobber.', file=fh)
return True, True, None
except (IOError) as error:

Просмотреть файл

@ -64,14 +64,13 @@ class TestClobberer(unittest.TestCase):
c = Clobberer(self.get_topsrcdir(), tmp)
self.assertFalse(c.clobber_needed())
# Side-effect is topobjdir is created with CLOBBER file touched.
required, performed, reason = c.maybe_do_clobber(os.getcwd(), True)
self.assertFalse(required)
self.assertFalse(performed)
self.assertIsNone(reason)
self.assertTrue(os.path.isdir(tmp))
self.assertTrue(os.path.exists(os.path.join(tmp, 'CLOBBER')))
self.assertFalse(os.path.isdir(tmp))
self.assertFalse(os.path.exists(os.path.join(tmp, 'CLOBBER')))
def test_objdir_no_clobber_file(self):
"""If CLOBBER does not exist in topobjdir, treat as empty."""
@ -84,7 +83,7 @@ class TestClobberer(unittest.TestCase):
self.assertFalse(performed)
self.assertIsNone(reason)
self.assertTrue(os.path.exists(os.path.join(c.topobjdir, 'CLOBBER')))
self.assertFalse(os.path.exists(os.path.join(c.topobjdir, 'CLOBBER')))
def test_objdir_clobber_newer(self):
"""If CLOBBER in topobjdir is newer, do nothing."""
@ -121,9 +120,7 @@ class TestClobberer(unittest.TestCase):
self.assertTrue(performed)
self.assertFalse(os.path.exists(dummy_path))
self.assertTrue(os.path.exists(c.obj_clobber))
self.assertGreaterEqual(os.path.getmtime(c.obj_clobber),
os.path.getmtime(c.src_clobber))
self.assertFalse(os.path.exists(c.obj_clobber))
def test_objdir_is_srcdir(self):
"""If topobjdir is the topsrcdir, refuse to clobber."""

Просмотреть файл

@ -23,12 +23,15 @@ const {
class Page extends ContentProcessDomain {
constructor(session) {
super(session);
this.enabled = false;
this.lifecycleEnabled = false;
this.onFrameNavigated = this.onFrameNavigated.bind(this);
}
destructor() {
this.setLifecycleEventsEnabled({ enabled: false });
this.disable();
super.destructor();
@ -44,6 +47,9 @@ class Page extends ContentProcessDomain {
this.chromeEventHandler.addEventListener("DOMContentLoaded", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.addEventListener("pagehide", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.addEventListener("pageshow", this, {
mozSystemGroup: true,
});
@ -57,6 +63,9 @@ class Page extends ContentProcessDomain {
this.chromeEventHandler.removeEventListener("DOMContentLoaded", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.removeEventListener("pagehide", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.removeEventListener("pageshow", this, {
mozSystemGroup: true,
});
@ -115,10 +124,22 @@ class Page extends ContentProcessDomain {
};
}
setLifecycleEventsEnabled() {}
addScriptToEvaluateOnNewDocument() {}
createIsolatedWorld() {}
/**
* Controls whether page will emit lifecycle events.
*
* @param {Object} options
* @param {boolean} options.enabled
* If true, starts emitting lifecycle events.
*/
setLifecycleEventsEnabled(options) {
const { enabled } = options;
this.lifecycleEnabled = enabled;
}
url() {
return this.content.location.href;
}
@ -136,8 +157,16 @@ class Page extends ContentProcessDomain {
});
}
emitLifecycleEvent(frameId, loaderId, name, timestamp) {
if (this.lifecycleEnabled) {
this.emit("Page.lifecycleEvent", { frameId, loaderId, name, timestamp });
}
}
handleEvent({ type, target }) {
if (target.defaultView != this.content) {
const isFrame = target.defaultView != this.content;
if (isFrame) {
// Ignore iframes for now
return;
}
@ -149,13 +178,44 @@ class Page extends ContentProcessDomain {
switch (type) {
case "DOMContentLoaded":
this.emit("Page.domContentEventFired", { timestamp });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"DOMContentLoaded",
timestamp
);
}
break;
case "pagehide":
// Maybe better to bound to "unload" once we can register for this event
this.emit("Page.frameStartedLoading", { frameId });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"init",
timestamp
);
}
break;
case "pageshow":
this.emit("Page.loadEventFired", { timestamp });
if (!isFrame) {
this.emitLifecycleEvent(
frameId,
/* loaderId */ null,
"load",
timestamp
);
}
// XXX this should most likely be sent differently
this.emit("Page.navigatedWithinDocument", { frameId, url });
this.emit("Page.frameStoppedLoading", { frameId });
break;
}
}

Просмотреть файл

@ -178,3 +178,12 @@ function getContentProperty(prop) {
_prop => content[_prop]
);
}
/**
* Return a new promise, which resolves after ms have been elapsed
*/
function timeoutPromise(ms) {
return new Promise(resolve => {
window.setTimeout(resolve, ms);
});
}

Просмотреть файл

@ -14,5 +14,6 @@ support-files =
[browser_javascriptDialog_confirm.js]
[browser_javascriptDialog_otherTarget.js]
[browser_javascriptDialog_prompt.js]
[browser_lifecycleEvent.js]
[browser_reload.js]
[browser_runtimeEvents.js]

Просмотреть файл

@ -42,11 +42,12 @@ add_task(async function(client) {
}
// Record all Page events that we assert in this test
function recordPromises() {
recordPromise("frameStoppedLoading", Page.frameStoppedLoading());
recordPromise("navigatedWithinDocument", Page.navigatedWithinDocument());
recordPromise("frameStartedLoading", Page.frameStartedLoading());
recordPromise("frameNavigated", Page.frameNavigated());
recordPromise("domContentEventFired", Page.domContentEventFired());
recordPromise("loadEventFired", Page.loadEventFired());
recordPromise("frameNavigated", Page.frameNavigated());
recordPromise("navigatedWithinDocument", Page.navigatedWithinDocument());
recordPromise("frameStoppedLoading", Page.frameStoppedLoading());
}
info("Test Page.navigate");
@ -107,6 +108,7 @@ async function assertNavigationEvents({ url, frameId }) {
// Assert the order in which they resolved
const expectedResolutions = [
"frameStartedLoading",
"frameNavigated",
"domContentEventFired",
"loadEventFired",
@ -120,6 +122,13 @@ async function assertNavigationEvents({ url, frameId }) {
);
// Now assert the data exposed by each of these events
const frameStartedLoading = resolutions.get("frameStartedLoading");
is(
frameStartedLoading.frameId,
frameId,
"frameStartedLoading frameId is the same one"
);
const frameNavigated = resolutions.get("frameNavigated");
ok(
!frameNavigated.frame.parentId,

Просмотреть файл

@ -0,0 +1,152 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the Page lifecycle events
const DOC = toDataURL("default-test-page");
add_task(async function noInitialEvents({ Page }) {
await Page.enable();
info("Page domain has been enabled");
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events are not enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId, timeout: 1000 });
});
add_task(async function noEventsAfterDisable({ Page }) {
await Page.enable();
info("Page domain has been enabled");
await Page.setLifecycleEventsEnabled({ enabled: true });
await Page.setLifecycleEventsEnabled({ enabled: false });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events are not enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId, timeout: 1000 });
});
add_task(async function navigateEvents({ Page }) {
await Page.enable();
info("Page domain has been enabled");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("A new page has been loaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
add_task(async function navigateEventsOnReload({ Page }) {
await Page.enable();
info("Page domain has been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("Initial page has been loaded");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
pageLoaded = Page.loadEventFired();
await Page.reload();
await pageLoaded;
info("The page has been reloaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
add_task(async function navigateEventsOnNavigateToSameURL({ Page }) {
await Page.enable();
info("Page domain has been enabled");
let pageLoaded = Page.loadEventFired();
const { frameId } = await Page.navigate({ url: DOC });
await pageLoaded;
info("Initial page has been loaded");
await Page.setLifecycleEventsEnabled({ enabled: true });
const promise = recordPromises(Page, ["init", "DOMContentLoaded", "load"]);
info("Lifecycle events have been enabled");
pageLoaded = Page.loadEventFired();
await Page.navigate({ url: DOC });
await pageLoaded;
info("The page has been reloaded");
await assertNavigationLifecycleEvents({ promise, frameId });
});
function recordPromises(Page, names) {
return new Promise(resolve => {
const resolutions = new Map();
const unsubscribe = Page.lifecycleEvent(event => {
info(`Received Page.lifecycleEvent for ${event.name}`);
resolutions.set(event.name, event);
if (event.name == names[names.length - 1]) {
unsubscribe();
resolve(resolutions);
}
});
});
}
async function assertNavigationLifecycleEvents({ promise, frameId, timeout }) {
// Wait for all the promises to resolve
const promises = [promise];
if (timeout) {
promises.push(timeoutPromise(timeout));
}
const resolutions = await Promise.race(promises);
if (timeout) {
is(resolutions, undefined, "No lifecycle events have been recorded");
return;
}
// Assert the order in which they resolved
const expectedResolutions = ["init", "DOMContentLoaded", "load"];
Assert.deepEqual(
[...resolutions.keys()],
expectedResolutions,
"Received various lifecycle events in the expected order"
);
// Now assert the data exposed by each of these events
const frameStartedLoading = resolutions.get("init");
is(frameStartedLoading.frameId, frameId, "init frameId is the same one");
const DOMContentLoaded = resolutions.get("DOMContentLoaded");
is(
DOMContentLoaded.frameId,
frameId,
"DOMContentLoaded frameId is the same one"
);
const load = resolutions.get("load");
is(load.frameId, frameId, "load frameId is the same one");
}

Просмотреть файл

@ -109,7 +109,9 @@ run-sequentially = hardcoded ports
# this test doesn't apply.
skip-if = toolkit == 'android'
[test_delegated_credentials.js]
run-sequentially = hardcoded ports
[test_delegated_credentials_weak.js]
run-sequentially = hardcoded ports
[test_der.js]
[test_enterprise_roots.js]
# This feature is implemented for Windows and OS X. However, we don't currently

Просмотреть файл

@ -356,7 +356,7 @@ android-api-16-gcp/debug:
platform: android-4-0-armv7-api16/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android/releng.manifest"
@ -380,7 +380,7 @@ android-x86-gcp/opt:
platform: android-4-2-x86/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android-x86/releng.manifest"
@ -403,7 +403,7 @@ android-api-16-gcp/opt:
platform: android-4-0-armv7-api16/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android/releng.manifest"
@ -426,7 +426,7 @@ android-aarch64-gcp/opt:
platform: android-5-0-aarch64/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android/releng.manifest"
@ -449,7 +449,7 @@ android-aarch64-gcp/debug:
platform: android-5-0-aarch64/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android/releng.manifest"
@ -472,7 +472,7 @@ android-x86_64-gcp/opt:
platform: android-5-0-x86_64/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android-x86/releng.manifest"
@ -495,7 +495,7 @@ android-x86_64-gcp/debug:
platform: android-5-0-x86_64/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
env:
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android-x86/releng.manifest"

Просмотреть файл

@ -1101,49 +1101,6 @@ linux64-tup/opt:
- linux64-nasm
- linux64-node
linux64-ccov/debug:
description: "Linux64-CCov Debug"
index:
product: firefox
job-name: linux64-ccov-debug
treeherder:
platform: linux64-ccov/debug
symbol: B
tier: 2
run-on-projects: ['mozilla-central', 'try']
worker-type: b-linux
worker:
artifacts:
- name: public/code-coverage-grcov.zip
path: /builds/worker/workspace/build/src/obj-firefox/code-coverage-grcov.zip
type: file
max-run-time: 7200
env:
FORCE_GCC: '1'
RUSTC_BOOTSTRAP: '1'
run:
using: mozharness
actions: [get-secrets, build]
config:
- builds/releng_base_firefox.py
- builds/releng_base_linux_64_builds.py
script: "mozharness/scripts/fx_desktop_build.py"
secrets: true
custom-build-variant-cfg: code-coverage-debug
mozconfig-variant: code-coverage-debug
tooltool-downloads: public
need-xvfb: true
fetches:
toolchain:
- linux64-clang-9
- linux64-rust
- linux64-gcc
- linux64-grcov
- linux64-cbindgen
- linux64-sccache
- linux64-nasm
- linux64-node
linux64-ccov/opt:
description: "Linux64-CCov Opt"
index:
@ -1268,7 +1225,7 @@ linux-gcp/debug:
platform: linux32/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
docker-image: {in-tree: debian7-i386-build}
max-run-time: 5400
@ -1308,7 +1265,7 @@ linux-gcp/opt:
platform: linux32/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
docker-image: {in-tree: debian7-i386-build}
max-run-time: 7200
@ -1347,7 +1304,7 @@ linux64-gcp/debug:
platform: linux64/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 5400
env:
@ -1386,7 +1343,7 @@ linux64-gcp/opt:
platform: linux64/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 7200
env:

Просмотреть файл

@ -395,7 +395,7 @@ macosx64-gcp/debug:
platform: osx-cross/debug
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 3600
env:
@ -438,7 +438,7 @@ macosx64-gcp/opt:
platform: osx-cross/opt
symbol: Bg
tier: 3
worker-type: gce/gecko-{level}-b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 7200
env:

Просмотреть файл

@ -118,15 +118,6 @@ linux64-asan-qr/opt:
test-sets:
- linux-qr-smoketests
linux64-ccov/debug:
build-platform: linux64-ccov/debug
test-sets:
- common-tests
- web-platform-tests
- awsy
- talos
- ccov-code-coverage-tests
linux64-ccov/opt:
build-platform: linux64-ccov/opt
test-sets:

Просмотреть файл

@ -2102,7 +2102,7 @@ var BrowserTestUtils = {
/**
* Opens a tab with a given uri and params object. If the params object is not set
* or the params parameter does not include a triggeringPricnipal then this function
* or the params parameter does not include a triggeringPrincipal then this function
* provides a params object using the systemPrincipal as the default triggeringPrincipal.
*
* @param {xul:tabbrowser} tabbrowser

Просмотреть файл

@ -0,0 +1,174 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* This @file implements the child side of Conduits, an abstraction over
* Fission IPC for extension API subject. See {@link ConduitsParent.jsm}
* for more details about the overall design.
*/
const EXPORTED_SYMBOLS = ["BaseConduit", "ConduitsChild"];
/**
* Base class for both child (Point) and parent (Broadcast) side of conduits,
* handles setting up send/receive method stubs.
*/
class BaseConduit {
/**
* @param {object} subject
* @param {ConduitAddress} address
*/
constructor(subject, address) {
this.subject = subject;
this.address = address;
this.id = address.id;
for (let name of address.send || []) {
this[`send${name}`] = this._send.bind(this, name, false);
}
for (let name of address.query || []) {
this[`query${name}`] = this._send.bind(this, name, true);
}
this.recv = new Map();
for (let name of address.recv || []) {
let method = this.subject[`recv${name}`];
if (!method) {
throw new Error(`recv${name} not found for conduit ${this.id}`);
}
this.recv.set(name, method.bind(this.subject));
}
}
/**
* Internal, partially @abstract, uses the actor to send the message/query.
* @param {string} method
* @param {boolean} query Flag indicating a response is expected.
* @param {JSWindowActor} actor
* @param {{arg: object, sender: ConduitID}} data
* @returns {Promise?}
*/
_send(method, query, actor, data) {
if (query) {
return actor.sendQuery(method, data);
}
actor.sendAsyncMessage(method, data);
}
/**
* Internal, calls the specific recvX method based on the message.
* @param {string} name Message/method name.
* @param {object} arg Message data, the one and only method argument.
* @param {object} meta Metadata about the method call.
*/
async _recv(name, arg, meta) {
let method = this.recv.get(name);
if (!method) {
throw new Error(`recv${name} not found for conduit ${this.id}`);
}
try {
return await method(arg, meta);
} catch (e) {
if (meta.query) {
return Promise.reject(e);
}
Cu.reportError(e);
}
}
}
/**
* Child side conduit, can only send/receive point-to-point messages via the
* one specific ConduitsChild actor.
*/
class PointConduit extends BaseConduit {
constructor(subject, address, actor) {
super(subject, address);
this.actor = actor;
this.actor.sendAsyncMessage("ConduitOpened", { arg: address });
}
/**
* Internal, sends messages via the actor, used by sendX stubs.
* @param {string} method
* @param {boolean} query
* @param {object?} arg
* @returns {Promise?}
*/
_send(method, query, arg = {}) {
if (!this.actor) {
throw new Error(`send${method} on closed conduit ${this.id}`);
}
let sender = this.id;
return super._send(method, query, this.actor, { arg, query, sender });
}
/**
* Closes the conduit from further IPC, notifies the parent side by default.
* @param {boolean} silent
*/
close(silent = false) {
let { actor } = this;
if (actor) {
this.actor = null;
actor.conduits.delete(this.id);
if (!silent) {
actor.sendAsyncMessage("ConduitClosed", { arg: this.id });
}
}
}
}
/**
* Implements the child side of the Conduits actor, manages conduit lifetimes.
*/
class ConduitsChild extends JSWindowActorChild {
constructor() {
super();
this.conduits = new Map();
}
/**
* Public entry point a child-side subject uses to open a conduit.
* @param {object} subject
* @param {ConduitAddress} address
* @returns {PointConduit}
*/
openConduit(subject, address) {
let conduit = new PointConduit(subject, address, this);
this.conduits.set(conduit.id, conduit);
return conduit;
}
/**
* JSWindowActor method, routes the message to the target subject.
* @returns {Promise?}
*/
receiveMessage({ name, data: { target, arg, query, sender } }) {
let conduit = this.conduits.get(target);
if (!conduit) {
throw new Error(`${name} for closed conduit ${target}: ${uneval(arg)}`);
}
return conduit._recv(name, arg, { sender, query, actor: this });
}
/**
* JSWindowActor method, called before actor is destroyed.
* Parent side will get the same call, so just silently close all conduits.
*/
willDestroy() {
for (let conduit of this.conduits.values()) {
conduit.close(true);
}
this.conduits.clear();
}
/**
* JSWindowActor method, ensure cleanup (see bug 1596187).
*/
didDestroy() {
this.willDestroy();
}
}

Просмотреть файл

@ -0,0 +1,227 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const EXPORTED_SYMBOLS = ["BroadcastConduit", "ConduitsParent"];
/**
* This @file implements the parent side of Conduits, an abstraction over
* Fission IPC for extension Contexts, API managers, Ports/Messengers, and
* other types of "subjects" participating in implementation of extension APIs.
*
* Additionally, knowledge about conduits from all child processes is gathered
* here, and used together with the full CanonicalBrowsingContext tree to route
* IPC messages and queries directly to the right subjects.
*
* Each Conduit is tied to one subject, attached to a ConduitAddress descriptor,
* and exposes an API for sending/receiving via an actor, or multiple actors in
* case of the parent process.
*
* @typedef {number|string} ConduitID
*
* @typedef {object} ConduitAddress
* @prop {ConduitID} id Globally unique across all processes.
* @prop {string[]} [recv]
* @prop {string[]} [send]
* @prop {string[]} [query]
* Lists of recvX, sendX, and queryX methods this subject will use.
*
* @example:
*
* init(actor) {
* this.conduit = actor.openConduit(this, {
* id: this.id,
* recv: ["recvAddNumber"],
* send: ["sendNumberUpdate"],
* });
* }
*
* recvAddNumber({ num }, { actor, sender }) {
* num += 1;
* this.conduit.sendNumberUpdate(sender.id, { num });
* }
*
*/
const {
ExtensionUtils: { DefaultMap, DefaultWeakMap },
} = ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
const { BaseConduit } = ChromeUtils.import(
"resource://gre/modules/ConduitsChild.jsm"
);
/**
* Internal, keeps track of all parent and remote (child) conduits.
*/
const Hub = {
/** @type Map<ConduitID, ConduitAddress> Info about all child conduits. */
remotes: new Map(),
/** @type Map<ConduitID, BroadcastConduit> All open parent conduits. */
conduits: new Map(),
/** @type Map<string, BroadcastConduit> Parent conduits by recvMethod. */
byMethod: new Map(),
/** @type WeakMap<ConduitsParent, Set<ConduitAddress>> Conduits by actor. */
byActor: new DefaultWeakMap(() => new Set()),
/** @type Map<ConduitID, Set<BroadcastConduit>> */
onRemoteClosed: new DefaultMap(() => new Set()),
/**
* Save info about a new parent conduit, register it as a global listener.
* @param {BroadcastConduit} conduit
*/
openConduit(conduit) {
this.conduits.set(conduit.id, conduit);
for (let name of conduit.address.recv || []) {
if (this.byMethod.get(name)) {
// For now, we only allow one parent conduit handling each recv method.
throw new Error(`Duplicate BroadcastConduit method name recv${name}`);
}
this.byMethod.set(name, conduit);
}
},
/**
* Cleanup.
* @param {BroadcastConduit} conduit
*/
closeConduit({ id, address }) {
this.conduits.delete(id);
for (let name of address.recv || []) {
this.byMethod.remove(name);
}
},
/**
* Save info about a new remote conduit.
* @param {ConduitAddress} address
* @param {ConduitsParent} actor
*/
recvConduitOpened(address, actor) {
address.actor = actor;
this.remotes.set(address.id, address);
this.byActor.get(actor).add(address);
},
/**
* Notifies listeners and cleans up after the remote conduit is closed.
* @param {ConduitAddress} remote
*/
recvConduitClosed(remote) {
this.remotes.delete(remote.id);
this.byActor.get(remote.actor).delete(remote);
remote.actor = null;
for (let conduit of this.onRemoteClosed.get(remote.id)) {
conduit.subject.recvConduitClosed(remote);
}
},
/**
* Close all remote conduits when the actor goes away.
* @param {ConduitsParent} actor
*/
actorClosed(actor) {
for (let remote of this.byActor.get(actor)) {
this.recvConduitClosed(remote);
}
this.byActor.delete(actor);
},
};
/**
* Parent side conduit, registers as a global listeners for certain messages,
* and can target specific child conduits when sending.
*/
class BroadcastConduit extends BaseConduit {
/**
* @param {object} subject
* @param {ConduitAddress} address
*/
constructor(subject, address) {
super(subject, address);
this.open = true;
Hub.openConduit(this);
}
/**
* Internal, sends a message to a specific conduit, used by sendX stubs.
* @param {string} method
* @param {boolean} query
* @param {ConduitID} target
* @param {object?} arg
* @returns {Promise<any>}
*/
_send(method, query, target, arg = {}) {
if (!this.open) {
throw new Error(`send${method} on closed conduit ${this.id}`);
}
let sender = this.address;
let { actor } = Hub.remotes.get(target);
return super._send(method, query, actor, { target, arg, query, sender });
}
/**
* Indicate the subject wants to listen for the specific conduit closing.
* The method `recvConduitClosed(address)` will be called.
* @param {ConduitID} target
*/
reportOnClosed(target) {
Hub.onRemoteClosed.get(target).add(this);
}
async close() {
this.open = false;
Hub.closeConduit(this);
}
}
/**
* Implements the parent side of the Conduits actor.
*/
class ConduitsParent extends JSWindowActorParent {
constructor() {
super();
}
/**
* JSWindowActor method, routes the message to the target subject.
* @returns {Promise?}
*/
receiveMessage({ name, data: { arg, query, sender } }) {
switch (name) {
case "ConduitOpened":
return Hub.recvConduitOpened(arg, this);
case "ConduitClosed":
return Hub.recvConduitClosed(Hub.remotes.get(arg));
}
let conduit = Hub.byMethod.get(name);
if (!conduit) {
throw new Error(`Parent conduit for recv${name} not found`);
}
sender = Hub.remotes.get(sender);
return conduit._recv(name, arg, { actor: this, query, sender });
}
/**
* JSWindowActor method, called before actor is destroyed.
*/
willDestroy() {
Hub.actorClosed(this);
}
/**
* JSWindowActor method, ensure cleanup (see bug 1596187).
*/
didDestroy() {
this.willDestroy();
}
}

Просмотреть файл

@ -1072,7 +1072,7 @@ class ProxyAPIImplementation extends SchemaAPIInterface {
map.ids.set(id, listener);
map.listeners.set(listener, id);
this.childApiManager.messageManager.sendAsyncMessage("API:AddListener", {
this.childApiManager.conduit.sendAddListener({
childId: this.childApiManager.id,
listenerId: id,
path: this.path,
@ -1092,7 +1092,7 @@ class ProxyAPIImplementation extends SchemaAPIInterface {
map.ids.delete(id);
map.removedIds.add(id);
this.childApiManager.messageManager.sendAsyncMessage("API:RemoveListener", {
this.childApiManager.conduit.sendRemoveListener({
childId: this.childApiManager.id,
listenerId: id,
path: this.path,
@ -1173,10 +1173,18 @@ class ChildAPIManager {
this.id = `${context.extension.id}.${context.contextId}`;
MessageChannel.addListener(messageManager, "API:RunListener", this);
messageManager.addMessageListener("API:CallResult", this);
this.conduit = context.openConduit(this, {
id: this.id,
send: ["CreateProxyContext", "APICall", "AddListener", "RemoveListener"],
recv: ["CallResult", "RunListener"],
});
this.messageFilterStrict = { childId: this.id };
this.conduit.sendCreateProxyContext({
childId: this.id,
extensionId: context.extension.id,
principal: context.principal,
...contextData,
});
this.listeners = new DefaultMap(() => ({
ids: new Map(),
@ -1187,15 +1195,6 @@ class ChildAPIManager {
// Map[callId -> Deferred]
this.callPromises = new Map();
let params = {
childId: this.id,
extensionId: context.extension.id,
principal: context.principal,
};
Object.assign(params, contextData);
this.messageManager.sendAsyncMessage("API:CreateProxyContext", params);
this.permissionsChangedCallbacks = new Set();
this.updatePermissions = null;
if (this.context.extension.optionalPermissions.length) {
@ -1217,50 +1216,42 @@ class ChildAPIManager {
this.schema.inject(obj, this);
}
receiveMessage({ name, messageName, data }) {
if (data.childId != this.id) {
return;
recvCallResult(data) {
let deferred = this.callPromises.get(data.callId);
this.callPromises.delete(data.callId);
if ("error" in data) {
deferred.reject(data.error);
} else {
let result = data.result.deserialize(this.context.cloneScope);
deferred.resolve(new NoCloneSpreadArgs(result));
}
}
switch (name || messageName) {
case "API:RunListener":
let map = this.listeners.get(data.path);
let listener = map.ids.get(data.listenerId);
recvRunListener(data) {
let map = this.listeners.get(data.path);
let listener = map.ids.get(data.listenerId);
if (listener) {
let args = data.args.deserialize(this.context.cloneScope);
let fire = () => this.context.applySafeWithoutClone(listener, args);
return Promise.resolve(
data.handlingUserInput
? withHandlingUserInput(this.context.contentWindow, fire)
: fire()
).then(result => {
if (result !== undefined) {
return new StructuredCloneHolder(result, this.context.cloneScope);
}
return result;
});
if (listener) {
let args = data.args.deserialize(this.context.cloneScope);
let fire = () => this.context.applySafeWithoutClone(listener, args);
return Promise.resolve(
data.handlingUserInput
? withHandlingUserInput(this.context.contentWindow, fire)
: fire()
).then(result => {
if (result !== undefined) {
return new StructuredCloneHolder(result, this.context.cloneScope);
}
if (!map.removedIds.has(data.listenerId)) {
Services.console.logStringMessage(
`Unknown listener at childId=${data.childId} path=${
data.path
} listenerId=${data.listenerId}\n`
);
}
break;
case "API:CallResult":
let deferred = this.callPromises.get(data.callId);
if ("error" in data) {
deferred.reject(data.error);
} else {
let result = data.result.deserialize(this.context.cloneScope);
deferred.resolve(new NoCloneSpreadArgs(result));
}
this.callPromises.delete(data.callId);
break;
return result;
});
}
if (!map.removedIds.has(data.listenerId)) {
Services.console.logStringMessage(
`Unknown listener at childId=${data.childId} path=${
data.path
} listenerId=${data.listenerId}\n`
);
}
}
@ -1271,11 +1262,7 @@ class ChildAPIManager {
* @param {Array} args The parameters for the function.
*/
callParentFunctionNoReturn(path, args) {
this.messageManager.sendAsyncMessage("API:Call", {
childId: this.id,
path,
args,
});
this.conduit.sendAPICall({ childId: this.id, path, args });
}
/**
@ -1299,7 +1286,8 @@ class ChildAPIManager {
// logged the api_call. Flag it so the parent doesn't log again.
let { alreadyLogged = true } = options;
this.messageManager.sendAsyncMessage("API:Call", {
// TODO: conduit.queryAPICall()
this.conduit.sendAPICall({
childId: this.id,
callId,
path,
@ -1335,11 +1323,8 @@ class ChildAPIManager {
}
close() {
this.messageManager.sendAsyncMessage("API:CloseProxyContext", {
childId: this.id,
});
this.messageManager.removeMessageListener("API:CallResult", this);
MessageChannel.removeListener(this.messageManager, "API:RunListener", this);
// Reports CONDUIT_CLOSED on the parent side.
this.conduit.close();
if (this.updatePermissions) {
this.context.extension.off("add-permissions", this.updatePermissions);

Просмотреть файл

@ -489,6 +489,11 @@ class BaseContext {
return this.extension.canAccessWindow(window);
}
openConduit(subject, address) {
let actor = this.contentWindow.getWindowGlobalChild().getActor("Conduits");
return actor.openConduit(subject, address);
}
setContentWindow(contentWindow) {
if (!this.canAccessWindow(contentWindow)) {
throw new Error(

Просмотреть файл

@ -24,6 +24,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
AddonManager: "resource://gre/modules/AddonManager.jsm",
AppConstants: "resource://gre/modules/AppConstants.jsm",
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
BroadcastConduit: "resource://gre/modules/ConduitsParent.jsm",
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
ExtensionData: "resource://gre/modules/Extension.jsm",
@ -901,13 +902,15 @@ ParentAPIManager = {
proxyContexts: new Map(),
init() {
// TODO: Bug 1595186 - remove/replace all usage of MessageManager below.
Services.obs.addObserver(this, "message-manager-close");
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.conduit = new BroadcastConduit(this, {
id: "ParentAPIManager",
recv: ["CreateProxyContext", "APICall", "AddListener", "RemoveListener"],
send: ["CallResult"],
query: ["RunListener"],
});
},
attachMessageManager(extension, processMessageManager) {
@ -945,32 +948,9 @@ ParentAPIManager = {
}
},
receiveMessage({ name, data, target }) {
try {
switch (name) {
case "API:CreateProxyContext":
this.createProxyContext(data, target);
break;
case "API:CloseProxyContext":
this.closeProxyContext(data.childId);
break;
case "API:Call":
this.call(data, target);
break;
case "API:AddListener":
this.addListener(data, target);
break;
case "API:RemoveListener":
this.removeListener(data);
break;
}
} catch (e) {
Cu.reportError(e);
}
recvCreateProxyContext(data, { actor, sender }) {
this.conduit.reportOnClosed(sender.id);
this.createProxyContext(data, actor.browsingContext.top.embedderElement);
},
createProxyContext(data, target) {
@ -1036,6 +1016,10 @@ ParentAPIManager = {
this.proxyContexts.set(childId, context);
},
recvConduitClosed(sender) {
this.closeProxyContext(sender.id);
},
closeProxyContext(childId) {
let context = this.proxyContexts.get(childId);
if (context) {
@ -1079,8 +1063,9 @@ ParentAPIManager = {
}
},
async call(data, target) {
async recvAPICall(data, { actor }) {
let context = this.getContextById(data.childId);
let target = actor.browsingContext.top.embedderElement;
if (context.parentMessageManager !== target.messageManager) {
throw new Error("Got message on unexpected message manager");
}
@ -1094,16 +1079,12 @@ ParentAPIManager = {
return;
}
context.parentMessageManager.sendAsyncMessage(
"API:CallResult",
Object.assign(
{
childId: data.childId,
callId: data.callId,
},
result
)
);
this.conduit.sendCallResult(data.childId, {
childId: data.childId,
callId: data.callId,
path: data.path,
...result,
});
};
try {
@ -1143,47 +1124,39 @@ ParentAPIManager = {
}
},
async addListener(data, target) {
async recvAddListener(data, { actor }) {
let context = this.getContextById(data.childId);
let target = actor.browsingContext.top.embedderElement;
if (context.parentMessageManager !== target.messageManager) {
throw new Error("Got message on unexpected message manager");
}
let { childId } = data;
let handlingUserInput = false;
let lowPriority = data.path.startsWith("webRequest.");
function listener(...listenerArgs) {
return context
.sendMessage(
context.parentMessageManager,
"API:RunListener",
{
childId,
handlingUserInput,
listenerId: data.listenerId,
path: data.path,
get args() {
return new StructuredCloneHolder(listenerArgs);
},
},
{
lowPriority,
recipient: { childId },
}
)
.then(result => {
let rv = result && result.deserialize(global);
ExtensionActivityLog.log(
context.extension.id,
context.viewType,
"api_event",
data.path,
{ args: listenerArgs, result: rv }
);
return rv;
});
}
// TODO: Bug 1587058 - Redesign webRequest event coelescing.
// let lowPriority = data.path.startsWith("webRequest.");
let listener = async (...listenerArgs) => {
let result = await this.conduit.queryRunListener(childId, {
childId,
handlingUserInput,
listenerId: data.listenerId,
path: data.path,
get args() {
return new StructuredCloneHolder(listenerArgs);
},
});
let rv = result && result.deserialize(global);
ExtensionActivityLog.log(
context.extension.id,
context.viewType,
"api_event",
data.path,
{ args: listenerArgs, result: rv }
);
return rv;
};
context.listenerProxies.set(data.listenerId, listener);
@ -1215,7 +1188,7 @@ ParentAPIManager = {
);
},
async removeListener(data) {
async recvRemoveListener(data) {
let context = this.getContextById(data.childId);
let listener = context.listenerProxies.get(data.listenerId);

Просмотреть файл

@ -9,6 +9,8 @@ with Files('**'):
BUG_COMPONENT = ('WebExtensions', 'General')
EXTRA_JS_MODULES += [
'ConduitsChild.jsm',
'ConduitsParent.jsm',
'Extension.jsm',
'ExtensionActions.jsm',
'ExtensionActivityLog.jsm',

Просмотреть файл

@ -30,7 +30,7 @@ customElements.define(
<toolbarbutton id="print-preview-navigateHome" class="print-preview-navigate-button tabbable" oncommand="parentNode.navigate(0, 0, 'home');" data-l10n-id="printpreview-homearrow"/>
<toolbarbutton id="print-preview-navigatePrevious" class="print-preview-navigate-button tabbable" oncommand="parentNode.navigate(-1, 0, 0);" data-l10n-id="printpreview-previousarrow"/>
<hbox align="center" pack="center">
<html:input id="print-preview-pageNumber" hidespinbuttons="true" type="number" value="1" min="1"/>
<html:input id="print-preview-pageNumber" class="input-number-mozbox" hidespinbuttons="true" type="number" value="1" min="1"/>
<label data-l10n-id="printpreview-of"/>
<label id="print-preview-totalPages" value="1"/>
</hbox>

Просмотреть файл

@ -595,6 +595,7 @@ var PrintUtils = {
is: "printpreview-toolbar",
});
printPreviewTB.setAttribute("fullscreentoolbar", true);
printPreviewTB.setAttribute("flex", "1");
printPreviewTB.id = "print-preview-toolbar";
let navToolbox = this._listener.getNavToolbox();

Просмотреть файл

@ -38,7 +38,6 @@
}
/* Rules required for style caching of anonymous content scrollbar parts */
scrollcorner, resizer, scrollbar, scrollbarbutton, slider {
/* All scrollbar parts must not inherit any properties from the scrollable
* element (except for visibility and pointer-events), for the anonymous
@ -90,10 +89,19 @@ scrollcorner, resizer, scrollbar, scrollbarbutton, slider {
box-sizing: border-box;
}
scrollbar[orient="vertical"],
slider[orient="vertical"],
thumb[orient="vertical"] {
-moz-box-orient: vertical;
}
thumb {
/* Prevent -moz-user-modify declaration from designmode.css having an
* effect. */
-moz-user-modify: initial;
-moz-box-align: center;
-moz-box-pack: center;
}
/* There are other rules that set direction and cursor on scrollbar,

Просмотреть файл

@ -569,26 +569,24 @@ tabmodalprompt {
display: none;
}
[orient="vertical"] { -moz-box-orient: vertical !important; }
[orient="horizontal"] { -moz-box-orient: horizontal !important; }
[align="start"] { -moz-box-align: start !important; }
[align="center"] { -moz-box-align: center !important; }
[align="end"] { -moz-box-align: end !important; }
[align="baseline"] { -moz-box-align: baseline !important; }
[align="stretch"] { -moz-box-align: stretch !important; }
[pack="start"] { -moz-box-pack: start !important; }
[pack="center"] { -moz-box-pack: center !important; }
[pack="end"] { -moz-box-pack: end !important; }
@supports -moz-bool-pref("layout.css.emulate-moz-box-with-flex") {
/* Support common XUL attributes in the emulated flex mode so we can
test the browser in this configuration without mass-changing existing
markup and CSS. */
[orient="vertical"] { -moz-box-orient: vertical; }
[orient="horizontal"] { -moz-box-orient: horizontal; }
[align="start"] { -moz-box-align: start; }
[align="center"] { -moz-box-align: center; }
[align="end"] { -moz-box-align: end; }
[align="baseline"] { -moz-box-align: baseline; }
[align="stretch"] { -moz-box-align: stretch; }
[pack="start"] { -moz-box-pack: start; }
[pack="center"] { -moz-box-pack: center; }
[pack="end"] { -moz-box-pack: end; }
/* This isn't a real solution for [flex] and [ordinal], but it covers enough
cases to render the browser chrome. If we get attr() in Bug 435426 this could
work for all cases. */
cases to render the browser chrome for us to test emulated flex mode without
mass-changing existing markup and CSS.
If we get attr() in Bug 435426 this could work for all cases. */
[flex="1"] { -moz-box-flex: 1; }
[flex="2"] { -moz-box-flex: 2; }
[flex="3"] { -moz-box-flex: 3; }

Просмотреть файл

@ -113,9 +113,9 @@ def main():
# in front of symbols.mozilla.org has a 300 second timeout, so we'll use that.
timeout=(10, 300),
**zip_arg)
# 500 is likely to be a transient failure.
# 429 or any 5XX is likely to be a transient failure.
# Break out for success or other error codes.
if r.status_code < 500:
if r.ok or (r.status_code < 500 and r.status_code != 429):
break
print_error(r)
except requests.exceptions.RequestException as e:

Просмотреть файл

@ -105,6 +105,18 @@ let ACTORS = {
allFrames: true,
},
Conduits: {
parent: {
moduleURI: "resource://gre/modules/ConduitsParent.jsm",
},
child: {
moduleURI: "resource://gre/modules/ConduitsChild.jsm",
},
allFrames: true,
},
DateTimePicker: {
parent: {
moduleURI: "resource://gre/actors/DateTimePickerParent.jsm",

Просмотреть файл

@ -6,30 +6,29 @@
== Styles used by the input[type="number"] element.
======================================================================= */
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
@namespace url("http://www.w3.org/1999/xhtml");
html|input[type="number"] {
input[type="number"] {
text-align: right;
}
html|input[type="number"][hidespinbuttons="true"] {
input[type="number"][hidespinbuttons="true"] {
-moz-appearance: textfield !important;
}
/* input[type=number] uses display: flex; by default which is incompatible with XUL flexbox
Forcing XUL flexbox allows changing the size of the input. */
xul|*:root html|input[type="number"],
xul|*:root html|input[type="number"]::-moz-number-wrapper {
.input-number-mozbox,
.input-number-mozbox::-moz-number-wrapper {
display: -moz-box;
-moz-box-align: center;
}
xul|*:root html|input[type="number"]::-moz-number-wrapper,
xul|*:root html|input[type="number"]::-moz-number-text {
.input-number-mozbox::-moz-number-wrapper,
.input-number-mozbox::-moz-number-text {
-moz-box-flex: 1;
}
xul|*:root html|input[type="number"]::-moz-number-wrapper {
.input-number-mozbox::-moz-number-wrapper {
width: 100%;
}

Просмотреть файл

@ -27,10 +27,6 @@
#define LOG(args) MOZ_LOG(mLog, mozilla::LogLevel::Debug, args)
#ifdef __MINGW32__
# define ASSOCF_NONE 0x0
#endif
// helper methods: forward declarations...
static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
nsString& aFileExtension);
@ -304,16 +300,10 @@ nsresult nsOSHelperAppService::GetDefaultAppInfo(
nsCOMPtr<nsILocalFileWin> lf = new nsLocalFile();
rv = lf->InitWithCommandLine(handlerCommand);
NS_ENSURE_SUCCESS(rv, rv);
lf.forget(aDefaultApplication);
wchar_t friendlyName[1024];
DWORD friendlyNameSize = 1024;
HRESULT hr = AssocQueryString(ASSOCF_NONE, ASSOCSTR_FRIENDLYAPPNAME,
PromiseFlatString(aAppInfo).get(), NULL,
friendlyName, &friendlyNameSize);
if (SUCCEEDED(hr) && friendlyNameSize > 1) {
aDefaultDescription.Assign(friendlyName, friendlyNameSize - 1);
}
// The "FileDescription" field contains the actual name of the application.
lf->GetVersionInfoField("FileDescription", aDefaultDescription);
lf.forget(aDefaultApplication);
return NS_OK;
}

Просмотреть файл

@ -44,6 +44,14 @@ nsTouchBarUpdater::UpdateTouchBarInputs(nsIBaseWindow* aWindow,
continue;
}
NSTouchBarItemIdentifier newIdentifier = [TouchBarInput nativeIdentifierWithXPCOM:input];
// We don't support updating the Share scrubber since it's a special
// Apple-made component that behaves differently from the other inputs.
if ([newIdentifier isEqualToString:[TouchBarInput nativeIdentifierWithType:@"scrubber"
withKey:@"share"]]) {
continue;
}
TouchBarInput* convertedInput = [[TouchBarInput alloc] initWithXPCOM:input];
[(nsTouchBar*)cocoaWin.touchBar updateItem:convertedInput];
}