Merge mozilla-central to mozilla-inbound.

This commit is contained in:
Cosmin Sabou 2018-12-13 06:01:44 +02:00
commit 7a9da4ebbf
200 changed files with 4335 additions and 2013 deletions

View File

@ -169,8 +169,12 @@ devtools/server/tests/unit/xpcshell_debugging_script.js
dom/abort/**
dom/animation/**
dom/asmjscache/**
dom/base/**
dom/battery/**
dom/base/*.*
dom/base/test/*.*
dom/base/test/unit/test_serializers_entities*.js
dom/base/test/unit_ipc/**
dom/base/test/jsmodules/**
dom/bindings/**
dom/broadcastchannel/**
dom/browser-element/**

View File

@ -39,5 +39,12 @@ module.exports = {
"env": {
"mozilla/browser-window": true
}
}, {
// TODO: Bug 1513639. Temporarily turn off reject-importGlobalProperties
// due to other ESLint enabling happening in DOM.
"files": "dom/**",
"rules": {
"mozilla/reject-importGlobalProperties": "off",
}
}]
};

24
Cargo.lock generated
View File

@ -840,7 +840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "euclid"
version = "0.19.3"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1049,7 +1049,7 @@ dependencies = [
"jsrust_shared 0.1.0",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mozurl 0.0.1",
"mp4parse_capi 0.10.1",
"mp4parse_capi 0.11.2",
"netwerk_helper 0.0.1",
"nserror 0.1.0",
"nsstring 0.1.0",
@ -1419,7 +1419,7 @@ version = "0.0.1"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0",
"selectors 0.20.0",
"servo_arc 0.1.1",
@ -1609,7 +1609,7 @@ dependencies = [
[[package]]
name = "mp4parse"
version = "0.10.1"
version = "0.11.2"
dependencies = [
"bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1624,11 +1624,11 @@ version = "0.1.0"
[[package]]
name = "mp4parse_capi"
version = "0.10.1"
version = "0.11.2"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mp4parse 0.10.1",
"mp4parse 0.11.2",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1875,7 +1875,7 @@ version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2366,7 +2366,7 @@ dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible 0.0.1",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0",
@ -2423,7 +2423,7 @@ dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"selectors 0.20.0",
@ -2962,7 +2962,7 @@ dependencies = [
"core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
@ -2978,7 +2978,7 @@ dependencies = [
"core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3190,7 +3190,7 @@ dependencies = [
"checksum encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1a8fa54e6689eb2549c4efed8d00d7f3b2b994a064555b0e8df4ae3764bcc4be"
"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "600657e7e5c03bfbccdc68721bc3b5abcb761553973387124eae9c9e4f02c210"
"checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727"
"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"

View File

@ -1,4 +1,4 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");

View File

@ -24,6 +24,14 @@ const READER_MODE_PREFIX = "about:reader";
let tabTracker;
let windowTracker;
function isPrivateTab(nativeTab) {
return PrivateBrowsingUtils.isBrowserPrivate(nativeTab.linkedBrowser);
}
function isPrivateWindow(window) {
return PrivateBrowsingUtils.isContentWindowPrivate(window);
}
// This function is pretty tightly tied to Extension.jsm.
// Its job is to fill in the |tab| property of the sender.
const getSender = (extension, target, sender) => {
@ -255,14 +263,19 @@ class WindowTracker extends WindowTrackerBase {
}
/**
* @property {DOMWindow|null} topNormalWindow
* @param {BaseContext} context
* The extension context
* @returns {DOMWindow|null} topNormalWindow
* The currently active, or topmost, browser window, or null if no
* browser window is currently open.
* Will return the topmost "normal" (i.e., not popup) window.
* @readonly
*/
get topNormalWindow() {
return BrowserWindowTracker.getTopWindow({allowPopups: false});
getTopNormalWindow(context) {
let options = {allowPopups: false};
if (!context.privateBrowsingAllowed) {
options.private = false;
}
return BrowserWindowTracker.getTopWindow(options);
}
}
@ -364,16 +377,18 @@ class TabTracker extends TabTrackerBase {
this.emit("tab-adopted", adoptingTab, adoptedTab);
if (this.has("tab-detached")) {
let nativeTab = adoptedTab;
let isPrivate = isPrivateTab(nativeTab);
let adoptedBy = adoptingTab;
let oldWindowId = windowTracker.getId(nativeTab.ownerGlobal);
let oldPosition = nativeTab._tPos;
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition});
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition, isPrivate});
}
if (this.has("tab-attached")) {
let nativeTab = adoptingTab;
let isPrivate = isPrivateTab(nativeTab);
let newWindowId = windowTracker.getId(nativeTab.ownerGlobal);
let newPosition = nativeTab._tPos;
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition});
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition, isPrivate});
}
}
@ -576,9 +591,16 @@ class TabTracker extends TabTrackerBase {
* @private
*/
emitActivated(nativeTab, previousTab = undefined) {
let previousTabIsPrivate, previousTabId;
if (previousTab && !previousTab.closing) {
previousTabId = this.getId(previousTab);
previousTabIsPrivate = isPrivateTab(previousTab);
}
this.emit("tab-activated", {
isPrivate: isPrivateTab(nativeTab),
tabId: this.getId(nativeTab),
previousTabId: previousTab && !previousTab.closing ? this.getId(previousTab) : undefined,
previousTabId,
previousTabIsPrivate,
windowId: windowTracker.getId(nativeTab.ownerGlobal)});
}
@ -592,7 +614,11 @@ class TabTracker extends TabTrackerBase {
emitHighlighted(window) {
let tabIds = window.gBrowser.selectedTabs.map(tab => this.getId(tab));
let windowId = windowTracker.getId(window);
this.emit("tabs-highlighted", {tabIds, windowId});
this.emit("tabs-highlighted", {
tabIds,
windowId,
isPrivate: isPrivateWindow(window),
});
}
/**
@ -605,7 +631,7 @@ class TabTracker extends TabTrackerBase {
* @private
*/
emitCreated(nativeTab, currentTabSize) {
this.emit("tab-created", {nativeTab, currentTabSize});
this.emit("tab-created", {nativeTab, currentTabSize, isPrivate: isPrivateTab(nativeTab)});
}
/**
@ -622,7 +648,7 @@ class TabTracker extends TabTrackerBase {
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
let tabId = this.getId(nativeTab);
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing, isPrivate: isPrivateTab(nativeTab)});
}
getBrowserData(browser) {
@ -1048,6 +1074,9 @@ class TabManager extends TabManagerBase {
let nativeTab = tabTracker.getTab(tabId, default_);
if (nativeTab) {
if (!this.extension.canAccessWindow(nativeTab.ownerGlobal)) {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}
return this.getWrapper(nativeTab);
}
return default_;
@ -1061,6 +1090,11 @@ class TabManager extends TabManagerBase {
return super.revokeActiveTabPermission(nativeTab);
}
canAccessTab(nativeTab) {
return this.extension.privateBrowsingAllowed ||
!PrivateBrowsingUtils.isBrowserPrivate(nativeTab.linkedBrowser);
}
wrapTab(nativeTab) {
return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
}
@ -1073,9 +1107,19 @@ class WindowManager extends WindowManagerBase {
return this.getWrapper(window);
}
* getAll() {
canAccessWindow(window, context) {
return (context && context.canAccessWindow(window)) || this.extension.canAccessWindow(window);
}
* getAll(context) {
for (let window of windowTracker.browserWindows()) {
yield this.getWrapper(window);
if (!this.canAccessWindow(window, context)) {
continue;
}
let wrapped = this.getWrapper(window);
if (wrapped) {
yield wrapped;
}
}
}

View File

@ -133,6 +133,7 @@ this.browserAction = class extends ExtensionAPI {
label: this.defaults.title || this.extension.name,
tooltiptext: this.defaults.title || "",
defaultArea: this.defaults.area,
showInPrivateBrowsing: this.extension.privateBrowsingAllowed,
// Don't attempt to load properties from the built-in widget string
// bundle.

View File

@ -178,7 +178,11 @@ class TabsUpdateFilterEventManager extends EventManager {
function getWindowID(windowId) {
if (windowId === Window.WINDOW_ID_CURRENT) {
return windowTracker.getId(windowTracker.topWindow);
let window = windowTracker.getTopWindow(context);
if (!window) {
return undefined;
}
return windowTracker.getId(window);
}
return windowId;
}
@ -201,7 +205,8 @@ class TabsUpdateFilterEventManager extends EventManager {
}
let fireForTab = (tab, changed) => {
if (!matchFilters(tab, changed)) {
// Tab may be null if private and not_allowed.
if (!tab || !matchFilters(tab, changed)) {
return;
}
@ -212,6 +217,9 @@ class TabsUpdateFilterEventManager extends EventManager {
};
let listener = event => {
if (!context.canAccessWindow(event.originalTarget.ownerGlobal)) {
return;
}
let needed = [];
if (event.type == "TabAttrModified") {
let changed = event.detail.changed;
@ -266,6 +274,10 @@ class TabsUpdateFilterEventManager extends EventManager {
let {gBrowser} = browser.ownerGlobal;
let tabElem = gBrowser.getTabForBrowser(browser);
if (tabElem) {
if (!context.canAccessWindow(tabElem.ownerGlobal)) {
return;
}
let changed = {status};
if (url) {
changed.url = url;
@ -279,7 +291,7 @@ class TabsUpdateFilterEventManager extends EventManager {
let {gBrowser} = message.target.ownerGlobal;
let nativeTab = gBrowser.getTabForBrowser(message.target);
if (nativeTab) {
if (nativeTab && context.canAccessWindow(nativeTab.ownerGlobal)) {
let tab = tabManager.getWrapper(nativeTab);
fireForTab(tab, {isArticle: message.data.isArticle});
}
@ -342,6 +354,29 @@ class TabsUpdateFilterEventManager extends EventManager {
}
}
function TabEventManager({context, name, event, listener}) {
let register = fire => {
let listener2 = (eventName, eventData, ...args) => {
if (!("isPrivate" in eventData)) {
throw new Error(`isPrivate property missing in tabTracker event "${eventName}"`);
}
if (eventData.isPrivate && !context.privateBrowsingAllowed) {
return;
}
listener(fire, eventData, ...args);
};
tabTracker.on(event, listener2);
return () => {
tabTracker.off(event, listener2);
};
};
return new EventManager({context, name, register}).api();
}
this.tabs = class extends ExtensionAPI {
static onUpdate(id, manifest) {
if (!manifest.permissions || !manifest.permissions.includes("tabHide")) {
@ -364,10 +399,25 @@ this.tabs = class extends ExtensionAPI {
let {tabManager, windowManager} = extension;
function getTabOrActive(tabId) {
if (tabId !== null) {
return tabTracker.getTab(tabId);
let tab = tabId !== null ? tabTracker.getTab(tabId) : tabTracker.activeTab;
if (!context.canAccessWindow(tab.ownerGlobal)) {
throw new ExtensionError(tabId === null ? "Cannot access activeTab" :
`Invalid tab ID: ${tabId}`);
}
return tabTracker.activeTab;
return tab;
}
function getNativeTabsFromIDArray(tabIds) {
if (!Array.isArray(tabIds)) {
tabIds = [tabIds];
}
return tabIds.map(tabId => {
let tab = tabTracker.getTab(tabId);
if (!context.canAccessWindow(tab.ownerGlobal)) {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}
return tab;
});
}
async function promiseTabWhenReady(tabId) {
@ -377,6 +427,10 @@ this.tabs = class extends ExtensionAPI {
} else {
tab = tabManager.getWrapper(tabTracker.activeTab);
}
if (!tab) {
throw new ExtensionError(tabId == null ?
"Cannot access activeTab" : `Invalid tab ID: ${tabId}`);
}
await tabListener.awaitTabReady(tab.nativeTab);
@ -385,95 +439,63 @@ this.tabs = class extends ExtensionAPI {
let self = {
tabs: {
onActivated: new EventManager({
onActivated: TabEventManager({
context,
name: "tabs.onActivated",
register: fire => {
let listener = (eventName, event) => {
fire.async(event);
};
tabTracker.on("tab-activated", listener);
return () => {
tabTracker.off("tab-activated", listener);
};
event: "tab-activated",
listener: (fire, event) => {
let {tabId, windowId, previousTabId, previousTabIsPrivate} = event;
if (previousTabIsPrivate && !context.privateBrowsingAllowed) {
previousTabId = undefined;
}
fire.async({tabId, previousTabId, windowId});
},
}).api(),
}),
onCreated: new EventManager({
onCreated: TabEventManager({
context,
name: "tabs.onCreated",
register: fire => {
let listener = (eventName, event) => {
fire.async(tabManager.convert(event.nativeTab, event.currentTabSize));
};
tabTracker.on("tab-created", listener);
return () => {
tabTracker.off("tab-created", listener);
};
event: "tab-created",
listener: (fire, event) => {
fire.async(tabManager.convert(event.nativeTab, event.currentTabSize));
},
}).api(),
}),
onHighlighted: new EventManager({
onHighlighted: TabEventManager({
context,
name: "tabs.onHighlighted",
register: fire => {
let listener = (eventName, event) => {
fire.async(event);
};
tabTracker.on("tabs-highlighted", listener);
return () => {
tabTracker.off("tabs-highlighted", listener);
};
event: "tabs-highlighted",
listener: (fire, event) => {
fire.async({tabIds: event.tabIds, windowId: event.windowId});
},
}).api(),
}),
onAttached: new EventManager({
onAttached: TabEventManager({
context,
name: "tabs.onAttached",
register: fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
};
tabTracker.on("tab-attached", listener);
return () => {
tabTracker.off("tab-attached", listener);
};
event: "tab-attached",
listener: (fire, event) => {
fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
},
}).api(),
}),
onDetached: new EventManager({
onDetached: TabEventManager({
context,
name: "tabs.onDetached",
register: fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {oldWindowId: event.oldWindowId, oldPosition: event.oldPosition});
};
tabTracker.on("tab-detached", listener);
return () => {
tabTracker.off("tab-detached", listener);
};
event: "tab-detached",
listener: (fire, event) => {
fire.async(event.tabId, {oldWindowId: event.oldWindowId, oldPosition: event.oldPosition});
},
}).api(),
}),
onRemoved: new EventManager({
onRemoved: TabEventManager({
context,
name: "tabs.onRemoved",
register: fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
};
tabTracker.on("tab-removed", listener);
return () => {
tabTracker.off("tab-removed", listener);
};
event: "tab-removed",
listener: (fire, event) => {
fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
},
}).api(),
}),
onReplaced: new EventManager({
context,
@ -489,11 +511,13 @@ this.tabs = class extends ExtensionAPI {
register: fire => {
let moveListener = event => {
let nativeTab = event.originalTarget;
fire.async(tabTracker.getId(nativeTab), {
windowId: windowTracker.getId(nativeTab.ownerGlobal),
fromIndex: event.detail,
toIndex: nativeTab._tPos,
});
if (context.canAccessWindow(nativeTab.ownerGlobal)) {
fire.async(tabTracker.getId(nativeTab), {
windowId: windowTracker.getId(nativeTab.ownerGlobal),
fromIndex: event.detail,
toIndex: nativeTab._tPos,
});
}
};
windowTracker.addListener("TabMove", moveListener);
@ -509,8 +533,10 @@ this.tabs = class extends ExtensionAPI {
return new Promise((resolve, reject) => {
let window = createProperties.windowId !== null ?
windowTracker.getWindow(createProperties.windowId, context) :
windowTracker.topNormalWindow;
windowTracker.getTopNormalWindow(context);
if (!window || !context.canAccessWindow(window)) {
throw new Error("Not allowed to create tabs on the target window");
}
if (!window.gBrowser) {
let obs = (finishedWindow, topic, data) => {
if (finishedWindow != window) {
@ -642,25 +668,15 @@ this.tabs = class extends ExtensionAPI {
});
},
async remove(tabs) {
if (!Array.isArray(tabs)) {
tabs = [tabs];
}
for (let tabId of tabs) {
let nativeTab = tabTracker.getTab(tabId);
async remove(tabIds) {
for (let nativeTab of getNativeTabsFromIDArray(tabIds)) {
nativeTab.ownerGlobal.gBrowser.removeTab(nativeTab);
}
},
async discard(tabIds) {
if (!Array.isArray(tabIds)) {
tabIds = [tabIds];
}
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
for (let tab of tabs) {
tab.ownerGlobal.gBrowser.discardBrowser(tab.linkedBrowser);
for (let nativeTab of getNativeTabsFromIDArray(tabIds)) {
nativeTab.ownerGlobal.gBrowser.discardBrowser(nativeTab.linkedBrowser);
}
},
@ -736,6 +752,7 @@ this.tabs = class extends ExtensionAPI {
if (!successor) {
throw new ExtensionError("Invalid successorTabId");
}
// This also ensures "privateness" matches.
if (successor.ownerDocument !== nativeTab.ownerDocument) {
throw new ExtensionError("Successor tab must be in the same window as the tab being updated");
}
@ -798,7 +815,7 @@ this.tabs = class extends ExtensionAPI {
async captureVisibleTab(windowId, options) {
let window = windowId == null ?
windowTracker.topWindow :
windowTracker.getTopWindow(context) :
windowTracker.getWindow(windowId, context);
let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
@ -809,25 +826,21 @@ this.tabs = class extends ExtensionAPI {
async detectLanguage(tabId) {
let tab = await promiseTabWhenReady(tabId);
return tab.sendMessage(context, "Extension:DetectLanguage");
},
async executeScript(tabId, details) {
let tab = await promiseTabWhenReady(tabId);
return tab.executeScript(context, details);
},
async insertCSS(tabId, details) {
let tab = await promiseTabWhenReady(tabId);
return tab.insertCSS(context, details);
},
async removeCSS(tabId, details) {
let tab = await promiseTabWhenReady(tabId);
return tab.removeCSS(context, details);
},
@ -839,7 +852,7 @@ this.tabs = class extends ExtensionAPI {
let destinationWindow = null;
if (moveProperties.windowId !== null) {
destinationWindow = windowTracker.getWindow(moveProperties.windowId);
destinationWindow = windowTracker.getWindow(moveProperties.windowId, context);
// Fail on an invalid window.
if (!destinationWindow) {
return Promise.reject({message: `Invalid window ID: ${moveProperties.windowId}`});
@ -856,8 +869,7 @@ this.tabs = class extends ExtensionAPI {
let indexMap = new Map();
let lastInsertion = new Map();
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
for (let nativeTab of tabs) {
for (let nativeTab of getNativeTabsFromIDArray(tabIds)) {
// If the window is not specified, use the window from the tab.
let window = destinationWindow || nativeTab.ownerGlobal;
let gBrowser = window.gBrowser;
@ -911,7 +923,8 @@ this.tabs = class extends ExtensionAPI {
},
duplicate(tabId) {
let nativeTab = tabTracker.getTab(tabId);
// Schema requires tab id.
let nativeTab = getTabOrActive(tabId);
let gBrowser = nativeTab.ownerGlobal.gBrowser;
let newTab = gBrowser.duplicateTab(nativeTab);
@ -1011,6 +1024,9 @@ this.tabs = class extends ExtensionAPI {
// Store the zoom level for all existing tabs.
for (let window of windowTracker.browserWindows()) {
if (!context.canAccessWindow(window)) {
continue;
}
for (let nativeTab of window.gBrowser.tabs) {
let browser = nativeTab.linkedBrowser;
zoomLevels.set(browser, getZoomLevel(browser));
@ -1019,7 +1035,9 @@ this.tabs = class extends ExtensionAPI {
let tabCreated = (eventName, event) => {
let browser = event.nativeTab.linkedBrowser;
zoomLevels.set(browser, getZoomLevel(browser));
if (!event.isPrivate || context.privateBrowsingAllowed) {
zoomLevels.set(browser, getZoomLevel(browser));
}
};
@ -1032,6 +1050,10 @@ this.tabs = class extends ExtensionAPI {
browser = browser.docShell.chromeEventHandler;
}
if (!context.canAccessWindow(browser.ownerGlobal)) {
return;
}
let {gBrowser} = browser.ownerGlobal;
let nativeTab = gBrowser.getTabForBrowser(browser);
if (!nativeTab) {
@ -1249,9 +1271,8 @@ this.tabs = class extends ExtensionAPI {
if (!tab.isInReaderMode && !tab.isArticle) {
throw new ExtensionError("The specified tab cannot be placed into reader mode.");
}
tab = getTabOrActive(tabId);
tab.linkedBrowser.messageManager.sendAsyncMessage("Reader:ToggleReaderMode");
let nativeTab = getTabOrActive(tabId);
nativeTab.linkedBrowser.messageManager.sendAsyncMessage("Reader:ToggleReaderMode");
},
moveInSuccession(tabIds, tabId, options) {
@ -1266,6 +1287,9 @@ this.tabs = class extends ExtensionAPI {
const referenceTab = tabTracker.getTab(tabId, null);
let referenceWindow = referenceTab && referenceTab.ownerGlobal;
if (referenceWindow && !context.canAccessWindow(referenceWindow)) {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}
let previousTab, lastSuccessor;
if (append) {
previousTab = referenceTab;
@ -1280,6 +1304,9 @@ this.tabs = class extends ExtensionAPI {
if (tab === null) {
continue;
}
if (!context.canAccessWindow(tab.ownerGlobal)) {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}
if (referenceWindow === null) {
referenceWindow = tab.ownerGlobal;
} else if (tab.ownerGlobal !== referenceWindow) {
@ -1310,12 +1337,7 @@ this.tabs = class extends ExtensionAPI {
throw new ExtensionError(`tabs.show is currently experimental and must be enabled with the ${TABHIDE_PREFNAME} preference.`);
}
if (!Array.isArray(tabIds)) {
tabIds = [tabIds];
}
for (let tabId of tabIds) {
let tab = tabTracker.getTab(tabId);
for (let tab of getNativeTabsFromIDArray(tabIds)) {
if (tab.ownerGlobal) {
tab.ownerGlobal.gBrowser.showTab(tab);
}
@ -1327,13 +1349,8 @@ this.tabs = class extends ExtensionAPI {
throw new ExtensionError(`tabs.hide is currently experimental and must be enabled with the ${TABHIDE_PREFNAME} preference.`);
}
if (!Array.isArray(tabIds)) {
tabIds = [tabIds];
}
let hidden = [];
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
for (let tab of tabs) {
for (let tab of getNativeTabsFromIDArray(tabIds)) {
if (tab.ownerGlobal && !tab.hidden) {
tab.ownerGlobal.gBrowser.hideTab(tab, extension.id);
if (tab.hidden) {
@ -1357,6 +1374,10 @@ this.tabs = class extends ExtensionAPI {
windowId = Window.WINDOW_ID_CURRENT;
}
let window = windowTracker.getWindow(windowId, context);
if (!context.canAccessWindow(window)) {
throw new ExtensionError(`Invalid window ID: ${windowId}`);
}
if (!Array.isArray(tabs)) {
tabs = [tabs];
} else if (tabs.length == 0) {

View File

@ -30,7 +30,11 @@ var {
*/
function WindowEventManager(context, name, event, listener) {
let register = fire => {
let listener2 = listener.bind(null, fire);
let listener2 = (window, ...args) => {
if (context.canAccessWindow(window)) {
listener(fire, window, ...args);
}
};
windowTracker.addListener(event, listener2);
return () => {
@ -69,6 +73,9 @@ this.windows = class extends ExtensionAPI {
// event when switching focus between two Firefox windows.
Promise.resolve().then(() => {
let window = Services.focus.activeWindow;
if (!context.canAccessWindow(window)) {
return;
}
let windowId = window ? windowTracker.getId(window) : Window.WINDOW_ID_NONE;
if (windowId !== lastOnFocusChangedWindowId) {
fire.async(windowId);
@ -87,7 +94,7 @@ this.windows = class extends ExtensionAPI {
get: function(windowId, getInfo) {
let window = windowTracker.getWindow(windowId, context);
if (!window) {
if (!window || !context.canAccessWindow(window)) {
return Promise.reject({message: `Invalid window ID: ${windowId}`});
}
return Promise.resolve(windowManager.convert(window, getInfo));
@ -95,17 +102,24 @@ this.windows = class extends ExtensionAPI {
getCurrent: function(getInfo) {
let window = context.currentWindow || windowTracker.topWindow;
if (!context.canAccessWindow(window)) {
return Promise.reject({message: `Invalid window`});
}
return Promise.resolve(windowManager.convert(window, getInfo));
},
getLastFocused: function(getInfo) {
let window = windowTracker.topWindow;
if (!context.canAccessWindow(window)) {
return Promise.reject({message: `Invalid window`});
}
return Promise.resolve(windowManager.convert(window, getInfo));
},
getAll: function(getInfo) {
let doNotCheckTypes = getInfo === null || getInfo.windowTypes === null;
let windows = [];
// incognito access is checked in getAll
for (let win of windowManager.getAll()) {
if (doNotCheckTypes || getInfo.windowTypes.includes(win.type)) {
windows.push(win.convert(getInfo));
@ -117,6 +131,9 @@ this.windows = class extends ExtensionAPI {
create: function(createData) {
let needResize = (createData.left !== null || createData.top !== null ||
createData.width !== null || createData.height !== null);
if (createData.incognito && !context.privateBrowsingAllowed) {
return Promise.reject({message: "Extension does not have permission for incognito mode"});
}
if (needResize) {
if (createData.state !== null && createData.state != "normal") {
@ -144,7 +161,9 @@ this.windows = class extends ExtensionAPI {
}
let tab = tabTracker.getTab(createData.tabId);
if (!context.canAccessWindow(tab.ownerGlobal)) {
return Promise.reject({message: `Invalid tab ID: ${createData.tabId}`});
}
// Private browsing tabs can only be moved to private browsing
// windows.
let incognito = PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser);
@ -260,6 +279,9 @@ this.windows = class extends ExtensionAPI {
}
let win = windowManager.get(windowId, context);
if (!win) {
return Promise.reject({message: `Invalid window ID: ${windowId}`});
}
if (updateInfo.focused) {
Services.focus.activeWindow = win.window;
}
@ -287,6 +309,9 @@ this.windows = class extends ExtensionAPI {
remove: function(windowId) {
let window = windowTracker.getWindow(windowId, context);
if (!context.canAccessWindow(window)) {
return Promise.reject({message: `Invalid window ID: ${windowId}`});
}
window.close();
return new Promise(resolve => {

View File

@ -50,6 +50,7 @@ support-files =
# bug 1369197
skip-if = os == 'linux'
[browser_ext_browserAction_disabled.js]
[browser_ext_browserAction_incognito.js]
[browser_ext_browserAction_pageAction_icon.js]
[browser_ext_browserAction_pageAction_icon_permissions.js]
[browser_ext_browserAction_popup.js]
@ -201,6 +202,7 @@ skip-if = (verify && !debug && (os == 'mac'))
[browser_ext_tabs_hide.js]
[browser_ext_tabs_hide_update.js]
[browser_ext_tabs_highlight.js]
[browser_ext_tabs_incognito_not_allowed.js]
[browser_ext_tabs_insertCSS.js]
[browser_ext_tabs_lastAccessed.js]
[browser_ext_tabs_lazy.js]
@ -250,6 +252,7 @@ tags = fullscreen
[browser_ext_windows_create_tabId.js]
[browser_ext_windows_create_url.js]
[browser_ext_windows_events.js]
[browser_ext_windows_incognito.js]
[browser_ext_windows_remove.js]
[browser_ext_windows_size.js]
skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode

View File

@ -0,0 +1,43 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
async function testIncognito(incognitoOverride) {
let privateAllowed = incognitoOverride != "not_allowed";
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {},
},
incognitoOverride,
});
await extension.startup();
await showBrowserAction(extension);
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
await showBrowserAction(extension, privateWindow);
let widgetId = makeWidgetId(extension.id) + "-browser-action";
let node = window.document.getElementById(widgetId);
ok(!!node, "popup exists in non-private window");
node = privateWindow.document.getElementById(widgetId);
if (privateAllowed) {
ok(!!node, "popup exists in private window");
} else {
ok(!node, "popup does not exist in private window");
}
await BrowserTestUtils.closeWindow(privateWindow);
await extension.unload();
}
add_task(async function test_browserAction_not_allowed() {
await testIncognito("not_allowed");
});
add_task(async function test_browserAction_allowed() {
await testIncognito();
});

View File

@ -106,3 +106,32 @@ add_task(async function testIncognitoPopup() {
await extension.awaitFinish("incognito");
await extension.unload();
});
add_task(async function test_pageAction_incognito_not_allowed() {
const URL = "http://example.com/";
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["*://example.com/*"],
"page_action": {
"show_matches": ["<all_urls>"],
"pinned": true,
},
},
incognitoOverride: "not_allowed",
});
await extension.startup();
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL, true, true);
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
await BrowserTestUtils.openNewForegroundTab(privateWindow.gBrowser, URL, true, true);
let elem = await getPageActionButton(extension, window);
ok(elem, "pageAction button state correct in non-PB");
elem = await getPageActionButton(extension, privateWindow);
ok(!elem, "pageAction button state correct in private window");
BrowserTestUtils.removeTab(tab);
await BrowserTestUtils.closeWindow(privateWindow);
await extension.unload();
});

View File

@ -2,8 +2,22 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function testTabEvents() {
// A single monitor for the tests. If it receives any
// incognito data in event listeners it will fail.
let monitor;
add_task(async function startup() {
monitor = await startIncognitoMonitorExtension();
});
registerCleanupFunction(async function finish() {
await monitor.unload();
});
// Test tab events from private windows, the monitor above will fail
// if it receives any.
add_task(async function test_tab_events_incognito_monitored() {
async function background() {
let incognito = true;
let events = [];
let eventPromise;
let checkEvents = () => {
@ -54,24 +68,23 @@ add_task(async function testTabEvents() {
}
try {
browser.test.log("Create second browser window");
let windows = await Promise.all([
browser.windows.getCurrent(),
browser.windows.create({url: "about:blank"}),
browser.windows.create({url: "about:blank", incognito}),
browser.windows.create({url: "about:blank", incognito}),
]);
let windowId = windows[0].id;
let otherWindowId = windows[1].id;
let [created] = await expectEvents(["onCreated"]);
let initialTab = created.tab;
let created = await expectEvents(["onCreated", "onCreated"]);
let initialTab = created[1].tab;
browser.test.log("Create tab in window 1");
let tab = await browser.tabs.create({windowId, index: 0, url: "about:blank"});
let oldIndex = tab.index;
browser.test.assertEq(0, oldIndex, "Tab has the expected index");
browser.test.assertEq(tab.incognito, incognito, "Tab is incognito");
[created] = await expectEvents(["onCreated"]);
browser.test.assertEq(tab.id, created.tab.id, "Got expected tab ID");
@ -123,6 +136,7 @@ add_task(async function testTabEvents() {
browser.test.log("Create additional tab in window 1");
tab = await browser.tabs.create({windowId, url: "about:blank"});
await expectEvents(["onCreated"]);
browser.test.assertEq(tab.incognito, incognito, "Tab is incognito");
browser.test.log("Create a new window, adopting the new tab");
@ -136,7 +150,7 @@ add_task(async function testTabEvents() {
});
let [window] = await Promise.all([
browser.windows.create({tabId: tab.id}),
browser.windows.create({tabId: tab.id, incognito}),
promiseAttached,
]);
@ -163,9 +177,11 @@ add_task(async function testTabEvents() {
browser.test.assertEq(1, attached.newPosition, "Expected onAttached new index");
browser.test.assertEq(windowId, attached.newWindowId,
"Expected onAttached new window id");
browser.test.assertEq(tab.incognito, incognito, "Tab is incognito");
browser.test.log("Remove the tab");
await browser.tabs.remove(tab.id);
browser.windows.remove(windowId);
browser.test.notifyPass("tabs-events");
} catch (e) {
@ -178,7 +194,6 @@ add_task(async function testTabEvents() {
manifest: {
"permissions": ["tabs"],
},
background,
});

View File

@ -0,0 +1,92 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function testExecuteScriptIncognitoNotAllowed() {
const url = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/file_iframe_document.html";
let extension = ExtensionTestUtils.loadExtension({
incognitoOverride: "not_allowed",
manifest: {
// captureTab requires all_urls permission
"permissions": ["<all_urls>", "tabs", "tabHide"],
},
background() {
browser.test.onMessage.addListener(async pbw => {
// expect one tab from the non-pb window
let tabs = await browser.tabs.query({windowId: pbw.windowId});
browser.test.assertEq(0, tabs.length, "unable to query tabs in private window");
tabs = await browser.tabs.query({active: true});
browser.test.assertEq(1, tabs.length, "unable to query active tab in private window");
browser.test.assertTrue(tabs[0].windowId != pbw.windowId, "unable to query active tab in private window");
// apis that take a tabId
let tabIdAPIs = ["captureTab", "detectLanguage", "duplicate", "get", "hide",
"reload", "getZoomSettings", "getZoom", "toggleReaderMode"];
for (let name of tabIdAPIs) {
await browser.test.assertRejects(browser.tabs[name](pbw.tabId),
/Invalid tab ID/,
`should not be able to ${name}`);
}
await browser.test.assertRejects(browser.tabs.captureVisibleTab(pbw.windowId),
/Invalid window ID/,
"should not be able to duplicate");
await browser.test.assertRejects(browser.tabs.create({windowId: pbw.windowId, url: "http://mochi.test/"}),
/Invalid window ID/,
"unable to create tab in private window");
await browser.test.assertRejects(browser.tabs.executeScript(pbw.tabId, {code: "document.URL"}),
/Invalid tab ID/,
"should not be able to executeScript");
let currentTab = await browser.tabs.getCurrent();
browser.test.assertTrue(!currentTab, "unable to get current tab in private window");
await browser.test.assertRejects(browser.tabs.highlight({windowId: pbw.windowId, tabs: [pbw.tabId]}),
/Invalid window ID/,
"should not be able to highlight");
await browser.test.assertRejects(browser.tabs.insertCSS(pbw.tabId, {code: "* { background: rgb(42, 42, 42) }"}),
/Invalid tab ID/,
"should not be able to insertCSS");
await browser.test.assertRejects(browser.tabs.move(pbw.tabId, {index: 0, windowId: tabs[0].windowId}),
/Invalid tab ID/,
"unable to move tab to private window");
await browser.test.assertRejects(browser.tabs.move(tabs[0].id, {index: 0, windowId: pbw.windowId}),
/Invalid window ID/,
"unable to move tab to private window");
await browser.test.assertRejects(browser.tabs.printPreview(),
/Cannot access activeTab/,
"unable to printpreview tab");
await browser.test.assertRejects(browser.tabs.removeCSS(pbw.tabId, {}),
/Invalid tab ID/,
"unable to remove tab css");
await browser.test.assertRejects(browser.tabs.sendMessage(pbw.tabId, "test"),
/Could not establish connection/,
"unable to sendmessage");
await browser.test.assertRejects(browser.tabs.setZoomSettings(pbw.tabId, {}),
/Invalid tab ID/,
"should not be able to set zoom settings");
await browser.test.assertRejects(browser.tabs.setZoom(pbw.tabId, 3),
/Invalid tab ID/,
"should not be able to set zoom");
await browser.test.assertRejects(browser.tabs.update(pbw.tabId, {}),
/Invalid tab ID/,
"should not be able to update tab");
await browser.test.assertRejects(browser.tabs.moveInSuccession([pbw.tabId], tabs[0].id),
/Invalid tab ID/,
"should not be able to moveInSuccession");
await browser.test.assertRejects(browser.tabs.moveInSuccession([tabs[0].id], pbw.tabId),
/Invalid tab ID/,
"should not be able to moveInSuccession");
browser.test.notifyPass("pass");
});
},
});
let winData = await getIncognitoWindow(url);
await extension.startup();
extension.sendMessage(winData.details);
await extension.awaitFinish("pass");
await BrowserTestUtils.closeWindow(winData.win);
await extension.unload();
});

View File

@ -4,12 +4,17 @@
const SITE_SPECIFIC_PREF = "browser.zoom.siteSpecific";
add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
gBrowser.selectedTab = tab1;
// A single monitor for the tests. If it receives any
// incognito data in event listeners it will fail.
let monitor;
add_task(async function startup() {
monitor = await startIncognitoMonitorExtension();
});
registerCleanupFunction(async function finish() {
await monitor.unload();
});
add_task(async function test_zoom_api() {
async function background() {
function promiseUpdated(tabId, attr) {
return new Promise(resolve => {
@ -101,10 +106,10 @@ add_task(async function() {
};
try {
let tabs = await browser.tabs.query({lastFocusedWindow: true});
browser.test.assertEq(tabs.length, 3, "We have three tabs");
let tabs = await browser.tabs.query({});
browser.test.assertEq(tabs.length, 4, "We have 4 tabs");
let tabIds = [tabs[1].id, tabs[2].id];
let tabIds = tabs.splice(1).map(tab => tab.id);
await checkZoom(tabIds[0], 1);
await browser.tabs.setZoom(tabIds[0], 2);
@ -132,6 +137,9 @@ add_task(async function() {
await browser.tabs.setZoom(tabIds[1], 1.5);
await checkZoom(tabIds[1], 1.5, 2);
browser.test.log(`Switch to tab 3, expect zoom to affect private window`);
await browser.tabs.setZoom(tabIds[2], 3);
await checkZoom(tabIds[2], 3, 1);
browser.test.log(`Switch to tab 1, expect asynchronous zoom change just after the switch`);
await Promise.all([
@ -153,10 +161,12 @@ add_task(async function() {
await Promise.all([
browser.tabs.setZoom(tabIds[0], 0),
browser.tabs.setZoom(tabIds[1], 0),
browser.tabs.setZoom(tabIds[2], 0),
]);
await Promise.all([
checkZoom(tabIds[0], 1, 1.1),
checkZoom(tabIds[1], 1, 1.5),
checkZoom(tabIds[2], 1, 3),
]);
@ -211,12 +221,24 @@ add_task(async function() {
extension.sendMessage("msg-done", id, resp);
});
let url = "http://example.com/";
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
let selectedBrowser = privateWindow.getBrowser().selectedBrowser;
BrowserTestUtils.loadURI(selectedBrowser, url);
await BrowserTestUtils.browserLoaded(selectedBrowser, false, url);
gBrowser.selectedTab = tab1;
await extension.startup();
await extension.awaitFinish("tab-zoom");
await extension.unload();
privateWindow.close();
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab2);
});

View File

@ -4,7 +4,9 @@
SimpleTest.requestCompleteLog();
add_task(async function testWindowsEvents() {
add_task(async function test_windows_events_not_allowed() {
let monitor = await startIncognitoMonitorExtension();
function background() {
browser.windows.onCreated.addListener(window => {
browser.test.log(`onCreated: windowId=${window.id}`);
@ -26,7 +28,6 @@ add_task(async function testWindowsEvents() {
browser.test.assertTrue(Number.isInteger(eventWindowId),
"windowId is an integer");
let window = await browser.windows.getLastFocused();
browser.test.sendMessage("window-focus-changed", {winId: eventWindowId, lastFocusedWindowId: window.id});
});
@ -44,6 +45,7 @@ add_task(async function testWindowsEvents() {
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {},
background,
});
@ -80,7 +82,7 @@ add_task(async function testWindowsEvents() {
is(winId, win1Id, "Got focus change event for the correct window ID.");
info("Create browser window 2");
let win2 = await BrowserTestUtils.openNewBrowserWindow();
let win2 = await BrowserTestUtils.openNewBrowserWindow({private: true});
let win2Id = await extension.awaitMessage("window-created");
info(`Window 2 ID: ${win2Id}`);
@ -114,4 +116,5 @@ add_task(async function testWindowsEvents() {
await extension.awaitFinish("windows.events");
await extension.unload();
await monitor.unload();
});

View File

@ -0,0 +1,49 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function test_window_incognito() {
const url = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/file_iframe_document.html";
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/"],
},
incognitoOverride: "not_allowed",
background() {
browser.test.onMessage.addListener(async pbw => {
await browser.test.assertRejects(browser.windows.get(pbw.windowId),
/Invalid window ID/,
"should not be able to get incognito window");
await browser.test.assertRejects(browser.windows.remove(pbw.windowId),
/Invalid window ID/,
"should not be able to remove incognito window");
await browser.test.assertRejects(browser.windows.getCurrent(),
/Invalid window/,
"should not be able to get incognito top window");
await browser.test.assertRejects(browser.windows.getLastFocused(),
/Invalid window/,
"should not be able to get incognito focused window");
await browser.test.assertRejects(browser.windows.create({incognito: true}),
/Extension does not have permission for incognito mode/,
"should not be able to create incognito window");
await browser.test.assertRejects(browser.windows.update(pbw.windowId, {focused: true}),
/Invalid window ID/,
"should not be able to update incognito window");
let windows = await browser.windows.getAll();
browser.test.assertEq(1, windows.length, "unable to get incognito window");
browser.test.notifyPass("pass");
});
},
});
let winData = await getIncognitoWindow(url);
await extension.startup();
extension.sendMessage(winData.details);
await extension.awaitFinish("pass");
await BrowserTestUtils.closeWindow(winData.win);
await extension.unload();
});

View File

@ -22,6 +22,7 @@
* promiseAnimationFrame getCustomizableUIPanelID
* awaitEvent BrowserWindowIterator
* navigateTab historyPushState promiseWindowRestored
* getIncognitoWindow startIncognitoMonitorExtension
*/
// There are shutdown issues for which multiple rejections are left uncaught.
@ -536,3 +537,123 @@ function navigateTab(tab, url) {
function historyPushState(tab, url) {
return locationChange(tab, url, (url) => { content.history.pushState(null, null, url); });
}
// A monitoring extension that fails if it receives data it should not.
async function startIncognitoMonitorExtension(failOnIncognitoEvent = true) {
function background(expectIncognito) {
// Bug 1513220 - We're unable to get the tab during onRemoved, so we track
// valid tabs in "seen" so we can at least validate tabs that we have "seen"
// during onRemoved. This means that the monitor extension must be started
// prior to creating any tabs that will be removed.
let seen = new Set();
function testTab(tab, eventName) {
browser.test.assertEq(tab.incognito, expectIncognito, `${eventName} ${tab.id}: monitor extension got expected incognito value`);
seen.add(tab.id);
}
async function testTabInfo(tabInfo, eventName) {
try {
if (typeof tabInfo == "number") {
testTab(await browser.tabs.get(tabInfo), eventName);
return;
} else if (typeof tabInfo == "object") {
if (tabInfo.id !== undefined) {
testTab(tabInfo, eventName);
return;
} else if (tabInfo.tab !== undefined) {
testTab(tabInfo.tab, eventName);
return;
} else if (tabInfo.tabIds !== undefined) {
for (let tabId of tabInfo.tabIds) {
testTab(await browser.tabs.get(tabId), eventName);
}
return;
} else if (tabInfo.tabId !== undefined) {
testTab(await browser.tabs.get(tabInfo.tabId), eventName);
return;
}
}
} catch (e) {
// tabInfo in onRemoved is tabId.
if (/Invalid tab ID/.test(e.message) && seen.has(tabInfo)) {
// This will happen on a window close or tab remove sometimes, async
// events fired may happen after the tab is removed. Just log it, we've
// already tested that the tab is ok for this extension to see it.
browser.test.log(`${eventName} received late ${e}`);
return;
}
browser.test.log(`${eventName} exception ${e}`);
}
browser.test.fail(`monitor extension got unknown tabInfo ${typeof tabInfo} ${JSON.stringify(tabInfo)}`);
}
let tabEvents = ["onUpdated", "onCreated", "onAttached", "onDetached",
"onRemoved", "onMoved", "onZoomChange",
"onHighlighted"];
for (let eventName of tabEvents) {
browser.tabs[eventName].addListener(async details => { await testTabInfo(details, eventName); });
}
browser.tabs.onReplaced.addListener(async (addedTabId, removedTabId) => {
await testTabInfo(addedTabId, "onReplaced");
await testTabInfo(removedTabId, "onReplaced");
});
browser.windows.onCreated.addListener(window => {
browser.test.assertEq(window.incognito, expectIncognito, `monitor extension got expected incognito value`);
});
browser.windows.onRemoved.addListener(async (windowId) => {
try {
let window = await browser.windows.get(windowId);
browser.test.assertEq(window.incognito, expectIncognito, `monitor extension got expected incognito value`);
} catch (e) {
// Window removal at end of tests can get here after window is gone.
browser.test.log(`onRemoved received late ${e}`);
}
});
browser.windows.onFocusChanged.addListener(async (windowId) => {
// onFocusChanged will also fire for blur so check actual window.incognito value.
let window = await browser.windows.get(windowId);
browser.test.assertEq(window.incognito, expectIncognito, `monitor extesion got unexpected window onFocusChanged event`);
});
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
incognitoOverride: failOnIncognitoEvent ? "not_allowed" : undefined,
background: `(${background})(${!failOnIncognitoEvent})`,
});
await extension.startup();
return extension;
}
async function getIncognitoWindow(url) {
// Since events will be limited based on incognito, we need a
// spanning extension to get the tab id so we can test access failure.
// avoid linting issue with background
/* eslint-disable no-use-before-define */
function background(expectUrl) {
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === "complete" && tab.url === expectUrl) {
browser.test.sendMessage("data", {tabId, windowId: tab.windowId});
}
});
}
let windowWatcher = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"],
},
background: `(${background})("${url}")`,
});
await windowWatcher.startup();
let data = windowWatcher.awaitMessage("data");
let win = await BrowserTestUtils.openNewBrowserWindow({private: true, url});
let browser = win.getBrowser().selectedBrowser;
BrowserTestUtils.loadURI(browser, url);
let details = await data;
await windowWatcher.unload();
return {win, details};
}

View File

@ -495,6 +495,14 @@ class FaviconLoader {
}
loadIcons() {
// If the page is unloaded immediately after the DeferredTask's timer fires
// we can still attempt to load icons, which will fail since the content
// window is no longer available. Checking if iconInfos has been cleared
// allows us to bail out early in this case.
if (this.iconInfos.length == 0) {
return;
}
let preferredWidth = PREFERRED_WIDTH * Math.ceil(this.mm.content.devicePixelRatio);
let { richIcon, tabIcon } = selectIcons(this.iconInfos, preferredWidth);
this.iconInfos = [];

View File

@ -21,7 +21,8 @@ ChromeUtils.defineModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
ChromeUtils.defineModuleGetter(this, "BinarySearch",
"resource://gre/modules/BinarySearch.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
const ACTION_ID_BOOKMARK = "bookmark";
const ACTION_ID_BOOKMARK_SEPARATOR = "bookmarkSeparator";
@ -523,6 +524,8 @@ var PageActions = {
* clicked.
* @param wantsSubview (bool, optional)
* Pass true to make an action that shows a panel subview when clicked.
* @param disablePrivateBrowsing (bool, optional)
* Pass true to prevent the action from showing in a private browsing window.
*/
function Action(options) {
setProperties(this, options, {
@ -550,6 +553,7 @@ function Action(options) {
urlbarIDOverride: false,
wantsIframe: false,
wantsSubview: false,
disablePrivateBrowsing: false,
// private
@ -618,6 +622,25 @@ Action.prototype = {
return this._id;
},
get disablePrivateBrowsing() {
return !!this._disablePrivateBrowsing;
},
/**
* Verifies that the action can be shown in a private window. For
* extensions, verifies the extension has access to the window.
*/
canShowInWindow(browserWindow) {
if (this._extensionID) {
let policy = WebExtensionPolicy.getByID(this._extensionID);
if (!policy.canAccessWindow(browserWindow)) {
return false;
}
}
return !(this.disablePrivateBrowsing &&
PrivateBrowsingUtils.isWindowPrivate(browserWindow));
},
/**
* True if the action is pinned to the urlbar. The action is shown in the
* urlbar if it's pinned and not disabled. (bool)
@ -1021,7 +1044,8 @@ Action.prototype = {
* disabled.
*/
shouldShowInPanel(browserWindow) {
return !this.__transient || !this.getDisabled(browserWindow);
return (!this.__transient || !this.getDisabled(browserWindow)) &&
this.canShowInWindow(browserWindow);
},
/**
@ -1033,7 +1057,8 @@ Action.prototype = {
* should be shown if it's both pinned and not disabled.
*/
shouldShowInUrlbar(browserWindow) {
return this.pinnedToUrlbar && !this.getDisabled(browserWindow);
return (this.pinnedToUrlbar && !this.getDisabled(browserWindow)) &&
this.canShowInWindow(browserWindow);
},
get _isBuiltIn() {

View File

@ -1657,6 +1657,31 @@ add_task(async function transient() {
otherAction.remove();
});
add_task(async function action_disablePrivateBrowsing() {
let id = "testWidget";
let action = PageActions.addAction(new PageActions.Action({
id,
disablePrivateBrowsing: true,
title: "title",
disabled: false,
pinnedToUrlbar: true,
}));
// Open an actionable page so that the main page action button appears.
let url = "http://example.com/";
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
await BrowserTestUtils.openNewForegroundTab(privateWindow.gBrowser, url, true, true);
Assert.ok(action.canShowInWindow(window), "should show in default window");
Assert.ok(!action.canShowInWindow(privateWindow), "should not show in private browser");
Assert.ok(action.shouldShowInUrlbar(window), "should show in default urlbar");
Assert.ok(!action.shouldShowInUrlbar(privateWindow), "should not show in default urlbar");
Assert.ok(action.shouldShowInPanel(window), "should show in default urlbar");
Assert.ok(!action.shouldShowInPanel(privateWindow), "should not show in default urlbar");
action.remove();
privateWindow.close();
});
function assertActivatedPageActionPanelHidden() {
Assert.ok(!document.getElementById(BrowserPageActions._activatedActionPanelID));

View File

@ -413,7 +413,7 @@ Tools.accessibility = {
panelLabel: l10n("accessibility.panelLabel"),
get tooltip() {
return l10n("accessibility.tooltip3",
"Shift+" + functionkey(l10n("accessibility.commandkey")));
"Shift+" + functionkey(l10n("accessibilityF12.commandkey")));
},
inMenu: true,

View File

@ -173,7 +173,7 @@ XPCOMUtils.defineLazyGetter(this, "KeyShortcuts", function() {
// Key for opening the Accessibility Panel
{
toolId: "accessibility",
shortcut: KeyShortcutsBundle.GetStringFromName("accessibility.commandkey"),
shortcut: KeyShortcutsBundle.GetStringFromName("accessibilityF12.commandkey"),
modifiers: "shift",
},
];

View File

@ -62,6 +62,6 @@ storage.commandkey=VK_F9
# Key pressed to open a toolbox with the DOM panel selected
dom.commandkey=W
# LOCALIZATION NOTE (accessibility.commandkey):
# LOCALIZATION NOTE (accessibilityF12.commandkey):
# Key pressed to open a toolbox with the accessibility panel selected
accessibility.commandkey=VK_F10
accessibilityF12.commandkey=VK_F12

View File

@ -1,9 +1,9 @@
/* globals chromeWindow */
// The main test function.
var test = function (isContent) {
var test = function(isContent) {
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["security.allow_eval_with_system_principal",
true]]});
SpecialPowers.pushPrefEnv({"set": [["security.allow_eval_with_system_principal", true]]});
let { ww } = SpecialPowers.Services;
window.chromeWindow = ww.activeWindow;
@ -28,38 +28,37 @@ var test = function (isContent) {
["screen.orientation.type", "'landscape-primary'"],
["screen.orientation.angle", 0],
["screen.mozOrientation", "'landscape-primary'"],
["devicePixelRatio", 1]
["devicePixelRatio", 1],
];
// checkPair: tests if members of pair [a, b] are equal when evaluated.
let checkPair = function (a, b) {
let checkPair = function(a, b) {
// eslint-disable-next-line no-eval
is(eval(a), eval(b), a + " should be equal to " + b);
};
// Returns generator object that iterates through pref values.
let prefVals = (function*() { yield false; yield true; })();
let prefVals = (function* () { yield false; yield true; })();
// The main test function, runs until all pref values are exhausted.
let nextTest = function () {
let {value : prefValue, done} = prefVals.next();
let nextTest = function() {
let {value: prefValue, done} = prefVals.next();
if (done) {
SimpleTest.finish();
return;
}
SpecialPowers.pushPrefEnv({set : [["privacy.resistFingerprinting", prefValue]]},
function () {
SpecialPowers.pushPrefEnv({set: [["privacy.resistFingerprinting", prefValue]]},
function() {
// We will be resisting fingerprinting if the pref is enabled,
// and we are in a content script (not chrome).
let resisting = prefValue && isContent;
// Check each of the pairs.
pairs.map(function ([item, onVal]) {
pairs.map(function([item, onVal]) {
if (resisting) {
checkPair("window." + item, onVal);
} else {
if (!item.startsWith("moz")) {
} else if (!item.startsWith("moz")) {
checkPair("window." + item, "chromeWindow." + item);
}
}
});
if (!resisting) {
// Hard to predict these values, but we can enforce constraints:
@ -70,7 +69,7 @@ var test = function (isContent) {
}
nextTest();
});
}
};
nextTest();
}
};

View File

@ -1,6 +1,8 @@
dump('loaded child cpow test\n');
/* eslint-env mozilla/frame-script */
dump("loaded child cpow test\n");
Cu.importGlobalProperties(["XMLHttpRequest"]);
var is_remote;
(function start() {
[is_remote] = sendRpcMessage("cpows:is_remote");
@ -41,28 +43,27 @@ Cu.importGlobalProperties(["XMLHttpRequest"]);
})();
function ok(condition, message) {
dump('condition: ' + condition + ', ' + message + '\n');
dump("condition: " + condition + ", " + message + "\n");
if (!condition) {
sendAsyncMessage("cpows:fail", { message: message });
sendAsyncMessage("cpows:fail", { message });
}
}
var sync_obj;
var async_obj;
function make_object()
{
function make_object() {
let o = { };
o.i = 5;
o.b = true;
o.s = "hello";
o.x = { i: 10 };
o.f = function () { return 99; };
o.ctor = function() { this.a = 3; }
o.f = function() { return 99; };
o.ctor = function() { this.a = 3; };
// Doing anything with this Proxy will throw.
var throwing = new Proxy({}, new Proxy({}, {
get: function (trap) { throw trap; }
get(trap) { throw trap; },
}));
let array = [1, 2, 3];
@ -81,17 +82,15 @@ function make_object()
"array": array,
"for_json": for_json,
"with_proto": with_proto,
"with_null_proto": with_null_proto
"with_null_proto": with_null_proto,
};
}
function make_json()
{
function make_json() {
return { check: "ok" };
}
function parent_test(finish)
{
function parent_test(finish) {
function f(check_func) {
// Make sure this doesn't crash.
let array = new Uint32Array(10);
@ -116,9 +115,9 @@ function parent_test(finish)
// is callable from unprivileged content. Greasemonkey uses this
// functionality.
let func = msg.objects.func;
let sb = Cu.Sandbox('http://www.example.com', {});
let sb = Cu.Sandbox("http://www.example.com", {});
sb.func = func;
ok(sb.eval('func()') == 101, "can call parent's function in child");
ok(sb.eval("func()") == 101, "can call parent's function in child");
finish();
});
@ -130,30 +129,27 @@ function error_reporting_test(finish) {
finish();
}
function dom_test(finish)
{
function dom_test(finish) {
let element = content.document.createElement("div");
element.id = "it_works";
content.document.body.appendChild(element);
sendRpcMessage("cpows:dom_test", {}, {element: element});
sendRpcMessage("cpows:dom_test", {}, {element});
Cu.schedulePreciseGC(function() {
sendRpcMessage("cpows:dom_test_after_gc");
finish();
});
}
function xray_test(finish)
{
function xray_test(finish) {
let element = content.document.createElement("div");
element.wrappedJSObject.foo = "hello";
sendRpcMessage("cpows:xray_test", {}, {element: element});
sendRpcMessage("cpows:xray_test", {}, {element});
finish();
}
function symbol_test(finish)
{
function symbol_test(finish) {
let iterator = Symbol.iterator;
let named = Symbol.for("cpow-test");
@ -161,15 +157,14 @@ function symbol_test(finish)
[iterator]: iterator,
[named]: named,
};
let test = ['a'];
sendRpcMessage("cpows:symbol_test", {}, {object: object, test: test});
let test = ["a"];
sendRpcMessage("cpows:symbol_test", {}, {object, test});
finish();
}
// Parent->Child references should go X->parent.privilegedJunkScope->child.privilegedJunkScope->Y
// Child->Parent references should go X->child.privilegedJunkScope->parent.unprivilegedJunkScope->Y
function compartment_test(finish)
{
function compartment_test(finish) {
// This test primarily checks various compartment invariants for CPOWs, and
// doesn't make sense to run in-process.
if (!is_remote) {
@ -177,46 +172,42 @@ function compartment_test(finish)
return;
}
let sb = Cu.Sandbox('http://www.example.com', { wantGlobalProperties: ['XMLHttpRequest'] });
sb.eval('function getUnprivilegedObject() { var xhr = new XMLHttpRequest(); xhr.expando = 42; return xhr; }');
let sb = Cu.Sandbox("http://www.example.com", { wantGlobalProperties: ["XMLHttpRequest"] });
sb.eval("function getUnprivilegedObject() { var xhr = new XMLHttpRequest(); xhr.expando = 42; return xhr; }");
function testParentObject(obj) {
let results = [];
function is(a, b, msg) { results.push({ result: a === b ? "PASS" : "FAIL", message: msg }) };
function ok(x, msg) { results.push({ result: x ? "PASS" : "FAIL", message: msg }) };
function is(a, b, msg) { results.push({ result: a === b ? "PASS" : "FAIL", message: msg }); }
function ok1(x, msg) { results.push({ result: x ? "PASS" : "FAIL", message: msg }); }
let cpowLocation = Cu.getRealmLocation(obj);
ok(/shared JSM global/.test(cpowLocation),
ok1(/shared JSM global/.test(cpowLocation),
"child->parent CPOWs should live in the privileged junk scope: " + cpowLocation);
is(obj(), 42, "child->parent CPOW is invokable");
try {
obj.expando;
ok(false, "child->parent CPOW cannot access properties");
ok1(false, "child->parent CPOW cannot access properties");
} catch (e) {
ok(true, "child->parent CPOW cannot access properties");
ok1(true, "child->parent CPOW cannot access properties");
}
return results;
}
sendRpcMessage("cpows:compartment_test", {}, { getUnprivilegedObject: sb.getUnprivilegedObject,
testParentObject: testParentObject });
testParentObject });
finish();
}
function regexp_test(finish)
{
function regexp_test(finish) {
sendRpcMessage("cpows:regexp_test", {}, { regexp: /myRegExp/g });
finish();
}
function postmessage_test(finish)
{
function postmessage_test(finish) {
sendRpcMessage("cpows:postmessage_test", {}, { win: content.window });
finish();
}
function sync_test(finish)
{
dump('beginning cpow sync test\n');
function sync_test(finish) {
dump("beginning cpow sync test\n");
sync_obj = make_object();
sendRpcMessage("cpows:sync",
make_json(),
@ -224,9 +215,8 @@ function sync_test(finish)
finish();
}
function async_test(finish)
{
dump('beginning cpow async test\n');
function async_test(finish) {
dump("beginning cpow async test\n");
async_obj = make_object();
sendAsyncMessage("cpows:async",
make_json(),
@ -237,22 +227,20 @@ function async_test(finish)
var rpc_obj;
function rpc_test(finish)
{
dump('beginning cpow rpc test\n');
function rpc_test(finish) {
dump("beginning cpow rpc test\n");
rpc_obj = make_object();
rpc_obj.data.reenter = function () {
rpc_obj.data.reenter = function() {
sendRpcMessage("cpows:reenter", { }, { data: { valid: true } });
return "ok";
}
};
sendRpcMessage("cpows:rpc",
make_json(),
rpc_obj);
finish();
}
function lifetime_test(finish)
{
function lifetime_test(finish) {
if (!is_remote) {
// Only run this test when running out-of-process. Otherwise it
// will fail, since local CPOWs don't follow the same ownership
@ -263,7 +251,7 @@ function lifetime_test(finish)
dump("beginning lifetime test\n");
var obj = {"will_die": {"f": 1}};
let [result] = sendRpcMessage("cpows:lifetime_test_1", {}, {obj: obj});
let [result] = sendRpcMessage("cpows:lifetime_test_1", {}, {obj});
ok(result == 10, "got sync result");
ok(obj.wont_die.f == undefined, "got reverse CPOW");
obj.will_die = null;
@ -276,8 +264,7 @@ function lifetime_test(finish)
});
}
function cancel_test(finish)
{
function cancel_test(finish) {
if (!is_remote) {
// No point in doing this in single-process mode.
finish();
@ -296,15 +283,14 @@ function cancel_test(finish)
if (fin1 && fin2) finish();
}
sendAsyncMessage("cpows:cancel_test", null, {f: f});
sendAsyncMessage("cpows:cancel_test", null, {f});
addMessageListener("cpows:cancel_test_done", msg => {
fin2 = true;
if (fin1 && fin2) finish();
});
}
function cancel_test2(finish)
{
function cancel_test2(finish) {
if (!is_remote) {
// No point in doing this in single-process mode.
finish();
@ -331,21 +317,20 @@ function cancel_test2(finish)
req.open("get", "http://example.com", false);
req.send(null);
ok(fin == true, "XHR happened");
ok(fin === true, "XHR happened");
fin1 = true;
if (fin1 && fin2) finish();
}
sendAsyncMessage("cpows:cancel_test2", null, {f: f});
sendAsyncMessage("cpows:cancel_test2", null, {f});
addMessageListener("cpows:cancel_test2_done", msg => {
fin2 = true;
if (fin1 && fin2) finish();
});
}
function unsafe_test(finish)
{
function unsafe_test(finish) {
if (!is_remote) {
// Only run this test when running out-of-process.
finish();
@ -361,8 +346,7 @@ function unsafe_test(finish)
});
}
function dead_test(finish)
{
function dead_test(finish) {
if (!is_remote) {
// Only run this test when running out-of-process.
finish();
@ -372,7 +356,7 @@ function dead_test(finish)
let gcTrigger = function() {
// Force the GC to dead-ify the thing.
content.windowUtils.garbageCollect();
}
};
{
let thing = { value: "Gonna croak" };

View File

@ -1,3 +1,4 @@
/* globals finishTest */
class XFoo extends HTMLElement {
constructor() {
super();
@ -7,7 +8,7 @@ class XFoo extends HTMLElement {
connectedCallback() {
finishTest(this.magicNumber === 42);
}
};
}
customElements.define("x-foo", XFoo);
document.firstChild.appendChild(document.createElement("x-foo"));

View File

@ -1,4 +1,4 @@
//# sourceMappingURL=bar.js.map
// # sourceMappingURL=bar.js.map
// Define a single function to prevent script source from being gc'd
function foo() {}

View File

@ -1,4 +1,4 @@
//# sourceMappingURL=bar.js.map
// # sourceMappingURL=bar.js.map
// Define a single function to prevent script source from being gc'd
function foo() {}

View File

@ -22,31 +22,31 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1339722
ChromeUtils.import("resource://gre/modules/Services.jsm");
const TOPIC = 'http-on-useragent-request';
const TOPIC = "http-on-useragent-request";
let win;
Services.obs.addObserver({
observe(subject, topic, data) {
info('Got ' + topic);
info("Got " + topic);
Services.obs.removeObserver(this, TOPIC);
// Query window proxy so it triggers DOMWindowCreated.
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
let win = channel.notificationCallbacks.getInterface(Ci.mozIDOMWindowProxy);
}
win = channel.notificationCallbacks.getInterface(Ci.mozIDOMWindowProxy);
},
}, TOPIC);
let docShell = SpecialPowers.wrap(window).docShell;
docShell.chromeEventHandler.addEventListener('DOMWindowCreated', function handler(e) {
docShell.chromeEventHandler.removeEventListener('DOMWindowCreated', handler);
let iframe = document.getElementById('testFrame');
is(e.target, iframe.contentDocument, 'verify event target');
docShell.chromeEventHandler.addEventListener("DOMWindowCreated", function handler(e) {
let iframe = document.getElementById("testFrame");
is(e.target, iframe.contentDocument, "verify event target");
// Remove the iframe to cause frameloader destroy.
iframe.remove();
setTimeout($ => {
ok(!document.getElementById('testFrame'), 'verify iframe removed');
ok(!document.getElementById("testFrame"), "verify iframe removed");
SimpleTest.finish();
}, 0);
});
}, {once: true});
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -28,26 +28,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1346936
ChromeUtils.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
window.onload = function () {
window.onload = function() {
SimpleTest.waitForExplicitFinish();
var iframe = document.createElement("iframe");
iframe.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.html";
iframe.onload = function () {
iframe.onload = function() {
var script = iframe.contentWindow.document.createElement("script");
script.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js";
script.onload = function () {
script.onload = function() {
var dbg = new Debugger(iframe.contentWindow);
ok(dbg, "Should be able to create debugger");
var scripts = dbg.findScripts({
url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js"
url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js",
});
ok(scripts.length > 0, "Should be able to find script");
is(scripts[0].source.sourceMapURL, "foo.js.map");
SimpleTest.finish();
}
};
iframe.contentWindow.document.body.appendChild(script);
};

View File

@ -22,13 +22,12 @@ SimpleTest.waitForExplicitFinish();
/*
* Register a custom nsIProtocolHandler service
* in order to be able to implement *and use* an
* in order to be able to implement *and use* an
* nsIChannel component written in Javascript.
*/
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
.getService(Ci.nsIContentSecurityManager);
@ -36,7 +35,7 @@ var PROTOCOL_SCHEME = "jsproto";
function CustomChannel(uri, loadInfo) {
this.URI = this.originalURI = uri;
this.URI = this.originalURI = uri;
this.loadInfo = loadInfo;
}
CustomChannel.prototype = {
@ -53,47 +52,47 @@ CustomChannel.prototype = {
loadGroup: null,
name: null,
status: Cr.NS_OK,
asyncOpen: function(listener, context) {
asyncOpen(listener, context) {
let stream = this.open();
try {
listener.onStartRequest(this, context);
} catch(e) {}
} catch (e) {}
try {
listener.onDataAvailable(this, context, stream, 0, stream.available());
} catch(e) {}
} catch (e) {}
try {
listener.onStopRequest(this, context, Cr.NS_OK);
} catch(e) {}
} catch (e) {}
},
asyncOpen2: function(listener) {
asyncOpen2(listener) {
// throws an error if security checks fail
var outListener = contentSecManager.performSecurityCheck(this, listener);
return this.asyncOpen(outListener, null);
},
open: function() {
open() {
let data = "bar";
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(data, data.length);
return stream;
},
open2: function() {
open2() {
// throws an error if security checks fail
contentSecManager.performSecurityCheck(this, null);
return this.open();
},
isPending: function() {
isPending() {
return false;
},
cancel: function() {
cancel() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
suspend: function() {
suspend() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
resume: function() {
resume() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
QueryInterface: ChromeUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest]),
};
@ -123,13 +122,13 @@ CustomProtocol.prototype = {
return new CustomChannel(URI, loadInfo);
},
newChannel: function newChannel(URI) {
return newChannel2(URI);
return this.newChannel2(URI);
},
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIProtocolHandler])
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIProtocolHandler]),
};
var gFactory = {
register: function() {
register() {
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
var classID = Components.ID("{ed064287-1e76-49ba-a28d-dc74394a8334}");
@ -143,7 +142,7 @@ var gFactory = {
registrar.unregisterFactory(classID, factory);
delete this.unregister;
};
}
},
};
// Register the custom procotol handler
@ -152,14 +151,14 @@ gFactory.register();
// Then, checks if XHR works with it
var xhr = new XMLHttpRequest();
xhr.open("GET", PROTOCOL_SCHEME + ":foo", true);
xhr.onload = function () {
xhr.onload = function() {
is(xhr.responseText, "bar", "protocol doesn't work");
gFactory.unregister();
SimpleTest.finish();
}
};
try {
xhr.send(null);
} catch(e) {
} catch (e) {
ok(false, e);
}
</script>

View File

@ -28,26 +28,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=765993
ChromeUtils.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
window.onload = function () {
window.onload = function() {
SimpleTest.waitForExplicitFinish();
var iframe = document.createElement("iframe");
iframe.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.html";
iframe.onload = function () {
iframe.onload = function() {
var script = iframe.contentWindow.document.createElement("script");
script.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.js";
script.onload = function () {
script.onload = function() {
var dbg = new Debugger(iframe.contentWindow);
ok(dbg, "Should be able to create debugger");
var scripts = dbg.findScripts({
url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.js"
url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.js",
});
ok(scripts.length > 0, "Should be able to find script");
is(scripts[0].source.sourceMapURL, "foo.js.map");
SimpleTest.finish();
}
};
iframe.contentWindow.document.body.appendChild(script);
};

View File

@ -16,15 +16,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650776
</div>
<pre id="test">
<script type="application/javascript">
ChromeUtils.import("resource://gre/modules/Services.jsm");
function createFileWithData(fileData) {
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var testFile = dirSvc.get("ProfD", Ci.nsIFile);
var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
testFile.append("testBug914381");
var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
0o666, 0);
outStream.write(fileData, fileData.length);
outStream.close();

View File

@ -20,7 +20,7 @@
</style>
<script>
'use strict';
"use strict";
SimpleTest.waitForExplicitFinish();
@ -58,18 +58,18 @@ function runTests() {
// Targets are provided in order we expect them to appear.
// Has to end in a non-todo element in order for testing logic to work.
let targetsFromRoot = [
{id:"root", message:"root with display:grid"},
{id:"a", message:"'plain' grid container with display:grid"},
{id:"b", message:"display:subgrid inside display:grid (to be fixed in Bug 1240834)", todo:true},
{id:"c", message:"'plain' grid container with display:inline-grid"},
{id:"d", message:"display:subgrid inside display:inline-grid (to be fixed in Bug 1240834)", todo:true},
{id:"e", message:"grid container with visibility:hidden"},
{id:"f", message:"grid container inside an element"},
{id:"g", message:"overflow:scroll grid container"},
{id:"h", message:"button as a grid container"},
{id:"i", message:"fieldset as a grid container"},
{id:"k1", message:"grid container containing a grid container"},
{id:"k2", message:"grid container inside a grid container"},
{id: "root", message: "root with display:grid"},
{id: "a", message: "'plain' grid container with display:grid"},
{id: "b", message: "display:subgrid inside display:grid (to be fixed in Bug 1240834)", todo: true},
{id: "c", message: "'plain' grid container with display:inline-grid"},
{id: "d", message: "display:subgrid inside display:inline-grid (to be fixed in Bug 1240834)", todo: true},
{id: "e", message: "grid container with visibility:hidden"},
{id: "f", message: "grid container inside an element"},
{id: "g", message: "overflow:scroll grid container"},
{id: "h", message: "button as a grid container"},
{id: "i", message: "fieldset as a grid container"},
{id: "k1", message: "grid container containing a grid container"},
{id: "k2", message: "grid container inside a grid container"},
];
is(elementsFromRoot.length, 10, "Found expected number of elements within document root.");
testTargetsAreInElements(targetsFromRoot, elementsFromRoot);
@ -79,7 +79,7 @@ function runTests() {
let elementsFromNonRoot = document.getElementById("a_non_root_element").getElementsWithGrid();
let targetsFromNonRoot = [
{id:"f", message:"grid container inside an element (from non-root element)"},
{id: "f", message: "grid container inside an element (from non-root element)"},
];
is(elementsFromNonRoot.length, 1, "Found expected number of elements from non-root element.");
testTargetsAreInElements(targetsFromNonRoot, elementsFromNonRoot);

View File

@ -4,28 +4,27 @@
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script>
'use strict';
"use strict";
SimpleTest.waitForExplicitFinish();
function runTests()
{
function runTests() {
let range = document.createRange();
let attempts = [
{startNode: "one", start:0, endNode:"one", end:0, textList:[], message:"Empty rect"},
{startNode: "one", start:2, endNode:"one", end:6, textList:["l on"], message:"Single line"},
{startNode: "implicit", start:6, endNode:"implicit", end:12, textList:["it bre"], message:"Implicit break"},
{startNode: "two.a", start:1, endNode:"two.b", end:2, textList:["wo", "", "li"], message:"Two lines"},
{startNode: "embed.a", start:7, endNode:"embed.b", end:2, textList:["th ", "simple nested", " ", "te"], message:"Simple nested"},
{startNode: "deep.a", start:2, endNode:"deep.b", end:2, textList:["ne with ", "complex, more deeply nested", " ", "te"], message:"Complex nested"},
{startNode: "image.a", start:7, endNode:"image.b", end:2, textList:["th inline ", "", " ", "im"], message:"Inline image"},
{startNode: "hyphen1", start:0, endNode:"hyphen1", end:3, textList:["a\u00AD", "b"], message:"Shy hyphen (active)"},
{startNode: "hyphen2", start:0, endNode:"hyphen2", end:3, textList:["c\u00ADd"], message:"Shy hyphen (inactive)"},
{startNode: "hyphen2", start:0, endNode:"hyphen2", end:2, textList:["c\u00AD"], message:"Shy hyphen (inactive, trailing)"},
{startNode: "hyphen2", start:1, endNode:"hyphen2", end:3, textList:["\u00ADd"], message:"Shy hyphen (inactive, leading)"},
{startNode: "uc", start:0, endNode:"uc", end:2, textList:["EF"], message:"UC transform"},
{startNode: "pre", start:0, endNode:"pre", end:3, textList:["g\n", "h"], message:"pre with break"},
{startNode: "one", start: 0, endNode: "one", end: 0, textList: [], message: "Empty rect"},
{startNode: "one", start: 2, endNode: "one", end: 6, textList: ["l on"], message: "Single line"},
{startNode: "implicit", start: 6, endNode: "implicit", end: 12, textList: ["it bre"], message: "Implicit break"},
{startNode: "two.a", start: 1, endNode: "two.b", end: 2, textList: ["wo", "", "li"], message: "Two lines"},
{startNode: "embed.a", start: 7, endNode: "embed.b", end: 2, textList: ["th ", "simple nested", " ", "te"], message: "Simple nested"},
{startNode: "deep.a", start: 2, endNode: "deep.b", end: 2, textList: ["ne with ", "complex, more deeply nested", " ", "te"], message: "Complex nested"},
{startNode: "image.a", start: 7, endNode: "image.b", end: 2, textList: ["th inline ", "", " ", "im"], message: "Inline image"},
{startNode: "hyphen1", start: 0, endNode: "hyphen1", end: 3, textList: ["a\u00AD", "b"], message: "Shy hyphen (active)"},
{startNode: "hyphen2", start: 0, endNode: "hyphen2", end: 3, textList: ["c\u00ADd"], message: "Shy hyphen (inactive)"},
{startNode: "hyphen2", start: 0, endNode: "hyphen2", end: 2, textList: ["c\u00AD"], message: "Shy hyphen (inactive, trailing)"},
{startNode: "hyphen2", start: 1, endNode: "hyphen2", end: 3, textList: ["\u00ADd"], message: "Shy hyphen (inactive, leading)"},
{startNode: "uc", start: 0, endNode: "uc", end: 2, textList: ["EF"], message: "UC transform"},
{startNode: "pre", start: 0, endNode: "pre", end: 3, textList: ["g\n", "h"], message: "pre with break"},
];
for (let attempt of attempts) {

View File

@ -5,25 +5,25 @@
ChromeUtils.import("resource://testing-common/httpd.js");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
const nsIDocumentEncoder = Ci.nsIDocumentEncoder;
const replacementChar = Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
function loadContentFile(aFile, aCharset) {
//if(aAsIso == undefined) aAsIso = false;
if(aCharset == undefined)
aCharset = 'UTF-8';
// if(aAsIso == undefined) aAsIso = false;
if (aCharset == undefined)
aCharset = "UTF-8";
var file = do_get_file(aFile);
var ios = Cc['@mozilla.org/network/io-service;1']
.getService(Ci.nsIIOService);
var chann = NetUtil.newChannel({
uri: ios.newFileURI(file),
loadUsingSystemPrincipal: true
uri: Services.io.newFileURI(file),
loadUsingSystemPrincipal: true,
});
chann.contentCharset = aCharset;
/*var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
/* var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components.interfaces.nsIScriptableInputStream);
inputStream.init(chann.open2());
return inputStream.read(file.fileSize);
@ -32,7 +32,7 @@ function loadContentFile(aFile, aCharset) {
var inputStream = Cc["@mozilla.org/intl/converter-input-stream;1"]
.createInstance(Ci.nsIConverterInputStream);
inputStream.init(chann.open2(), aCharset, 1024, replacementChar);
var str = {}, content = '';
var str = {}, content = "";
while (inputStream.readString(4096, str) != 0) {
content += str.value;
}

View File

@ -37,7 +37,7 @@ function ParseFile(file) {
var fileStr = C["@mozilla.org/network/file-input-stream;1"]
.createInstance(nsIFileInputStream);
// Init for readonly reading
fileStr.init(file, 0x01, 0o400, nsIFileInputStream.CLOSE_ON_EOF);
fileStr.init(file, 0x01, 0o400, nsIFileInputStream.CLOSE_ON_EOF);
return ParseXML(fileStr);
}
@ -47,7 +47,7 @@ function ParseXML(data) {
}
Assert.equal(data instanceof nsIInputStream, true);
return getParser().parseFromStream(data, "UTF-8", data.available(),
"application/xml");
}

View File

@ -23,7 +23,7 @@ function headerCheckHandler(metadata, response) {
try {
let headerValue = metadata.getHeader("X-Custom-Header");
Assert.equal(headerValue, "present");
} catch(e) {
} catch (e) {
do_throw("No header present after redirect");
}
try {
@ -55,5 +55,5 @@ function run_test() {
request.setRequestHeader("X-Unwanted-Header", "present");
do_throw("Shouldn't be able to set a header after send");
} catch (x) {
}
}
}

View File

@ -4,14 +4,13 @@
/* If charset parameter is invalid, the encoding should be detected as UTF-8 */
function run_test()
{
function run_test() {
let body = '<?xml version="1.0"><html>%c3%80</html>';
let result = '<?xml version="1.0"><html>\u00c0</html>';
let xhr = new XMLHttpRequest();
xhr.open('GET',
'data:text/xml;charset=abc,' + body,
xhr.open("GET",
"data:text/xml;charset=abc," + body,
false);
xhr.send(null);

View File

@ -1,10 +1,8 @@
//Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
// Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var prefetch = Cc["@mozilla.org/prefetch-service;1"].
getService(Ci.nsIPrefetchService);
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var ios = Services.io;
var prefs = Services.prefs;
Cu.importGlobalProperties(["DOMParser"]);
var parser = new DOMParser();
@ -13,7 +11,7 @@ var doc;
var docbody = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' +
'<link id="node1"/><link id="node2"/>' +
'</body></html>';
"</body></html>";
var node1;
var node2;
@ -34,27 +32,27 @@ add_test(function test_cancel1() {
var uri = ios.newURI("http://localhost/1");
prefetch.prefetchURI(uri, uri, node1, true);
Assert.ok(prefetch.hasMoreElements(), 'There is a request in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
// Trying to prefetch again the same uri with the same node will fail.
var didFail = 0;
try {
prefetch.prefetchURI(uri, uri, node1, true);
} catch(e) {
} catch (e) {
didFail = 1;
}
Assert.ok(didFail == 1, 'Prefetching the same request with the same ' +
'node fails.');
Assert.ok(didFail == 1, "Prefetching the same request with the same " +
"node fails.");
Assert.ok(prefetch.hasMoreElements(), 'There is still request in ' +
'the queue');
Assert.ok(prefetch.hasMoreElements(), "There is still request in " +
"the queue");
prefetch.cancelPrefetchPreloadURI(uri, node1);
Assert.ok(!prefetch.hasMoreElements(), 'There is no request in the ' +
'queue');
Assert.ok(!prefetch.hasMoreElements(), "There is no request in the " +
"queue");
run_next_test();
});
@ -66,16 +64,16 @@ add_test(function test_cancel2() {
prefetch.prefetchURI(uri, uri, node1, true);
prefetch.prefetchURI(uri, uri, node2, true);
Assert.ok(prefetch.hasMoreElements(), 'There are requests in the queue');
Assert.ok(prefetch.hasMoreElements(), "There are requests in the queue");
prefetch.cancelPrefetchPreloadURI(uri, node1);
Assert.ok(prefetch.hasMoreElements(), 'There is still one more request ' +
'in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is still one more request " +
"in the queue");
prefetch.cancelPrefetchPreloadURI(uri, node2);
Assert.ok(!prefetch.hasMoreElements(), 'There is no request in the queue');
Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
run_next_test();
});
@ -85,22 +83,22 @@ add_test(function test_cancel3() {
var uri = ios.newURI("http://localhost/1");
prefetch.prefetchURI(uri, uri, node1, true);
Assert.ok(prefetch.hasMoreElements(), 'There is a request in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
var didFail = 0;
try {
prefetch.cancelPrefetchPreloadURI(uri, node2, true);
} catch(e) {
} catch (e) {
didFail = 1;
}
Assert.ok(didFail == 1, 'Canceling the request failed');
Assert.ok(didFail == 1, "Canceling the request failed");
Assert.ok(prefetch.hasMoreElements(), 'There is still a request ' +
'in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is still a request " +
"in the queue");
prefetch.cancelPrefetchPreloadURI(uri, node1);
Assert.ok(!prefetch.hasMoreElements(), 'There is no request in the queue');
Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
run_next_test();
});
@ -111,21 +109,21 @@ add_test(function test_cancel4() {
var uri2 = ios.newURI("http://localhost/2");
prefetch.prefetchURI(uri1, uri1, node1, true);
Assert.ok(prefetch.hasMoreElements(), 'There is a request in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
var didFail = 0;
try {
prefetch.cancelPrefetchPreloadURI(uri2, node1);
} catch(e) {
} catch (e) {
didFail = 1;
}
Assert.ok(didFail == 1, 'Canceling the request failed');
Assert.ok(didFail == 1, "Canceling the request failed");
Assert.ok(prefetch.hasMoreElements(), 'There is still a request ' +
'in the queue');
Assert.ok(prefetch.hasMoreElements(), "There is still a request " +
"in the queue");
prefetch.cancelPrefetchPreloadURI(uri1, node1);
Assert.ok(!prefetch.hasMoreElements(), 'There is no request in the queue');
Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
run_next_test();
});

View File

@ -14,7 +14,7 @@ let textTests = {
"foob": "Zm9vYg",
"fooba": "Zm9vYmE",
"foobar": "Zm9vYmFy",
}
};
// Examples from RFC 4648, section 9.
let binaryTests = [{

View File

@ -6,11 +6,10 @@
var gExpectedStatus = null;
var gNextTestFunc = null;
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var prefs = Services.prefs;
var asyncXHR = {
load: function() {
load() {
var request = new XMLHttpRequest();
request.open("GET", "http://localhost:4444/test_error_code.xml", true);
@ -22,8 +21,8 @@ var asyncXHR = {
var request = event.target.channel.QueryInterface(Ci.nsIRequest);
Assert.equal(request.status, gExpectedStatus);
gNextTestFunc();
}
}
},
};
function run_test() {
do_test_pending();
@ -32,15 +31,11 @@ function run_test() {
// network offline
function run_test_pt1() {
var ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
try {
ioService.manageOfflineStatus = false;
Services.io.manageOfflineStatus = false;
} catch (e) {
}
catch (e) {
}
ioService.offline = true;
Services.io.offline = true;
prefs.setBoolPref("network.dns.offline-localhost", false);
gExpectedStatus = Cr.NS_ERROR_OFFLINE;
@ -51,9 +46,7 @@ function run_test_pt1() {
// connection refused
function run_test_pt2() {
var ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
ioService.offline = false;
Services.io.offline = false;
prefs.clearUserPref("network.dns.offline-localhost");
gExpectedStatus = Cr.NS_ERROR_CONNECTION_REFUSED;

View File

@ -1,12 +1,10 @@
function run_test()
{
function run_test() {
test_generate_xpath();
}
// TEST CODE
function test_generate_xpath()
{
function test_generate_xpath() {
let docString = `
<html>
<body>

View File

@ -5,8 +5,7 @@
Cu.importGlobalProperties(["NodeFilter"]);
function run_test()
{
function run_test() {
/*
* NOTE: [i] is not allowed in this test, since it's done via classinfo and
* we don't have that in xpcshell; the workaround is item(i). Suck.
@ -22,7 +21,7 @@ function run_test()
test_isEqualNode_wholeDoc();
// XXX should Node.isEqualNode(null) throw or return false?
//test_isEqualNode_null();
// test_isEqualNode_null();
}
@ -30,14 +29,12 @@ function run_test()
var doc, root; // cache for use in all tests
function init()
{
function init() {
doc = ParseFile("isequalnode_data.xml");
root = doc.documentElement;
}
function test_isEqualNode_setAttribute()
{
function test_isEqualNode_setAttribute() {
// NOTE: 0, 2 are whitespace
var test1 = doc.getElementById("test_setAttribute");
var node1 = test1.childNodes.item(1);
@ -79,18 +76,15 @@ function test_isEqualNode_setAttribute()
check_neq_nodes(node1, node2);
}
function test_isEqualNode_clones()
{
function test_isEqualNode_clones() {
// tests all elements and attributes in the document
var all_elts = doc.getElementsByTagName("*");
for (var i = 0; i < all_elts.length; i++)
{
for (var i = 0; i < all_elts.length; i++) {
var elt = all_elts.item(i);
check_eq_nodes(elt, elt.cloneNode(true));
var attrs = elt.attributes;
for (var j = 0; j < attrs.length; j++)
{
for (var j = 0; j < attrs.length; j++) {
var attr = attrs.item(j);
check_eq_nodes(attr, attr.cloneNode(true));
}
@ -127,8 +121,7 @@ function test_isEqualNode_clones()
check_eq_nodes(att, att.cloneNode(false));
}
function test_isEqualNode_variety()
{
function test_isEqualNode_variety() {
const nodes =
[
doc.createElement("foo"),
@ -144,13 +137,11 @@ function test_isEqualNode_variety()
doc.createProcessingInstruction("foo", "href='biz'"),
doc.implementation.createDocumentType("foo", "href='biz'", ""),
doc.implementation.createDocument("http://example.com/", "foo", null),
doc.createDocumentFragment()
doc.createDocumentFragment(),
];
for (var i = 0; i < nodes.length; i++)
{
for (var j = i; j < nodes.length; j++)
{
for (var i = 0; i < nodes.length; i++) {
for (var j = i; j < nodes.length; j++) {
if (i == j)
check_eq_nodes(nodes[i], nodes[j]);
else
@ -159,8 +150,7 @@ function test_isEqualNode_variety()
}
}
function test_isEqualNode_normalization()
{
function test_isEqualNode_normalization() {
var norm = doc.getElementById("test_normalization");
var node1 = norm.childNodes.item(1);
var node2 = norm.childNodes.item(3);
@ -197,8 +187,7 @@ function test_isEqualNode_normalization()
check_eq_nodes(at1, at2);
// Attr.appendChild isn't implemented yet (bug 56758), so don't run this yet
if (false)
{
if (false) {
at1.appendChild(doc.createTextNode("rasp"));
at2.appendChild(doc.createTextNode("rasp"));
check_eq_nodes(at1, at2);
@ -308,8 +297,7 @@ function test_isEqualNode_normalization()
check_eq_nodes(node1, node2);
}
function test_isEqualNode_whitespace()
{
function test_isEqualNode_whitespace() {
equality_check_kids("test_pi1", true);
equality_check_kids("test_pi2", true);
equality_check_kids("test_pi3", false);
@ -338,40 +326,34 @@ function test_isEqualNode_whitespace()
equality_check_kids("test_cdata5", false);
}
function test_isEqualNode_namespaces()
{
function test_isEqualNode_namespaces() {
equality_check_kids("test_ns1", false);
equality_check_kids("test_ns2", false);
// XXX want more tests here!
}
function test_isEqualNode_null()
{
function test_isEqualNode_null() {
check_neq_nodes(doc, null);
var elts = doc.getElementsByTagName("*");
for (var i = 0; i < elts.length; i++)
{
for (var i = 0; i < elts.length; i++) {
var elt = elts.item(i);
check_neq_nodes(elt, null);
var attrs = elt.attributes;
for (var j = 0; j < attrs.length; j++)
{
for (var j = 0; j < attrs.length; j++) {
var att = attrs.item(j);
check_neq_nodes(att, null);
for (var k = 0; k < att.childNodes.length; k++)
{
for (var k = 0; k < att.childNodes.length; k++) {
check_neq_nodes(att.childNodes.item(k), null);
}
}
}
}
function test_isEqualNode_wholeDoc()
{
function test_isEqualNode_wholeDoc() {
doc = ParseFile("isequalnode_data.xml");
var doc2 = ParseFile("isequalnode_data.xml");
var tw1 =
@ -383,7 +365,7 @@ function test_isEqualNode_wholeDoc()
do {
check_eq_nodes(tw1.currentNode, tw2.currentNode);
tw1.nextNode();
} while(tw2.nextNode());
} while (tw2.nextNode());
}
// TESTING FUNCTIONS
@ -397,8 +379,7 @@ function test_isEqualNode_wholeDoc()
* are whitespace-sensitive, and a stray space introduced during an edit to the
* file could result in a correct but unexpected (in)equality failure.
*/
function equality_check_kids(parentId, areEqual)
{
function equality_check_kids(parentId, areEqual) {
var parent = doc.getElementById(parentId);
var kid1 = parent.childNodes.item(1);
var kid2 = parent.childNodes.item(3);
@ -409,8 +390,7 @@ function equality_check_kids(parentId, areEqual)
check_neq_nodes(kid1, kid2);
}
function check_eq_nodes(n1, n2)
{
function check_eq_nodes(n1, n2) {
if (n1 && !n1.isEqualNode(n2))
do_throw(n1 + " should be equal to " + n2);
if (n2 && !n2.isEqualNode(n1))
@ -419,8 +399,7 @@ function check_eq_nodes(n1, n2)
do_throw("nodes both null!");
}
function check_neq_nodes(n1, n2)
{
function check_neq_nodes(n1, n2) {
if (n1 && n1.isEqualNode(n2))
do_throw(n1 + " should not be equal to " + n2);
if (n2 && n2.isEqualNode(n1))

View File

@ -19,8 +19,8 @@ function errors() {
// The following errors MUST be captured.
new TypeError("This is a TypeError: " + Math.random()),
new SyntaxError("This is a SyntaxError: " + Math.random()),
new ReferenceError("This is a ReferenceError: " + Math.random())
]
new ReferenceError("This is a ReferenceError: " + Math.random()),
];
}
function isDeveloperError(e) {
@ -52,5 +52,5 @@ function run_test() {
ChromeUtils.clearRecentJSDevError();
Assert.equal(ChromeUtils.recentJSDevError, undefined);
}
};
}

View File

@ -1,7 +1,6 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
function run_test()
{
function run_test() {
test_getElementsByTagName();
test_getElementsByTagNameNS();
test_getElementsByAttribute();
@ -10,19 +9,18 @@ function run_test()
// What else should we test?
// XXXbz we need more tests here to test liveness!
}
}
function test_getElementsByTagName()
{
function test_getElementsByTagName() {
var doc = ParseFile("nodelist_data_1.xml");
var root = doc.documentElement;
// Check that getElementsByTagName returns an HTMLCollection.
Assert.equal(ChromeUtils.getClassName(doc.getElementsByTagName("*")),
"HTMLCollection")
"HTMLCollection");
Assert.ok(ChromeUtils.getClassName(root.getElementsByTagName("*")),
"HTMLCollection");
// Check that getElementsByTagName excludes the element it's called on.
Assert.equal(doc.getElementsByTagName("*").length,
root.getElementsByTagName("*").length + 1);
@ -42,7 +40,7 @@ function test_getElementsByTagName()
for (var i = 1; i <= numTests; ++i) {
Assert.ok(Element.isInstance(doc.getElementById("test" + i)));
Assert.equal(doc.getElementById("test" + i),
doc.getElementsByTagName("test").item(i-1));
doc.getElementsByTagName("test").item(i - 1));
}
// Check that we handle tagnames containing ':' correctly
@ -59,8 +57,7 @@ function test_getElementsByTagName()
Assert.equal(doc.getElementsByTagName("bar:test").length, 4);
}
function test_getElementsByTagNameNS()
{
function test_getElementsByTagNameNS() {
var doc = ParseFile("nodelist_data_1.xml");
var root = doc.documentElement;
@ -77,7 +74,7 @@ function test_getElementsByTagNameNS()
for (var i = 0; i < list1.length; ++i) {
Assert.equal(list1.item(i), list2.item(i));
}
// Check that getElementsByTagNameNS excludes the element it's called on.
Assert.equal(doc.getElementsByTagNameNS("*", "*").length,
root.getElementsByTagNameNS("*", "*").length + 1);
@ -98,14 +95,14 @@ function test_getElementsByTagNameNS()
// Check that we get the right things in the right order
var numTests = doc.getElementsByTagNameNS("*", "test").length;
Assert.equal(numTests, 14);
for (var i = 1; i <= numTests; ++i) {
for (i = 1; i <= numTests; ++i) {
Assert.ok(Element.isInstance(doc.getElementById("test" + i)));
Assert.equal(doc.getElementById("test" + i),
doc.getElementsByTagNameNS("*", "test").item(i-1));
doc.getElementsByTagNameNS("*", "test").item(i - 1));
}
// Check general proper functioning of having a non-wildcard namespace.
@ -134,14 +131,14 @@ function test_getElementsByTagNameNS()
Assert.equal(doc.getElementsByTagNameNS("foo", "foo:test").length, 0);
Assert.equal(doc.getElementsByTagNameNS("bar", "foo:test").length, 0);
Assert.equal(doc.getElementsByTagNameNS("*", "foo:test").length, 0);
Assert.equal(ChromeUtils.getClassName(doc.getElementsByTagNameNS(null, "foo2:test")),
"HTMLCollection");
Assert.equal(doc.getElementsByTagNameNS(null, "foo2:test").length, 0);
Assert.equal(doc.getElementsByTagNameNS("foo2", "foo2:test").length, 0);
Assert.equal(doc.getElementsByTagNameNS("bar", "foo2:test").length, 0);
Assert.equal(doc.getElementsByTagNameNS("*", "foo2:test").length, 0);
Assert.equal(ChromeUtils.getClassName(doc.getElementsByTagNameNS(null, "bar:test")),
"HTMLCollection");
Assert.equal(doc.getElementsByTagNameNS(null, "bar:test").length, 0);
@ -160,14 +157,13 @@ function test_getElementsByTagNameNS()
Assert.equal(list2.length, 0);
var newNode = doc.createElementNS("random-bogus-namespace", "foo");
doc.documentElement.appendChild(newNode);
var newNode = doc.createElementNS("random-bogus-namespace2", "foo");
newNode = doc.createElementNS("random-bogus-namespace2", "foo");
doc.documentElement.appendChild(newNode);
Assert.equal(list1.length, 1);
Assert.equal(list2.length, 1);
Assert.equal(list1.length, 1);
Assert.equal(list2.length, 1);
}
function test_getElementsByAttribute()
{
function test_getElementsByAttribute() {
var doc = ParseFile("nodelist_data_2.xul");
var root = doc.documentElement;
@ -283,8 +279,7 @@ function test_getElementsByAttribute()
0);
}
function test_getElementsByAttributeNS()
{
function test_getElementsByAttributeNS() {
var doc = ParseFile("nodelist_data_2.xul");
var root = doc.documentElement;
@ -306,7 +301,7 @@ function test_getElementsByAttributeNS()
Assert.equal(ChromeUtils.getClassName(master2), "XULElement");
Assert.equal(ChromeUtils.getClassName(master3), "XULElement");
Assert.equal(ChromeUtils.getClassName(external), "XULElement");
// Test wildcard namespace
Assert.equal(root.getElementsByAttributeNS("*", "foo", "foo").length,
38);
@ -353,7 +348,7 @@ function test_getElementsByAttributeNS()
master2.getElementsByAttribute("foo", "foo").length);
Assert.equal(master3.getElementsByAttributeNS("", "foo", "foo").length,
master3.getElementsByAttribute("foo", "foo").length);
// Test namespace "foo"
Assert.equal(root.getElementsByAttributeNS("foo", "foo", "foo").length,
24);

View File

@ -3,8 +3,7 @@
* 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/. */
function run_test()
{
function run_test() {
/*
* NOTE: [i] is not allowed in this test, since it's done via classinfo and
* we don't have that in xpcshell; the workaround is item(i). Suck.
@ -23,13 +22,11 @@ function run_test()
var doc; // cache for use in all tests
function init()
{
function init() {
doc = ParseFile("empty_document.xml");
}
function test_element()
{
function test_element() {
var x = doc.createElement("funk");
// one empty Text node
@ -102,8 +99,7 @@ function test_element()
// UTILITY FUNCTIONS
function clearKids(node)
{
function clearKids(node) {
while (node.hasChildNodes())
node.removeChild(node.childNodes.item(0));
}

View File

@ -122,7 +122,7 @@ function evalXPathInDocumentFragment(aContextNode, aPath) {
}
return NodeFilter.FILTER_ACCEPT;
}
},
};
// Look for the node matching the step from the document fragment.
@ -194,7 +194,7 @@ function processParsedDocument(doc) {
var splits = doc.getElementsByTagName("split");
var i;
for (i = splits.length - 1; i >= 0; i--) {
var node = splits.item(i);
let node = splits.item(i);
node.remove();
}
splits = null;
@ -202,7 +202,7 @@ function processParsedDocument(doc) {
// Replace empty CDATA sections.
var emptyData = doc.getElementsByTagName("empty-cdata");
for (i = emptyData.length - 1; i >= 0; i--) {
var node = emptyData.item(i);
let node = emptyData.item(i);
var cdata = doc.createCDATASection("");
node.parentNode.replaceChild(cdata, node);
}
@ -291,7 +291,7 @@ function do_extract_test(doc) {
foundEnd = true;
break;
}
} while (walker.nextNode())
} while (walker.nextNode());
Assert.ok(foundEnd);
/* Now, we reset our test for the deleteContents case. This one differs
@ -302,8 +302,8 @@ function do_extract_test(doc) {
dump("Delete contents test " + i + "\n\n");
baseFrag = getFragment(baseSource);
baseRange = getRange(baseSource, baseFrag);
var startContainer = baseRange.startContainer;
var endContainer = baseRange.endContainer;
startContainer = baseRange.startContainer;
endContainer = baseRange.endContainer;
baseRange.deleteContents();
Assert.ok(baseFrag.isEqualNode(resultFrag));
@ -324,7 +324,7 @@ function do_extract_test(doc) {
foundEnd = true;
break;
}
} while (walker.nextNode())
} while (walker.nextNode());
Assert.ok(foundEnd);
// Clean up after ourselves.
@ -351,8 +351,6 @@ function do_miscellaneous_tests(doc) {
// Let's try some invalid inputs to our DOM range and see what happens.
var currentTest = tests.item(0);
var baseSource = currentTest.firstChild;
var baseResult = baseSource.nextSibling;
var baseExtract = baseResult.nextSibling;
var baseFrag = getFragment(baseSource);
@ -389,7 +387,7 @@ function do_miscellaneous_tests(doc) {
} catch (e) {
Assert.equal(e.name, "IndexSizeError");
}
// Invalid index
var newOffset = isText(startContainer) ?
startContainer.nodeValue.length + 1 :
@ -400,7 +398,7 @@ function do_miscellaneous_tests(doc) {
} catch (e) {
Assert.equal(e.name, "IndexSizeError");
}
newOffset--;
// Valid index
baseRange.setStart(startContainer, newOffset);
@ -414,7 +412,7 @@ function do_miscellaneous_tests(doc) {
Assert.equal(baseRange.startOffset, 0);
Assert.ok(baseRange.collapsed);
} else {
do_throw("The first test should be a text-only range test. Test is invalid.")
do_throw("The first test should be a text-only range test. Test is invalid.");
}
/* See what happens when a range has a startContainer in one fragment, and an
@ -422,9 +420,9 @@ function do_miscellaneous_tests(doc) {
should collapse to the new container and offset. */
baseRange = getRange(baseSource, baseFrag);
startContainer = baseRange.startContainer;
var startOffset = baseRange.startOffset;
startOffset = baseRange.startOffset;
endContainer = baseRange.endContainer;
var endOffset = baseRange.endOffset;
endOffset = baseRange.endOffset;
dump("External fragment test\n\n");

View File

@ -7,8 +7,7 @@
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var prefs = Services.prefs;
// Since this test creates a TYPE_DOCUMENT channel via javascript, it will
// end up using the wrong LoadInfo constructor. Setting this pref will disable
@ -17,8 +16,7 @@ prefs.setBoolPref("network.loadinfo.skip_type_assertion", true);
var NS_ERROR_INVALID_ARG = Cr.NS_ERROR_INVALID_ARG;
function do_check_throws(f, result, stack)
{
function do_check_throws(f, result, stack) {
if (!stack) {
try {
// We might not have a 'Components' object.
@ -47,15 +45,15 @@ function run_test() {
let uri2 = NetUtil.newURI(spec2);
const contentPolicyType = Ci.nsIContentPolicy.TYPE_DOCUMENT;
let channel1 = NetUtil.newChannel({uri: uri1, loadUsingSystemPrincipal: true, contentPolicyType});
let channel2 = NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true, contentPolicyType});
NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true, contentPolicyType});
// Create some file:// URIs.
let filespec1 = "file://foo.txt";
let filespec2 = "file://bar.txt";
let fileuri1 = NetUtil.newURI(filespec1);
let fileuri2 = NetUtil.newURI(filespec2);
let filechannel1 = NetUtil.newChannel({uri: fileuri1, loadUsingSystemPrincipal: true});
let filechannel2 = NetUtil.newChannel({uri: fileuri2, loadUsingSystemPrincipal: true});
NetUtil.newChannel({uri: fileuri1, loadUsingSystemPrincipal: true});
NetUtil.newChannel({uri: fileuri2, loadUsingSystemPrincipal: true});
// Test isThirdPartyURI.
Assert.ok(!util.isThirdPartyURI(uri1, uri1));

View File

@ -5,17 +5,15 @@
Cu.importGlobalProperties(["NodeFilter"]);
function run_test()
{
function run_test() {
test_treeWalker_currentNode();
}
// TEST CODE
function test_treeWalker_currentNode()
{
function test_treeWalker_currentNode() {
var XHTMLDocString = '<html xmlns="http://www.w3.org/1999/xhtml">';
XHTMLDocString += '<body><input/>input</body></html>';
XHTMLDocString += "<body><input/>input</body></html>";
var doc = ParseXML(XHTMLDocString);

View File

@ -41,6 +41,6 @@ function run_test() {
xhr2.onload = function() {
server.stop(do_test_finished);
}
};
};
}

View File

@ -5,13 +5,12 @@
// Test setting .responseType and .withCredentials is allowed
// in non-window non-Worker context
function run_test()
{
function run_test() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'data:,', false);
xhr.open("GET", "data:,", false);
var exceptionThrown = false;
try {
xhr.responseType = '';
xhr.responseType = "";
xhr.withCredentials = false;
} catch (e) {
exceptionThrown = true;

View File

@ -1,4 +1,4 @@
function run_test () {
function run_test() {
for (var i = 0; i < tests.length && tests[i][0]; ++i) {
if (!tests[i][0].call()) {
do_throw(tests[i][1]);
@ -13,7 +13,7 @@ var tests = [
[ test4, "" ],
[ test5, "" ],
[ test6, "" ],
[ null ]
[ null ],
];
function test1() {
@ -30,19 +30,19 @@ function test3() {
function test4() {
var doc = ParseXML("<root/>");
Assert.equal(doc.documentElement.namespaceURI, null);
Assert.equal(doc.documentElement.namespaceURI, null);
return true;
}
function test5() {
var doc = ParseXML("<root xmlns=''/>");
Assert.equal(doc.documentElement.namespaceURI, null);
Assert.equal(doc.documentElement.namespaceURI, null);
return true;
}
function test6() {
var doc = ParseXML("<root xmlns='ns1'/>");
Assert.notEqual(doc.documentElement.namespaceURI, null);
Assert.equal(doc.documentElement.namespaceURI, 'ns1');
Assert.notEqual(doc.documentElement.namespaceURI, null);
Assert.equal(doc.documentElement.namespaceURI, "ns1");
return true;
}

View File

@ -29,7 +29,7 @@ var tests = [
test8,
test9,
test10,
null
null,
];
function testString(str) {
@ -40,17 +40,17 @@ function test1() {
// Basic round-tripping which we expect to hand back the same text
// as we passed in (not strictly required for correctness in some of
// those cases, but best for readability of serializer output)
testString('<root/>');
testString('<root><child/></root>');
testString("<root/>");
testString("<root><child/></root>");
testString('<root xmlns=""/>');
testString('<root xml:lang="en"/>');
testString('<root xmlns="ns1"><child xmlns="ns2"/></root>')
testString('<root xmlns="ns1"><child xmlns=""/></root>')
testString('<a:root xmlns:a="ns1"><child/></a:root>')
testString('<a:root xmlns:a="ns1"><a:child/></a:root>')
testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1"/></a:root>')
testString('<a:root xmlns:a="ns1"><a:child xmlns:a="ns2"/></a:root>')
testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1" b:attr=""/></a:root>')
testString('<root xmlns="ns1"><child xmlns="ns2"/></root>');
testString('<root xmlns="ns1"><child xmlns=""/></root>');
testString('<a:root xmlns:a="ns1"><child/></a:root>');
testString('<a:root xmlns:a="ns1"><a:child/></a:root>');
testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1"/></a:root>');
testString('<a:root xmlns:a="ns1"><a:child xmlns:a="ns2"/></a:root>');
testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1" b:attr=""/></a:root>');
}
function test2() {
@ -90,8 +90,8 @@ function test3() {
root.appendChild(child);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<prefix:root xmlns:prefix="ns1"><a0:child xmlns:a0="ns2"/>'+
'</prefix:root>');
'<prefix:root xmlns:prefix="ns1"><a0:child xmlns:a0="ns2"/>' +
"</prefix:root>");
}
@ -130,9 +130,9 @@ function test4() {
'<root xmlns="ns1" a0:local="val" xmlns:a0="ns1"/>');
// Tree-walking test
doc = ParseXML('<root xmlns="ns1" xmlns:a="ns2">'+
'<child xmlns:b="ns2" xmlns:a="ns3">'+
'<child2/></child></root>');
doc = ParseXML('<root xmlns="ns1" xmlns:a="ns2">' +
'<child xmlns:b="ns2" xmlns:a="ns3">' +
"<child2/></child></root>");
root = doc.documentElement;
var node = root.firstChild.firstChild;
node.setAttributeNS("ns4", "l1", "v1");
@ -153,8 +153,8 @@ function test4() {
// "a1" earlier, and discard it in favor of something we get off the
// namespace stack, apparently
Assert.equal(SerializeXML(doc),
'<root xmlns="ns1" xmlns:a="ns2">'+
'<child xmlns:b="ns2" xmlns:a="ns3">'+
'<root xmlns="ns1" xmlns:a="ns2">' +
'<child xmlns:b="ns2" xmlns:a="ns3">' +
'<child2 a0:l1="v1" xmlns:a0="ns4"' +
' a0:l2="v2"' +
' l3="v3"' +
@ -173,8 +173,8 @@ function test4() {
function test5() {
// Handling of kids in the null namespace when the default is a
// different namespace (bug 301260).
var doc = ParseXML('<root xmlns="ns1"/>')
var child = doc.createElement('child');
var doc = ParseXML('<root xmlns="ns1"/>');
var child = doc.createElement("child");
doc.documentElement.appendChild(child);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
@ -192,8 +192,8 @@ function test6() {
root.appendChild(child1);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<prefix:root xmlns:prefix="ns1"><a0:child1 xmlns:a0="ns2">'+
'<prefix:child2/></a0:child1></prefix:root>');
'<prefix:root xmlns:prefix="ns1"><a0:child1 xmlns:a0="ns2">' +
"<prefix:child2/></a0:child1></prefix:root>");
doc = ParseXML('<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2"/></root>');
root = doc.documentElement;
@ -202,10 +202,10 @@ function test6() {
child1.appendChild(child2);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2">'+
'<child2/></prefix:child1></root>');
'<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2">' +
"<child2/></prefix:child1></root>");
doc = ParseXML('<prefix:root xmlns:prefix="ns1">'+
doc = ParseXML('<prefix:root xmlns:prefix="ns1">' +
'<prefix:child1 xmlns:prefix="ns2"/></prefix:root>');
root = doc.documentElement;
child1 = root.firstChild;
@ -213,7 +213,7 @@ function test6() {
child1.appendChild(child2);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<prefix:root xmlns:prefix="ns1"><prefix:child1 xmlns:prefix="ns2">'+
'<prefix:root xmlns:prefix="ns1"><prefix:child1 xmlns:prefix="ns2">' +
'<a0:child2 xmlns:a0="ns1"/></prefix:child1></prefix:root>');
@ -225,29 +225,29 @@ function test6() {
root.appendChild(child1);
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<root xmlns="ns1"><child1 xmlns="ns2"><child2 xmlns="ns1"/>'+
'</child1></root>');
'<root xmlns="ns1"><child1 xmlns="ns2"><child2 xmlns="ns1"/>' +
"</child1></root>");
}
function test7() {
// Handle xmlns attribute declaring a default namespace on a non-namespaced
// element (bug 326994).
var doc = ParseXML('<root xmlns=""/>')
var doc = ParseXML('<root xmlns=""/>');
var root = doc.documentElement;
root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns",
"http://www.w3.org/1999/xhtml");
do_check_serialize(doc);
Assert.equal(SerializeXML(doc), '<root/>');
Assert.equal(SerializeXML(doc), "<root/>");
doc = ParseXML('<root xmlns=""><child1/></root>')
doc = ParseXML('<root xmlns=""><child1/></root>');
root = doc.documentElement;
root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns",
"http://www.w3.org/1999/xhtml");
do_check_serialize(doc);
Assert.equal(SerializeXML(doc), '<root><child1/></root>');
Assert.equal(SerializeXML(doc), "<root><child1/></root>");
doc = ParseXML('<root xmlns="http://www.w3.org/1999/xhtml">' +
'<child1 xmlns=""><child2/></child1></root>')
'<child1 xmlns=""><child2/></child1></root>');
root = doc.documentElement;
var child1 = root.firstChild;
@ -256,12 +256,12 @@ function test7() {
do_check_serialize(doc);
Assert.equal(SerializeXML(doc),
'<root xmlns="http://www.w3.org/1999/xhtml"><child1 xmlns="">' +
'<child2/></child1></root>');
"<child2/></child1></root>");
doc = ParseXML('<root xmlns="http://www.w3.org/1999/xhtml">' +
'<child1 xmlns="">' +
'<child2 xmlns="http://www.w3.org/1999/xhtml"></child2>' +
'</child1></root>')
"</child1></root>");
root = doc.documentElement;
child1 = root.firstChild;
var child2 = child1.firstChild;
@ -276,8 +276,8 @@ function test7() {
function test8() {
// Test behavior of serializing with a given charset.
var str1 = '<?xml version="1.0" encoding="windows-1252"?>'+LB+'<root/>';
var str2 = '<?xml version="1.0" encoding="UTF-8"?>'+LB+'<root/>';
var str1 = '<?xml version="1.0" encoding="windows-1252"?>' + LB + "<root/>";
var str2 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + "<root/>";
var doc1 = ParseXML(str1);
var doc2 = ParseXML(str2);
@ -305,12 +305,12 @@ function test8() {
function test9() {
// Test behavior of serializing between given charsets, using
// windows-1252-representable text.
var contents = '<root>' +
'\u00BD + \u00BE == \u00BD\u00B2 + \u00BC + \u00BE' +
'</root>';
var str1 = '<?xml version="1.0" encoding="windows-1252"?>'+ LB + contents;
var str2 = '<?xml version="1.0" encoding="UTF-8"?>'+ LB + contents;
var str3 = '<?xml version="1.0" encoding="UTF-16"?>'+ LB + contents;
var contents = "<root>" +
"\u00BD + \u00BE == \u00BD\u00B2 + \u00BC + \u00BE" +
"</root>";
var str1 = '<?xml version="1.0" encoding="windows-1252"?>' + LB + contents;
var str2 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + contents;
var str3 = '<?xml version="1.0" encoding="UTF-16"?>' + LB + contents;
var doc1 = ParseXML(str1);
var doc2 = ParseXML(str2);
var doc3 = ParseXML(str3);
@ -333,13 +333,13 @@ function test10() {
// Unicode characters (XXX but only BMP ones because I don't know
// how to create one with non-BMP characters, either with JS strings
// or using DOM APIs).
var contents = '<root>' +
'AZaz09 \u007F ' + // U+000000 to U+00007F
'\u0080 \u0398 \u03BB \u0725 ' + // U+000080 to U+0007FF
'\u0964 \u0F5F \u20AC \uFFFB' + // U+000800 to U+00FFFF
'</root>';
var str1 = '<?xml version="1.0" encoding="UTF-8"?>'+ LB + contents;
var str2 = '<?xml version="1.0" encoding="UTF-16"?>'+ LB + contents;
var contents = "<root>" +
"AZaz09 \u007F " + // U+000000 to U+00007F
"\u0080 \u0398 \u03BB \u0725 " + // U+000080 to U+0007FF
"\u0964 \u0F5F \u20AC \uFFFB" + // U+000800 to U+00FFFF
"</root>";
var str1 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + contents;
var str2 = '<?xml version="1.0" encoding="UTF-16"?>' + LB + contents;
var doc1 = ParseXML(str1);
var doc2 = ParseXML(str2);

View File

@ -4,8 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
async function xmlEncode(aFile, aFlags, aCharset) {
if(aFlags == undefined) aFlags = 0;
if(aCharset == undefined) aCharset = "UTF-8";
if (aFlags == undefined) aFlags = 0;
if (aCharset == undefined) aCharset = "UTF-8";
var doc = await do_parse_document(aFile, "text/xml");
@ -83,13 +83,13 @@ add_task(async function() {
encoder.setCharset("UTF-8");
// it doesn't support this flags
encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap);
encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap);
encoder.setWrapColumn(40);
result = encoder.encodeToString();
expected = loadContentFile("4_result_5.xml");
Assert.equal(expected, result);
encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputWrap);
encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputWrap);
encoder.setWrapColumn(40);
result = encoder.encodeToString();
expected = loadContentFile("4_result_6.xml");

View File

@ -94,6 +94,23 @@ interface WebExtensionPolicy {
*/
static readonly attribute boolean isExtensionProcess;
/**
* Set based on the manifest.incognito value:
* If "spanning" or "split" will be true.
* If "not_allowed" will be false.
*/
[Pure]
attribute boolean privateBrowsingAllowed;
/**
* Returns true if the extension can access a window. Access is
* determined by matching the windows private browsing context
* with privateBrowsingMode. This does not, and is not meant to
* handle specific differences between spanning and split mode.
*/
[Affects=Nothing]
boolean canAccessWindow(WindowProxy window);
/**
* Returns true if the extension has cross-origin access to the given URI.
*/
@ -193,4 +210,6 @@ dictionary WebExtensionInit {
DOMString? contentSecurityPolicy = null;
sequence<DOMString>? backgroundScripts = null;
boolean privateBrowsingAllowed = true;
};

View File

@ -1630,10 +1630,6 @@ void HTMLMediaElement::SetVisible(bool aVisible) {
}
}
bool HTMLMediaElement::IsVideoDecodingSuspended() const {
return mDecoder && mDecoder->IsVideoDecodingSuspended();
}
already_AddRefed<layers::Image> HTMLMediaElement::GetCurrentImage() {
MarkAsTainted();

View File

@ -560,9 +560,6 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// For use by mochitests. Enabling pref "media.test.video-suspend"
bool HasSuspendTaint() const;
// For use by mochitests. Enabling pref "media.test.video-suspend"
bool IsVideoDecodingSuspended() const;
// Synchronously, return the next video frame and mark the element unable to
// participate in decode suspending.
//

View File

@ -435,11 +435,9 @@ void MediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent) {
break;
case MediaPlaybackEvent::EnterVideoSuspend:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
mIsVideoDecodingSuspended = true;
break;
case MediaPlaybackEvent::ExitVideoSuspend:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
mIsVideoDecodingSuspended = false;
break;
case MediaPlaybackEvent::StartVideoSuspendTimer:
GetOwner()->DispatchAsyncEvent(
@ -462,10 +460,6 @@ void MediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent) {
}
}
bool MediaDecoder::IsVideoDecodingSuspended() const {
return mIsVideoDecodingSuspended;
}
void MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError) {
DecodeError(aError);
}
@ -973,13 +967,11 @@ void MediaDecoder::UpdateVideoDecodeMode() {
return;
}
// If the element is in-tree with UNTRACKED visibility, that means the element
// is not close enough to the viewport so we have not start to update its
// visibility. In this case, it's equals to invisible.
// If an element is in-tree with UNTRACKED visibility, the visibility is
// incomplete and don't update the video decode mode.
if (mIsElementInTree && mElementVisibility == Visibility::UNTRACKED) {
LOG("UpdateVideoDecodeMode(), set Suspend because element hasn't be "
"updated visibility state.");
mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
LOG("UpdateVideoDecodeMode(), early return because we have incomplete "
"visibility states.");
return;
}

View File

@ -312,8 +312,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
void SetIsBackgroundVideoDecodingAllowed(bool aAllowed);
bool IsVideoDecodingSuspended() const;
/******
* The following methods must only be called on the main
* thread.
@ -580,9 +578,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
MediaEventListener mOnDecodeWarning;
MediaEventListener mOnNextFrameStatus;
// True if we have suspended video decoding.
bool mIsVideoDecodingSuspended = false;
protected:
// PlaybackRate and pitch preservation status we should start at.
double mPlaybackRate;

File diff suppressed because it is too large Load Diff

View File

@ -62,8 +62,6 @@ class GetUserMediaWindowListener;
class MediaManager;
class SourceListener;
LogModule* GetMediaManagerLog();
class MediaDevice : public nsIMediaDevice {
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -218,8 +216,10 @@ class MediaManager final : public nsIMediaManagerService,
typedef MozPromise<RefPtr<DOMMediaStream>, RefPtr<MediaMgrError>, true>
StreamPromise;
typedef MozPromise<RefPtr<MediaDeviceSetRefCnt>, RefPtr<MediaMgrError>, true>
MediaDeviceSetPromise;
typedef MozPromise<const char*, nsresult, false> BadConstraintsPromise;
DevicesPromise;
typedef MozPromise<bool, RefPtr<MediaMgrError>, true> MgrPromise;
typedef MozPromise<const char*, RefPtr<MediaMgrError>, true>
BadConstraintsPromise;
RefPtr<StreamPromise> GetUserMedia(
nsPIDOMWindowInner* aWindow,
@ -231,8 +231,8 @@ class MediaManager final : public nsIMediaManagerService,
const dom::MediaStreamConstraints& aConstraints,
dom::MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
uint64_t aInnerWindowID = 0, const nsAString& aCallID = nsString());
RefPtr<MediaDeviceSetPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow,
dom::CallerType aCallerType);
RefPtr<DevicesPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow,
dom::CallerType aCallerType);
nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
dom::Promise& aPromise);
@ -282,18 +282,19 @@ class MediaManager final : public nsIMediaManagerService,
addition to normal devices) */
};
RefPtr<MediaDeviceSetPromise> EnumerateRawDevices(
uint64_t aWindowId, dom::MediaSourceEnum aVideoInputType,
dom::MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
DeviceEnumerationType aVideoInputEnumType = DeviceEnumerationType::Normal,
DeviceEnumerationType aAudioInputEnumType =
DeviceEnumerationType::Normal);
RefPtr<MediaDeviceSetPromise> EnumerateDevicesImpl(
RefPtr<MgrPromise> EnumerateRawDevices(
uint64_t aWindowId, dom::MediaSourceEnum aVideoInputType,
dom::MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType);
DeviceEnumerationType aAudioInputEnumType,
const RefPtr<MediaDeviceSetRefCnt>& aOutDevices);
RefPtr<MgrPromise> EnumerateDevicesImpl(
uint64_t aWindowId, dom::MediaSourceEnum aVideoInputType,
dom::MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType,
const RefPtr<MediaDeviceSetRefCnt>& aOutDevices);
RefPtr<BadConstraintsPromise> SelectSettings(
const dom::MediaStreamConstraints& aConstraints, bool aIsChrome,

View File

@ -57,67 +57,136 @@ static void UpdateTrackProtectedInfo(mozilla::TrackInfo& aConfig,
}
}
void MP4AudioInfo::Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackAudioInfo* audio) {
UpdateTrackProtectedInfo(*this, audio->protected_data);
MediaResult MP4AudioInfo::Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackAudioInfo* audio) {
MOZ_DIAGNOSTIC_ASSERT(audio->sample_info_count > 0,
"Must have at least one audio sample info");
if (audio->sample_info_count == 0) {
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL("Got 0 audio sample info while updating audio track"));
}
if (track->codec == MP4PARSE_CODEC_OPUS) {
bool hasCrypto = false;
Mp4parseCodec codecType = audio->sample_info[0].codec_type;
for (uint32_t i = 0; i < audio->sample_info_count; i++) {
if (audio->sample_info[0].codec_type != codecType) {
// Different codecs in a single track. We don't handle this.
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Multiple codecs encountered while updating audio track"));
}
// Update our encryption info if any is present on the sample info.
if (audio->sample_info[i].protected_data.is_encrypted) {
if (hasCrypto) {
// Multiple crypto entries found. We don't handle this.
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Multiple crypto info encountered while updating audio track"));
}
UpdateTrackProtectedInfo(*this, audio->sample_info[i].protected_data);
hasCrypto = true;
}
}
// We assume that the members of the first sample info are representative of
// the entire track. This code will need to be updated should this assumption
// ever not hold. E.g. if we need to handle different codecs in a single
// track, or if we have different numbers or channels in a single track.
Mp4parseByteData codecSpecificConfig =
audio->sample_info[0].codec_specific_config;
if (codecType == MP4PARSE_CODEC_OPUS) {
mMimeType = NS_LITERAL_CSTRING("audio/opus");
// The Opus decoder expects the container's codec delay or
// pre-skip value, in microseconds, as a 64-bit int at the
// start of the codec-specific config blob.
if (audio->codec_specific_config.data &&
audio->codec_specific_config.length >= 12) {
uint16_t preskip = mozilla::LittleEndian::readUint16(
audio->codec_specific_config.data + 10);
if (codecSpecificConfig.data && codecSpecificConfig.length >= 12) {
uint16_t preskip =
mozilla::LittleEndian::readUint16(codecSpecificConfig.data + 10);
mozilla::OpusDataDecoder::AppendCodecDelay(
mCodecSpecificConfig, mozilla::FramesToUsecs(preskip, 48000).value());
} else {
// This file will error later as it will be rejected by the opus decoder.
mozilla::OpusDataDecoder::AppendCodecDelay(mCodecSpecificConfig, 0);
}
} else if (track->codec == MP4PARSE_CODEC_AAC) {
} else if (codecType == MP4PARSE_CODEC_AAC) {
mMimeType = NS_LITERAL_CSTRING("audio/mp4a-latm");
} else if (track->codec == MP4PARSE_CODEC_FLAC) {
} else if (codecType == MP4PARSE_CODEC_FLAC) {
mMimeType = NS_LITERAL_CSTRING("audio/flac");
} else if (track->codec == MP4PARSE_CODEC_MP3) {
} else if (codecType == MP4PARSE_CODEC_MP3) {
mMimeType = NS_LITERAL_CSTRING("audio/mpeg");
}
mRate = audio->sample_rate;
mChannels = audio->channels;
mBitDepth = audio->bit_depth;
mExtendedProfile = audio->extended_profile;
mRate = audio->sample_info[0].sample_rate;
mChannels = audio->sample_info[0].channels;
mBitDepth = audio->sample_info[0].bit_depth;
mExtendedProfile = audio->sample_info[0].extended_profile;
mDuration = TimeUnit::FromMicroseconds(track->duration);
mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
mTrackId = track->track_id;
// In stagefright, mProfile is kKeyAACProfile, mExtendedProfile is kKeyAACAOT.
if (audio->profile <= 4) {
mProfile = audio->profile;
if (audio->sample_info[0].profile <= 4) {
mProfile = audio->sample_info[0].profile;
}
if (audio->extra_data.length > 0) {
mExtraData->AppendElements(audio->extra_data.data,
audio->extra_data.length);
}
if (audio->codec_specific_config.length > 0) {
mCodecSpecificConfig->AppendElements(audio->codec_specific_config.data,
audio->codec_specific_config.length);
}
Mp4parseByteData extraData = audio->sample_info[0].extra_data;
// If length is 0 we append nothing
mExtraData->AppendElements(extraData.data, extraData.length);
mCodecSpecificConfig->AppendElements(codecSpecificConfig.data,
codecSpecificConfig.length);
return NS_OK;
}
void MP4VideoInfo::Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackVideoInfo* video) {
UpdateTrackProtectedInfo(*this, video->protected_data);
if (track->codec == MP4PARSE_CODEC_AVC) {
MediaResult MP4VideoInfo::Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackVideoInfo* video) {
MOZ_DIAGNOSTIC_ASSERT(video->sample_info_count > 0,
"Must have at least one video sample info");
if (video->sample_info_count == 0) {
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL("Got 0 audio sample info while updating video track"));
}
bool hasCrypto = false;
Mp4parseCodec codecType = video->sample_info[0].codec_type;
for (uint32_t i = 0; i < video->sample_info_count; i++) {
if (video->sample_info[0].codec_type != codecType) {
// Different codecs in a single track. We don't handle this.
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Multiple codecs encountered while updating video track"));
}
// Update our encryption info if any is present on the sample info.
if (video->sample_info[i].protected_data.is_encrypted) {
if (hasCrypto) {
// Multiple crypto entries found. We don't handle this.
return MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Multiple crypto info encountered while updating video track"));
}
UpdateTrackProtectedInfo(*this, video->sample_info[i].protected_data);
hasCrypto = true;
}
}
// We assume that the members of the first sample info are representative of
// the entire track. This code will need to be updated should this assumption
// ever not hold. E.g. if we need to handle different codecs in a single
// track, or if we have different numbers or channels in a single track.
if (codecType == MP4PARSE_CODEC_AVC) {
mMimeType = NS_LITERAL_CSTRING("video/avc");
} else if (track->codec == MP4PARSE_CODEC_VP9) {
} else if (codecType == MP4PARSE_CODEC_VP9) {
mMimeType = NS_LITERAL_CSTRING("video/vp9");
} else if (track->codec == MP4PARSE_CODEC_AV1) {
} else if (codecType == MP4PARSE_CODEC_AV1) {
mMimeType = NS_LITERAL_CSTRING("video/av1");
} else if (track->codec == MP4PARSE_CODEC_MP4V) {
} else if (codecType == MP4PARSE_CODEC_MP4V) {
mMimeType = NS_LITERAL_CSTRING("video/mp4v-es");
}
mTrackId = track->track_id;
@ -125,13 +194,13 @@ void MP4VideoInfo::Update(const Mp4parseTrackInfo* track,
mMediaTime = TimeUnit::FromMicroseconds(track->media_time);
mDisplay.width = video->display_width;
mDisplay.height = video->display_height;
mImage.width = video->image_width;
mImage.height = video->image_height;
mImage.width = video->sample_info[0].image_width;
mImage.height = video->sample_info[0].image_height;
mRotation = ToSupportedRotation(video->rotation);
if (video->extra_data.data) {
mExtraData->AppendElements(video->extra_data.data,
video->extra_data.length);
}
Mp4parseByteData extraData = video->sample_info[0].extra_data;
// If length is 0 we append nothing
mExtraData->AppendElements(extraData.data, extraData.length);
return NS_OK;
}
bool MP4VideoInfo::IsValid() const {

View File

@ -6,6 +6,7 @@
#define DECODER_DATA_H_
#include "MediaInfo.h"
#include "MediaResult.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
#include "mozilla/Types.h"
@ -53,8 +54,8 @@ class MP4AudioInfo : public mozilla::AudioInfo {
public:
MP4AudioInfo() = default;
void Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackAudioInfo* audio);
MediaResult Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackAudioInfo* audio);
virtual bool IsValid() const override;
};
@ -63,8 +64,8 @@ class MP4VideoInfo : public mozilla::VideoInfo {
public:
MP4VideoInfo() = default;
void Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackVideoInfo* video);
MediaResult Update(const Mp4parseTrackInfo* track,
const Mp4parseTrackVideoInfo* video);
virtual bool IsValid() const override;
};

View File

@ -155,7 +155,55 @@ MP4Metadata::ResultAndTrackCount MP4Metadata::GetNumberTracks(
if (rv != MP4PARSE_STATUS_OK) {
continue;
}
if (track_info.codec == MP4PARSE_CODEC_UNKNOWN) {
if (track_info.track_type == MP4PARSE_TRACK_TYPE_AUDIO) {
Mp4parseTrackAudioInfo audio;
auto rv = mp4parse_get_track_audio_info(mParser.get(), i, &audio);
if (rv != MP4PARSE_STATUS_OK) {
MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
("mp4parse_get_track_audio_info returned error %d", rv));
continue;
}
MOZ_DIAGNOSTIC_ASSERT(audio.sample_info_count > 0,
"Must have at least one audio sample info");
if (audio.sample_info_count == 0) {
return {
MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Got 0 audio sample info while checking number tracks")),
MP4Metadata::NumberTracksError()};
}
// We assume the codec of the first sample info is representative of the
// whole track and skip it if we don't recognize the codec.
if (audio.sample_info[0].codec_type == MP4PARSE_CODEC_UNKNOWN) {
continue;
}
} else if (track_info.track_type == MP4PARSE_TRACK_TYPE_VIDEO) {
Mp4parseTrackVideoInfo video;
auto rv = mp4parse_get_track_video_info(mParser.get(), i, &video);
if (rv != MP4PARSE_STATUS_OK) {
MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
("mp4parse_get_track_video_info returned error %d", rv));
continue;
}
MOZ_DIAGNOSTIC_ASSERT(video.sample_info_count > 0,
"Must have at least one video sample info");
if (video.sample_info_count == 0) {
return {
MediaResult(
NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Got 0 video sample info while checking number tracks")),
MP4Metadata::NumberTracksError()};
}
// We assume the codec of the first sample info is representative of the
// whole track and skip it if we don't recognize the codec.
if (video.sample_info[0].codec_type == MP4PARSE_CODEC_UNKNOWN) {
continue;
}
} else {
// Only audio and video are supported
continue;
}
if (TrackTypeEqual(aType, track_info.track_type)) {
@ -219,50 +267,71 @@ MP4Metadata::ResultAndTrackInfo MP4Metadata::GetTrackInfo(
nullptr};
}
#ifdef DEBUG
const char* codec_string = "unrecognized";
switch (info.codec) {
case MP4PARSE_CODEC_UNKNOWN:
codec_string = "unknown";
break;
case MP4PARSE_CODEC_AAC:
codec_string = "aac";
break;
case MP4PARSE_CODEC_OPUS:
codec_string = "opus";
break;
case MP4PARSE_CODEC_FLAC:
codec_string = "flac";
break;
case MP4PARSE_CODEC_ALAC:
codec_string = "alac";
break;
case MP4PARSE_CODEC_AVC:
codec_string = "h.264";
break;
case MP4PARSE_CODEC_VP9:
codec_string = "vp9";
break;
case MP4PARSE_CODEC_AV1:
codec_string = "av1";
break;
case MP4PARSE_CODEC_MP3:
codec_string = "mp3";
break;
case MP4PARSE_CODEC_MP4V:
codec_string = "mp4v";
break;
case MP4PARSE_CODEC_JPEG:
codec_string = "jpeg";
break;
case MP4PARSE_CODEC_AC3:
codec_string = "ac-3";
break;
case MP4PARSE_CODEC_EC3:
codec_string = "ec-3";
break;
bool haveSampleInfo = false;
const char* codecString = "unrecognized";
Mp4parseCodec codecType = MP4PARSE_CODEC_UNKNOWN;
if (info.track_type == MP4PARSE_TRACK_TYPE_AUDIO) {
Mp4parseTrackAudioInfo audio;
auto rv = mp4parse_get_track_audio_info(mParser.get(), trackIndex.value(),
&audio);
if (rv == MP4PARSE_STATUS_OK && audio.sample_info_count > 0) {
codecType = audio.sample_info[0].codec_type;
haveSampleInfo = true;
}
} else if (info.track_type == MP4PARSE_TRACK_TYPE_VIDEO) {
Mp4parseTrackVideoInfo video;
auto rv = mp4parse_get_track_video_info(mParser.get(), trackIndex.value(),
&video);
if (rv == MP4PARSE_STATUS_OK && video.sample_info_count > 0) {
codecType = video.sample_info[0].codec_type;
haveSampleInfo = true;
}
}
if (haveSampleInfo) {
switch (codecType) {
case MP4PARSE_CODEC_UNKNOWN:
codecString = "unknown";
break;
case MP4PARSE_CODEC_AAC:
codecString = "aac";
break;
case MP4PARSE_CODEC_OPUS:
codecString = "opus";
break;
case MP4PARSE_CODEC_FLAC:
codecString = "flac";
break;
case MP4PARSE_CODEC_ALAC:
codecString = "alac";
break;
case MP4PARSE_CODEC_AVC:
codecString = "h.264";
break;
case MP4PARSE_CODEC_VP9:
codecString = "vp9";
break;
case MP4PARSE_CODEC_AV1:
codecString = "av1";
break;
case MP4PARSE_CODEC_MP3:
codecString = "mp3";
break;
case MP4PARSE_CODEC_MP4V:
codecString = "mp4v";
break;
case MP4PARSE_CODEC_JPEG:
codecString = "jpeg";
break;
case MP4PARSE_CODEC_AC3:
codecString = "ac-3";
break;
case MP4PARSE_CODEC_EC3:
codecString = "ec-3";
break;
}
}
MOZ_LOG(gMP4MetadataLog, LogLevel::Debug,
("track codec %s (%u)\n", codec_string, info.codec));
("track codec %s (%u)\n", codecString, codecType));
#endif
// This specialization interface is crazy.
@ -281,7 +350,18 @@ MP4Metadata::ResultAndTrackInfo MP4Metadata::GetTrackInfo(
nullptr};
}
auto track = mozilla::MakeUnique<MP4AudioInfo>();
track->Update(&info, &audio);
MediaResult updateStatus = track->Update(&info, &audio);
if (updateStatus != NS_OK) {
MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
("Updating audio track failed with %s",
updateStatus.Message().get()));
return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Failed to update %s track #%zu with error: %s",
TrackTypeToStr(aType), aTrackNumber,
updateStatus.Message().get())),
nullptr};
}
e = std::move(track);
} break;
case TrackInfo::TrackType::kVideoTrack: {
@ -297,7 +377,18 @@ MP4Metadata::ResultAndTrackInfo MP4Metadata::GetTrackInfo(
nullptr};
}
auto track = mozilla::MakeUnique<MP4VideoInfo>();
track->Update(&info, &video);
MediaResult updateStatus = track->Update(&info, &video);
if (updateStatus != NS_OK) {
MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
("Updating video track failed with %s",
updateStatus.Message().get()));
return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
RESULT_DETAIL(
"Failed to update %s track #%zu with error: %s",
TrackTypeToStr(aType), aTrackNumber,
updateStatus.Message().get())),
nullptr};
}
e = std::move(track);
} break;
default:

View File

@ -18,13 +18,13 @@
#include "webrtc/common_video/include/video_frame_buffer.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
mozilla::LogModule* GetMediaManagerLog();
#define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
#define LOGFRAME(msg) \
MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
namespace mozilla {
extern LazyLogModule gMediaManagerLog;
#define LOG(...) MOZ_LOG(gMediaManagerLog, LogLevel::Debug, (__VA_ARGS__))
#define LOG_FRAME(...) \
MOZ_LOG(gMediaManagerLog, LogLevel::Verbose, (__VA_ARGS__))
using dom::ConstrainLongRange;
using dom::MediaSourceEnum;
using dom::MediaTrackConstraints;
@ -52,7 +52,7 @@ MediaEngineRemoteVideoSource::MediaEngineRemoteVideoSource(
}
void MediaEngineRemoteVideoSource::Init() {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
char deviceName[kMaxDeviceNameLength];
@ -61,7 +61,7 @@ void MediaEngineRemoteVideoSource::Init() {
mCapEngine, mCaptureIndex, deviceName,
kMaxDeviceNameLength, uniqueId,
kMaxUniqueIdLength, nullptr)) {
LOG(("Error initializing RemoteVideoSource (GetCaptureDevice)"));
LOG("Error initializing RemoteVideoSource (GetCaptureDevice)");
return;
}
@ -72,7 +72,7 @@ void MediaEngineRemoteVideoSource::Init() {
}
void MediaEngineRemoteVideoSource::Shutdown() {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
if (!mInitDone) {
@ -94,7 +94,7 @@ void MediaEngineRemoteVideoSource::Shutdown() {
}
void MediaEngineRemoteVideoSource::SetName(nsString aName) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
mDeviceName = std::move(aName);
@ -166,26 +166,26 @@ nsresult MediaEngineRemoteVideoSource::Allocate(
const nsString& aDeviceId,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
AllocationHandle** aOutHandle, const char** aOutBadConstraint) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
MOZ_ASSERT(mState == kReleased);
if (!mInitDone) {
LOG(("Init not done"));
LOG("Init not done");
return NS_ERROR_FAILURE;
}
NormalizedConstraints constraints(aConstraints);
webrtc::CaptureCapability newCapability;
LOG(("ChooseCapability(kFitness) for mCapability (Allocate) ++"));
LOG("ChooseCapability(kFitness) for mCapability (Allocate) ++");
if (!ChooseCapability(constraints, aPrefs, aDeviceId, newCapability,
kFitness)) {
*aOutBadConstraint =
MediaConstraintsHelper::FindBadConstraint(constraints, this, aDeviceId);
return NS_ERROR_FAILURE;
}
LOG(("ChooseCapability(kFitness) for mCapability (Allocate) --"));
LOG("ChooseCapability(kFitness) for mCapability (Allocate) --");
if (camera::GetChildAndCall(&camera::CamerasChild::AllocateCaptureDevice,
mCapEngine, mUniqueId.get(), kMaxUniqueIdLength,
@ -201,13 +201,13 @@ nsresult MediaEngineRemoteVideoSource::Allocate(
mCapability = newCapability;
}
LOG(("Video device %d allocated", mCaptureIndex));
LOG("Video device %d allocated", mCaptureIndex);
return NS_OK;
}
nsresult MediaEngineRemoteVideoSource::Deallocate(
const RefPtr<const AllocationHandle>& aHandle) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
MOZ_ASSERT(mState == kStopped || mState == kAllocated);
@ -231,7 +231,7 @@ nsresult MediaEngineRemoteVideoSource::Deallocate(
mImageContainer = nullptr;
mRescalingBufferPool.Release();
LOG(("Video device %d deallocated", mCaptureIndex));
LOG("Video device %d deallocated", mCaptureIndex);
if (camera::GetChildAndCall(&camera::CamerasChild::ReleaseCaptureDevice,
mCapEngine, mCaptureIndex)) {
@ -244,7 +244,7 @@ nsresult MediaEngineRemoteVideoSource::SetTrack(
const RefPtr<const AllocationHandle>& aHandle,
const RefPtr<SourceMediaStream>& aStream, TrackID aTrackID,
const PrincipalHandle& aPrincipal) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
MOZ_ASSERT(mState == kAllocated);
@ -271,7 +271,7 @@ nsresult MediaEngineRemoteVideoSource::SetTrack(
nsresult MediaEngineRemoteVideoSource::Start(
const RefPtr<const AllocationHandle>& aHandle) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
MOZ_ASSERT(mState == kAllocated || mState == kStopped);
@ -288,7 +288,7 @@ nsresult MediaEngineRemoteVideoSource::Start(
if (camera::GetChildAndCall(&camera::CamerasChild::StartCapture, mCapEngine,
mCaptureIndex, mCapability, this)) {
LOG(("StartCapture failed"));
LOG("StartCapture failed");
MutexAutoLock lock(mMutex);
mState = kStopped;
return NS_ERROR_FAILURE;
@ -326,7 +326,7 @@ nsresult MediaEngineRemoteVideoSource::Start(
nsresult MediaEngineRemoteVideoSource::FocusOnSelectedSource(
const RefPtr<const AllocationHandle>& aHandle) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
int result;
@ -337,7 +337,7 @@ nsresult MediaEngineRemoteVideoSource::FocusOnSelectedSource(
nsresult MediaEngineRemoteVideoSource::Stop(
const RefPtr<const AllocationHandle>& aHandle) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
if (mState == kStopped || mState == kAllocated) {
@ -369,21 +369,21 @@ nsresult MediaEngineRemoteVideoSource::Reconfigure(
const RefPtr<AllocationHandle>& aHandle,
const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId, const char** aOutBadConstraint) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
MOZ_ASSERT(mInitDone);
NormalizedConstraints constraints(aConstraints);
webrtc::CaptureCapability newCapability;
LOG(("ChooseCapability(kFitness) for mTargetCapability (Reconfigure) ++"));
LOG("ChooseCapability(kFitness) for mTargetCapability (Reconfigure) ++");
if (!ChooseCapability(constraints, aPrefs, aDeviceId, newCapability,
kFitness)) {
*aOutBadConstraint =
MediaConstraintsHelper::FindBadConstraint(constraints, this, aDeviceId);
return NS_ERROR_INVALID_ARG;
}
LOG(("ChooseCapability(kFitness) for mTargetCapability (Reconfigure) --"));
LOG("ChooseCapability(kFitness) for mTargetCapability (Reconfigure) --");
if (mCapability == newCapability) {
return NS_OK;
@ -397,10 +397,9 @@ nsresult MediaEngineRemoteVideoSource::Reconfigure(
if (NS_WARN_IF(NS_FAILED(rv))) {
nsAutoCString name;
GetErrorName(rv, name);
LOG(
("Video source %p for video device %d Reconfigure() failed "
"unexpectedly in Stop(). rv=%s",
this, mCaptureIndex, name.Data()));
LOG("Video source %p for video device %d Reconfigure() failed "
"unexpectedly in Stop(). rv=%s",
this, mCaptureIndex, name.Data());
return NS_ERROR_UNEXPECTED;
}
}
@ -416,10 +415,9 @@ nsresult MediaEngineRemoteVideoSource::Reconfigure(
if (NS_WARN_IF(NS_FAILED(rv))) {
nsAutoCString name;
GetErrorName(rv, name);
LOG(
("Video source %p for video device %d Reconfigure() failed "
"unexpectedly in Start(). rv=%s",
this, mCaptureIndex, name.Data()));
LOG("Video source %p for video device %d Reconfigure() failed "
"unexpectedly in Start(). rv=%s",
this, mCaptureIndex, name.Data());
return NS_ERROR_UNEXPECTED;
}
}
@ -614,12 +612,12 @@ int MediaEngineRemoteVideoSource::DeliverFrame(
#ifdef DEBUG
static uint32_t frame_num = 0;
LOGFRAME(
("frame %d (%dx%d)->(%dx%d); rotation %d, timeStamp %u, "
"ntpTimeMs %" PRIu64 ", renderTimeMs %" PRIu64,
frame_num++, aProps.width(), aProps.height(), dst_width, dst_height,
aProps.rotation(), aProps.timeStamp(), aProps.ntpTimeMs(),
aProps.renderTimeMs()));
LOG_FRAME(
"frame %d (%dx%d)->(%dx%d); rotation %d, timeStamp %u, ntpTimeMs %" PRIu64
", renderTimeMs %" PRIu64,
frame_num++, aProps.width(), aProps.height(), dst_width, dst_height,
aProps.rotation(), aProps.timeStamp(), aProps.ntpTimeMs(),
aProps.renderTimeMs());
#endif
if (mImageSize.width != dst_width || mImageSize.height != dst_height) {
@ -773,26 +771,26 @@ static void LogCapability(const char* aHeader,
"I420", "RED", "ULPFEC",
"Generic codec", "Unknown codec"};
LOG(("%s: %4u x %4u x %2u maxFps, %s. Distance = %" PRIu32, aHeader,
aCapability.width, aCapability.height, aCapability.maxFPS,
codec[std::min(std::max(uint32_t(0), uint32_t(aCapability.videoType)),
uint32_t(sizeof(codec) / sizeof(*codec) - 1))],
aDistance));
LOG("%s: %4u x %4u x %2u maxFps, %s. Distance = %" PRIu32, aHeader,
aCapability.width, aCapability.height, aCapability.maxFPS,
codec[std::min(std::max(uint32_t(0), uint32_t(aCapability.videoType)),
uint32_t(sizeof(codec) / sizeof(*codec) - 1))],
aDistance);
}
bool MediaEngineRemoteVideoSource::ChooseCapability(
const NormalizedConstraints& aConstraints, const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId, webrtc::CaptureCapability& aCapability,
const DistanceCalculation aCalculate) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
LOG(("ChooseCapability: prefs: %dx%d @%dfps", aPrefs.GetWidth(),
aPrefs.GetHeight(), aPrefs.mFPS));
if (MOZ_LOG_TEST(gMediaManagerLog, LogLevel::Debug)) {
LOG("ChooseCapability: prefs: %dx%d @%dfps", aPrefs.GetWidth(),
aPrefs.GetHeight(), aPrefs.mFPS);
MediaConstraintsHelper::LogConstraints(aConstraints);
if (!aConstraints.mAdvanced.empty()) {
LOG(("Advanced array[%zu]:", aConstraints.mAdvanced.size()));
LOG("Advanced array[%zu]:", aConstraints.mAdvanced.size());
for (auto& advanced : aConstraints.mAdvanced) {
MediaConstraintsHelper::LogConstraints(advanced);
}
@ -893,8 +891,8 @@ bool MediaEngineRemoteVideoSource::ChooseCapability(
}
if (candidateSet.IsEmpty()) {
LOG(("failed to find capability match from %zu choices",
candidateSet.Length()));
LOG("failed to find capability match from %zu choices",
candidateSet.Length());
return false;
}
@ -952,7 +950,7 @@ void MediaEngineRemoteVideoSource::GetSettings(
}
void MediaEngineRemoteVideoSource::Refresh(int aIndex) {
LOG((__PRETTY_FUNCTION__));
LOG(__PRETTY_FUNCTION__);
AssertIsOnOwningThread();
// NOTE: mCaptureIndex might have changed when allocated!

View File

@ -34,14 +34,11 @@ using namespace webrtc;
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
LogModule* GetMediaManagerLog();
#define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
#define LOG_FRAMES(msg) \
MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
extern LazyLogModule gMediaManagerLog;
#define LOG(...) MOZ_LOG(gMediaManagerLog, LogLevel::Debug, (__VA_ARGS__))
#define LOG_FRAME(...) \
MOZ_LOG(gMediaManagerLog, LogLevel::Verbose, (__VA_ARGS__))
#define LOG_ERROR(...) MOZ_LOG(gMediaManagerLog, LogLevel::Error, (__VA_ARGS__))
/**
* WebRTC Microphone MediaEngineSource.
@ -144,9 +141,9 @@ nsresult MediaEngineWebRTCMicrophoneSource::EvaluateSettings(
c.mChannelCount.Get(std::min(aInPrefs.mChannels, maxChannels));
prefs.mChannels = std::max(1, std::min(prefs.mChannels, maxChannels));
LOG(("Audio config: aec: %d, agc: %d, noise: %d, channels: %d",
prefs.mAecOn ? prefs.mAec : -1, prefs.mAgcOn ? prefs.mAgc : -1,
prefs.mNoiseOn ? prefs.mNoise : -1, prefs.mChannels));
LOG("Audio config: aec: %d, agc: %d, noise: %d, channels: %d",
prefs.mAecOn ? prefs.mAec : -1, prefs.mAgcOn ? prefs.mAgc : -1,
prefs.mNoiseOn ? prefs.mNoise : -1, prefs.mChannels);
*aOutPrefs = prefs;
@ -161,7 +158,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::Reconfigure(
AssertIsOnOwningThread();
MOZ_ASSERT(mStream);
LOG(("Mic source %p Reconfigure ", this));
LOG("Mic source %p Reconfigure ", this);
NormalizedConstraints constraints(aConstraints);
MediaEnginePrefs outputPrefs;
@ -174,8 +171,8 @@ nsresult MediaEngineWebRTCMicrophoneSource::Reconfigure(
nsAutoCString name;
GetErrorName(rv, name);
LOG(("Mic source %p Reconfigure() failed unexpectedly. rv=%s", this,
name.Data()));
LOG("Mic source %p Reconfigure() failed unexpectedly. rv=%s", this,
name.Data());
Stop(nullptr);
return NS_ERROR_UNEXPECTED;
}
@ -502,9 +499,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::Deallocate(
MOZ_ASSERT(mState != kStarted, "Source not stopped");
mState = kReleased;
LOG(("Audio device %s deallocated",
NS_ConvertUTF16toUTF8(mDeviceName).get()));
LOG("Audio device %s deallocated", NS_ConvertUTF16toUTF8(mDeviceName).get());
return NS_OK;
}
@ -532,7 +527,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::SetTrack(
aStream->AddAudioTrack(aTrackID, aStream->GraphRate(), segment,
SourceMediaStream::ADDTRACK_QUEUED);
LOG(("Stream %p registered for microphone capture", aStream.get()));
LOG("Stream %p registered for microphone capture", aStream.get());
return NS_OK;
}
@ -608,8 +603,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::Stop(
const RefPtr<const AllocationHandle>&) {
AssertIsOnOwningThread();
LOG(("Mic source %p Stop()", this));
LOG("Mic source %p Stop()", this);
MOZ_ASSERT(mStream, "SetTrack must have been called before ::Stop");
if (mState == kStopped) {
@ -725,9 +719,8 @@ void AudioInputProcessing::UpdateAECSettings(
if (aLevel != EchoCancellation::SuppressionLevel::kLowSuppression &&
aLevel != EchoCancellation::SuppressionLevel::kModerateSuppression &&
aLevel != EchoCancellation::SuppressionLevel::kHighSuppression) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error,
("Attempt to set invalid AEC suppression level %d",
static_cast<int>(aLevel)));
LOG_ERROR("Attempt to set invalid AEC suppression level %d",
static_cast<int>(aLevel));
aLevel = EchoCancellation::SuppressionLevel::kModerateSuppression;
}
@ -744,16 +737,14 @@ void AudioInputProcessing::UpdateAGCSettings(bool aEnable,
if (aMode != GainControl::Mode::kAdaptiveAnalog &&
aMode != GainControl::Mode::kAdaptiveDigital &&
aMode != GainControl::Mode::kFixedDigital) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error,
("Attempt to set invalid AGC mode %d", static_cast<int>(aMode)));
LOG_ERROR("Attempt to set invalid AGC mode %d", static_cast<int>(aMode));
aMode = GainControl::Mode::kAdaptiveDigital;
}
#if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID)
if (aMode == GainControl::Mode::kAdaptiveAnalog) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error,
("Invalid AGC mode kAgcAdaptiveAnalog on mobile"));
LOG_ERROR("Invalid AGC mode kAgcAdaptiveAnalog on mobile");
MOZ_ASSERT_UNREACHABLE(
"Bad pref set in all.js or in about:config"
" for the auto gain, on mobile.");
@ -770,9 +761,8 @@ void AudioInputProcessing::UpdateNSSettings(
aLevel != NoiseSuppression::Level::kModerate &&
aLevel != NoiseSuppression::Level::kHigh &&
aLevel != NoiseSuppression::Level::kVeryHigh) {
MOZ_LOG(GetMediaManagerLog(), LogLevel::Error,
("Attempt to set invalid noise suppression level %d",
static_cast<int>(aLevel)));
LOG_ERROR("Attempt to set invalid noise suppression level %d",
static_cast<int>(aLevel));
aLevel = NoiseSuppression::Level::kModerate;
}
@ -835,7 +825,7 @@ void AudioInputProcessing::Pull(const RefPtr<SourceMediaStream>& aStream,
}
}
LOG_FRAMES(("Pulling %" PRId64 " frames of silence.", delta));
LOG_FRAME("Pulling %" PRId64 " frames of silence.", delta);
// This assertion fails when we append silence here in the same iteration
// as there were real audio samples already appended by the audio callback.
@ -1034,8 +1024,8 @@ void AudioInputProcessing::PacketizeAndProcess(MediaStreamGraphImpl* aGraph,
continue;
}
LOG_FRAMES(("Appending %" PRIu32 " frames of packetized audio",
mPacketizerInput->PacketSize()));
LOG_FRAME("Appending %" PRIu32 " frames of packetized audio",
mPacketizerInput->PacketSize());
#ifdef DEBUG
mLastCallbackAppendTime = mStream->GraphImpl()->IterationEnd();
@ -1093,7 +1083,7 @@ void AudioInputProcessing::InsertInGraph(const T* aBuffer, size_t aFrames,
write_channels.Elements());
}
LOG_FRAMES(("Appending %zu frames of raw audio", aFrames));
LOG_FRAME("Appending %zu frames of raw audio", aFrames);
MOZ_ASSERT(aChannels == channels.Length());
segment.AppendFrames(buffer.forget(), channels, aFrames, mPrincipal);

View File

@ -14,10 +14,12 @@
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/MediaManager.h"
mozilla::LogModule* GetMediaManagerLog();
#undef LOG
#define LOG(msg, ...) \
MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, (msg, ##__VA_ARGS__))
#ifdef MOZ_WEBRTC
extern mozilla::LazyLogModule gMediaManagerLog;
#else
static mozilla::LazyLogModule gMediaManagerLog("MediaManager");
#endif
#define LOG(...) MOZ_LOG(gMediaManagerLog, LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -218,10 +218,6 @@ partial interface HTMLMediaElement {
[Pref="media.test.video-suspend"]
boolean hasSuspendTaint();
[ChromeOnly]
// This one is used for testing only
readonly attribute boolean isVideoDecodingSuspended;
};
/* Audio Output Devices API */

View File

@ -679,11 +679,12 @@ nsresult txEXSLTRegExFunctionCall::evaluate(txIEvalContext* aContext,
JSAutoRealm ar(cx, sandbox);
ErrorResult er;
GlobalObject global(cx, sandbox);
Optional<JS::HandleObject> targetObj(cx, sandbox);
JS::RootedObject obj(cx);
ChromeUtils::Import(
global,
NS_LITERAL_STRING("resource://gre/modules/txEXSLTRegExFunctions.jsm"),
Optional<JS::HandleObject>(), &obj, er);
targetObj, &obj, er);
MOZ_ALWAYS_TRUE(!er.Failed());
JS::RootedString str(

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0">
<title>Touch-action on a zero-opacity element</title>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<script type="application/javascript">
function* test(testDriver) {
var target = document.getElementById('target');
document.body.addEventListener('touchend', testDriver, { passive: true });
// drag the page up to scroll down by 50px
yield ok(synthesizeNativeTouchDrag(target, 10, 100, 0, -50),
"Synthesized native vertical drag, waiting for touch-end event...");
yield flushApzRepaints(testDriver);
is(window.scrollX, 0, "X scroll offset didn't change");
is(window.scrollY, 0, "Y scroll offset didn't change");
}
waitUntilApzStable()
.then(runContinuation(test))
.then(subtestDone);
</script>
</head>
<body style="border: solid 1px green">
<div id="spacer" style="height: 2000px">
Inside the black border is a zero-opacity touch-action none.
<div id="border" style="border: solid 1px black">
<div id="target" style="opacity: 0; height: 300px; touch-action: none">this text shouldn't be visible</div>
</div>
</div>
</body>
</html>

View File

@ -23,8 +23,11 @@ var subtests = [
// Tests that touch-action CSS properties are handled in APZ without waiting
// on the main-thread, when possible
{'file': 'helper_touch_action_regions.html', 'prefs': touch_action_prefs},
// Tests that touch-action inside zero-opacity items are respected
{'file': 'helper_touch_action_zero_opacity_bug1500864.html', 'prefs': touch_action_prefs},
// Add new subtests to test_group_touch_events-4.html, not this file.
// Add new subtests to test_group_touchevents-4.html, not this file (exceptions
// may be made for quick-running tests that need the touch-action prefs)
];
if (isApzEnabled()) {

View File

@ -10,7 +10,7 @@
<script type="application/javascript">
var subtests = [
// touch-action tests with :active::after CSS property
// clicking on element with :active::after CSS property
{'file': 'helper_bug1473108.html'},
// Add new subtests here. If this starts timing out because it's taking too
// long, create a test_group_touchevents-5.html file. Refer to 1423011#c57

View File

@ -1873,6 +1873,43 @@ TransactionId WebRenderBridgeParent::FlushTransactionIdsForEpoch(
}
#endif
if (fracLatencyNorm > 200) {
aOutputStats->AppendElement(FrameStats(
transactionId.mId, aCompositeStartTime, aRenderStartTime, aEndTime,
fracLatencyNorm,
aStats ? (double(aStats->resource_upload_time) / 1000000.0) : 0.0,
aStats ? (double(aStats->gpu_cache_upload_time) / 1000000.0) : 0.0,
transactionId.mTxnStartTime, transactionId.mRefreshStartTime,
transactionId.mFwdTime, transactionId.mSceneBuiltTime,
transactionId.mSkippedComposites, transactionId.mTxnURL));
}
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
if (fracLatencyNorm > 200) {
wr::RenderThread::Get()->NotifySlowFrame(mApi->GetId());
}
if (transactionId.mContainsSVGGroup) {
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG,
fracLatencyNorm);
}
if (aStats) {
latencyMs -= (double(aStats->resource_upload_time) / 1000000.0);
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
}
Telemetry::Accumulate(
Telemetry::CONTENT_FRAME_TIME_WITHOUT_RESOURCE_UPLOAD,
fracLatencyNorm);
if (aStats) {
latencyMs -= (double(aStats->gpu_cache_upload_time) / 1000000.0);
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
}
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITHOUT_UPLOAD,
fracLatencyNorm);
// Record CONTENT_FRAME_TIME_REASON.
//
// This uses the refresh start time (CONTENT_FRAME_TIME uses the start of
@ -1916,43 +1953,6 @@ TransactionId WebRenderBridgeParent::FlushTransactionIdsForEpoch(
LABELS_CONTENT_FRAME_TIME_REASON::SlowComposite);
}
}
if (fracLatencyNorm > 200) {
aOutputStats->AppendElement(FrameStats(
transactionId.mId, aCompositeStartTime, aRenderStartTime, aEndTime,
fracLatencyNorm,
aStats ? (double(aStats->resource_upload_time) / 1000000.0) : 0.0,
aStats ? (double(aStats->gpu_cache_upload_time) / 1000000.0) : 0.0,
transactionId.mTxnStartTime, transactionId.mRefreshStartTime,
transactionId.mFwdTime, transactionId.mSceneBuiltTime,
transactionId.mSkippedComposites, transactionId.mTxnURL));
}
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
if (fracLatencyNorm > 200) {
wr::RenderThread::Get()->NotifySlowFrame(mApi->GetId());
}
if (transactionId.mContainsSVGGroup) {
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG,
fracLatencyNorm);
}
if (aStats) {
latencyMs -= (double(aStats->resource_upload_time) / 1000000.0);
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
}
Telemetry::Accumulate(
Telemetry::CONTENT_FRAME_TIME_WITHOUT_RESOURCE_UPLOAD,
fracLatencyNorm);
if (aStats) {
latencyMs -= (double(aStats->gpu_cache_upload_time) / 1000000.0);
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
}
Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITHOUT_UPLOAD,
fracLatencyNorm);
}
#if defined(ENABLE_FRAME_LATENCY_LOG)

View File

@ -1541,6 +1541,13 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
MOZ_ASSERT(item && itemType == item->GetType());
}
if (mForEventsAndPluginsOnly &&
(itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
itemType != DisplayItemType::TYPE_PLUGIN)) {
// Only process hit test info items or plugin items.
continue;
}
bool forceNewLayerData = false;
size_t layerCountBeforeRecursing = mLayerScrollData.size();
if (apzEnabled) {
@ -1594,6 +1601,13 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
GP("attempting to enter the grouping code\n");
}
AutoRestore<bool> restoreForEventsAndPluginsOnly(
mForEventsAndPluginsOnly);
if (itemType == DisplayItemType::TYPE_OPACITY &&
static_cast<nsDisplayOpacity*>(item)->ForEventsAndPluginsOnly()) {
mForEventsAndPluginsOnly = true;
}
if (dumpEnabled) {
std::stringstream ss;
nsFrame::PrintDisplayItem(aDisplayListBuilder, item, ss,

View File

@ -42,6 +42,7 @@ class WebRenderCommandBuilder {
mBuilderDumpIndex(0),
mDumpIndent(0),
mDoGrouping(false),
mForEventsAndPluginsOnly(false),
mContainsSVGGroup(false) {}
void Destroy();
@ -199,6 +200,10 @@ class WebRenderCommandBuilder {
// blob image.
bool mDoGrouping;
// True if we're currently within an opacity:0 container, and only
// plugin and hit test items should be considered.
bool mForEventsAndPluginsOnly;
// True if the most recently build display list contained an svg that
// we did grouping for.
bool mContainsSVGGroup;

View File

@ -1 +1 @@
a6700dac955d9fe8fc6e68668969b02c2d803dbf
b5f190951f27dd04067489b9fbbeb87f55765f57

View File

@ -1942,7 +1942,7 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
if *out_is_reference_frame {
let ref_frame_id = state.frame_builder
.dl_builder
.push_reference_frame(&prim_info, transform_binding, perspective);
.push_reference_frame(&prim_info, transform_style, transform_binding, perspective);
*out_reference_frame_id = pack_clip_id(ref_frame_id);
prim_info.rect.origin = LayoutPoint::zero();

View File

@ -18,7 +18,7 @@ metadata:
# instances configured and running.
tasks:
# For the docker-worker tasks, the Docker image used
# (staktrace/webrender-test:debian) was created using the Dockerfile in
# (staktrace/webrender-test:debian-v2) was created using the Dockerfile in
# ci-scripts/docker-image.
#
# The docker image may need to be updated over time if the set of required
@ -44,7 +44,7 @@ tasks:
- master
payload:
maxRunTime: 7200
image: 'staktrace/webrender-test:debian'
image: 'staktrace/webrender-test:debian-v2'
env:
RUST_BACKTRACE: 'full'
RUSTFLAGS: '--deny warnings'
@ -78,7 +78,7 @@ tasks:
- master
payload:
maxRunTime: 7200
image: 'staktrace/webrender-test:debian'
image: 'staktrace/webrender-test:debian-v2'
env:
RUST_BACKTRACE: 'full'
RUSTFLAGS: '--deny warnings'
@ -131,22 +131,13 @@ tasks:
git checkout {{event.head.sha}}
source $HOME/servotidy-venv/bin/activate
servo-tidy
sccache --stop-server || true
mkdir -p ../artifacts
RUST_LOG=sccache=trace SCCACHE_ERROR_LOG=$PWD/../artifacts/sccache.log sccache --start-server
export RUST_BACKTRACE=full
export RUSTFLAGS='--deny warnings'
export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig:$PKG_CONFIG_PATH"
export RUSTC_WRAPPER=sccache
echo 'exec make -j1 "$@"' > $HOME/make # See #2638
chmod +x $HOME/make
export MAKE="$HOME/make"
ci-scripts/macos-release-tests.sh
sccache --stop-server || true
artifacts:
- name: public/sccache.log
path: artifacts/sccache.log
type: file
routes:
- "index.garbage.webrender.ci.{{event.head.user.login}}.{{event.head.repo.branch}}.osx-release"
- metadata:
@ -176,21 +167,12 @@ tasks:
git checkout {{event.head.sha}}
source $HOME/servotidy-venv/bin/activate
servo-tidy
sccache --stop-server || true
mkdir -p ../artifacts
RUST_LOG=sccache=trace SCCACHE_ERROR_LOG=$PWD/../artifacts/sccache.log sccache --start-server
export RUST_BACKTRACE=full
export RUSTFLAGS='--deny warnings'
export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig:$PKG_CONFIG_PATH"
export RUSTC_WRAPPER=sccache
echo 'exec make -j1 "$@"' > $HOME/make # See #2638
chmod +x $HOME/make
export MAKE="$HOME/make"
ci-scripts/macos-debug-tests.sh
sccache --stop-server || true
artifacts:
- name: public/sccache.log
path: artifacts/sccache.log
type: file
routes:
- "index.garbage.webrender.ci.{{event.head.user.login}}.{{event.head.repo.branch}}.osx-debug"

22
gfx/wr/Cargo.lock generated
View File

@ -334,7 +334,7 @@ dependencies = [
name = "direct-composition"
version = "0.1.0"
dependencies = [
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.57.2",
@ -391,7 +391,7 @@ dependencies = [
[[package]]
name = "euclid"
version = "0.19.3"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -728,7 +728,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -953,7 +953,7 @@ dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -968,7 +968,7 @@ name = "pathfinder_gfx_utils"
version = "0.2.0"
source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316"
dependencies = [
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -981,7 +981,7 @@ dependencies = [
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1018,7 +1018,7 @@ version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1575,7 +1575,7 @@ version = "0.1.0"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1594,7 +1594,7 @@ dependencies = [
"core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1674,7 +1674,7 @@ dependencies = [
"crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1803,7 +1803,7 @@ dependencies = [
"checksum dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b46afd0d0bbbea88fc083ea293e40865e26a75ec9d38cf5d05a23ac3e2ffe02"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
"checksum euclid 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "600657e7e5c03bfbccdc68721bc3b5abcb761553973387124eae9c9e4f02c210"
"checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727"
"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"

View File

@ -16,15 +16,5 @@ install:
build: false
test_script:
- cd webrender_api
- cargo test --verbose
- cd ../webrender
- cargo test --verbose
- cargo check --verbose --no-default-features --features pathfinder
- cd ../wrench
- cargo test --verbose
- cargo run --release -- --angle reftest
- cd ../examples
- cargo check --verbose
- cd ../direct-composition
- cargo check --verbose
- cmd.exe /c ci-scripts\windows-tests.cmd
- cmd.exe /c ci-scripts\windows-pathfinder.cmd

View File

@ -14,9 +14,12 @@ test "$(whoami)" == 'root'
# Install stuff we need
apt-get -y update
apt-get install -y \
bzip2 \
cmake \
curl \
gcc \
git \
g++ \
libfontconfig1-dev \
libgl1-mesa-dev \
libx11-dev \
@ -45,4 +48,5 @@ rm -f libfreetype.so.6
ln -s /usr/local/lib/libfreetype.so.6
# Other stuff we need
pip install setuptools
pip install mako voluptuous PyYAML servo-tidy

View File

@ -0,0 +1,14 @@
:: 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/. */
:: This must be run from the root webrender directory!
:: Users may set the CARGOFLAGS environment variable to pass
:: additional flags to cargo if desired.
if NOT DEFINED CARGOFLAGS SET CARGOFLAGS=--verbose
pushd webrender
cargo check %CARGOFLAGS% --no-default-features --features pathfinder
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd

View File

@ -0,0 +1,36 @@
:: 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/. */
:: This must be run from the root webrender directory!
:: Users may set the CARGOFLAGS environment variable to pass
:: additional flags to cargo if desired.
if NOT DEFINED CARGOFLAGS SET CARGOFLAGS=--verbose
pushd webrender_api
cargo test %CARGOFLAGS%
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
pushd webrender
cargo test %CARGOFLAGS%
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
pushd wrench
cargo test --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
cargo run --release -- --angle reftest
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
pushd examples
cargo check --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd
pushd direct-composition
cargo check --verbose
if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
popd

View File

@ -48,6 +48,7 @@ impl App {
let reference_frame_id = builder.push_reference_frame(
&LayoutPrimitiveInfo::new(LayoutRect::new(bounds.origin, LayoutSize::zero())),
TransformStyle::Flat,
Some(PropertyBinding::Binding(property_key, LayoutTransform::identity())),
None,
);

View File

@ -63,6 +63,7 @@ impl Example for App {
let info = LayoutPrimitiveInfo::new(sub_bounds);
let reference_frame_id = builder.push_reference_frame(
&info,
TransformStyle::Flat,
Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
None,
);

View File

@ -1040,7 +1040,7 @@ impl AlphaBatchBuilder {
let key = BatchKey::new(
kind,
non_segmented_blend_mode,
BlendMode::None,
BatchTextures::color(cache_item.texture_id),
);

View File

@ -4,7 +4,7 @@
use api::{ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
use api::{PipelineId, ScrollClamping, ScrollNodeState, ScrollLocation};
use api::{LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
use api::{TransformStyle, LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
use gpu_types::TransformPalette;
use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
@ -343,6 +343,7 @@ impl ClipScrollTree {
pub fn add_reference_frame(
&mut self,
parent_index: Option<SpatialNodeIndex>,
transform_style: TransformStyle,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
@ -350,6 +351,7 @@ impl ClipScrollTree {
) -> SpatialNodeIndex {
let node = SpatialNode::new_reference_frame(
parent_index,
transform_style,
source_transform,
source_perspective,
origin_in_parent_reference_frame,
@ -495,6 +497,7 @@ fn add_reference_frame(
) -> SpatialNodeIndex {
cst.add_reference_frame(
parent,
TransformStyle::Preserve3D,
Some(PropertyBinding::Value(transform)),
None,
origin_in_parent_reference_frame,

View File

@ -590,6 +590,7 @@ impl<'a> DisplayListFlattener<'a> {
Some(clip_and_scroll_ids.scroll_node_id),
clip_and_scroll_ids.clip_node_id,
pipeline_id,
reference_frame.transform_style,
reference_frame.transform,
reference_frame.perspective,
reference_frame_relative_offset + item.rect().origin.to_vector(),
@ -676,6 +677,7 @@ impl<'a> DisplayListFlattener<'a> {
Some(info.clip_id),
None,
iframe_pipeline_id,
TransformStyle::Flat,
None,
None,
origin,
@ -1568,6 +1570,7 @@ impl<'a> DisplayListFlattener<'a> {
parent_scroll_id: Option<ClipId>,
parent_clip_id: Option<ClipId>,
pipeline_id: PipelineId,
transform_style: TransformStyle,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
@ -1575,6 +1578,7 @@ impl<'a> DisplayListFlattener<'a> {
let parent_index = parent_scroll_id.map(|id| self.id_to_index_mapper.get_spatial_node_index(id));
let index = self.clip_scroll_tree.add_reference_frame(
parent_index,
transform_style,
source_transform,
source_perspective,
origin_in_parent_reference_frame,
@ -1606,6 +1610,7 @@ impl<'a> DisplayListFlattener<'a> {
None,
None,
pipeline_id,
TransformStyle::Flat,
None,
None,
LayoutVector2D::zero(),

View File

@ -2189,11 +2189,15 @@ impl PicturePrimitive {
match tile_cache.dirty_region {
Some(ref dirty_region) => {
// Texture cache descriptor for each tile.
// TODO(gw): If / when we start to use tile caches with
// clip masks and/or transparent backgrounds,
// we will need to correctly select an opacity
// here and a blend mode in batch.rs.
let descriptor = ImageDescriptor::new(
TILE_SIZE_DP,
TILE_SIZE_DP,
ImageFormat::BGRA8,
false, // TODO(gw): Detect when background color is opaque!
true,
false,
);

View File

@ -5,7 +5,7 @@
use api::{ExternalScrollId, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollLocation};
use api::{ScrollSensitivity, StickyOffsetBounds};
use api::{TransformStyle, ScrollSensitivity, StickyOffsetBounds};
use clip_scroll_tree::{CoordinateSystem, CoordinateSystemId, SpatialNodeIndex, TransformUpdateState};
use euclid::SideOffsets2D;
use gpu_types::TransformPalette;
@ -115,6 +115,7 @@ impl SpatialNode {
pub fn new_reference_frame(
parent_index: Option<SpatialNodeIndex>,
transform_style: TransformStyle,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
@ -124,6 +125,7 @@ impl SpatialNode {
let source_perspective = source_perspective.map_or_else(
LayoutFastTransform::identity, |perspective| perspective.into());
let info = ReferenceFrameInfo {
transform_style,
source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)),
source_perspective,
origin_in_parent_reference_frame,
@ -256,6 +258,7 @@ impl SpatialNode {
SpatialNodeType::ReferenceFrame(ref mut info) => {
// Resolve the transform against any property bindings.
let source_transform = scene_properties.resolve_layout_transform(&info.source_transform);
// Do a change-basis operation on the perspective matrix using
// the scroll offset.
let scrolled_perspective = info.source_perspective
@ -274,6 +277,7 @@ impl SpatialNode {
.post_translate(state.parent_accumulated_scroll_offset)
.to_transform()
.with_destination::<LayoutPixel>();
self.world_viewport_transform =
state.parent_reference_frame_transform.pre_mul(&relative_transform.into());
self.world_content_transform = self.world_viewport_transform;
@ -485,6 +489,15 @@ impl SpatialNode {
}
SpatialNodeType::ReferenceFrame(ref info) => {
state.parent_reference_frame_transform = self.world_viewport_transform;
let should_flatten =
info.transform_style == TransformStyle::Flat &&
info.source_perspective.is_identity();
if should_flatten {
state.parent_reference_frame_transform = state.parent_reference_frame_transform.project_to_2d();
}
state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
state.coordinate_system_relative_scale_offset = self.coordinate_system_relative_scale_offset;
let translation = -info.origin_in_parent_reference_frame;
@ -644,6 +657,7 @@ pub struct ReferenceFrameInfo {
/// here so that we can resolve the animated transform and update the tree each
/// frame.
pub source_transform: PropertyBinding<LayoutTransform>,
pub transform_style: TransformStyle,
pub source_perspective: LayoutFastTransform,
/// The original, not including the transform and relative to the parent reference frame,

View File

@ -556,7 +556,7 @@ impl<U> MaxRect for TypedRect<f32, U> {
/// An enum that tries to avoid expensive transformation matrix calculations
/// when possible when dealing with non-perspective axis-aligned transformations.
#[derive(Debug, Clone, Copy)]
#[derive(Debug)]
pub enum FastTransform<Src, Dst> {
/// A simple offset, which can be used without doing any matrix math.
Offset(TypedVector2D<f32, Src>),
@ -569,6 +569,14 @@ pub enum FastTransform<Src, Dst> {
},
}
impl<Src, Dst> Clone for FastTransform<Src, Dst> {
fn clone(&self) -> Self {
*self
}
}
impl<Src, Dst> Copy for FastTransform<Src, Dst> { }
impl<Src, Dst> FastTransform<Src, Dst> {
pub fn identity() -> Self {
FastTransform::Offset(TypedVector2D::zero())
@ -651,6 +659,14 @@ impl<Src, Dst> FastTransform<Src, Dst> {
}
}
#[inline(always)]
pub fn project_to_2d(&self) -> Self {
match *self {
FastTransform::Offset(..) => self.clone(),
FastTransform::Transform { ref transform, .. } => FastTransform::with_transform(transform.project_to_2d()),
}
}
#[inline(always)]
pub fn is_backface_visible(&self) -> bool {
match *self {

View File

@ -529,6 +529,7 @@ pub struct CacheMarkerDisplayItem {
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ReferenceFrame {
pub transform_style: TransformStyle,
pub transform: Option<PropertyBinding<LayoutTransform>>,
pub perspective: Option<LayoutTransform>,
pub id: ClipId,

View File

@ -1250,12 +1250,14 @@ impl DisplayListBuilder {
pub fn push_reference_frame(
&mut self,
info: &LayoutPrimitiveInfo,
transform_style: TransformStyle,
transform: Option<PropertyBinding<LayoutTransform>>,
perspective: Option<LayoutTransform>,
) -> ClipId {
let id = self.generate_spatial_index();
let item = SpecificDisplayItem::PushReferenceFrame(PushReferenceFrameDisplayListItem {
reference_frame: ReferenceFrame {
transform_style,
transform,
perspective,
id,

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,27 @@
# This is the same as nested-rotate-x.yaml but without the preserve-3d.
---
root:
items:
-
bounds: [260, 260, 231, 231]
"clip-rect": [260, 260, 231, 231]
type: border
width: 3
"border-type": normal
color: 0 0 255 1.0000
style: dashed
-
bounds: [300, 300, 0, 0]
"clip-rect": [300, 300, 0, 0]
type: "stacking-context"
transform: [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 75, -75, 1]
items:
-
type: "stacking-context"
transform: [1, 0, 0, 0, 0, 0.8660254, -0.5, 0, 0, 0.5, 0.8660254, 0, 0, 10.048096, 37.5, 1]
items:
-
bounds: [0, 0, 150, 150]
"clip-rect": [0, 0, 150, 150]
type: rect
color: 255 255 0 0.4000

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -14,6 +14,7 @@ root:
"clip-rect": [300, 300, 0, 0]
type: "stacking-context"
transform: [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 75, -75, 1]
transform-style: preserve-3d
items:
-
type: "stacking-context"

View File

@ -17,6 +17,8 @@ platform(linux,mac) color_targets(2) alpha_targets(0) fuzzy(1,180) == screen-spa
platform(linux,mac) fuzzy(1,331) color_targets(1) alpha_targets(0) == screen-space-blit-trivial.yaml screen-space-blit-trivial.png
platform(linux) fuzzy(11,4592) == screen-space-blur.yaml screen-space-blur.png
platform(linux,mac) == nested-rotate-x.yaml nested-rotate-x.png
platform(linux,mac) != nested-rotate-x.yaml nested-rotate-x-flat.yaml
platform(linux,mac) == nested-rotate-x-flat.yaml nested-rotate-x-flat.png
platform(linux,mac) == nested-preserve-3d.yaml nested-preserve-3d.png
platform(linux,mac) fuzzy(1,283) == near-plane-clip.yaml near-plane-clip.png
platform(linux,mac) == perspective-mask.yaml perspective-mask.png

View File

@ -1555,6 +1555,10 @@ impl YamlFrameReader {
info.rect = bounds;
let transform_style = yaml["transform-style"]
.as_transform_style()
.unwrap_or(TransformStyle::Flat);
let transform_origin = yaml["transform-origin"]
.as_point()
.unwrap_or(default_transform_origin);
@ -1575,7 +1579,12 @@ impl YamlFrameReader {
_ => yaml["perspective"].as_matrix4d(),
};
let reference_frame_id = dl.push_reference_frame(info, transform.into(), perspective);
let reference_frame_id = dl.push_reference_frame(
info,
transform_style,
transform.into(),
perspective,
);
let numeric_id = yaml["id"].as_i64();
if let Some(numeric_id) = numeric_id {

Some files were not shown because too many files have changed in this diff Show More