mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Merge mozilla-central to mozilla-inbound.
This commit is contained in:
commit
7a9da4ebbf
@ -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/**
|
||||
|
@ -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
24
Cargo.lock
generated
@ -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"
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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 => {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
});
|
@ -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();
|
||||
});
|
||||
|
@ -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,
|
||||
});
|
||||
|
||||
|
@ -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();
|
||||
});
|
@ -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);
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
@ -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};
|
||||
}
|
||||
|
@ -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 = [];
|
||||
|
@ -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() {
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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",
|
||||
},
|
||||
];
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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" };
|
||||
|
@ -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"));
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -27,8 +27,7 @@ SimpleTest.waitForExplicitFinish();
|
||||
*/
|
||||
|
||||
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>
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ let textTests = {
|
||||
"foob": "Zm9vYg",
|
||||
"fooba": "Zm9vYmE",
|
||||
"foobar": "Zm9vYmFy",
|
||||
}
|
||||
};
|
||||
|
||||
// Examples from RFC 4648, section 9.
|
||||
let binaryTests = [{
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
function run_test()
|
||||
{
|
||||
function run_test() {
|
||||
|
||||
test_getElementsByTagName();
|
||||
test_getElementsByTagNameNS();
|
||||
@ -12,14 +11,13 @@ function run_test()
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -102,10 +99,10 @@ function test_getElementsByTagNameNS()
|
||||
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.
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
@ -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");
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -41,6 +41,6 @@ function run_test() {
|
||||
|
||||
xhr2.onload = function() {
|
||||
server.stop(do_test_finished);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
@ -43,6 +43,6 @@ function test5() {
|
||||
function test6() {
|
||||
var doc = ParseXML("<root xmlns='ns1'/>");
|
||||
Assert.notEqual(doc.documentElement.namespaceURI, null);
|
||||
Assert.equal(doc.documentElement.namespaceURI, 'ns1');
|
||||
Assert.equal(doc.documentElement.namespaceURI, "ns1");
|
||||
return true;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -1630,10 +1630,6 @@ void HTMLMediaElement::SetVisible(bool aVisible) {
|
||||
}
|
||||
}
|
||||
|
||||
bool HTMLMediaElement::IsVideoDecodingSuspended() const {
|
||||
return mDecoder && mDecoder->IsVideoDecodingSuspended();
|
||||
}
|
||||
|
||||
already_AddRefed<layers::Image> HTMLMediaElement::GetCurrentImage() {
|
||||
MarkAsTainted();
|
||||
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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!
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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(
|
||||
|
@ -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>
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -1 +1 @@
|
||||
a6700dac955d9fe8fc6e68668969b02c2d803dbf
|
||||
b5f190951f27dd04067489b9fbbeb87f55765f57
|
||||
|
@ -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();
|
||||
|
@ -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
22
gfx/wr/Cargo.lock
generated
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
14
gfx/wr/ci-scripts/windows-pathfinder.cmd
Executable file
14
gfx/wr/ci-scripts/windows-pathfinder.cmd
Executable 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
|
36
gfx/wr/ci-scripts/windows-tests.cmd
Executable file
36
gfx/wr/ci-scripts/windows-tests.cmd
Executable 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
|
@ -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,
|
||||
);
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -1040,7 +1040,7 @@ impl AlphaBatchBuilder {
|
||||
|
||||
let key = BatchKey::new(
|
||||
kind,
|
||||
non_segmented_blend_mode,
|
||||
BlendMode::None,
|
||||
BatchTextures::color(cache_item.texture_id),
|
||||
);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
BIN
gfx/wr/wrench/reftests/transforms/nested-rotate-x-flat.png
Normal file
BIN
gfx/wr/wrench/reftests/transforms/nested-rotate-x-flat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
27
gfx/wr/wrench/reftests/transforms/nested-rotate-x-flat.yaml
Normal file
27
gfx/wr/wrench/reftests/transforms/nested-rotate-x-flat.yaml
Normal 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 |
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user